linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/19] Delayed Attributes
@ 2019-09-05 22:18 Allison Collins
  2019-09-05 22:18 ` [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
                   ` (19 more replies)
  0 siblings, 20 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

Hi all,

This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
parent pointers which can be used in a number of optimizations.  Since
delayed attributes can be implemented as a stand alone feature, I've
decided to subdivide the set to help make it more manageable.  Delayed
attributes may also provide the infastructure to later break up large
attributes into smaller transactions instead of one large bwrite.

Changes since v2:
Mostly review updates collected since v2.  Patch 17 is new and adds a
new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
renames have been simplified into separate remove and set opertaions
which removes the need for the INCOMPLETE state used in non delayed
operations

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: Add delayed attribute routines
  xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
  xfs: Enable delayed attributes

Allison Henderson (4):
  xfs: Add xfs_has_attr and subroutines
  xfs: Set up infastructure for deferred attribute operations
  xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  xfs_io: Add delayed attributes error tag

 fs/xfs/Makefile                 |    2 +-
 fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
 fs/xfs/libxfs/xfs_attr.h        |   53 +-
 fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
 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    |    8 +-
 fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
 fs/xfs/libxfs/xfs_defer.c       |    1 +
 fs/xfs/libxfs/xfs_defer.h       |    3 +
 fs/xfs/libxfs/xfs_dir2.c        |   22 +-
 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/libxfs/xfs_errortag.h    |    4 +-
 fs/xfs/libxfs/xfs_format.h      |   11 +-
 fs/xfs/libxfs/xfs_fs.h          |    1 +
 fs/xfs/libxfs/xfs_log_format.h  |   44 +-
 fs/xfs/libxfs/xfs_sb.c          |    2 +
 fs/xfs/libxfs/xfs_types.h       |    1 +
 fs/xfs/scrub/attr.c             |   12 +-
 fs/xfs/scrub/common.c           |    2 +
 fs/xfs/xfs_acl.c                |   29 +-
 fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h          |   88 ++++
 fs/xfs/xfs_attr_list.c          |    1 +
 fs/xfs/xfs_error.c              |    3 +
 fs/xfs/xfs_ioctl.c              |   30 +-
 fs/xfs/xfs_ioctl32.c            |    2 +
 fs/xfs/xfs_iops.c               |   14 +-
 fs/xfs/xfs_log.c                |    4 +
 fs/xfs/xfs_log_recover.c        |  173 +++++++
 fs/xfs/xfs_ondisk.h             |    2 +
 fs/xfs/xfs_super.c              |    4 +
 fs/xfs/xfs_trace.h              |   20 +-
 fs/xfs/xfs_trans.h              |    1 -
 fs/xfs/xfs_xattr.c              |   31 +-
 39 files changed, 2509 insertions(+), 359 deletions(-)
 create mode 100644 fs/xfs/xfs_attr_item.c
 create mode 100644 fs/xfs/xfs_attr_item.h

-- 
2.7.4


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

* [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-18 16:43   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
 fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
 fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
 fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
 fs/xfs/xfs_iops.c        | 12 ++++++++----
 fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
 6 files changed, 80 insertions(+), 75 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7589cb7..d0308d6 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -61,9 +61,7 @@ STATIC int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
-	int			flags)
+	struct xfs_name		*name)
 {
 
 	if (!name)
@@ -73,9 +71,9 @@ 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;
-	args->namelen = namelen;
+	args->flags = name->type;
+	args->name = name->name;
+	args->namelen = name->len;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -139,30 +137,28 @@ 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)
+	int			*valuelenp)
 {
 	struct xfs_da_args	args;
 	uint			lock_mode;
 	int			error;
 
-	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
+	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
 
 	XFS_STATS_INC(ip->i_mount, xs_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);
 	if (error)
 		return error;
 
 	/* Entirely possible to look up a name which doesn't exist */
 	args.op_flags = XFS_DA_OP_OKNOENT;
-	if (flags & ATTR_ALLOC)
+	if (name->type & ATTR_ALLOC)
 		args.op_flags |= XFS_DA_OP_ALLOCVAL;
 	else
 		args.value = *value;
@@ -175,7 +171,7 @@ xfs_attr_get(
 
 	/* on error, we have to clean up allocated value buffers */
 	if (error) {
-		if (flags & ATTR_ALLOC) {
+		if (name->type & ATTR_ALLOC) {
 			kmem_free(args.value);
 			*value = NULL;
 		}
@@ -339,16 +335,14 @@ 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)
+	int			valuelen)
 {
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_da_args	args;
 	struct xfs_trans_res	tres;
-	int			rsvd = (flags & ATTR_ROOT) != 0;
+	int			rsvd = (name->type & ATTR_ROOT) != 0;
 	int			error, local;
 
 	XFS_STATS_INC(mp, xs_attr_set);
@@ -356,7 +350,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);
 	if (error)
 		return error;
 
@@ -419,7 +413,7 @@ xfs_attr_set(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args.trans);
 
-	if ((flags & ATTR_KERNOTIME) == 0)
+	if ((name->type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 
 	/*
@@ -444,9 +438,7 @@ xfs_attr_set(
 int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
-	int			flags)
+	struct xfs_name		*name)
 {
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_da_args	args;
@@ -457,7 +449,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);
 	if (error)
 		return error;
 
@@ -478,7 +470,7 @@ xfs_attr_remove(
 	 */
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
 			XFS_ATTRRM_SPACE_RES(mp), 0,
-			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
+			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
 			&args.trans);
 	if (error)
 		return error;
@@ -501,7 +493,7 @@ xfs_attr_remove(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args.trans);
 
-	if ((flags & ATTR_KERNOTIME) == 0)
+	if ((name->type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 
 	/*
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
+		 unsigned char *value, int valuelen);
 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 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..f8fb6e10 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);
+	name.type = ATTR_ALLOC | ATTR_ROOT;
+	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
 	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);
+		name.type = ATTR_ROOT;
+		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
 
 		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);
 
 		/*
 		 * 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 d440426..626420d 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
-	size_t			namelen;
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+		.type		= flags,
+	};
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -439,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);
 	if (error)
 		goto out_kfree;
 
@@ -463,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;
@@ -474,8 +476,10 @@ 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);
+	xname.type = flags;
+	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+		.type		= flags,
+	};
 
 	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);
 	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 92de0a7..469e8e2 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -49,10 +49,14 @@ 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,
-				     ATTR_SECURE);
+		struct xfs_name	name = {
+			.name	= xattr->name,
+			.len	= strlen(xattr->name),
+			.type	= ATTR_SECURE,
+		};
+
+		error = xfs_attr_set(ip, &name,
+				     xattr->value, xattr->value_len);
 		if (error < 0)
 			break;
 	}
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 59ffe6c..6309da4 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -20,19 +20,21 @@ 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);
+	struct xfs_name xname = {
+		.name	= name,
+		.len	= strlen(name),
+		.type	= handler->flags
+	};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
-		xflags |= ATTR_KERNOVAL;
+		xname.type |= ATTR_KERNOVAL;
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
-			     &asize, xflags);
+	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
 	if (error)
 		return error;
 	return asize;
@@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		struct inode *inode, const char *name, const void *value,
 		size_t size, int flags)
 {
-	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),
+		.type		= handler->flags,
+	};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
-		xflags |= ATTR_CREATE;
+		xname.type |= ATTR_CREATE;
 	if (flags & XATTR_REPLACE)
-		xflags |= ATTR_REPLACE;
+		xname.type |= 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);
+	error = xfs_attr_set(ip, &xname, (void *)value, size);
 	if (!error)
-		xfs_forget_acl(inode, name, xflags);
+		xfs_forget_acl(inode, name, xname.type);
 
 	return error;
 }
-- 
2.7.4


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

* [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
  2019-09-05 22:18 ` [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-18 16:44   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 03/19] xfs: Add xfs_dabuf defines Allison Collins
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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>
---
 fs/xfs/libxfs/xfs_attr.c        |  34 ++++++-------
 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        |  22 ++++-----
 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, 130 insertions(+), 125 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index d0308d6..50e099f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -71,13 +71,13 @@ xfs_attr_args_init(
 	args->geo = dp->i_mount->m_attr_geo;
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
-	args->flags = name->type;
-	args->name = name->name;
-	args->namelen = name->len;
-	if (args->namelen >= MAXNAMELEN)
+	args->name.type = name->type;
+	args->name.name = name->name;
+	args->name.len = name->len;
+	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;
 }
 
@@ -234,7 +234,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)
@@ -369,7 +369,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)
@@ -528,10 +528,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)
@@ -541,15 +541,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)
@@ -594,11 +594,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;
 		}
@@ -868,10 +868,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);
@@ -1003,7 +1003,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 b9f0196..07ce320 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -402,7 +402,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;
 	}
@@ -615,27 +615,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);
@@ -685,11 +685,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;
 	}
@@ -752,11 +752,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;
 	}
@@ -783,13 +783,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;
@@ -863,13 +863,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);
@@ -1070,12 +1070,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;
@@ -1403,7 +1403,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) &&
@@ -1427,15 +1427,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;
@@ -2348,29 +2349,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);
@@ -2412,16 +2415,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,
@@ -2637,7 +2641,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;
@@ -2645,7 +2649,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);
 }
 
 
@@ -2699,8 +2703,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..e8d6721 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,8 @@ xfs_dir_createname(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	args->name.name = name->name;
+	args->name.len = name->len;
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->inumber = inum;
@@ -355,8 +355,8 @@ 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;
+	args->name.name = name->name;
+	args->name.len = name->len;
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->dp = dp;
@@ -427,8 +427,8 @@ xfs_dir_removename(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	args->name.name = name->name;
+	args->name.len = name->len;
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->inumber = ino;
@@ -488,8 +488,8 @@ xfs_dir_replace(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	args->name.name = name->name;
+	args->name.len = name->len;
 	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 9595ced..94269b9 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 85f14fc..fdc1431 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 eaae275..e0f524d 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1669,7 +1669,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)
@@ -1678,9 +1678,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;
@@ -1733,7 +1734,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)
@@ -1743,12 +1744,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] 64+ messages in thread

* [PATCH v3 03/19] xfs: Add xfs_dabuf defines
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
  2019-09-05 22:18 ` [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
  2019-09-05 22:18 ` [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-06  3:37   ` Darrick J. Wong
  2019-09-05 22:18 ` [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines Allison Collins
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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_leaf.h | 3 +++
 fs/xfs/libxfs/xfs_da_btree.c  | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 7b74e18..536a290 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..2b94685 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -2534,7 +2534,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.
 		 */
-- 
2.7.4


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

* [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (2 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 03/19] xfs: Add xfs_dabuf defines Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-19 17:47   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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 Henderson <allison.henderson@oracle.com>
Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 150 +++++++++++++++++++++++++++---------------
 fs/xfs/libxfs/xfs_attr.h      |   1 +
 fs/xfs/libxfs/xfs_attr_leaf.c |  92 +++++++++++++++++---------
 fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
 4 files changed, 161 insertions(+), 84 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 50e099f..a297857 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_leaf_has_attr(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);
 
@@ -309,6 +312,32 @@ 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_shortform_has_attr(args, NULL, NULL);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_leaf_has_attr(args, &bp);
+		xfs_trans_brelse(args->trans, bp);
+	} else {
+		error = xfs_attr_node_hasname(args, NULL);
+	}
+
+	return error;
+}
+
+/*
  * Remove the attribute specified in @args.
  */
 int
@@ -574,26 +603,17 @@ 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, -1, &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_leaf_has_attr(args, &bp);
 	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
@@ -745,6 +765,25 @@ xfs_attr_leaf_addname(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+STATIC int
+xfs_leaf_has_attr(
+	struct xfs_da_args      *args,
+	struct xfs_buf		**bp)
+{
+	int                     error = 0;
+
+	args->blkno = 0;
+	error = xfs_attr3_leaf_read(args->trans, args->dp,
+			args->blkno, 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
@@ -764,12 +803,8 @@ xfs_attr_leaf_removename(
 	 * Remove the attribute.
 	 */
 	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
-	if (error)
-		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
+	error = xfs_leaf_has_attr(args, &bp);
 	if (error == -ENOATTR) {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -808,12 +843,7 @@ 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);
-	if (error)
-		return error;
-
-	error = xfs_attr3_leaf_lookup_int(bp, args);
+	error = xfs_leaf_has_attr(args, &bp);
 	if (error != -EEXIST)  {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -823,6 +853,43 @@ 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;
+	struct xfs_inode	*dp;
+	int			retval, error;
+
+	/*
+	 * 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 == 0)
+		error = retval;
+
+	if (statep != NULL)
+		*statep = state;
+	else
+		xfs_da_state_free(state);
+
+	return error;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
@@ -855,17 +922,14 @@ 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)
+	error = xfs_attr_node_hasname(args, &state);
+	if (error == -EEXIST)
 		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)) {
@@ -1070,29 +1134,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.
@@ -1314,20 +1364,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 cedb4e2..fb56d81 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 xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
+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 07ce320..a501538 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -590,6 +590,53 @@ 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
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ *	  list
+ */
+int
+xfs_shortform_has_attr(
+	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.
  */
@@ -598,7 +645,7 @@ 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;
+	int offset, size, error;
 	xfs_mount_t *mp;
 	xfs_inode_t *dp;
 	struct xfs_ifork *ifp;
@@ -612,18 +659,10 @@ 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++) {
+	error = xfs_shortform_has_attr(args, &sfe, NULL);
 #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);
+	ASSERT(error != -EEXIST);
 #endif
-	}
 
 	offset = (char *)sfe - (char *)sf;
 	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
@@ -668,33 +707,24 @@ 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_shortform_has_attr(args, &sfe, &base);
+	if (error == -ENOATTR)
+		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 536a290..58e9327 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_shortform_has_attr(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] 64+ messages in thread

* [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (3 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:49   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 72 +++++++++++++++++++++++++++++++----------
 fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
 2 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index db9247a..080a284 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,57 @@ xfs_attr_rmtval_set(
 			return error;
 	}
 
+	error = xfs_attr_rmtval_set_value(args);
+	return error;
+}
+
+
+/*
+ * 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 = args->rmtblkno;
+
+	/*
+	 * 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] 64+ messages in thread

* [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (4 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:49   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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>
---
 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 a297857..7a6dd37 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -710,6 +710,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
@@ -1046,6 +1053,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 a501538..3903e5c 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2919,10 +2919,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] 64+ messages in thread

* [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (5 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:49   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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 | 43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7a6dd37..f27e2c6 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -593,19 +593,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;
+	int			retval, error;
 
 	trace_xfs_attr_leaf_addname(args);
 
@@ -650,13 +643,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.
 		 */
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
+	}
+	return retval;
+}
+
+
+/*
+ * 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			retval, error, forkoff;
+	struct xfs_buf		*bp = NULL;
+	struct xfs_inode	*dp = args->dp;
+
+	retval = xfs_attr_leaf_try_add(args, bp);
+	if (retval == -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;
-- 
2.7.4


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

* [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (6 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:50   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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 | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index f27e2c6..318c543 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -227,7 +227,7 @@ xfs_attr_try_sf_addname(
 {
 
 	struct xfs_mount	*mp = dp->i_mount;
-	int			error, error2;
+	int			error;
 
 	error = xfs_attr_shortform_addname(args);
 	if (error == -ENOSPC)
@@ -243,9 +243,7 @@ xfs_attr_try_sf_addname(
 	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;
 }
 
 /*
@@ -257,7 +255,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,
@@ -277,8 +275,11 @@ 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) {
+			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] 64+ messages in thread

* [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (7 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:50   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions Allison Collins
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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>
---
 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 318c543..5e5b688 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1199,6 +1199,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 3903e5c..bcd86c3 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2801,10 +2801,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] 64+ messages in thread

* [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (8 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:50   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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 | 84 +++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
 2 files changed, 86 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index bcd86c3..79650c9 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2757,6 +2757,36 @@ xfs_attr3_leaf_clearflag(
 }
 
 /*
+ * Check if the INCOMPLETE flag on an entry in a leaf block is set.
+ */
+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;
+
+	trace_xfs_attr_leaf_setflag(args);
+
+	/*
+	 * Set up the operation.
+	 */
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);
+	if (error)
+		return error;
+
+	leaf = bp->b_addr;
+	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
+
+	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
+	return 0;
+}
+
+/*
  * Set the INCOMPLETE flag on an entry in a leaf block.
  */
 int
@@ -2918,3 +2948,57 @@ 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.
+ *
+ * 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;
+
+	trace_xfs_attr_leaf_flipflags(args);
+
+	/*
+	 * Read the block containing the "old" attr
+	 */
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &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));
+
+	return 0;
+}
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 58e9327..d82229b 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] 64+ messages in thread

* [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (9 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:51   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 29 +++++++++++++++++++++--------
 fs/xfs/libxfs/xfs_attr_remote.h |  1 +
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 080a284..1b13795 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -589,21 +589,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.
@@ -645,7 +638,27 @@ 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.
 	 */
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] 64+ messages in thread

* [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (10 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:51   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 13/19] xfs: Add delay context to xfs_da_args Allison Collins
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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      | 14 ++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5e5b688..781dd8a 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -783,6 +783,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
+
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	return error;
 }
@@ -1140,6 +1146,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 79650c9..786b851 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2750,10 +2750,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] 64+ messages in thread

* [PATCH v3 13/19] xfs: Add delay context to xfs_da_args
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (11 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 13:51   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 14/19] xfs: Add delayed attribute routines Allison Collins
                   ` (6 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 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 flags member 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 | 23 +++++++++++++++++++++++
 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, 35 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index bed4f40..ebe1295 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -42,6 +42,28 @@ enum xfs_dacmp {
 	XFS_CMP_CASE		/* names are same but differ in case */
 };
 
+#define		XFS_DC_INIT		0x01 /* Init delay info */
+#define		XFS_DC_FOUND_LBLK	0x02 /* We found leaf blk for attr */
+#define		XFS_DC_FOUND_NBLK	0x04 /* We found node blk for attr */
+#define		XFS_DC_ALLOC_LEAF	0x08 /* We are allocating leaf blocks */
+#define		XFS_DC_ALLOC_NODE	0x10 /* We are allocating node blocks */
+#define		XFS_DC_RM_LEAF_BLKS	0x20 /* We are removing leaf blocks */
+#define		XFS_DC_RM_NODE_BLKS	0x40 /* We are removing node blocks */
+
+/*
+ * Context used for keeping track of delayed attribute operations
+ */
+struct xfs_delay_context {
+	unsigned int		flags;
+	struct xfs_buf		*leaf_bp;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	xfs_fileoff_t		lfileoff;
+	int			blkcnt;
+	struct xfs_da_state	*state;
+	struct xfs_da_state_blk *blk;
+};
+
 /*
  * Structure to ease passing around component names.
  */
@@ -69,6 +91,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 f8fb6e10..4e85b38 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 00758fd..467c53c 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 626420d..2cabdc2 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 1e08bf7..7153780 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 469e8e2..57de5f1 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 6309da4..470e605 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] 64+ messages in thread

* [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (12 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 13/19] xfs: Add delay context to xfs_da_args Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-20 15:28   ` Brian Foster
  2019-09-05 22:18 ` [PATCH v3 15/19] xfs: Set up infastructure for deferred attribute operations Allison Collins
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

This patch adds new delayed attribute routines:

xfs_attr_set_later
xfs_attr_remove_later
xfs_leaf_addname_later
xfs_node_addname_later
xfs_node_removename_later

These routines are similar to their existing counter parts,
but they do not roll or commit transactions.  They instead
return -EAGAIN to allow the calling function to roll the
transaction and recall the function.  This allows the
attribute operations to be logged in multiple smaller
transactions.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 781dd8a..310f5b2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -45,6 +45,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_leaf_addname_later(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp);
 
@@ -53,12 +54,14 @@ STATIC int xfs_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp);
  */
 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_node_addname_later(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_node_removename_later(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);
-
+STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
 
 STATIC int
 xfs_attr_args_init(
@@ -313,6 +316,112 @@ xfs_attr_set_args(
 }
 
 /*
+ * Set 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_set_later(
+	struct xfs_da_args	*args,
+	struct xfs_buf          **leaf_bp)
+{
+	struct xfs_inode	*dp = args->dp;
+	int			error = 0;
+	int			sf_size;
+
+	/*
+	 * 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,
+	 * upgrade it to a single-leaf-block attribute list.
+	 */
+	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+	     dp->i_d.di_anextents == 0)) {
+		/*
+		 * Build initial attribute list (if required).
+		 */
+		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+			xfs_attr_shortform_create(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;
+
+		/*
+		 * 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);
+		if (error)
+			return error;
+
+		/*
+		 * 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.
+		 */
+
+		xfs_trans_bhold(args->trans, *leaf_bp);
+		return -EAGAIN;
+	}
+
+	/*
+	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
+	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
+	 * that it is not done yet, and need to be recalled to finish up from
+	 * the last EAGAIN it returned
+	 */
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
+	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
+		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
+			error = xfs_attr_leaf_try_add(args, *leaf_bp);
+			args->dc.flags |= XFS_DC_FOUND_LBLK;
+
+			if (error && error != -ENOSPC)
+				return error;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_leaf_addname_later(args);
+		if (error && error != -ENOSPC)
+			return error;
+	} else {
+		error = xfs_node_addname_later(args);
+	}
+
+	return error;
+}
+
+
+
+/*
  * Return EEXIST if attr is found, or ENOATTR if not
  */
 int
@@ -362,6 +471,57 @@ xfs_attr_remove_args(
 	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;
+	struct xfs_buf		*bp;
+	int			forkoff, error = 0;
+
+	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_remove(args);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
+		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
+		/*
+		 * If we fit in a block AND we are not in the middle of
+		 * removing node blocks, remove the leaf attribute.
+		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
+		 * signal that it is not done yet, and needs to be recalled to
+		 * to finish up from the last -EAGAIN
+		 */
+		error = xfs_leaf_has_attr(args, &bp);
+		if (error == -ENOATTR) {
+			xfs_trans_brelse(args->trans, bp);
+			return error;
+		}
+		error = 0;
+
+		xfs_attr3_leaf_remove(bp, args);
+
+		/* If the result is small enough, shrink it into the inode.*/
+		forkoff = xfs_attr_shortform_allfit(bp, dp);
+		if (forkoff)
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+	} else {
+		error = xfs_node_removename_later(args);
+	}
+
+	return error;
+}
+
+
+
 int
 xfs_attr_set(
 	struct xfs_inode	*dp,
@@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
+ *
+ * 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.
+ */
+STATIC int
+xfs_leaf_addname_later(
+	struct xfs_da_args	*args)
+{
+	int			error, nmap;
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_bmbt_irec	*map = &args->dc.map;
+
+	/*
+	 * If there was an out-of-line value, allocate the blocks we
+	 * identified for its storage and copy the value.  This is done
+	 * after we create the attribute so that we don't overflow the
+	 * maximum size of a transaction and/or hit a deadlock.
+	 */
+	if (args->rmtblkno > 0) {
+		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
+			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));
+
+			error = xfs_attr_rmt_find_hole(args);
+			if (error)
+				return error;
+
+			args->dc.blkcnt = args->rmtblkcnt;
+			args->dc.lblkno = args->rmtblkno;
+			args->dc.flags |= XFS_DC_ALLOC_LEAF;
+		}
+
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+		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));
+
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
+		if (error)
+			return error;
+	}
+
+	if (args->rmtblkno > 0) {
+		/*
+		 * Added a "remote" value, just clear the incomplete flag.
+		 */
+		error = xfs_attr3_leaf_clearflag(args);
+	}
+	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
+	return error;
+}
+
+/*
  * Return EEXIST if attr is found, or ENOATTR if not
  */
 STATIC int
@@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
 }
 
 /*
+ * Remove a name from a B-tree attribute list.
+ *
+ * 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
+ * -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.
+ */
+STATIC int
+xfs_node_removename_later(
+	struct xfs_da_args	*args)
+{
+	struct xfs_da_state	*state = NULL;
+	struct xfs_da_state_blk	*blk;
+	struct xfs_buf		*bp;
+	int			error, forkoff, retval = 0;
+	struct xfs_inode	*dp = args->dp;
+	int			done = 0;
+
+	trace_xfs_attr_node_removename(args);
+
+	if (args->dc.state == NULL) {
+		error = xfs_attr_node_hasname(args, &args->dc.state);
+		if (error != -EEXIST)
+			goto out;
+		else
+			error = 0;
+
+		/*
+		 * If there is an out-of-line value, de-allocate the blocks.
+		 * This is done before we remove the attribute so that we don't
+		 * overflow the maximum size of a transaction and/or hit a
+		 * deadlock.
+		 */
+		state = args->dc.state;
+		args->dc.blk = &state->path.blk[state->path.active - 1];
+		ASSERT(args->dc.blk->bp != NULL);
+		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
+	}
+	state = args->dc.state;
+	blk = args->dc.blk;
+
+	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
+		bool isset;
+
+		error = xfs_attr3_leaf_flag_is_set(args, &isset);
+		if (error)
+			goto out;
+		if (!isset) {
+			/*
+			 * Fill in disk block numbers in the state structure
+			 * so that we can get the buffers back after we commit
+			 * several transactions in the following calls.
+			 */
+			error = xfs_attr_fillstate(state);
+			if (error)
+				goto out;
+
+			/*
+			 * Mark the attribute as INCOMPLETE, then bunmapi() the
+			 * remote value.
+			 */
+			error = xfs_attr3_leaf_setflag(args);
+			if (error)
+				goto out;
+
+			return -EAGAIN;
+		}
+
+		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
+			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
+			error = xfs_attr_rmtval_invalidate(args);
+			if (error)
+				goto out;
+		}
+
+		/*
+		 * 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;
+
+			if (!done)
+				return -EAGAIN;
+		}
+
+		if (error)
+			goto out;
+
+		/*
+		 * Refill the state structure with buffers, the prior calls
+		 * released our buffers.
+		 */
+		error = xfs_attr_refillstate(state);
+		if (error)
+			goto out;
+	}
+
+	/*
+	 * Remove the name and update the hashvals in the tree.
+	 */
+	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
+		blk = &state->path.blk[state->path.active - 1];
+		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+		retval = xfs_attr3_leaf_remove(blk->bp, args);
+		xfs_da3_fixhashpath(state, &state->path);
+
+		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
+	}
+
+	/*
+	 * Check to see if the tree needs to be collapsed.
+	 */
+	if (retval && (state->path.active > 1)) {
+		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
+		error = xfs_da3_join(state);
+		if (error)
+			goto out;
+
+		return -EAGAIN;
+	}
+
+	/*
+	 * If the result is small enough, push it all into the inode.
+	 */
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		/*
+		 * Have to get rid of the copy of this dabuf in the state.
+		 */
+		ASSERT(state->path.active == 1);
+		ASSERT(state->path.blk[0].bp);
+		state->path.blk[0].bp = NULL;
+
+		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
+		if (error)
+			goto out;
+
+		forkoff = xfs_attr_shortform_allfit(bp, dp);
+		if (forkoff) {
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+			/* bp is gone due to xfs_da_shrink_inode */
+			if (error)
+				goto out;
+		} else
+			xfs_trans_brelse(args->trans, bp);
+	}
+out:
+	if (state != NULL)
+		xfs_da_state_free(state);
+
+	return error;
+}
+
+/*
+ * Add a name to a Btree-format attribute list.
+ *
+ * This will involve walking down the Btree, and may involve splitting
+ * leaf nodes and even splitting intermediate nodes up to and including
+ * the root node (a special case of an intermediate node).
+ *
+ * "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
+ * -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.
+ */
+STATIC int
+xfs_node_addname_later(
+	struct xfs_da_args	*args)
+{
+	struct xfs_da_state	*state = NULL;
+	struct xfs_da_state_blk	*blk;
+	struct xfs_inode	*dp;
+	int			retval, error = 0;
+	int			nmap;
+	struct xfs_bmbt_irec    *map = &args->dc.map;
+
+	trace_xfs_attr_node_addname(args);
+
+	/*
+	 * Fill in bucket of arguments/results/context to carry around.
+	 */
+	dp = args->dp;
+
+	if (args->dc.flags & XFS_DC_FOUND_NBLK)
+		goto found_blk;
+
+	/*
+	 * Search to see if name already exists, and get back a pointer
+	 * to where it should go.
+	 */
+	retval = xfs_attr_node_hasname(args, &state);
+	blk = &state->path.blk[state->path.active-1];
+	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
+		goto out;
+	} else if (retval == -EEXIST) {
+		if (args->name.type & ATTR_CREATE)
+			goto out;
+
+		trace_xfs_attr_node_replace(args);
+
+		/* save the attribute state for later removal*/
+		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
+		args->blkno2 = args->blkno;		/* set 2nd entry info*/
+		args->index2 = args->index;
+		args->rmtblkno2 = args->rmtblkno;
+		args->rmtblkcnt2 = args->rmtblkcnt;
+		args->rmtvaluelen2 = args->rmtvaluelen;
+
+		/*
+		 * clear the remote attr state now that it is saved so that the
+		 * values reflect the state of the attribute we are about to
+		 * add, not the attribute we just found and will remove later.
+		 */
+		args->rmtblkno = 0;
+		args->rmtblkcnt = 0;
+		args->rmtvaluelen = 0;
+	}
+
+	retval = xfs_attr3_leaf_add(blk->bp, state->args);
+	if (retval == -ENOSPC) {
+		if (state->path.active == 1) {
+			/*
+			 * Its really a single leaf node, but it had
+			 * out-of-line values so it looked like it *might*
+			 * have been a b-tree.
+			 */
+			xfs_da_state_free(state);
+			state = NULL;
+			error = xfs_attr3_leaf_to_node(args);
+			if (error)
+				goto out;
+
+			return -EAGAIN;
+		}
+
+		/*
+		 * Split as many Btree elements as required.
+		 * This code tracks the new and old attr's location
+		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
+		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
+		 */
+		error = xfs_da3_split(state);
+		if (error)
+			goto out;
+	} else {
+		/*
+		 * Addition succeeded, update Btree hashvals.
+		 */
+		xfs_da3_fixhashpath(state, &state->path);
+	}
+
+	/*
+	 * Kill the state structure, we're done with it and need to
+	 * allow the buffers to come back later.
+	 */
+	xfs_da_state_free(state);
+	state = NULL;
+
+	args->dc.flags |= XFS_DC_FOUND_NBLK;
+	return -EAGAIN;
+found_blk:
+
+	/*
+	 * If there was an out-of-line value, allocate the blocks we
+	 * identified for its storage and copy the value.  This is done
+	 * after we create the attribute so that we don't overflow the
+	 * maximum size of a transaction and/or hit a deadlock.
+	 */
+	if (args->rmtblkno > 0) {
+		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
+			args->dc.flags |= XFS_DC_ALLOC_NODE;
+			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));
+
+			error = xfs_attr_rmt_find_hole(args);
+			if (error)
+				return error;
+
+			args->dc.blkcnt = args->rmtblkcnt;
+			args->dc.lblkno = args->rmtblkno;
+		}
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+		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));
+
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
+		if (error)
+			return error;
+	}
+
+	if (args->rmtblkno > 0) {
+		/*
+		 * Added a "remote" value, just clear the incomplete flag.
+		 */
+		error = xfs_attr3_leaf_clearflag(args);
+		if (error)
+			goto out;
+	}
+	retval = error = 0;
+
+out:
+	if (state)
+		xfs_da_state_free(state);
+	if (error)
+		return error;
+
+	return retval;
+}
+
+
+
+/*
  * Fill in the disk block numbers in the state structure for the buffers
  * that are attached to the state structure.
  * This is done so that we can quickly reattach ourselves to those buffers
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index fb56d81..6203766 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* [PATCH v3 15/19] xfs: Set up infastructure for deferred attribute operations
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (13 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 14/19] xfs: Add delayed attribute routines Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-05 22:18 ` [PATCH v3 16/19] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

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

Currently attributes are modified directly across one or more
transactions.  But they are not logged or replayed in the event of
an error. The goal of delayed attributes is to enable logging and
replaying of attribute operations using the existing delayed
operations infrastructure.  This will later enable the attributes
to become part of larger multi part operations that also must first
be recorded to the log.  This is mostly of interest in the scheme of
parent pointers which would need to maintain an attribute containing
parent inode information any time an inode is moved, created, or
removed.  Parent pointers would then be of interest to any feature
that would need to quickly derive an inode path from the mount
point.  Online scrub, nfs lookups and fs grow or shrink operations
are all features that could take advantage of this.

This patch adds two new log item types for setting or removing
attributes as deferred operations.  The xfs_attri_log_item logs an
intent to set or remove an attribute.  The corresponding
xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
is freed once the transaction is done.  Both log items use a generic
xfs_attr_log_format structure that contains the attribute name,
value, flags, inode, and an op_flag that indicates if the operations
is a set or remove.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/Makefile                |   2 +-
 fs/xfs/libxfs/xfs_attr.c       |   5 +-
 fs/xfs/libxfs/xfs_attr.h       |  33 ++
 fs/xfs/libxfs/xfs_defer.c      |   1 +
 fs/xfs/libxfs/xfs_defer.h      |   3 +
 fs/xfs/libxfs/xfs_log_format.h |  44 ++-
 fs/xfs/libxfs/xfs_types.h      |   1 +
 fs/xfs/xfs_attr_item.c         | 756 +++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h         |  88 +++++
 fs/xfs/xfs_log.c               |   4 +
 fs/xfs/xfs_log_recover.c       | 173 ++++++++++
 fs/xfs/xfs_ondisk.h            |   2 +
 fs/xfs/xfs_trans.h             |   1 -
 13 files changed, 1107 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 06b68b6..70b4716 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -102,6 +102,7 @@ xfs-y				+= xfs_log.o \
 				   xfs_bmap_item.o \
 				   xfs_buf_item.o \
 				   xfs_extfree_item.o \
+				   xfs_attr_item.o \
 				   xfs_icreate_item.o \
 				   xfs_inode_item.o \
 				   xfs_refcount_item.o \
@@ -109,7 +110,6 @@ xfs-y				+= xfs_log.o \
 				   xfs_log_recover.o \
 				   xfs_trans_ail.o \
 				   xfs_trans_buf.o
-
 # optional features
 xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
 				   xfs_dquot_item.o \
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 310f5b2..7680789 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -24,6 +24,7 @@
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
+#include "xfs_attr_item.h"
 
 /*
  * xfs_attr.c
@@ -63,7 +64,7 @@ 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
+int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
@@ -190,7 +191,7 @@ xfs_attr_get(
 /*
  * Calculate how many blocks we need for the new attribute,
  */
-STATIC int
+int
 xfs_attr_calc_size(
 	struct xfs_da_args	*args,
 	int			*local)
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 6203766..1e0c25e 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -80,6 +80,36 @@ typedef struct attrlist_ent {	/* data from attr_list() */
 } attrlist_ent_t;
 
 /*
+ * List of attrs to commit later.
+ */
+struct xfs_attr_item {
+	struct xfs_inode	*xattri_ip;
+	void			*xattri_value;		/* attr value */
+	void			*xattri_name;		/* attr name */
+	uint32_t		xattri_op_flags;	/* attr op set or rm */
+	uint32_t		xattri_value_len;	/* length of value */
+	uint32_t		xattri_name_len;	/* length of name */
+	uint32_t		xattri_flags;		/* attr flags */
+
+	/* used to log this item to an intent */
+	struct list_head	xattri_list;
+
+	/*
+	 * xfs_da_args needs to remain instantiated across transaction rolls
+	 * during the defer finish, so store it here
+	 */
+	struct xfs_da_args	xattri_args;
+
+	/*
+	 * A byte array follows the header containing the file name and
+	 * attribute value.
+	 */
+};
+
+#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
+	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
+
+/*
  * Given a pointer to the (char*) buffer containing the attr_list() result,
  * and an index, return a pointer to the indicated attribute in the buffer.
  */
@@ -157,5 +187,8 @@ 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);
+int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
+		       struct xfs_name *name);
+int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
index 2255752..6749022 100644
--- a/fs/xfs/libxfs/xfs_defer.c
+++ b/fs/xfs/libxfs/xfs_defer.c
@@ -176,6 +176,7 @@ static const struct xfs_defer_op_type *defer_op_types[] = {
 	[XFS_DEFER_OPS_TYPE_RMAP]	= &xfs_rmap_update_defer_type,
 	[XFS_DEFER_OPS_TYPE_FREE]	= &xfs_extent_free_defer_type,
 	[XFS_DEFER_OPS_TYPE_AGFL_FREE]	= &xfs_agfl_free_defer_type,
+	[XFS_DEFER_OPS_TYPE_ATTR]	= &xfs_attr_defer_type,
 };
 
 /*
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index 7c28d76..b9ff7b9 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/libxfs/xfs_defer.h
@@ -17,6 +17,7 @@ enum xfs_defer_ops_type {
 	XFS_DEFER_OPS_TYPE_RMAP,
 	XFS_DEFER_OPS_TYPE_FREE,
 	XFS_DEFER_OPS_TYPE_AGFL_FREE,
+	XFS_DEFER_OPS_TYPE_ATTR,
 	XFS_DEFER_OPS_TYPE_MAX,
 };
 
@@ -60,5 +61,7 @@ extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
 extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
 extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
+extern const struct xfs_defer_op_type xfs_attr_defer_type;
+
 
 #endif /* __XFS_DEFER_H__ */
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index e5f97c6..acdb8ad 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -117,7 +117,12 @@ struct xfs_unmount_log_format {
 #define XLOG_REG_TYPE_CUD_FORMAT	24
 #define XLOG_REG_TYPE_BUI_FORMAT	25
 #define XLOG_REG_TYPE_BUD_FORMAT	26
-#define XLOG_REG_TYPE_MAX		26
+#define XLOG_REG_TYPE_ATTRI_FORMAT	27
+#define XLOG_REG_TYPE_ATTRD_FORMAT	28
+#define XLOG_REG_TYPE_ATTR_NAME	29
+#define XLOG_REG_TYPE_ATTR_VALUE	30
+#define XLOG_REG_TYPE_MAX		30
+
 
 /*
  * Flags to log operation header
@@ -240,6 +245,8 @@ typedef struct xfs_trans_header {
 #define	XFS_LI_CUD		0x1243
 #define	XFS_LI_BUI		0x1244	/* bmbt update intent */
 #define	XFS_LI_BUD		0x1245
+#define	XFS_LI_ATTRI		0x1246  /* attr set/remove intent*/
+#define	XFS_LI_ATTRD		0x1247  /* attr set/remove done */
 
 #define XFS_LI_TYPE_DESC \
 	{ XFS_LI_EFI,		"XFS_LI_EFI" }, \
@@ -255,7 +262,9 @@ typedef struct xfs_trans_header {
 	{ XFS_LI_CUI,		"XFS_LI_CUI" }, \
 	{ XFS_LI_CUD,		"XFS_LI_CUD" }, \
 	{ XFS_LI_BUI,		"XFS_LI_BUI" }, \
-	{ XFS_LI_BUD,		"XFS_LI_BUD" }
+	{ XFS_LI_BUD,		"XFS_LI_BUD" }, \
+	{ XFS_LI_ATTRI,		"XFS_LI_ATTRI" }, \
+	{ XFS_LI_ATTRD,		"XFS_LI_ATTRD" }
 
 /*
  * Inode Log Item Format definitions.
@@ -853,4 +862,35 @@ struct xfs_icreate_log {
 	__be32		icl_gen;	/* inode generation number to use */
 };
 
+/*
+ * Flags for deferred attribute operations.
+ * Upper bits are flags, lower byte is type code
+ */
+#define XFS_ATTR_OP_FLAGS_SET		1	/* Set the attribute */
+#define XFS_ATTR_OP_FLAGS_REMOVE	2	/* Remove the attribute */
+#define XFS_ATTR_OP_FLAGS_TYPE_MASK	0x0FF	/* Flags type mask */
+
+/*
+ * This is the structure used to lay out an attr log item in the
+ * log.
+ */
+struct xfs_attri_log_format {
+	uint16_t	alfi_type;	/* attri log item type */
+	uint16_t	alfi_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfi_id;	/* attri identifier */
+	xfs_ino_t       alfi_ino;	/* the inode for this attr operation */
+	uint32_t        alfi_op_flags;	/* marks the op as a set or remove */
+	uint32_t        alfi_name_len;	/* attr name length */
+	uint32_t        alfi_value_len;	/* attr value length */
+	uint32_t        alfi_attr_flags;/* attr flags */
+};
+
+struct xfs_attrd_log_format {
+	uint16_t	alfd_type;	/* attrd log item type */
+	uint16_t	alfd_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfd_alf_id;	/* id of corresponding attrd */
+};
+
 #endif /* __XFS_LOG_FORMAT_H__ */
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 300b3e9..ade55d4 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -11,6 +11,7 @@ typedef uint32_t	prid_t;		/* project ID */
 typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
 typedef uint32_t	xfs_agino_t;	/* inode # within allocation grp */
 typedef uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef uint32_t	xfs_attrlen_t;	/* attr length */
 typedef uint32_t	xfs_agnumber_t;	/* allocation group number */
 typedef int32_t		xfs_extnum_t;	/* # of extents in a file */
 typedef int16_t		xfs_aextnum_t;	/* # extents in an attribute fork */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
new file mode 100644
index 0000000..a4abcf3
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Allison Collins <allison.henderson@oracle.com>
+ */
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_shared.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
+#include "xfs_attr_item.h"
+#include "xfs_log.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_shared.h"
+#include "xfs_attr_item.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
+#include "libxfs/xfs_da_format.h"
+#include "xfs_inode.h"
+#include "xfs_quota.h"
+
+/*
+ * This routine is called to allocate an "attr free done" log item.
+ */
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans		*tp,
+		  struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_attrd_log_item		*attrdp;
+
+	ASSERT(tp != NULL);
+
+	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
+	ASSERT(attrdp != NULL);
+
+	xfs_trans_add_item(tp, &attrdp->attrd_item);
+	return attrdp;
+}
+
+/*
+ * Log an ATTRI it to the ATTRD when the attr op is done.  An attr operation
+ * may be a set or a remove.  Note that the transaction is marked dirty
+ * regardless of whether the operation succeeds or fails to support the
+ * ATTRI/ATTRD lifecycle rules.
+ */
+int
+xfs_trans_attr(
+	struct xfs_da_args		*args,
+	struct xfs_attrd_log_item	*attrdp,
+	struct xfs_buf			**leaf_bp,
+	uint32_t			op_flags)
+{
+	int				error;
+
+	error = xfs_qm_dqattach_locked(args->dp, 0);
+	if (error)
+		return error;
+
+	switch (op_flags) {
+	case XFS_ATTR_OP_FLAGS_SET:
+		args->op_flags |= XFS_DA_OP_ADDNAME;
+		error = xfs_attr_set_later(args, leaf_bp);
+		break;
+	case XFS_ATTR_OP_FLAGS_REMOVE:
+		ASSERT(XFS_IFORK_Q((args->dp)));
+		error = xfs_attr_remove_later(args);
+		break;
+	default:
+		error = -EFSCORRUPTED;
+		break;
+	}
+
+	/*
+	 * Mark the transaction dirty, even on error. This ensures the
+	 * transaction is aborted, which:
+	 *
+	 * 1.) releases the ATTRI and frees the ATTRD
+	 * 2.) shuts down the filesystem
+	 */
+	args->trans->t_flags |= XFS_TRANS_DIRTY;
+	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
+
+	return error;
+}
+
+static int
+xfs_attr_diff_items(
+	void				*priv,
+	struct list_head		*a,
+	struct list_head		*b)
+{
+	return 0;
+}
+
+/* Get an ATTRI. */
+STATIC void *
+xfs_attr_create_intent(
+	struct xfs_trans		*tp,
+	unsigned int			count)
+{
+	struct xfs_attri_log_item	*attrip;
+
+	ASSERT(tp != NULL);
+	ASSERT(count == 1);
+
+	attrip = xfs_attri_init(tp->t_mountp);
+	ASSERT(attrip != NULL);
+
+	xfs_trans_add_item(tp, &attrip->attri_item);
+	return attrip;
+}
+
+/* Log an attr to the intent item. */
+STATIC void
+xfs_attr_log_item(
+	struct xfs_trans		*tp,
+	void				*intent,
+	struct list_head		*item)
+{
+	struct xfs_attri_log_item	*attrip = intent;
+	struct xfs_attr_item		*attr;
+	struct xfs_attri_log_format	*attrp;
+	char				*name_value;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
+
+	/*
+	 * At this point the xfs_attr_item has been constructed, and we've
+	 * created the log intent. Fill in the attri log item and log format
+	 * structure with fields from this xfs_attr_item
+	 */
+	attrp = &attrip->attri_format;
+	attrp->alfi_ino = attr->xattri_ip->i_ino;
+	attrp->alfi_op_flags = attr->xattri_op_flags;
+	attrp->alfi_value_len = attr->xattri_value_len;
+	attrp->alfi_name_len = attr->xattri_name_len;
+	attrp->alfi_attr_flags = attr->xattri_flags;
+
+	attrip->attri_name = name_value;
+	attrip->attri_value = &name_value[attr->xattri_name_len];
+	attrip->attri_name_len = attr->xattri_name_len;
+	attrip->attri_value_len = attr->xattri_value_len;
+}
+
+/* Get an ATTRD so we can process all the attrs. */
+STATIC void *
+xfs_attr_create_done(
+	struct xfs_trans		*tp,
+	void				*intent,
+	unsigned int			count)
+{
+	return xfs_trans_get_attrd(tp, intent);
+}
+
+/* Process an attr. */
+STATIC int
+xfs_attr_finish_item(
+	struct xfs_trans		*tp,
+	struct list_head		*item,
+	void				*done_item,
+	void				**state)
+{
+	struct xfs_attr_item		*attr;
+	char				*name_value;
+	int				error;
+	int				local;
+	struct xfs_da_args		*args;
+	struct xfs_name			name;
+	struct xfs_attrd_log_item	*attrdp;
+	struct xfs_attri_log_item	*attrip;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	args = &attr->xattri_args;
+
+	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+	name.name = name_value;
+	name.len = attr->xattri_name_len;
+	name.type = attr->xattri_flags;
+
+	if (!(args->dc.flags & XFS_DC_INIT)) {
+		/* Only need to initialize args context once */
+		error = xfs_attr_args_init(args, attr->xattri_ip, &name);
+		if (error)
+			goto out;
+
+		args->hashval = xfs_da_hashname(args->name.name,
+						args->name.len);
+		args->value = &name_value[attr->xattri_name_len];
+		args->valuelen = attr->xattri_value_len;
+		args->op_flags = XFS_DA_OP_OKNOENT;
+
+		/* must match existing transaction block res */
+		args->total = xfs_attr_calc_size(args, &local);
+		args->dc.flags |= XFS_DC_INIT;
+	}
+
+	/*
+	 * Always reset trans after EAGAIN cycle
+	 * since the transaction is new
+	 */
+	args->trans = tp;
+
+	error = xfs_trans_attr(args, done_item,	&args->dc.leaf_bp,
+			       attr->xattri_op_flags);
+out:
+	/*
+	 * The attrip refers to xfs_attr_item memory to log the name and value
+	 * with the intent item. This already occurred when the intent was
+	 * committed so these fields are no longer accessed. Clear them out of
+	 * caution since we're about to free the xfs_attr_item.
+	 */
+	attrdp = (struct xfs_attrd_log_item *)done_item;
+	attrip = attrdp->attrd_attrip;
+	attrip->attri_name = NULL;
+	attrip->attri_value = NULL;
+
+	if (error != -EAGAIN)
+		kmem_free(attr);
+
+	return error;
+}
+
+/* Abort all pending ATTRs. */
+STATIC void
+xfs_attr_abort_intent(
+	void				*intent)
+{
+	xfs_attri_release(intent);
+}
+
+/* Cancel an attr */
+STATIC void
+xfs_attr_cancel_item(
+	struct list_head		*item)
+{
+	struct xfs_attr_item	*attr;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	kmem_free(attr);
+}
+
+const struct xfs_defer_op_type xfs_attr_defer_type = {
+	.max_items	= 1,
+	.diff_items	= xfs_attr_diff_items,
+	.create_intent	= xfs_attr_create_intent,
+	.abort_intent	= xfs_attr_abort_intent,
+	.log_item	= xfs_attr_log_item,
+	.create_done	= xfs_attr_create_done,
+	.finish_item	= xfs_attr_finish_item,
+	.cancel_item	= xfs_attr_cancel_item,
+};
+
+static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attri_log_item, attri_item);
+}
+
+void
+xfs_attri_item_free(
+	struct xfs_attri_log_item	*attrip)
+{
+	kmem_free(attrip->attri_item.li_lv_shadow);
+	kmem_free(attrip);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attri item. We
+ * only need 1 iovec for an attri item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attri_item_sizeof(
+	struct xfs_attri_log_item *attrip)
+{
+	return sizeof(struct xfs_attri_log_format);
+}
+
+STATIC void
+xfs_attri_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
+
+	*nvecs += 1;
+	*nbytes += xfs_attri_item_sizeof(attrip);
+
+	/* Attr set and remove operations require a name */
+	ASSERT(attrip->attri_name_len > 0);
+
+	*nvecs += 1;
+	*nbytes += ATTR_NVEC_SIZE(attrip->attri_name_len);
+
+	/*
+	 * Set ops can accept a value of 0 len to clear an attr value.  Remove
+	 * ops do not need a value at all.  So only account for the value
+	 * when it is needed.
+	 */
+	if (attrip->attri_value_len > 0) {
+		*nvecs += 1;
+		*nbytes += ATTR_NVEC_SIZE(attrip->attri_value_len);
+	}
+}
+
+/*
+ * This is called to fill in the log iovecs for the given attri log
+ * item. We use  1 iovec for the attri_format_item, 1 for the name, and
+ * another for the value if it is present
+ */
+STATIC void
+xfs_attri_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+	struct xfs_log_iovec		*vecp = NULL;
+
+	attrip->attri_format.alfi_type = XFS_LI_ATTRI;
+	attrip->attri_format.alfi_size = 1;
+
+	/*
+	 * This size accounting must be done before copying the attrip into the
+	 * iovec.  If we do it after, the wrong size will be recorded to the log
+	 * and we trip across assertion checks for bad region sizes later during
+	 * the log recovery.
+	 */
+
+	ASSERT(attrip->attri_name_len > 0);
+	attrip->attri_format.alfi_size++;
+
+	if (attrip->attri_value_len > 0)
+		attrip->attri_format.alfi_size++;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
+			&attrip->attri_format,
+			xfs_attri_item_sizeof(attrip));
+	if (attrip->attri_name_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
+				attrip->attri_name,
+				ATTR_NVEC_SIZE(attrip->attri_name_len));
+
+	if (attrip->attri_value_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
+				attrip->attri_value,
+				ATTR_NVEC_SIZE(attrip->attri_value_len));
+}
+
+/*
+ * The unpin operation is the last place an ATTRI is manipulated in the log. It
+ * is either inserted in the AIL or aborted in the event of a log I/O error. In
+ * either case, the ATTRI transaction has been successfully committed to make
+ * it this far. Therefore, we expect whoever committed the ATTRI to either
+ * construct and commit the ATTRD or drop the ATTRD's reference in the event of
+ * error. Simply drop the log's ATTRI reference now that the log is done with
+ * it.
+ */
+STATIC void
+xfs_attri_item_unpin(
+	struct xfs_log_item	*lip,
+	int			remove)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+
+	xfs_attri_release(attrip);
+}
+
+/*
+ * attri items have no locking or pushing.  However, since ATTRIs are pulled
+ * from the AIL when their corresponding ATTRDs are committed to disk, their
+ * situation is very similar to being pinned.  Return XFS_ITEM_PINNED so that
+ * the caller will eventually flush the log.  This should help in getting the
+ * ATTRI out of the AIL.
+ */
+STATIC uint
+xfs_attri_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRI is logged only once and cannot be moved in the log, so simply
+ * return the lsn at which it's been logged.
+ */
+STATIC xfs_lsn_t
+xfs_attri_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	return lsn;
+}
+
+STATIC void
+xfs_attri_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+STATIC void
+xfs_attri_item_release(
+	struct xfs_log_item	*lip)
+{
+	xfs_attri_release(ATTRI_ITEM(lip));
+}
+
+static const struct xfs_item_ops xfs_attri_item_ops = {
+	.iop_size	= xfs_attri_item_size,
+	.iop_format	= xfs_attri_item_format,
+	.iop_unpin	= xfs_attri_item_unpin,
+	.iop_committed	= xfs_attri_item_committed,
+	.iop_push	= xfs_attri_item_push,
+	.iop_committing = xfs_attri_item_committing,
+	.iop_release    = xfs_attri_item_release,
+};
+
+
+/*
+ * Allocate and initialize an attri item
+ */
+struct xfs_attri_log_item *
+xfs_attri_init(
+	struct xfs_mount	*mp)
+
+{
+	struct xfs_attri_log_item	*attrip;
+	uint				size;
+
+	size = (uint)(sizeof(struct xfs_attri_log_item));
+	attrip = kmem_zalloc(size, 0);
+
+	xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
+			  &xfs_attri_item_ops);
+	attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
+	atomic_set(&attrip->attri_refcount, 2);
+
+	return attrip;
+}
+
+/*
+ * Copy an attr format buffer from the given buf, and into the destination attr
+ * format structure.
+ */
+int
+xfs_attri_copy_format(struct xfs_log_iovec *buf,
+		      struct xfs_attri_log_format *dst_attr_fmt)
+{
+	struct xfs_attri_log_format *src_attr_fmt = buf->i_addr;
+	uint len = sizeof(struct xfs_attri_log_format);
+
+	if (buf->i_len != len)
+		return -EFSCORRUPTED;
+
+	memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
+	return 0;
+}
+
+/*
+ * Freeing the attrip requires that we remove it from the AIL if it has already
+ * been placed there. However, the ATTRI may not yet have been placed in the
+ * AIL when called by xfs_attri_release() from ATTRD processing due to the
+ * ordering of committed vs unpin operations in bulk insert operations. Hence
+ * the reference count to ensure only the last caller frees the ATTRI.
+ */
+void
+xfs_attri_release(
+	struct xfs_attri_log_item	*attrip)
+{
+	ASSERT(atomic_read(&attrip->attri_refcount) > 0);
+	if (atomic_dec_and_test(&attrip->attri_refcount)) {
+		xfs_trans_ail_remove(&attrip->attri_item,
+				     SHUTDOWN_LOG_IO_ERROR);
+		xfs_attri_item_free(attrip);
+	}
+}
+
+static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attrd_log_item, attrd_item);
+}
+
+STATIC void
+xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
+{
+	kmem_free(attrdp->attrd_item.li_lv_shadow);
+	kmem_free(attrdp);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attrd item.
+ * We only need 1 iovec for an attrd item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attrd_item_sizeof(
+	struct xfs_attrd_log_item *attrdp)
+{
+	return sizeof(struct xfs_attrd_log_format);
+}
+
+STATIC void
+xfs_attrd_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	*nvecs += 1;
+	*nbytes += xfs_attrd_item_sizeof(attrdp);
+}
+
+/*
+ * This is called to fill in the log iovecs for the given attrd log item. We use
+ * only 1 iovec for the attrd_format, and we point that at the attr_log_format
+ * structure embedded in the attrd item.
+ */
+STATIC void
+xfs_attrd_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	struct xfs_log_iovec	*vecp = NULL;
+
+	attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
+	attrdp->attrd_format.alfd_size = 1;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
+			&attrdp->attrd_format, xfs_attrd_item_sizeof(attrdp));
+}
+
+/*
+ * There isn't much you can do to push on an attrd item.  It is simply stuck
+ * waiting for the log to be flushed to disk.
+ */
+STATIC uint
+xfs_attrd_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * When the attrd item is committed to disk, all we need to do is delete our
+ * reference to our partner attri item and then free ourselves. Since we're
+ * freeing ourselves we must return -1 to keep the transaction code from
+ * further referencing this item.
+ */
+STATIC xfs_lsn_t
+xfs_attrd_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+
+	/*
+	 * Drop the ATTRI reference regardless of whether the ATTRD has been
+	 * aborted. Once the ATTRD transaction is constructed, it is the sole
+	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
+	 * is aborted due to log I/O error).
+	 */
+	xfs_attri_release(attrdp->attrd_attrip);
+	xfs_attrd_item_free(attrdp);
+
+	return NULLCOMMITLSN;
+}
+
+STATIC void
+xfs_attrd_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+/*
+ * The ATTRD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the ATTRI and free the
+ * ATTRD.
+ */
+STATIC void
+xfs_attrd_item_release(
+	struct xfs_log_item     *lip)
+{
+	struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
+
+	xfs_attri_release(attrdp->attrd_attrip);
+	xfs_attrd_item_free(attrdp);
+}
+
+static const struct xfs_item_ops xfs_attrd_item_ops = {
+	.iop_size	= xfs_attrd_item_size,
+	.iop_format	= xfs_attrd_item_format,
+	.iop_committed	= xfs_attrd_item_committed,
+	.iop_push	= xfs_attrd_item_push,
+	.iop_committing = xfs_attrd_item_committing,
+	.iop_release    = xfs_attrd_item_release,
+};
+
+/*
+ * Allocate and initialize an attrd item
+ */
+struct xfs_attrd_log_item *
+xfs_attrd_init(
+	struct xfs_mount		*mp,
+	struct xfs_attri_log_item	*attrip)
+
+{
+	struct xfs_attrd_log_item	*attrdp;
+	uint				size;
+
+	size = (uint)(sizeof(struct xfs_attrd_log_item));
+	attrdp = kmem_zalloc(size, 0);
+
+	xfs_log_item_init(mp, &attrdp->attrd_item, XFS_LI_ATTRD,
+			  &xfs_attrd_item_ops);
+	attrdp->attrd_attrip = attrip;
+	attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
+
+	return attrdp;
+}
+
+/*
+ * Process an attr intent item that was recovered from the log.  We need to
+ * delete the attr that it describes.
+ */
+int
+xfs_attri_recover(
+	struct xfs_mount		*mp,
+	struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_inode		*ip;
+	struct xfs_attrd_log_item	*attrdp;
+	struct xfs_da_args		args;
+	struct xfs_attri_log_format	*attrp;
+	struct xfs_trans_res		tres;
+	int				local;
+	int				error, err2 = 0;
+	int				rsvd = 0;
+	struct xfs_name			name;
+	struct xfs_buf			*leaf_bp = NULL;
+
+	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
+
+	/*
+	 * First check the validity of the attr described by the ATTRI.  If any
+	 * are bad, then assume that all are bad and just toss the ATTRI.
+	 */
+	attrp = &attrip->attri_format;
+	if (!(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
+	      attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
+	    (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
+	    (attrp->alfi_name_len > XATTR_NAME_MAX) ||
+	    (attrp->alfi_name_len == 0)) {
+		/*
+		 * This will pull the ATTRI from the AIL and free the memory
+		 * associated with it.
+		 */
+		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
+		xfs_attri_release(attrip);
+		return -EFSCORRUPTED;
+	}
+
+	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
+	if (error)
+		return error;
+
+	name.name = attrip->attri_name;
+	name.len = attrp->alfi_name_len;
+	name.type = attrp->alfi_attr_flags;
+	error = xfs_attr_args_init(&args, ip, &name);
+	if (error)
+		goto out_rele;
+
+	args.hashval = xfs_da_hashname(args.name.name, args.name.len);
+	args.value = attrip->attri_value;
+	args.valuelen = attrp->alfi_value_len;
+	args.op_flags = XFS_DA_OP_OKNOENT;
+	args.total = xfs_attr_calc_size(&args, &local);
+
+	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
+			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
+	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+
+	error = xfs_trans_alloc(mp, &tres, args.total,  0,
+				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
+	if (error)
+		goto out_rele;
+	attrdp = xfs_trans_get_attrd(args.trans, attrip);
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+	xfs_trans_ijoin(args.trans, ip, 0);
+
+	do {
+		error = xfs_trans_attr(&args, attrdp, &leaf_bp,
+				       attrp->alfi_op_flags);
+		if (error && error != -EAGAIN)
+			goto abort_error;
+
+		xfs_trans_log_inode(args.trans, ip,
+				XFS_ILOG_CORE | XFS_ILOG_ADATA);
+
+		err2 = xfs_trans_roll(&args.trans);
+		if (err2) {
+			error = err2;
+			goto abort_error;
+		}
+
+		/* Rejoin inode and leaf if needed */
+		xfs_trans_ijoin(args.trans, ip, 0);
+		if (leaf_bp) {
+			xfs_trans_bjoin(args.trans, leaf_bp);
+			xfs_trans_bhold(args.trans, leaf_bp);
+		}
+
+	} while (error == -EAGAIN);
+
+	error = xfs_trans_commit(args.trans);
+	if (error)
+		goto abort_error;
+
+	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	xfs_irele(ip);
+	return error;
+
+abort_error:
+	xfs_trans_cancel(args.trans);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+out_rele:
+	xfs_irele(ip);
+	return error;
+}
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
new file mode 100644
index 0000000..0c4cd72
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Allison Collins <allison.henderson@oracle.com>
+ */
+#ifndef	__XFS_ATTR_ITEM_H__
+#define	__XFS_ATTR_ITEM_H__
+
+/* kernel only ATTRI/ATTRD definitions */
+
+struct xfs_mount;
+struct kmem_zone;
+
+/*
+ * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
+ */
+#define	XFS_ATTRI_RECOVERED	1
+
+
+/* iovec length must be 32-bit aligned */
+#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
+				size + sizeof(int32_t) - \
+				(size % sizeof(int32_t)))
+
+/*
+ * This is the "attr intention" log item.  It is used to log the fact that some
+ * attribute operations need to be processed.  An operation is currently either
+ * a set or remove.  Set or remove operations are described by the xfs_attr_item
+ * which may be logged to this intent.  Intents are used in conjunction with the
+ * "attr done" log item described below.
+ *
+ * The ATTRI is reference counted so that it is not freed prior to both the
+ * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
+ * inserted into the AIL even in the event of out of order ATTRI/ATTRD
+ * processing. In other words, an ATTRI is born with two references:
+ *
+ *      1.) an ATTRI held reference to track ATTRI AIL insertion
+ *      2.) an ATTRD held reference to track ATTRD commit
+ *
+ * On allocation, both references are the responsibility of the caller. Once the
+ * ATTRI is added to and dirtied in a transaction, ownership of reference one
+ * transfers to the transaction. The reference is dropped once the ATTRI is
+ * inserted to the AIL or in the event of failure along the way (e.g., commit
+ * failure, log I/O error, etc.). Note that the caller remains responsible for
+ * the ATTRD reference under all circumstances to this point. The caller has no
+ * means to detect failure once the transaction is committed, however.
+ * Therefore, an ATTRD is required after this point, even in the event of
+ * unrelated failure.
+ *
+ * Once an ATTRD is allocated and dirtied in a transaction, reference two
+ * transfers to the transaction. The ATTRD reference is dropped once it reaches
+ * the unpin handler. Similar to the ATTRI, the reference also drops in the
+ * event of commit failure or log I/O errors. Note that the ATTRD is not
+ * inserted in the AIL, so at this point both the ATTRI and ATTRD are freed.
+ */
+struct xfs_attri_log_item {
+	struct xfs_log_item		attri_item;
+	atomic_t			attri_refcount;
+	unsigned long			attri_flags;	/* misc flags */
+	int				attri_name_len;
+	void				*attri_name;
+	int				attri_value_len;
+	void				*attri_value;
+	struct xfs_attri_log_format	attri_format;
+};
+
+/*
+ * This is the "attr done" log item.  It is used to log the fact that some attrs
+ * earlier mentioned in an attri item have been freed.
+ */
+struct xfs_attrd_log_item {
+	struct xfs_attri_log_item	*attrd_attrip;
+	struct xfs_log_item		attrd_item;
+	struct xfs_attrd_log_format	attrd_format;
+};
+
+struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
+struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+int xfs_attri_copy_format(struct xfs_log_iovec *buf,
+			   struct xfs_attri_log_format *dst_attri_fmt);
+void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
+void			xfs_attri_release(struct xfs_attri_log_item *attrip);
+
+int			xfs_attri_recover(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+
+#endif	/* __XFS_ATTR_ITEM_H__ */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 3e0a105..3de9e18 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2002,6 +2002,10 @@ xlog_print_tic_res(
 	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
 	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
 	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
+	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
+	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
+	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
+	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
 	};
 	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
 #undef REG_TYPE_STR
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index f05c6c9..11378f9 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -20,6 +20,7 @@
 #include "xfs_log_recover.h"
 #include "xfs_inode_item.h"
 #include "xfs_extfree_item.h"
+#include "xfs_attr_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
@@ -1887,6 +1888,8 @@ xlog_recover_reorder_trans(
 		case XFS_LI_CUD:
 		case XFS_LI_BUI:
 		case XFS_LI_BUD:
+		case XFS_LI_ATTRI:
+		case XFS_LI_ATTRD:
 			trace_xfs_log_recover_item_reorder_tail(log,
 							trans, item, pass);
 			list_move_tail(&item->ri_list, &inode_list);
@@ -3424,6 +3427,118 @@ xlog_recover_efd_pass2(
 	return 0;
 }
 
+STATIC int
+xlog_recover_attri_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item,
+	xfs_lsn_t                       lsn)
+{
+	int                             error;
+	struct xfs_mount                *mp = log->l_mp;
+	struct xfs_attri_log_item       *attrip;
+	struct xfs_attri_log_format     *attri_formatp;
+	char				*name = NULL;
+	char				*value = NULL;
+	int				region = 0;
+
+	attri_formatp = item->ri_buf[region].i_addr;
+
+	attrip = xfs_attri_init(mp);
+	error = xfs_attri_copy_format(&item->ri_buf[region],
+				      &attrip->attri_format);
+	if (error) {
+		xfs_attri_item_free(attrip);
+		return error;
+	}
+
+	attrip->attri_name_len = attri_formatp->alfi_name_len;
+	attrip->attri_value_len = attri_formatp->alfi_value_len;
+	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
+			      attrip->attri_name_len + attrip->attri_value_len,
+			      0);
+
+	ASSERT(attrip->attri_name_len > 0);
+	region++;
+	name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
+	memcpy(name, item->ri_buf[region].i_addr,
+	       attrip->attri_name_len);
+	attrip->attri_name = name;
+
+	if (attrip->attri_value_len > 0) {
+		region++;
+		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
+			attrip->attri_name_len;
+		memcpy(value, item->ri_buf[region].i_addr,
+			attrip->attri_value_len);
+		attrip->attri_value = value;
+	}
+
+	spin_lock(&log->l_ailp->ail_lock);
+	/*
+	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
+	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
+	 * directly and drop the ATTRI reference. Note that
+	 * xfs_trans_ail_update() drops the AIL lock.
+	 */
+	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
+	xfs_attri_release(attrip);
+	return 0;
+}
+
+
+/*
+ * This routine is called when an ATTRD format structure is found in a committed
+ * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
+ * it was still in the log. To do this it searches the AIL for the ATTRI with
+ * an id equal to that in the ATTRD format structure. If we find it we drop
+ * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
+ */
+STATIC int
+xlog_recover_attrd_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item)
+{
+	struct xfs_attrd_log_format	*attrd_formatp;
+	struct xfs_attri_log_item	*attrip = NULL;
+	struct xfs_log_item		*lip;
+	uint64_t			attri_id;
+	struct xfs_ail_cursor		cur;
+	struct xfs_ail			*ailp = log->l_ailp;
+
+	attrd_formatp = item->ri_buf[0].i_addr;
+	ASSERT((item->ri_buf[0].i_len ==
+				(sizeof(struct xfs_attrd_log_format))));
+	attri_id = attrd_formatp->alfd_alf_id;
+
+	/*
+	 * Search for the ATTRI with the id in the ATTRD format structure in the
+	 * AIL.
+	 */
+	spin_lock(&ailp->ail_lock);
+	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+	while (lip != NULL) {
+		if (lip->li_type == XFS_LI_ATTRI) {
+			attrip = (struct xfs_attri_log_item *)lip;
+			if (attrip->attri_format.alfi_id == attri_id) {
+				/*
+				 * Drop the ATTRD reference to the ATTRI. This
+				 * removes the ATTRI from the AIL and frees it.
+				 */
+				spin_unlock(&ailp->ail_lock);
+				xfs_attri_release(attrip);
+				spin_lock(&ailp->ail_lock);
+				break;
+			}
+		}
+		lip = xfs_trans_ail_cursor_next(ailp, &cur);
+	}
+
+	xfs_trans_ail_cursor_done(&cur);
+	spin_unlock(&ailp->ail_lock);
+
+	return 0;
+}
+
 /*
  * This routine is called to create an in-core extent rmap update
  * item from the rui format structure which was logged on disk.
@@ -3976,6 +4091,8 @@ xlog_recover_ra_pass2(
 		break;
 	case XFS_LI_EFI:
 	case XFS_LI_EFD:
+	case XFS_LI_ATTRI:
+	case XFS_LI_ATTRD:
 	case XFS_LI_QUOTAOFF:
 	case XFS_LI_RUI:
 	case XFS_LI_RUD:
@@ -4004,6 +4121,8 @@ xlog_recover_commit_pass1(
 	case XFS_LI_INODE:
 	case XFS_LI_EFI:
 	case XFS_LI_EFD:
+	case XFS_LI_ATTRI:
+	case XFS_LI_ATTRD:
 	case XFS_LI_DQUOT:
 	case XFS_LI_ICREATE:
 	case XFS_LI_RUI:
@@ -4042,6 +4161,10 @@ xlog_recover_commit_pass2(
 		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
 	case XFS_LI_EFD:
 		return xlog_recover_efd_pass2(log, item);
+	case XFS_LI_ATTRI:
+		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
+	case XFS_LI_ATTRD:
+		return xlog_recover_attrd_pass2(log, item);
 	case XFS_LI_RUI:
 		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
 	case XFS_LI_RUD:
@@ -4603,6 +4726,48 @@ xlog_recover_cancel_efi(
 	spin_lock(&ailp->ail_lock);
 }
 
+/* Release the ATTRI since we're cancelling everything. */
+STATIC void
+xlog_recover_cancel_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item         *attrip;
+
+	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
+
+	spin_unlock(&ailp->ail_lock);
+	xfs_attri_release(attrip);
+	spin_lock(&ailp->ail_lock);
+}
+
+
+/* Recover the ATTRI if necessary. */
+STATIC int
+xlog_recover_process_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item       *attrip;
+	int                             error;
+
+	/*
+	 * Skip ATTRIs that we've already processed.
+	 */
+	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
+	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags))
+		return 0;
+
+	spin_unlock(&ailp->ail_lock);
+	error = xfs_attri_recover(mp, attrip);
+	spin_lock(&ailp->ail_lock);
+
+	return error;
+}
+
+
 /* Recover the RUI if necessary. */
 STATIC int
 xlog_recover_process_rui(
@@ -4731,6 +4896,7 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
 	case XFS_LI_RUI:
 	case XFS_LI_CUI:
 	case XFS_LI_BUI:
+	case XFS_LI_ATTRI:
 		return true;
 	default:
 		return false;
@@ -4849,6 +5015,10 @@ xlog_recover_process_intents(
 		case XFS_LI_EFI:
 			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
 			break;
+		case XFS_LI_ATTRI:
+			error = xlog_recover_process_attri(log->l_mp,
+							   ailp, lip);
+			break;
 		case XFS_LI_RUI:
 			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
 			break;
@@ -4914,6 +5084,9 @@ xlog_recover_cancel_intents(
 		case XFS_LI_BUI:
 			xlog_recover_cancel_bui(log->l_mp, ailp, lip);
 			break;
+		case XFS_LI_ATTRI:
+			xlog_recover_cancel_attri(log->l_mp, ailp, lip);
+			break;
 		}
 
 		lip = xfs_trans_ail_cursor_next(ailp, &cur);
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index b6701b4..120fb0c 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -125,6 +125,8 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header,		16);
+	XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format,	40);
+	XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format,	16);
 
 	/*
 	 * The v5 superblock format extended several v4 header structures with
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 64d7f17..4dd5607 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -229,7 +229,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
 void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
 bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
 void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
-
 int		xfs_trans_commit(struct xfs_trans *);
 int		xfs_trans_roll(struct xfs_trans **);
 int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
-- 
2.7.4


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

* [PATCH v3 16/19] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (14 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 15/19] xfs: Set up infastructure for deferred attribute operations Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-05 22:18 ` [PATCH v3 17/19] xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR Allison Collins
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

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

These routines set up set and start a new deferred attribute
operation.  These functions are meant to be called by other
code needing to initiate a deferred attribute operation.
New helper function xfs_attr_item_init also added

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_attr.h |  5 +++
 2 files changed, 90 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7680789..f502396 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -25,6 +25,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_attr_item.h"
+#include "xfs_attr.h"
 
 /*
  * xfs_attr.c
@@ -622,6 +623,70 @@ xfs_attr_set(
 	goto out_unlock;
 }
 
+STATIC int
+xfs_attr_item_init(
+	struct xfs_inode	*dp,		/* inode for attr operation */
+	struct xfs_trans	*tp,		/* transaction for attr op */
+	struct xfs_name		*name,		/* attr name, len and flags */
+	const unsigned char	*value,		/* attr value */
+	unsigned int		valuelen,	/* attr value len */
+	int			op_flags,	/* op flag (set or remove) */
+	struct xfs_attr_item	**attr)		/* new xfs_attr_item */
+{
+
+	struct xfs_attr_item	*new;
+	char			*name_value;
+
+	/*
+	 * All set operations must have a name but not necessarily a value.
+	 */
+	if (!name->len) {
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	new = kmem_alloc_large(XFS_ATTR_ITEM_SIZEOF(name->len, valuelen),
+			 KM_NOFS);
+	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, valuelen));
+	new->xattri_ip = dp;
+	new->xattri_op_flags = op_flags;
+	new->xattri_name_len = name->len;
+	new->xattri_value_len = valuelen;
+	new->xattri_flags = name->type;
+	memcpy(&name_value[0], name->name, name->len);
+	new->xattri_name = name_value;
+	new->xattri_value = name_value + name->len;
+
+	if (valuelen > 0)
+		memcpy(&name_value[name->len], value, valuelen);
+
+	*attr = new;
+	return 0;
+}
+
+/* Sets an attribute for an inode as a deferred operation */
+int
+xfs_attr_set_deferred(
+	struct xfs_inode	*dp,
+	struct xfs_trans	*tp,
+	struct xfs_name		*name,
+	const unsigned char	*value,
+	unsigned int		valuelen)
+{
+	struct xfs_attr_item	*new;
+	int			error = 0;
+
+	error = xfs_attr_item_init(dp, tp, name, value, valuelen,
+				 XFS_ATTR_OP_FLAGS_SET, &new);
+	if (error)
+		return error;
+
+	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
+
 /*
  * Generic handler routine to remove a name from an attribute list.
  * Transitions attribute list from Btree to shortform as necessary.
@@ -703,6 +768,26 @@ xfs_attr_remove(
 	return error;
 }
 
+/* Removes an attribute for an inode as a deferred operation */
+int
+xfs_attr_remove_deferred(
+	struct xfs_inode        *dp,
+	struct xfs_trans	*tp,
+	struct xfs_name		*name)
+{
+
+	struct xfs_attr_item *new;
+
+	int error  = xfs_attr_item_init(dp, tp, name, NULL, 0,
+				  XFS_ATTR_OP_FLAGS_REMOVE, &new);
+	if (error)
+		return error;
+
+	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
+
 /*========================================================================
  * External routines when attribute list is inside the inode
  *========================================================================*/
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 1e0c25e..0dfec5c 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -190,5 +190,10 @@ bool xfs_attr_namecheck(const void *name, size_t length);
 int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
 		       struct xfs_name *name);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
+int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
+			  struct xfs_name *name, const unsigned char *value,
+			  unsigned int valuelen);
+int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
+			    struct xfs_name *name);
 
 #endif	/* __XFS_ATTR_H__ */
-- 
2.7.4


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

* [PATCH v3 17/19] xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (15 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 16/19] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-05 22:18 ` [PATCH v3 18/19] xfs: Enable delayed attributes Allison Collins
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
which can be used to control turning on/off delayed attributes

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h | 11 ++++++++++-
 fs/xfs/libxfs/xfs_fs.h     |  1 +
 fs/xfs/libxfs/xfs_sb.c     |  2 ++
 fs/xfs/xfs_super.c         |  4 ++++
 4 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index c968b60..8316624 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -479,7 +479,9 @@ xfs_sb_has_incompat_feature(
 	return (sbp->sb_features_incompat & feature) != 0;
 }
 
-#define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0
+#define XFS_SB_FEAT_INCOMPAT_LOG_DELATTR   (1 << 0)	/* Delayed Attributes */
+#define XFS_SB_FEAT_INCOMPAT_LOG_ALL \
+	(XFS_SB_FEAT_INCOMPAT_LOG_DELATTR)
 #define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_LOG_ALL
 static inline bool
 xfs_sb_has_incompat_log_feature(
@@ -546,6 +548,13 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
 		(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
 }
 
+static inline bool xfs_sb_version_hasdelattr(struct xfs_sb *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+		(sbp->sb_features_log_incompat &
+		XFS_SB_FEAT_INCOMPAT_LOG_DELATTR));
+}
+
 /*
  * end of superblock version macros
  */
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 52d03a3..3ee13e8 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -249,6 +249,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_SPINODES	(1 << 18) /* sparse inode chunks   */
 #define XFS_FSOP_GEOM_FLAGS_RMAPBT	(1 << 19) /* reverse mapping btree */
 #define XFS_FSOP_GEOM_FLAGS_REFLINK	(1 << 20) /* files can share blocks */
+#define XFS_FSOP_GEOM_FLAGS_DELATTR	(1 << 21) /* delayed attributes	    */
 
 /*
  * Minimum and maximum sizes need for growth checks.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index a08dd8f..a2f30d2 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -1132,6 +1132,8 @@ xfs_fs_geometry(
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
 	if (xfs_sb_version_hasreflink(sbp))
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
+	if (xfs_sb_version_hasdelattr(sbp))
+		geo->flags |= XFS_FSOP_GEOM_FLAGS_DELATTR;
 	if (xfs_sb_version_hassector(sbp))
 		geo->logsectsize = sbp->sb_logsectsize;
 	else
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index f945023..26c4337 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1726,6 +1726,10 @@ xfs_fs_fill_super(
 		goto out_filestream_unmount;
 	}
 
+	if (xfs_sb_version_hasdelattr(&mp->m_sb))
+		xfs_alert(mp,
+	"EXPERIMENTAL delayed attrs feature enabled. Use at your own risk!");
+
 	error = xfs_mountfs(mp);
 	if (error)
 		goto out_filestream_unmount;
-- 
2.7.4


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

* [PATCH v3 18/19] xfs: Enable delayed attributes
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (16 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 17/19] xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-05 22:18 ` [PATCH v3 19/19] xfs_io: Add delayed attributes error tag Allison Collins
  2019-09-16 12:27 ` [PATCH v3 00/19] Delayed Attributes Brian Foster
  19 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

Finally enable delayed attributes in xfs_attr_set and
xfs_attr_remove.  We only do this for new filesystems that have
the feature bit enabled because we cant add new log entries to
older filesystems

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index f502396..1040479 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -532,6 +532,7 @@ xfs_attr_set(
 	int			valuelen)
 {
 	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_sb		*sbp = &mp->m_sb;
 	struct xfs_da_args	args;
 	struct xfs_trans_res	tres;
 	int			rsvd = (name->type & ATTR_ROOT) != 0;
@@ -590,7 +591,34 @@ xfs_attr_set(
 		goto out_trans_cancel;
 
 	xfs_trans_ijoin(args.trans, dp, 0);
-	error = xfs_attr_set_args(&args);
+	if (xfs_sb_version_hasdelattr(sbp)) {
+		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_deferred(dp, args.trans, name);
+			if (error)
+				goto out_trans_cancel;
+
+			name->type |= ATTR_CREATE;
+		}
+
+		error = xfs_attr_set_deferred(dp, args.trans, name, value,
+					      valuelen);
+	} else {
+		error = xfs_attr_set_args(&args);
+	}
+
 	if (error)
 		goto out_trans_cancel;
 	if (!args.trans) {
@@ -697,6 +725,7 @@ xfs_attr_remove(
 	struct xfs_name		*name)
 {
 	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_sb		*sbp = &mp->m_sb;
 	struct xfs_da_args	args;
 	int			error;
 
@@ -738,7 +767,14 @@ xfs_attr_remove(
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
 
-	error = xfs_attr_remove_args(&args);
+	error = xfs_has_attr(&args);
+	if (error == -ENOATTR)
+		goto out;
+
+	if (xfs_sb_version_hasdelattr(sbp))
+		error = xfs_attr_remove_deferred(dp, args.trans, name);
+	else
+		error = xfs_attr_remove_args(&args);
 	if (error)
 		goto out;
 
-- 
2.7.4


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

* [PATCH v3 19/19] xfs_io: Add delayed attributes error tag
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (17 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 18/19] xfs: Enable delayed attributes Allison Collins
@ 2019-09-05 22:18 ` Allison Collins
  2019-09-16 12:27 ` [PATCH v3 00/19] Delayed Attributes Brian Foster
  19 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-05 22:18 UTC (permalink / raw)
  To: linux-xfs

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

This patch adds an error tag that we can use to test
delayed attribute recovery and replay

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_errortag.h | 4 +++-
 fs/xfs/xfs_attr_item.c       | 8 ++++++++
 fs/xfs/xfs_error.c           | 3 +++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index 79e6c4f..85d5850 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -55,7 +55,8 @@
 #define XFS_ERRTAG_FORCE_SCRUB_REPAIR			32
 #define XFS_ERRTAG_FORCE_SUMMARY_RECALC			33
 #define XFS_ERRTAG_IUNLINK_FALLBACK			34
-#define XFS_ERRTAG_MAX					35
+#define XFS_ERRTAG_DELAYED_ATTR				35
+#define XFS_ERRTAG_MAX					36
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -95,5 +96,6 @@
 #define XFS_RANDOM_FORCE_SCRUB_REPAIR			1
 #define XFS_RANDOM_FORCE_SUMMARY_RECALC			1
 #define XFS_RANDOM_IUNLINK_FALLBACK			(XFS_RANDOM_DEFAULT/10)
+#define XFS_RANDOM_DELAYED_ATTR				1
 
 #endif /* __XFS_ERRORTAG_H_ */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index a4abcf3..691ea6b 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -33,6 +33,8 @@
 #include "libxfs/xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_quota.h"
+#include "xfs_error.h"
+#include "xfs_errortag.h"
 
 /*
  * This routine is called to allocate an "attr free done" log item.
@@ -71,6 +73,11 @@ xfs_trans_attr(
 	if (error)
 		return error;
 
+	if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_DELAYED_ATTR)) {
+		error = -EIO;
+		goto out;
+	}
+
 	switch (op_flags) {
 	case XFS_ATTR_OP_FLAGS_SET:
 		args->op_flags |= XFS_DA_OP_ADDNAME;
@@ -85,6 +92,7 @@ xfs_trans_attr(
 		break;
 	}
 
+out:
 	/*
 	 * Mark the transaction dirty, even on error. This ensures the
 	 * transaction is aborted, which:
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 849fd44..c468a91 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -53,6 +53,7 @@ static unsigned int xfs_errortag_random_default[] = {
 	XFS_RANDOM_FORCE_SCRUB_REPAIR,
 	XFS_RANDOM_FORCE_SUMMARY_RECALC,
 	XFS_RANDOM_IUNLINK_FALLBACK,
+	XFS_RANDOM_DELAYED_ATTR,
 };
 
 struct xfs_errortag_attr {
@@ -162,6 +163,7 @@ XFS_ERRORTAG_ATTR_RW(buf_lru_ref,	XFS_ERRTAG_BUF_LRU_REF);
 XFS_ERRORTAG_ATTR_RW(force_repair,	XFS_ERRTAG_FORCE_SCRUB_REPAIR);
 XFS_ERRORTAG_ATTR_RW(bad_summary,	XFS_ERRTAG_FORCE_SUMMARY_RECALC);
 XFS_ERRORTAG_ATTR_RW(iunlink_fallback,	XFS_ERRTAG_IUNLINK_FALLBACK);
+XFS_ERRORTAG_ATTR_RW(delayed_attr,	XFS_ERRTAG_DELAYED_ATTR);
 
 static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -199,6 +201,7 @@ static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(force_repair),
 	XFS_ERRORTAG_ATTR_LIST(bad_summary),
 	XFS_ERRORTAG_ATTR_LIST(iunlink_fallback),
+	XFS_ERRORTAG_ATTR_LIST(delayed_attr),
 	NULL,
 };
 
-- 
2.7.4


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

* Re: [PATCH v3 03/19] xfs: Add xfs_dabuf defines
  2019-09-05 22:18 ` [PATCH v3 03/19] xfs: Add xfs_dabuf defines Allison Collins
@ 2019-09-06  3:37   ` Darrick J. Wong
  0 siblings, 0 replies; 64+ messages in thread
From: Darrick J. Wong @ 2019-09-06  3:37 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:21PM -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_leaf.h | 3 +++
>  fs/xfs/libxfs/xfs_da_btree.c  | 3 ++-
>  2 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 7b74e18..536a290 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..2b94685 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.c
> +++ b/fs/xfs/libxfs/xfs_da_btree.c
> @@ -2534,7 +2534,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) {

Er... convert the users of -1 and -2 too, please...

--D

>  		/*
>  		 * Optimize the one-block case.
>  		 */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
                   ` (18 preceding siblings ...)
  2019-09-05 22:18 ` [PATCH v3 19/19] xfs_io: Add delayed attributes error tag Allison Collins
@ 2019-09-16 12:27 ` Brian Foster
  2019-09-16 18:41   ` Allison Collins
  19 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-16 12:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
> Hi all,
> 
> This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
> parent pointers which can be used in a number of optimizations.  Since
> delayed attributes can be implemented as a stand alone feature, I've
> decided to subdivide the set to help make it more manageable.  Delayed
> attributes may also provide the infastructure to later break up large
> attributes into smaller transactions instead of one large bwrite.
> 
> Changes since v2:
> Mostly review updates collected since v2.  Patch 17 is new and adds a
> new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
> renames have been simplified into separate remove and set opertaions
> which removes the need for the INCOMPLETE state used in non delayed
> operations
> 
> 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

Hi Allison,

The first patch in the series doesn't apply to current for-next or
master. What is the baseline for this series? Perhaps a rebase is in
order..?

Brian

>   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: Add delayed attribute routines
>   xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
>   xfs: Enable delayed attributes
> 
> Allison Henderson (4):
>   xfs: Add xfs_has_attr and subroutines
>   xfs: Set up infastructure for deferred attribute operations
>   xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
>   xfs_io: Add delayed attributes error tag
> 
>  fs/xfs/Makefile                 |    2 +-
>  fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
>  fs/xfs/libxfs/xfs_attr.h        |   53 +-
>  fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
>  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    |    8 +-
>  fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
>  fs/xfs/libxfs/xfs_defer.c       |    1 +
>  fs/xfs/libxfs/xfs_defer.h       |    3 +
>  fs/xfs/libxfs/xfs_dir2.c        |   22 +-
>  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/libxfs/xfs_errortag.h    |    4 +-
>  fs/xfs/libxfs/xfs_format.h      |   11 +-
>  fs/xfs/libxfs/xfs_fs.h          |    1 +
>  fs/xfs/libxfs/xfs_log_format.h  |   44 +-
>  fs/xfs/libxfs/xfs_sb.c          |    2 +
>  fs/xfs/libxfs/xfs_types.h       |    1 +
>  fs/xfs/scrub/attr.c             |   12 +-
>  fs/xfs/scrub/common.c           |    2 +
>  fs/xfs/xfs_acl.c                |   29 +-
>  fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr_item.h          |   88 ++++
>  fs/xfs/xfs_attr_list.c          |    1 +
>  fs/xfs/xfs_error.c              |    3 +
>  fs/xfs/xfs_ioctl.c              |   30 +-
>  fs/xfs/xfs_ioctl32.c            |    2 +
>  fs/xfs/xfs_iops.c               |   14 +-
>  fs/xfs/xfs_log.c                |    4 +
>  fs/xfs/xfs_log_recover.c        |  173 +++++++
>  fs/xfs/xfs_ondisk.h             |    2 +
>  fs/xfs/xfs_super.c              |    4 +
>  fs/xfs/xfs_trace.h              |   20 +-
>  fs/xfs/xfs_trans.h              |    1 -
>  fs/xfs/xfs_xattr.c              |   31 +-
>  39 files changed, 2509 insertions(+), 359 deletions(-)
>  create mode 100644 fs/xfs/xfs_attr_item.c
>  create mode 100644 fs/xfs/xfs_attr_item.h
> 
> -- 
> 2.7.4
> 

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-16 12:27 ` [PATCH v3 00/19] Delayed Attributes Brian Foster
@ 2019-09-16 18:41   ` Allison Collins
  2019-09-16 19:23     ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-16 18:41 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/16/19 5:27 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
>> Hi all,
>>
>> This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
>> parent pointers which can be used in a number of optimizations.  Since
>> delayed attributes can be implemented as a stand alone feature, I've
>> decided to subdivide the set to help make it more manageable.  Delayed
>> attributes may also provide the infastructure to later break up large
>> attributes into smaller transactions instead of one large bwrite.
>>
>> Changes since v2:
>> Mostly review updates collected since v2.  Patch 17 is new and adds a
>> new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
>> renames have been simplified into separate remove and set opertaions
>> which removes the need for the INCOMPLETE state used in non delayed
>> operations
>>
>> 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
> 
> Hi Allison,
> 
> The first patch in the series doesn't apply to current for-next or
> master. What is the baseline for this series? Perhaps a rebase is in
> order..?
> 
> Brian

The base line for the kernel space set is:
eb77b23 xfs: add a xfs_valid_startblock helper

And the user space set is:
e74aec5 xfsprogs: Release v5.3.0-rc1

And xfstests:
cda9817 common/quota: enable project quota correctly on f2fs

Yes, the for-next's may have advanced a bit since, so I'll need to 
update it.  Sometimes stuff moves so fast, by the time I've worked 
through all the conflicts, there's a new for-next already! I kind of 
figured though that people are still sort of settling on what they want 
the design to even look like, especially WRT to the *_later routines 
which are sort of complicated.  So I haven't been too worried about it 
since rebasing is mostly just mechanical adjustments, and it could be 
the next review may take the design in a different direction anyway.

For now though, please use those baselines if you want to apply the 
sets.  I will work on getting the bases updated.

Thanks!

Allison

> 
>>    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: Add delayed attribute routines
>>    xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
>>    xfs: Enable delayed attributes
>>
>> Allison Henderson (4):
>>    xfs: Add xfs_has_attr and subroutines
>>    xfs: Set up infastructure for deferred attribute operations
>>    xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
>>    xfs_io: Add delayed attributes error tag
>>
>>   fs/xfs/Makefile                 |    2 +-
>>   fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
>>   fs/xfs/libxfs/xfs_attr.h        |   53 +-
>>   fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
>>   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    |    8 +-
>>   fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
>>   fs/xfs/libxfs/xfs_defer.c       |    1 +
>>   fs/xfs/libxfs/xfs_defer.h       |    3 +
>>   fs/xfs/libxfs/xfs_dir2.c        |   22 +-
>>   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/libxfs/xfs_errortag.h    |    4 +-
>>   fs/xfs/libxfs/xfs_format.h      |   11 +-
>>   fs/xfs/libxfs/xfs_fs.h          |    1 +
>>   fs/xfs/libxfs/xfs_log_format.h  |   44 +-
>>   fs/xfs/libxfs/xfs_sb.c          |    2 +
>>   fs/xfs/libxfs/xfs_types.h       |    1 +
>>   fs/xfs/scrub/attr.c             |   12 +-
>>   fs/xfs/scrub/common.c           |    2 +
>>   fs/xfs/xfs_acl.c                |   29 +-
>>   fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
>>   fs/xfs/xfs_attr_item.h          |   88 ++++
>>   fs/xfs/xfs_attr_list.c          |    1 +
>>   fs/xfs/xfs_error.c              |    3 +
>>   fs/xfs/xfs_ioctl.c              |   30 +-
>>   fs/xfs/xfs_ioctl32.c            |    2 +
>>   fs/xfs/xfs_iops.c               |   14 +-
>>   fs/xfs/xfs_log.c                |    4 +
>>   fs/xfs/xfs_log_recover.c        |  173 +++++++
>>   fs/xfs/xfs_ondisk.h             |    2 +
>>   fs/xfs/xfs_super.c              |    4 +
>>   fs/xfs/xfs_trace.h              |   20 +-
>>   fs/xfs/xfs_trans.h              |    1 -
>>   fs/xfs/xfs_xattr.c              |   31 +-
>>   39 files changed, 2509 insertions(+), 359 deletions(-)
>>   create mode 100644 fs/xfs/xfs_attr_item.c
>>   create mode 100644 fs/xfs/xfs_attr_item.h
>>
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-16 18:41   ` Allison Collins
@ 2019-09-16 19:23     ` Brian Foster
  2019-09-16 20:42       ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-16 19:23 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Sep 16, 2019 at 11:41:13AM -0700, Allison Collins wrote:
> On 9/16/19 5:27 AM, Brian Foster wrote:
> > On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
> > > Hi all,
> > > 
> > > This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
> > > parent pointers which can be used in a number of optimizations.  Since
> > > delayed attributes can be implemented as a stand alone feature, I've
> > > decided to subdivide the set to help make it more manageable.  Delayed
> > > attributes may also provide the infastructure to later break up large
> > > attributes into smaller transactions instead of one large bwrite.
> > > 
> > > Changes since v2:
> > > Mostly review updates collected since v2.  Patch 17 is new and adds a
> > > new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
> > > renames have been simplified into separate remove and set opertaions
> > > which removes the need for the INCOMPLETE state used in non delayed
> > > operations
> > > 
> > > 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
> > 
> > Hi Allison,
> > 
> > The first patch in the series doesn't apply to current for-next or
> > master. What is the baseline for this series? Perhaps a rebase is in
> > order..?
> > 
> > Brian
> 
> The base line for the kernel space set is:
> eb77b23 xfs: add a xfs_valid_startblock helper
> 

Hmm, I still cannot apply:

$ git log --oneline -1
eb77b23b565e (HEAD -> ac-delayed-attrs-v3, tag: xfs-5.4-merge-4) xfs: add a xfs_valid_startblock helper
$ git am <mbox>
Applying: xfs: Replace attribute parameters with struct xfs_name
error: patch failed: fs/xfs/libxfs/xfs_attr.c:61
error: fs/xfs/libxfs/xfs_attr.c: patch does not apply
error: patch failed: fs/xfs/libxfs/xfs_attr.h:144
error: fs/xfs/libxfs/xfs_attr.h: patch does not apply
error: patch failed: fs/xfs/xfs_acl.c:135
error: fs/xfs/xfs_acl.c: patch does not apply
error: patch failed: fs/xfs/xfs_ioctl.c:431
error: fs/xfs/xfs_ioctl.c: patch does not apply
error: patch failed: fs/xfs/xfs_iops.c:49
error: fs/xfs/xfs_iops.c: patch does not apply
error: patch failed: fs/xfs/xfs_xattr.c:20
error: fs/xfs/xfs_xattr.c: patch does not apply
Patch failed at 0001 xfs: Replace attribute parameters with struct xfs_name
hint: Use 'git am --show-current-patch' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

Have you tried to pull the patches from the mailing list and apply to
your baseline locally? I haven't seen issues merging other patches, so I
don't _think_ my local tree is busted..

Brian

> And the user space set is:
> e74aec5 xfsprogs: Release v5.3.0-rc1
> 
> And xfstests:
> cda9817 common/quota: enable project quota correctly on f2fs
> 
> Yes, the for-next's may have advanced a bit since, so I'll need to update
> it.  Sometimes stuff moves so fast, by the time I've worked through all the
> conflicts, there's a new for-next already! I kind of figured though that
> people are still sort of settling on what they want the design to even look
> like, especially WRT to the *_later routines which are sort of complicated.
> So I haven't been too worried about it since rebasing is mostly just
> mechanical adjustments, and it could be the next review may take the design
> in a different direction anyway.
> 
> For now though, please use those baselines if you want to apply the sets.  I
> will work on getting the bases updated.
> 
> Thanks!
> 
> Allison
> 
> > 
> > >    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: Add delayed attribute routines
> > >    xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
> > >    xfs: Enable delayed attributes
> > > 
> > > Allison Henderson (4):
> > >    xfs: Add xfs_has_attr and subroutines
> > >    xfs: Set up infastructure for deferred attribute operations
> > >    xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
> > >    xfs_io: Add delayed attributes error tag
> > > 
> > >   fs/xfs/Makefile                 |    2 +-
> > >   fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
> > >   fs/xfs/libxfs/xfs_attr.h        |   53 +-
> > >   fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
> > >   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    |    8 +-
> > >   fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
> > >   fs/xfs/libxfs/xfs_defer.c       |    1 +
> > >   fs/xfs/libxfs/xfs_defer.h       |    3 +
> > >   fs/xfs/libxfs/xfs_dir2.c        |   22 +-
> > >   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/libxfs/xfs_errortag.h    |    4 +-
> > >   fs/xfs/libxfs/xfs_format.h      |   11 +-
> > >   fs/xfs/libxfs/xfs_fs.h          |    1 +
> > >   fs/xfs/libxfs/xfs_log_format.h  |   44 +-
> > >   fs/xfs/libxfs/xfs_sb.c          |    2 +
> > >   fs/xfs/libxfs/xfs_types.h       |    1 +
> > >   fs/xfs/scrub/attr.c             |   12 +-
> > >   fs/xfs/scrub/common.c           |    2 +
> > >   fs/xfs/xfs_acl.c                |   29 +-
> > >   fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
> > >   fs/xfs/xfs_attr_item.h          |   88 ++++
> > >   fs/xfs/xfs_attr_list.c          |    1 +
> > >   fs/xfs/xfs_error.c              |    3 +
> > >   fs/xfs/xfs_ioctl.c              |   30 +-
> > >   fs/xfs/xfs_ioctl32.c            |    2 +
> > >   fs/xfs/xfs_iops.c               |   14 +-
> > >   fs/xfs/xfs_log.c                |    4 +
> > >   fs/xfs/xfs_log_recover.c        |  173 +++++++
> > >   fs/xfs/xfs_ondisk.h             |    2 +
> > >   fs/xfs/xfs_super.c              |    4 +
> > >   fs/xfs/xfs_trace.h              |   20 +-
> > >   fs/xfs/xfs_trans.h              |    1 -
> > >   fs/xfs/xfs_xattr.c              |   31 +-
> > >   39 files changed, 2509 insertions(+), 359 deletions(-)
> > >   create mode 100644 fs/xfs/xfs_attr_item.c
> > >   create mode 100644 fs/xfs/xfs_attr_item.h
> > > 
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-16 19:23     ` Brian Foster
@ 2019-09-16 20:42       ` Allison Collins
  2019-09-17  4:43         ` Darrick J. Wong
  2019-09-17 12:17         ` Brian Foster
  0 siblings, 2 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-16 20:42 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/16/19 12:23 PM, Brian Foster wrote:
> On Mon, Sep 16, 2019 at 11:41:13AM -0700, Allison Collins wrote:
>> On 9/16/19 5:27 AM, Brian Foster wrote:
>>> On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
>>>> Hi all,
>>>>
>>>> This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
>>>> parent pointers which can be used in a number of optimizations.  Since
>>>> delayed attributes can be implemented as a stand alone feature, I've
>>>> decided to subdivide the set to help make it more manageable.  Delayed
>>>> attributes may also provide the infastructure to later break up large
>>>> attributes into smaller transactions instead of one large bwrite.
>>>>
>>>> Changes since v2:
>>>> Mostly review updates collected since v2.  Patch 17 is new and adds a
>>>> new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
>>>> renames have been simplified into separate remove and set opertaions
>>>> which removes the need for the INCOMPLETE state used in non delayed
>>>> operations
>>>>
>>>> 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
>>>
>>> Hi Allison,
>>>
>>> The first patch in the series doesn't apply to current for-next or
>>> master. What is the baseline for this series? Perhaps a rebase is in
>>> order..?
>>>
>>> Brian

Ah!  Super sorry, there should be 20 patches, not 19.  I should have 
started the format patch tool one commit earlier.

This should be the first patch:
https://github.com/allisonhenderson/xfs_work/commit/3f923b577d4a2113434e9bc79e1745ce182849d4

In fact if it helps to simply download the sets, I made some git hub links:
https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_v3
https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_xfsprog_v2
https://github.com/allisonhenderson/xfs_work/tree/Delayed_Attr_xfstests_v2

Would you prefer I resend the sets, or are the links easier?

Sorry about the confusion!
Allison

>>
>> The base line for the kernel space set is:
>> eb77b23 xfs: add a xfs_valid_startblock helper
>>
> 
> Hmm, I still cannot apply:
> 
> $ git log --oneline -1
> eb77b23b565e (HEAD -> ac-delayed-attrs-v3, tag: xfs-5.4-merge-4) xfs: add a xfs_valid_startblock helper
> $ git am <mbox>
> Applying: xfs: Replace attribute parameters with struct xfs_name
> error: patch failed: fs/xfs/libxfs/xfs_attr.c:61
> error: fs/xfs/libxfs/xfs_attr.c: patch does not apply
> error: patch failed: fs/xfs/libxfs/xfs_attr.h:144
> error: fs/xfs/libxfs/xfs_attr.h: patch does not apply
> error: patch failed: fs/xfs/xfs_acl.c:135
> error: fs/xfs/xfs_acl.c: patch does not apply
> error: patch failed: fs/xfs/xfs_ioctl.c:431
> error: fs/xfs/xfs_ioctl.c: patch does not apply
> error: patch failed: fs/xfs/xfs_iops.c:49
> error: fs/xfs/xfs_iops.c: patch does not apply
> error: patch failed: fs/xfs/xfs_xattr.c:20
> error: fs/xfs/xfs_xattr.c: patch does not apply
> Patch failed at 0001 xfs: Replace attribute parameters with struct xfs_name
> hint: Use 'git am --show-current-patch' to see the failed patch
> When you have resolved this problem, run "git am --continue".
> If you prefer to skip this patch, run "git am --skip" instead.
> To restore the original branch and stop patching, run "git am --abort".
> 
> Have you tried to pull the patches from the mailing list and apply to
> your baseline locally? I haven't seen issues merging other patches, so I
> don't _think_ my local tree is busted..
> 
> Brian
> 
>> And the user space set is:
>> e74aec5 xfsprogs: Release v5.3.0-rc1
>>
>> And xfstests:
>> cda9817 common/quota: enable project quota correctly on f2fs
>>
>> Yes, the for-next's may have advanced a bit since, so I'll need to update
>> it.  Sometimes stuff moves so fast, by the time I've worked through all the
>> conflicts, there's a new for-next already! I kind of figured though that
>> people are still sort of settling on what they want the design to even look
>> like, especially WRT to the *_later routines which are sort of complicated.
>> So I haven't been too worried about it since rebasing is mostly just
>> mechanical adjustments, and it could be the next review may take the design
>> in a different direction anyway.
>>
>> For now though, please use those baselines if you want to apply the sets.  I
>> will work on getting the bases updated.
>>
>> Thanks!
>>
>> Allison
>>
>>>
>>>>     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: Add delayed attribute routines
>>>>     xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
>>>>     xfs: Enable delayed attributes
>>>>
>>>> Allison Henderson (4):
>>>>     xfs: Add xfs_has_attr and subroutines
>>>>     xfs: Set up infastructure for deferred attribute operations
>>>>     xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
>>>>     xfs_io: Add delayed attributes error tag
>>>>
>>>>    fs/xfs/Makefile                 |    2 +-
>>>>    fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
>>>>    fs/xfs/libxfs/xfs_attr.h        |   53 +-
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
>>>>    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    |    8 +-
>>>>    fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
>>>>    fs/xfs/libxfs/xfs_defer.c       |    1 +
>>>>    fs/xfs/libxfs/xfs_defer.h       |    3 +
>>>>    fs/xfs/libxfs/xfs_dir2.c        |   22 +-
>>>>    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/libxfs/xfs_errortag.h    |    4 +-
>>>>    fs/xfs/libxfs/xfs_format.h      |   11 +-
>>>>    fs/xfs/libxfs/xfs_fs.h          |    1 +
>>>>    fs/xfs/libxfs/xfs_log_format.h  |   44 +-
>>>>    fs/xfs/libxfs/xfs_sb.c          |    2 +
>>>>    fs/xfs/libxfs/xfs_types.h       |    1 +
>>>>    fs/xfs/scrub/attr.c             |   12 +-
>>>>    fs/xfs/scrub/common.c           |    2 +
>>>>    fs/xfs/xfs_acl.c                |   29 +-
>>>>    fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
>>>>    fs/xfs/xfs_attr_item.h          |   88 ++++
>>>>    fs/xfs/xfs_attr_list.c          |    1 +
>>>>    fs/xfs/xfs_error.c              |    3 +
>>>>    fs/xfs/xfs_ioctl.c              |   30 +-
>>>>    fs/xfs/xfs_ioctl32.c            |    2 +
>>>>    fs/xfs/xfs_iops.c               |   14 +-
>>>>    fs/xfs/xfs_log.c                |    4 +
>>>>    fs/xfs/xfs_log_recover.c        |  173 +++++++
>>>>    fs/xfs/xfs_ondisk.h             |    2 +
>>>>    fs/xfs/xfs_super.c              |    4 +
>>>>    fs/xfs/xfs_trace.h              |   20 +-
>>>>    fs/xfs/xfs_trans.h              |    1 -
>>>>    fs/xfs/xfs_xattr.c              |   31 +-
>>>>    39 files changed, 2509 insertions(+), 359 deletions(-)
>>>>    create mode 100644 fs/xfs/xfs_attr_item.c
>>>>    create mode 100644 fs/xfs/xfs_attr_item.h
>>>>
>>>> -- 
>>>> 2.7.4
>>>>

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-16 20:42       ` Allison Collins
@ 2019-09-17  4:43         ` Darrick J. Wong
  2019-09-17 12:17         ` Brian Foster
  1 sibling, 0 replies; 64+ messages in thread
From: Darrick J. Wong @ 2019-09-17  4:43 UTC (permalink / raw)
  To: Allison Collins; +Cc: Brian Foster, linux-xfs

On Mon, Sep 16, 2019 at 01:42:53PM -0700, Allison Collins wrote:
> On 9/16/19 12:23 PM, Brian Foster wrote:
> > On Mon, Sep 16, 2019 at 11:41:13AM -0700, Allison Collins wrote:
> > > On 9/16/19 5:27 AM, Brian Foster wrote:
> > > > On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
> > > > > Hi all,
> > > > > 
> > > > > This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
> > > > > parent pointers which can be used in a number of optimizations.  Since
> > > > > delayed attributes can be implemented as a stand alone feature, I've
> > > > > decided to subdivide the set to help make it more manageable.  Delayed
> > > > > attributes may also provide the infastructure to later break up large
> > > > > attributes into smaller transactions instead of one large bwrite.
> > > > > 
> > > > > Changes since v2:
> > > > > Mostly review updates collected since v2.  Patch 17 is new and adds a
> > > > > new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
> > > > > renames have been simplified into separate remove and set opertaions
> > > > > which removes the need for the INCOMPLETE state used in non delayed
> > > > > operations
> > > > > 
> > > > > 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
> > > > 
> > > > Hi Allison,
> > > > 
> > > > The first patch in the series doesn't apply to current for-next or
> > > > master. What is the baseline for this series? Perhaps a rebase is in
> > > > order..?
> > > > 
> > > > Brian
> 
> Ah!  Super sorry, there should be 20 patches, not 19.  I should have started
> the format patch tool one commit earlier.
> 
> This should be the first patch:
> https://github.com/allisonhenderson/xfs_work/commit/3f923b577d4a2113434e9bc79e1745ce182849d4
> 
> In fact if it helps to simply download the sets, I made some git hub links:
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_v3
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_xfsprog_v2
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_Attr_xfstests_v2
> 
> Would you prefer I resend the sets, or are the links easier?

<shrug> You might as well send it labeled "[PATCH 0/19]" or something.
I've been curious to see if lore sorts by subject or date. :P

--D

> Sorry about the confusion!
> Allison
> 
> > > 
> > > The base line for the kernel space set is:
> > > eb77b23 xfs: add a xfs_valid_startblock helper
> > > 
> > 
> > Hmm, I still cannot apply:
> > 
> > $ git log --oneline -1
> > eb77b23b565e (HEAD -> ac-delayed-attrs-v3, tag: xfs-5.4-merge-4) xfs: add a xfs_valid_startblock helper
> > $ git am <mbox>
> > Applying: xfs: Replace attribute parameters with struct xfs_name
> > error: patch failed: fs/xfs/libxfs/xfs_attr.c:61
> > error: fs/xfs/libxfs/xfs_attr.c: patch does not apply
> > error: patch failed: fs/xfs/libxfs/xfs_attr.h:144
> > error: fs/xfs/libxfs/xfs_attr.h: patch does not apply
> > error: patch failed: fs/xfs/xfs_acl.c:135
> > error: fs/xfs/xfs_acl.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_ioctl.c:431
> > error: fs/xfs/xfs_ioctl.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_iops.c:49
> > error: fs/xfs/xfs_iops.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_xattr.c:20
> > error: fs/xfs/xfs_xattr.c: patch does not apply
> > Patch failed at 0001 xfs: Replace attribute parameters with struct xfs_name
> > hint: Use 'git am --show-current-patch' to see the failed patch
> > When you have resolved this problem, run "git am --continue".
> > If you prefer to skip this patch, run "git am --skip" instead.
> > To restore the original branch and stop patching, run "git am --abort".
> > 
> > Have you tried to pull the patches from the mailing list and apply to
> > your baseline locally? I haven't seen issues merging other patches, so I
> > don't _think_ my local tree is busted..
> > 
> > Brian
> > 
> > > And the user space set is:
> > > e74aec5 xfsprogs: Release v5.3.0-rc1
> > > 
> > > And xfstests:
> > > cda9817 common/quota: enable project quota correctly on f2fs
> > > 
> > > Yes, the for-next's may have advanced a bit since, so I'll need to update
> > > it.  Sometimes stuff moves so fast, by the time I've worked through all the
> > > conflicts, there's a new for-next already! I kind of figured though that
> > > people are still sort of settling on what they want the design to even look
> > > like, especially WRT to the *_later routines which are sort of complicated.
> > > So I haven't been too worried about it since rebasing is mostly just
> > > mechanical adjustments, and it could be the next review may take the design
> > > in a different direction anyway.
> > > 
> > > For now though, please use those baselines if you want to apply the sets.  I
> > > will work on getting the bases updated.
> > > 
> > > Thanks!
> > > 
> > > Allison
> > > 
> > > > 
> > > > >     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: Add delayed attribute routines
> > > > >     xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
> > > > >     xfs: Enable delayed attributes
> > > > > 
> > > > > Allison Henderson (4):
> > > > >     xfs: Add xfs_has_attr and subroutines
> > > > >     xfs: Set up infastructure for deferred attribute operations
> > > > >     xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
> > > > >     xfs_io: Add delayed attributes error tag
> > > > > 
> > > > >    fs/xfs/Makefile                 |    2 +-
> > > > >    fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
> > > > >    fs/xfs/libxfs/xfs_attr.h        |   53 +-
> > > > >    fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
> > > > >    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    |    8 +-
> > > > >    fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
> > > > >    fs/xfs/libxfs/xfs_defer.c       |    1 +
> > > > >    fs/xfs/libxfs/xfs_defer.h       |    3 +
> > > > >    fs/xfs/libxfs/xfs_dir2.c        |   22 +-
> > > > >    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/libxfs/xfs_errortag.h    |    4 +-
> > > > >    fs/xfs/libxfs/xfs_format.h      |   11 +-
> > > > >    fs/xfs/libxfs/xfs_fs.h          |    1 +
> > > > >    fs/xfs/libxfs/xfs_log_format.h  |   44 +-
> > > > >    fs/xfs/libxfs/xfs_sb.c          |    2 +
> > > > >    fs/xfs/libxfs/xfs_types.h       |    1 +
> > > > >    fs/xfs/scrub/attr.c             |   12 +-
> > > > >    fs/xfs/scrub/common.c           |    2 +
> > > > >    fs/xfs/xfs_acl.c                |   29 +-
> > > > >    fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
> > > > >    fs/xfs/xfs_attr_item.h          |   88 ++++
> > > > >    fs/xfs/xfs_attr_list.c          |    1 +
> > > > >    fs/xfs/xfs_error.c              |    3 +
> > > > >    fs/xfs/xfs_ioctl.c              |   30 +-
> > > > >    fs/xfs/xfs_ioctl32.c            |    2 +
> > > > >    fs/xfs/xfs_iops.c               |   14 +-
> > > > >    fs/xfs/xfs_log.c                |    4 +
> > > > >    fs/xfs/xfs_log_recover.c        |  173 +++++++
> > > > >    fs/xfs/xfs_ondisk.h             |    2 +
> > > > >    fs/xfs/xfs_super.c              |    4 +
> > > > >    fs/xfs/xfs_trace.h              |   20 +-
> > > > >    fs/xfs/xfs_trans.h              |    1 -
> > > > >    fs/xfs/xfs_xattr.c              |   31 +-
> > > > >    39 files changed, 2509 insertions(+), 359 deletions(-)
> > > > >    create mode 100644 fs/xfs/xfs_attr_item.c
> > > > >    create mode 100644 fs/xfs/xfs_attr_item.h
> > > > > 
> > > > > -- 
> > > > > 2.7.4
> > > > > 

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

* Re: [PATCH v3 00/19] Delayed Attributes
  2019-09-16 20:42       ` Allison Collins
  2019-09-17  4:43         ` Darrick J. Wong
@ 2019-09-17 12:17         ` Brian Foster
  1 sibling, 0 replies; 64+ messages in thread
From: Brian Foster @ 2019-09-17 12:17 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Sep 16, 2019 at 01:42:53PM -0700, Allison Collins wrote:
> On 9/16/19 12:23 PM, Brian Foster wrote:
> > On Mon, Sep 16, 2019 at 11:41:13AM -0700, Allison Collins wrote:
> > > On 9/16/19 5:27 AM, Brian Foster wrote:
> > > > On Thu, Sep 05, 2019 at 03:18:18PM -0700, Allison Collins wrote:
> > > > > Hi all,
> > > > > 
> > > > > This set is a subset of a larger series for 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 will help break up more complex operations when we later introduce
> > > > > parent pointers which can be used in a number of optimizations.  Since
> > > > > delayed attributes can be implemented as a stand alone feature, I've
> > > > > decided to subdivide the set to help make it more manageable.  Delayed
> > > > > attributes may also provide the infastructure to later break up large
> > > > > attributes into smaller transactions instead of one large bwrite.
> > > > > 
> > > > > Changes since v2:
> > > > > Mostly review updates collected since v2.  Patch 17 is new and adds a
> > > > > new feature bit that is enabled through mkfs.xfs -n delattr.  Attr
> > > > > renames have been simplified into separate remove and set opertaions
> > > > > which removes the need for the INCOMPLETE state used in non delayed
> > > > > operations
> > > > > 
> > > > > 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
> > > > 
> > > > Hi Allison,
> > > > 
> > > > The first patch in the series doesn't apply to current for-next or
> > > > master. What is the baseline for this series? Perhaps a rebase is in
> > > > order..?
> > > > 
> > > > Brian
> 
> Ah!  Super sorry, there should be 20 patches, not 19.  I should have started
> the format patch tool one commit earlier.
> 
> This should be the first patch:
> https://github.com/allisonhenderson/xfs_work/commit/3f923b577d4a2113434e9bc79e1745ce182849d4
> 

Ah, Ok... no problem. I thought something strange was going on here.

> In fact if it helps to simply download the sets, I made some git hub links:
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_v3
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_attr_xfsprog_v2
> https://github.com/allisonhenderson/xfs_work/tree/Delayed_Attr_xfstests_v2
> 
> Would you prefer I resend the sets, or are the links easier?
> 

No need to resend the whole thing if the rest of the patches match. It
looks like the first patch was already reviewed anyways, though as
Darrick points out it might be good to reply with that first patch for
posterity (with [PATCH v3 0.5/19] or something in the subject...).
Thanks.

Brian

> Sorry about the confusion!
> Allison
> 
> > > 
> > > The base line for the kernel space set is:
> > > eb77b23 xfs: add a xfs_valid_startblock helper
> > > 
> > 
> > Hmm, I still cannot apply:
> > 
> > $ git log --oneline -1
> > eb77b23b565e (HEAD -> ac-delayed-attrs-v3, tag: xfs-5.4-merge-4) xfs: add a xfs_valid_startblock helper
> > $ git am <mbox>
> > Applying: xfs: Replace attribute parameters with struct xfs_name
> > error: patch failed: fs/xfs/libxfs/xfs_attr.c:61
> > error: fs/xfs/libxfs/xfs_attr.c: patch does not apply
> > error: patch failed: fs/xfs/libxfs/xfs_attr.h:144
> > error: fs/xfs/libxfs/xfs_attr.h: patch does not apply
> > error: patch failed: fs/xfs/xfs_acl.c:135
> > error: fs/xfs/xfs_acl.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_ioctl.c:431
> > error: fs/xfs/xfs_ioctl.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_iops.c:49
> > error: fs/xfs/xfs_iops.c: patch does not apply
> > error: patch failed: fs/xfs/xfs_xattr.c:20
> > error: fs/xfs/xfs_xattr.c: patch does not apply
> > Patch failed at 0001 xfs: Replace attribute parameters with struct xfs_name
> > hint: Use 'git am --show-current-patch' to see the failed patch
> > When you have resolved this problem, run "git am --continue".
> > If you prefer to skip this patch, run "git am --skip" instead.
> > To restore the original branch and stop patching, run "git am --abort".
> > 
> > Have you tried to pull the patches from the mailing list and apply to
> > your baseline locally? I haven't seen issues merging other patches, so I
> > don't _think_ my local tree is busted..
> > 
> > Brian
> > 
> > > And the user space set is:
> > > e74aec5 xfsprogs: Release v5.3.0-rc1
> > > 
> > > And xfstests:
> > > cda9817 common/quota: enable project quota correctly on f2fs
> > > 
> > > Yes, the for-next's may have advanced a bit since, so I'll need to update
> > > it.  Sometimes stuff moves so fast, by the time I've worked through all the
> > > conflicts, there's a new for-next already! I kind of figured though that
> > > people are still sort of settling on what they want the design to even look
> > > like, especially WRT to the *_later routines which are sort of complicated.
> > > So I haven't been too worried about it since rebasing is mostly just
> > > mechanical adjustments, and it could be the next review may take the design
> > > in a different direction anyway.
> > > 
> > > For now though, please use those baselines if you want to apply the sets.  I
> > > will work on getting the bases updated.
> > > 
> > > Thanks!
> > > 
> > > Allison
> > > 
> > > > 
> > > > >     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: Add delayed attribute routines
> > > > >     xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR
> > > > >     xfs: Enable delayed attributes
> > > > > 
> > > > > Allison Henderson (4):
> > > > >     xfs: Add xfs_has_attr and subroutines
> > > > >     xfs: Set up infastructure for deferred attribute operations
> > > > >     xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
> > > > >     xfs_io: Add delayed attributes error tag
> > > > > 
> > > > >    fs/xfs/Makefile                 |    2 +-
> > > > >    fs/xfs/libxfs/xfs_attr.c        | 1068 ++++++++++++++++++++++++++++++++++-----
> > > > >    fs/xfs/libxfs/xfs_attr.h        |   53 +-
> > > > >    fs/xfs/libxfs/xfs_attr_leaf.c   |  277 ++++++----
> > > > >    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    |    8 +-
> > > > >    fs/xfs/libxfs/xfs_da_btree.h    |   27 +-
> > > > >    fs/xfs/libxfs/xfs_defer.c       |    1 +
> > > > >    fs/xfs/libxfs/xfs_defer.h       |    3 +
> > > > >    fs/xfs/libxfs/xfs_dir2.c        |   22 +-
> > > > >    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/libxfs/xfs_errortag.h    |    4 +-
> > > > >    fs/xfs/libxfs/xfs_format.h      |   11 +-
> > > > >    fs/xfs/libxfs/xfs_fs.h          |    1 +
> > > > >    fs/xfs/libxfs/xfs_log_format.h  |   44 +-
> > > > >    fs/xfs/libxfs/xfs_sb.c          |    2 +
> > > > >    fs/xfs/libxfs/xfs_types.h       |    1 +
> > > > >    fs/xfs/scrub/attr.c             |   12 +-
> > > > >    fs/xfs/scrub/common.c           |    2 +
> > > > >    fs/xfs/xfs_acl.c                |   29 +-
> > > > >    fs/xfs/xfs_attr_item.c          |  764 ++++++++++++++++++++++++++++
> > > > >    fs/xfs/xfs_attr_item.h          |   88 ++++
> > > > >    fs/xfs/xfs_attr_list.c          |    1 +
> > > > >    fs/xfs/xfs_error.c              |    3 +
> > > > >    fs/xfs/xfs_ioctl.c              |   30 +-
> > > > >    fs/xfs/xfs_ioctl32.c            |    2 +
> > > > >    fs/xfs/xfs_iops.c               |   14 +-
> > > > >    fs/xfs/xfs_log.c                |    4 +
> > > > >    fs/xfs/xfs_log_recover.c        |  173 +++++++
> > > > >    fs/xfs/xfs_ondisk.h             |    2 +
> > > > >    fs/xfs/xfs_super.c              |    4 +
> > > > >    fs/xfs/xfs_trace.h              |   20 +-
> > > > >    fs/xfs/xfs_trans.h              |    1 -
> > > > >    fs/xfs/xfs_xattr.c              |   31 +-
> > > > >    39 files changed, 2509 insertions(+), 359 deletions(-)
> > > > >    create mode 100644 fs/xfs/xfs_attr_item.c
> > > > >    create mode 100644 fs/xfs/xfs_attr_item.h
> > > > > 
> > > > > -- 
> > > > > 2.7.4
> > > > > 

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

* Re: [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-05 22:18 ` [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-09-18 16:43   ` Brian Foster
  2019-09-18 18:09     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-18 16:43 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:19PM -0700, Allison Collins wrote:
> This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
>  fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>  fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
>  fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
>  fs/xfs/xfs_iops.c        | 12 ++++++++----
>  fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
>  6 files changed, 80 insertions(+), 75 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7589cb7..d0308d6 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -139,30 +137,28 @@ 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)
> +	int			*valuelenp)
>  {
>  	struct xfs_da_args	args;
>  	uint			lock_mode;
>  	int			error;
>  
> -	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> +	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);

While this looks like a nice cleanup, I'm not a huge fan of burying the
attr flags in the xfs_name like this. To me they are distinct parameters
and the interface isn't as clear for new callers. Other than that the
patch looks good.

BTW after looking at the next patch, a reasonable compromise might be to
leave the flags param for the top level xfs_attr_*() functions and then
bury the value in args->name.type for the rest of the lower level code
to use. Just a thought..

Brian

>  
>  	XFS_STATS_INC(ip->i_mount, xs_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);
>  	if (error)
>  		return error;
>  
>  	/* Entirely possible to look up a name which doesn't exist */
>  	args.op_flags = XFS_DA_OP_OKNOENT;
> -	if (flags & ATTR_ALLOC)
> +	if (name->type & ATTR_ALLOC)
>  		args.op_flags |= XFS_DA_OP_ALLOCVAL;
>  	else
>  		args.value = *value;
> @@ -175,7 +171,7 @@ xfs_attr_get(
>  
>  	/* on error, we have to clean up allocated value buffers */
>  	if (error) {
> -		if (flags & ATTR_ALLOC) {
> +		if (name->type & ATTR_ALLOC) {
>  			kmem_free(args.value);
>  			*value = NULL;
>  		}
> @@ -339,16 +335,14 @@ 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)
> +	int			valuelen)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_da_args	args;
>  	struct xfs_trans_res	tres;
> -	int			rsvd = (flags & ATTR_ROOT) != 0;
> +	int			rsvd = (name->type & ATTR_ROOT) != 0;
>  	int			error, local;
>  
>  	XFS_STATS_INC(mp, xs_attr_set);
> @@ -356,7 +350,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);
>  	if (error)
>  		return error;
>  
> @@ -419,7 +413,7 @@ xfs_attr_set(
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args.trans);
>  
> -	if ((flags & ATTR_KERNOTIME) == 0)
> +	if ((name->type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>  
>  	/*
> @@ -444,9 +438,7 @@ xfs_attr_set(
>  int
>  xfs_attr_remove(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> -	int			flags)
> +	struct xfs_name		*name)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_da_args	args;
> @@ -457,7 +449,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);
>  	if (error)
>  		return error;
>  
> @@ -478,7 +470,7 @@ xfs_attr_remove(
>  	 */
>  	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>  			XFS_ATTRRM_SPACE_RES(mp), 0,
> -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> +			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>  			&args.trans);
>  	if (error)
>  		return error;
> @@ -501,7 +493,7 @@ xfs_attr_remove(
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args.trans);
>  
> -	if ((flags & ATTR_KERNOTIME) == 0)
> +	if ((name->type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>  
>  	/*
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> +		 unsigned char *value, int valuelen);
>  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 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..f8fb6e10 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);
> +	name.type = ATTR_ALLOC | ATTR_ROOT;
> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
>  	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);
> +		name.type = ATTR_ROOT;
> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
>  
>  		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);
>  
>  		/*
>  		 * 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 d440426..626420d 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
>  {
>  	unsigned char		*kbuf;
>  	int			error = -EFAULT;
> -	size_t			namelen;
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +		.type		= flags,
> +	};
>  
>  	if (*len > XFS_XATTR_SIZE_MAX)
>  		return -EINVAL;
> @@ -439,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);
>  	if (error)
>  		goto out_kfree;
>  
> @@ -463,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;
> @@ -474,8 +476,10 @@ 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);
> +	xname.type = flags;
> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	kfree(kbuf);
> @@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
>  	uint32_t		flags)
>  {
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +		.type		= flags,
> +	};
>  
>  	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);
>  	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 92de0a7..469e8e2 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -49,10 +49,14 @@ 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,
> -				     ATTR_SECURE);
> +		struct xfs_name	name = {
> +			.name	= xattr->name,
> +			.len	= strlen(xattr->name),
> +			.type	= ATTR_SECURE,
> +		};
> +
> +		error = xfs_attr_set(ip, &name,
> +				     xattr->value, xattr->value_len);
>  		if (error < 0)
>  			break;
>  	}
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 59ffe6c..6309da4 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -20,19 +20,21 @@ 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);
> +	struct xfs_name xname = {
> +		.name	= name,
> +		.len	= strlen(name),
> +		.type	= handler->flags
> +	};
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> -		xflags |= ATTR_KERNOVAL;
> +		xname.type |= ATTR_KERNOVAL;
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> -			     &asize, xflags);
> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, const void *value,
>  		size_t size, int flags)
>  {
> -	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),
> +		.type		= handler->flags,
> +	};
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> -		xflags |= ATTR_CREATE;
> +		xname.type |= ATTR_CREATE;
>  	if (flags & XATTR_REPLACE)
> -		xflags |= ATTR_REPLACE;
> +		xname.type |= 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);
> +	error = xfs_attr_set(ip, &xname, (void *)value, size);
>  	if (!error)
> -		xfs_forget_acl(inode, name, xflags);
> +		xfs_forget_acl(inode, name, xname.type);
>  
>  	return error;
>  }
> -- 
> 2.7.4
> 

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

* Re: [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2019-09-05 22:18 ` [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2019-09-18 16:44   ` Brian Foster
  2019-09-18 16:47     ` Christoph Hellwig
  2019-09-18 19:55     ` Allison Collins
  0 siblings, 2 replies; 64+ messages in thread
From: Brian Foster @ 2019-09-18 16:44 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:20PM -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>
> ---
>  fs/xfs/libxfs/xfs_attr.c        |  34 ++++++-------
>  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        |  22 ++++-----
>  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, 130 insertions(+), 125 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index d0308d6..50e099f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -71,13 +71,13 @@ xfs_attr_args_init(
>  	args->geo = dp->i_mount->m_attr_geo;
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
> -	args->flags = name->type;
> -	args->name = name->name;
> -	args->namelen = name->len;
> -	if (args->namelen >= MAXNAMELEN)
> +	args->name.type = name->type;
> +	args->name.name = name->name;
> +	args->name.len = name->len;

Looks like this could be a struct copy:

	args->name = *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;
>  }
>  
...
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 867c5de..e8d6721 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
...
> @@ -259,8 +259,8 @@ xfs_dir_createname(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	args->name.name = name->name;
> +	args->name.len = name->len;
>  	args->filetype = name->type;
>  	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>  	args->inumber = inum;
> @@ -355,8 +355,8 @@ 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;
> +	args->name.name = name->name;
> +	args->name.len = name->len;
>  	args->filetype = name->type;
>  	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>  	args->dp = dp;
> @@ -427,8 +427,8 @@ xfs_dir_removename(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	args->name.name = name->name;
> +	args->name.len = name->len;
>  	args->filetype = name->type;
>  	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>  	args->inumber = ino;
> @@ -488,8 +488,8 @@ xfs_dir_replace(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	args->name.name = name->name;
> +	args->name.len = name->len;
>  	args->filetype = name->type;
>  	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>  	args->inumber = inum;

More struct copy candidates above. Modulo that and the comments on the
previous patch, the rest LGTM:

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

> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 9595ced..94269b9 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 85f14fc..fdc1431 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 eaae275..e0f524d 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -1669,7 +1669,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)
> @@ -1678,9 +1678,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;
> @@ -1733,7 +1734,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)
> @@ -1743,12 +1744,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	[flat|nested] 64+ messages in thread

* Re: [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2019-09-18 16:44   ` Brian Foster
@ 2019-09-18 16:47     ` Christoph Hellwig
  2019-09-18 19:55     ` Allison Collins
  1 sibling, 0 replies; 64+ messages in thread
From: Christoph Hellwig @ 2019-09-18 16:47 UTC (permalink / raw)
  To: Brian Foster; +Cc: Allison Collins, linux-xfs

On Wed, Sep 18, 2019 at 12:44:08PM -0400, Brian Foster wrote:
> > +	args->name.type = name->type;
> > +	args->name.name = name->name;
> > +	args->name.len = name->len;
> 
> Looks like this could be a struct copy:

Would it make sense to include a pointer instead so that we don't
have to copy the structure?

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

* Re: [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-18 16:43   ` Brian Foster
@ 2019-09-18 18:09     ` Allison Collins
  2019-09-18 18:14       ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-18 18:09 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 9/18/19 9:43 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:19PM -0700, Allison Collins wrote:
>> This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
>>   fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>>   fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
>>   fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
>>   fs/xfs/xfs_iops.c        | 12 ++++++++----
>>   fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
>>   6 files changed, 80 insertions(+), 75 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7589cb7..d0308d6 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
> ...
>> @@ -139,30 +137,28 @@ 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)
>> +	int			*valuelenp)
>>   {
>>   	struct xfs_da_args	args;
>>   	uint			lock_mode;
>>   	int			error;
>>   
>> -	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
>> +	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> 
> While this looks like a nice cleanup, I'm not a huge fan of burying the
> attr flags in the xfs_name like this. To me they are distinct parameters
> and the interface isn't as clear for new callers. Other than that the
> patch looks good.
> 
> BTW after looking at the next patch, a reasonable compromise might be to
> leave the flags param for the top level xfs_attr_*() functions and then
> bury the value in args->name.type for the rest of the lower level code
> to use. Just a thought..
> 
> Brian

Yes, this was a sort of cleanup suggested in the last review.  While it 
is nice to have less parameters, I ended up having mixed feels about 
using type for flags.  Mostly just because a name of "type" generally 
implies that the field should be handled like an enumeration, and a 
"flag" implies that is should be handled like a bitmask.  So I found 
myself doing a lot of double takes just in looking at it.  I am fine 
with moving flags back out, but I would like folks to weigh in so that 
we have a consensus on what people are comfortable with.

I'm not sure I like the idea of putting "value" in "type" though. 
Generally a "value" implies a sort of payload with a length (of which we 
have).  But but I think separating value and valuelen would look all 
sorts of weird.  I think either value should stay outside with valuelen, 
or we should probably bite the bullet and introduce a new struct for the 
purpose.  Thoughts?

Allison

> 
>>   
>>   	XFS_STATS_INC(ip->i_mount, xs_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);
>>   	if (error)
>>   		return error;
>>   
>>   	/* Entirely possible to look up a name which doesn't exist */
>>   	args.op_flags = XFS_DA_OP_OKNOENT;
>> -	if (flags & ATTR_ALLOC)
>> +	if (name->type & ATTR_ALLOC)
>>   		args.op_flags |= XFS_DA_OP_ALLOCVAL;
>>   	else
>>   		args.value = *value;
>> @@ -175,7 +171,7 @@ xfs_attr_get(
>>   
>>   	/* on error, we have to clean up allocated value buffers */
>>   	if (error) {
>> -		if (flags & ATTR_ALLOC) {
>> +		if (name->type & ATTR_ALLOC) {
>>   			kmem_free(args.value);
>>   			*value = NULL;
>>   		}
>> @@ -339,16 +335,14 @@ 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)
>> +	int			valuelen)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>>   	struct xfs_da_args	args;
>>   	struct xfs_trans_res	tres;
>> -	int			rsvd = (flags & ATTR_ROOT) != 0;
>> +	int			rsvd = (name->type & ATTR_ROOT) != 0;
>>   	int			error, local;
>>   
>>   	XFS_STATS_INC(mp, xs_attr_set);
>> @@ -356,7 +350,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);
>>   	if (error)
>>   		return error;
>>   
>> @@ -419,7 +413,7 @@ xfs_attr_set(
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args.trans);
>>   
>> -	if ((flags & ATTR_KERNOTIME) == 0)
>> +	if ((name->type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>>   
>>   	/*
>> @@ -444,9 +438,7 @@ xfs_attr_set(
>>   int
>>   xfs_attr_remove(
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> -	int			flags)
>> +	struct xfs_name		*name)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>>   	struct xfs_da_args	args;
>> @@ -457,7 +449,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);
>>   	if (error)
>>   		return error;
>>   
>> @@ -478,7 +470,7 @@ xfs_attr_remove(
>>   	 */
>>   	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>>   			XFS_ATTRRM_SPACE_RES(mp), 0,
>> -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>> +			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>>   			&args.trans);
>>   	if (error)
>>   		return error;
>> @@ -501,7 +493,7 @@ xfs_attr_remove(
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args.trans);
>>   
>> -	if ((flags & ATTR_KERNOTIME) == 0)
>> +	if ((name->type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>>   
>>   	/*
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>> +		 unsigned char *value, int valuelen);
>>   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 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..f8fb6e10 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);
>> +	name.type = ATTR_ALLOC | ATTR_ROOT;
>> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
>>   	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);
>> +		name.type = ATTR_ROOT;
>> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
>>   
>>   		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);
>>   
>>   		/*
>>   		 * 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 d440426..626420d 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error = -EFAULT;
>> -	size_t			namelen;
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +		.type		= flags,
>> +	};
>>   
>>   	if (*len > XFS_XATTR_SIZE_MAX)
>>   		return -EINVAL;
>> @@ -439,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);
>>   	if (error)
>>   		goto out_kfree;
>>   
>> @@ -463,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;
>> @@ -474,8 +476,10 @@ 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);
>> +	xname.type = flags;
>> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	kfree(kbuf);
>> @@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
>>   	uint32_t		flags)
>>   {
>>   	int			error;
>> -	size_t			namelen;
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +		.type		= flags,
>> +	};
>>   
>>   	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);
>>   	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 92de0a7..469e8e2 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -49,10 +49,14 @@ 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,
>> -				     ATTR_SECURE);
>> +		struct xfs_name	name = {
>> +			.name	= xattr->name,
>> +			.len	= strlen(xattr->name),
>> +			.type	= ATTR_SECURE,
>> +		};
>> +
>> +		error = xfs_attr_set(ip, &name,
>> +				     xattr->value, xattr->value_len);
>>   		if (error < 0)
>>   			break;
>>   	}
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 59ffe6c..6309da4 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -20,19 +20,21 @@ 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);
>> +	struct xfs_name xname = {
>> +		.name	= name,
>> +		.len	= strlen(name),
>> +		.type	= handler->flags
>> +	};
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (!size) {
>> -		xflags |= ATTR_KERNOVAL;
>> +		xname.type |= ATTR_KERNOVAL;
>>   		value = NULL;
>>   	}
>>   
>> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
>> -			     &asize, xflags);
>> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
>>   	if (error)
>>   		return error;
>>   	return asize;
>> @@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   		struct inode *inode, const char *name, const void *value,
>>   		size_t size, int flags)
>>   {
>> -	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),
>> +		.type		= handler->flags,
>> +	};
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (flags & XATTR_CREATE)
>> -		xflags |= ATTR_CREATE;
>> +		xname.type |= ATTR_CREATE;
>>   	if (flags & XATTR_REPLACE)
>> -		xflags |= ATTR_REPLACE;
>> +		xname.type |= 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);
>> +	error = xfs_attr_set(ip, &xname, (void *)value, size);
>>   	if (!error)
>> -		xfs_forget_acl(inode, name, xflags);
>> +		xfs_forget_acl(inode, name, xname.type);
>>   
>>   	return error;
>>   }
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-18 18:09     ` Allison Collins
@ 2019-09-18 18:14       ` Brian Foster
  2019-09-18 18:48         ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-18 18:14 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Sep 18, 2019 at 11:09:48AM -0700, Allison Collins wrote:
> 
> 
> On 9/18/19 9:43 AM, Brian Foster wrote:
> > On Thu, Sep 05, 2019 at 03:18:19PM -0700, Allison Collins wrote:
> > > This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
> > >   fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
> > >   fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
> > >   fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
> > >   fs/xfs/xfs_iops.c        | 12 ++++++++----
> > >   fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
> > >   6 files changed, 80 insertions(+), 75 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 7589cb7..d0308d6 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > ...
> > > @@ -139,30 +137,28 @@ 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)
> > > +	int			*valuelenp)
> > >   {
> > >   	struct xfs_da_args	args;
> > >   	uint			lock_mode;
> > >   	int			error;
> > > -	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> > > +	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> > 
> > While this looks like a nice cleanup, I'm not a huge fan of burying the
> > attr flags in the xfs_name like this. To me they are distinct parameters
> > and the interface isn't as clear for new callers. Other than that the
> > patch looks good.
> > 
> > BTW after looking at the next patch, a reasonable compromise might be to
> > leave the flags param for the top level xfs_attr_*() functions and then
> > bury the value in args->name.type for the rest of the lower level code
> > to use. Just a thought..
> > 
> > Brian
> 
> Yes, this was a sort of cleanup suggested in the last review.  While it is
> nice to have less parameters, I ended up having mixed feels about using type
> for flags.  Mostly just because a name of "type" generally implies that the
> field should be handled like an enumeration, and a "flag" implies that is
> should be handled like a bitmask.  So I found myself doing a lot of double
> takes just in looking at it.  I am fine with moving flags back out, but I
> would like folks to weigh in so that we have a consensus on what people are
> comfortable with.
> 

Sure..

> I'm not sure I like the idea of putting "value" in "type" though. Generally
> a "value" implies a sort of payload with a length (of which we have).  But
> but I think separating value and valuelen would look all sorts of weird.  I
> think either value should stay outside with valuelen, or we should probably
> bite the bullet and introduce a new struct for the purpose.  Thoughts?
> 

Note that I was referring to the flags value in a general sense, not the
actual attr value. I.e., leave the xfs_attr_() flags param, then store
flags in args->name.type if you really wanted to save the extra field
from args and remove the rest of the flags passing beneath the top level
functions.

Brian

> Allison
> 
> > 
> > >   	XFS_STATS_INC(ip->i_mount, xs_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);
> > >   	if (error)
> > >   		return error;
> > >   	/* Entirely possible to look up a name which doesn't exist */
> > >   	args.op_flags = XFS_DA_OP_OKNOENT;
> > > -	if (flags & ATTR_ALLOC)
> > > +	if (name->type & ATTR_ALLOC)
> > >   		args.op_flags |= XFS_DA_OP_ALLOCVAL;
> > >   	else
> > >   		args.value = *value;
> > > @@ -175,7 +171,7 @@ xfs_attr_get(
> > >   	/* on error, we have to clean up allocated value buffers */
> > >   	if (error) {
> > > -		if (flags & ATTR_ALLOC) {
> > > +		if (name->type & ATTR_ALLOC) {
> > >   			kmem_free(args.value);
> > >   			*value = NULL;
> > >   		}
> > > @@ -339,16 +335,14 @@ 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)
> > > +	int			valuelen)
> > >   {
> > >   	struct xfs_mount	*mp = dp->i_mount;
> > >   	struct xfs_da_args	args;
> > >   	struct xfs_trans_res	tres;
> > > -	int			rsvd = (flags & ATTR_ROOT) != 0;
> > > +	int			rsvd = (name->type & ATTR_ROOT) != 0;
> > >   	int			error, local;
> > >   	XFS_STATS_INC(mp, xs_attr_set);
> > > @@ -356,7 +350,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);
> > >   	if (error)
> > >   		return error;
> > > @@ -419,7 +413,7 @@ xfs_attr_set(
> > >   	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > >   		xfs_trans_set_sync(args.trans);
> > > -	if ((flags & ATTR_KERNOTIME) == 0)
> > > +	if ((name->type & ATTR_KERNOTIME) == 0)
> > >   		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
> > >   	/*
> > > @@ -444,9 +438,7 @@ xfs_attr_set(
> > >   int
> > >   xfs_attr_remove(
> > >   	struct xfs_inode	*dp,
> > > -	const unsigned char	*name,
> > > -	size_t			namelen,
> > > -	int			flags)
> > > +	struct xfs_name		*name)
> > >   {
> > >   	struct xfs_mount	*mp = dp->i_mount;
> > >   	struct xfs_da_args	args;
> > > @@ -457,7 +449,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);
> > >   	if (error)
> > >   		return error;
> > > @@ -478,7 +470,7 @@ xfs_attr_remove(
> > >   	 */
> > >   	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
> > >   			XFS_ATTRRM_SPACE_RES(mp), 0,
> > > -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> > > +			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> > >   			&args.trans);
> > >   	if (error)
> > >   		return error;
> > > @@ -501,7 +493,7 @@ xfs_attr_remove(
> > >   	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > >   		xfs_trans_set_sync(args.trans);
> > > -	if ((flags & ATTR_KERNOTIME) == 0)
> > > +	if ((name->type & ATTR_KERNOTIME) == 0)
> > >   		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
> > >   	/*
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> > > +		 unsigned char *value, int valuelen);
> > >   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 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..f8fb6e10 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);
> > > +	name.type = ATTR_ALLOC | ATTR_ROOT;
> > > +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
> > >   	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);
> > > +		name.type = ATTR_ROOT;
> > > +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
> > >   		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);
> > >   		/*
> > >   		 * 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 d440426..626420d 100644
> > > --- a/fs/xfs/xfs_ioctl.c
> > > +++ b/fs/xfs/xfs_ioctl.c
> > > @@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
> > >   {
> > >   	unsigned char		*kbuf;
> > >   	int			error = -EFAULT;
> > > -	size_t			namelen;
> > > +	struct xfs_name		xname = {
> > > +		.name		= name,
> > > +		.len		= strlen(name),
> > > +		.type		= flags,
> > > +	};
> > >   	if (*len > XFS_XATTR_SIZE_MAX)
> > >   		return -EINVAL;
> > > @@ -439,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);
> > >   	if (error)
> > >   		goto out_kfree;
> > > @@ -463,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;
> > > @@ -474,8 +476,10 @@ 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);
> > > +	xname.type = flags;
> > > +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
> > >   	if (!error)
> > >   		xfs_forget_acl(inode, name, flags);
> > >   	kfree(kbuf);
> > > @@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
> > >   	uint32_t		flags)
> > >   {
> > >   	int			error;
> > > -	size_t			namelen;
> > > +	struct xfs_name		xname = {
> > > +		.name		= name,
> > > +		.len		= strlen(name),
> > > +		.type		= flags,
> > > +	};
> > >   	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);
> > >   	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 92de0a7..469e8e2 100644
> > > --- a/fs/xfs/xfs_iops.c
> > > +++ b/fs/xfs/xfs_iops.c
> > > @@ -49,10 +49,14 @@ 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,
> > > -				     ATTR_SECURE);
> > > +		struct xfs_name	name = {
> > > +			.name	= xattr->name,
> > > +			.len	= strlen(xattr->name),
> > > +			.type	= ATTR_SECURE,
> > > +		};
> > > +
> > > +		error = xfs_attr_set(ip, &name,
> > > +				     xattr->value, xattr->value_len);
> > >   		if (error < 0)
> > >   			break;
> > >   	}
> > > diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> > > index 59ffe6c..6309da4 100644
> > > --- a/fs/xfs/xfs_xattr.c
> > > +++ b/fs/xfs/xfs_xattr.c
> > > @@ -20,19 +20,21 @@ 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);
> > > +	struct xfs_name xname = {
> > > +		.name	= name,
> > > +		.len	= strlen(name),
> > > +		.type	= handler->flags
> > > +	};
> > >   	/* Convert Linux syscall to XFS internal ATTR flags */
> > >   	if (!size) {
> > > -		xflags |= ATTR_KERNOVAL;
> > > +		xname.type |= ATTR_KERNOVAL;
> > >   		value = NULL;
> > >   	}
> > > -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> > > -			     &asize, xflags);
> > > +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
> > >   	if (error)
> > >   		return error;
> > >   	return asize;
> > > @@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
> > >   		struct inode *inode, const char *name, const void *value,
> > >   		size_t size, int flags)
> > >   {
> > > -	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),
> > > +		.type		= handler->flags,
> > > +	};
> > >   	/* Convert Linux syscall to XFS internal ATTR flags */
> > >   	if (flags & XATTR_CREATE)
> > > -		xflags |= ATTR_CREATE;
> > > +		xname.type |= ATTR_CREATE;
> > >   	if (flags & XATTR_REPLACE)
> > > -		xflags |= ATTR_REPLACE;
> > > +		xname.type |= 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);
> > > +	error = xfs_attr_set(ip, &xname, (void *)value, size);
> > >   	if (!error)
> > > -		xfs_forget_acl(inode, name, xflags);
> > > +		xfs_forget_acl(inode, name, xname.type);
> > >   	return error;
> > >   }
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-18 18:14       ` Brian Foster
@ 2019-09-18 18:48         ` Allison Collins
  2019-09-18 19:06           ` Darrick J. Wong
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-18 18:48 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/18/19 11:14 AM, Brian Foster wrote:
> On Wed, Sep 18, 2019 at 11:09:48AM -0700, Allison Collins wrote:
>>
>>
>> On 9/18/19 9:43 AM, Brian Foster wrote:
>>> On Thu, Sep 05, 2019 at 03:18:19PM -0700, Allison Collins wrote:
>>>> This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
>>>>    fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>>>>    fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
>>>>    fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
>>>>    fs/xfs/xfs_iops.c        | 12 ++++++++----
>>>>    fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
>>>>    6 files changed, 80 insertions(+), 75 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 7589cb7..d0308d6 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> ...
>>>> @@ -139,30 +137,28 @@ 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)
>>>> +	int			*valuelenp)
>>>>    {
>>>>    	struct xfs_da_args	args;
>>>>    	uint			lock_mode;
>>>>    	int			error;
>>>> -	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
>>>> +	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
>>>
>>> While this looks like a nice cleanup, I'm not a huge fan of burying the
>>> attr flags in the xfs_name like this. To me they are distinct parameters
>>> and the interface isn't as clear for new callers. Other than that the
>>> patch looks good.
>>>
>>> BTW after looking at the next patch, a reasonable compromise might be to
>>> leave the flags param for the top level xfs_attr_*() functions and then
>>> bury the value in args->name.type for the rest of the lower level code
>>> to use. Just a thought..
>>>
>>> Brian
>>
>> Yes, this was a sort of cleanup suggested in the last review.  While it is
>> nice to have less parameters, I ended up having mixed feels about using type
>> for flags.  Mostly just because a name of "type" generally implies that the
>> field should be handled like an enumeration, and a "flag" implies that is
>> should be handled like a bitmask.  So I found myself doing a lot of double
>> takes just in looking at it.  I am fine with moving flags back out, but I
>> would like folks to weigh in so that we have a consensus on what people are
>> comfortable with.
>>
> 
> Sure..
> 
>> I'm not sure I like the idea of putting "value" in "type" though. Generally
>> a "value" implies a sort of payload with a length (of which we have).  But
>> but I think separating value and valuelen would look all sorts of weird.  I
>> think either value should stay outside with valuelen, or we should probably
>> bite the bullet and introduce a new struct for the purpose.  Thoughts?
>>
> 
> Note that I was referring to the flags value in a general sense, not the
> actual attr value. I.e., leave the xfs_attr_() flags param, then store
> flags in args->name.type if you really wanted to save the extra field
> from args and remove the rest of the flags passing beneath the top level
> functions.
> 
> Brian

Oh, I see, I misunderstood what you meant.  That makes more sense :-) 
Sure that seems like a reasonable compromise.  Lets see if we can get a 
consensus from folks though, because little stuff like this tends to 
pepper small changes up through the set, and it would be nice to get 
everyone settled on the same page.  :-)

Allison

> 
>> Allison
>>
>>>
>>>>    	XFS_STATS_INC(ip->i_mount, xs_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);
>>>>    	if (error)
>>>>    		return error;
>>>>    	/* Entirely possible to look up a name which doesn't exist */
>>>>    	args.op_flags = XFS_DA_OP_OKNOENT;
>>>> -	if (flags & ATTR_ALLOC)
>>>> +	if (name->type & ATTR_ALLOC)
>>>>    		args.op_flags |= XFS_DA_OP_ALLOCVAL;
>>>>    	else
>>>>    		args.value = *value;
>>>> @@ -175,7 +171,7 @@ xfs_attr_get(
>>>>    	/* on error, we have to clean up allocated value buffers */
>>>>    	if (error) {
>>>> -		if (flags & ATTR_ALLOC) {
>>>> +		if (name->type & ATTR_ALLOC) {
>>>>    			kmem_free(args.value);
>>>>    			*value = NULL;
>>>>    		}
>>>> @@ -339,16 +335,14 @@ 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)
>>>> +	int			valuelen)
>>>>    {
>>>>    	struct xfs_mount	*mp = dp->i_mount;
>>>>    	struct xfs_da_args	args;
>>>>    	struct xfs_trans_res	tres;
>>>> -	int			rsvd = (flags & ATTR_ROOT) != 0;
>>>> +	int			rsvd = (name->type & ATTR_ROOT) != 0;
>>>>    	int			error, local;
>>>>    	XFS_STATS_INC(mp, xs_attr_set);
>>>> @@ -356,7 +350,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);
>>>>    	if (error)
>>>>    		return error;
>>>> @@ -419,7 +413,7 @@ xfs_attr_set(
>>>>    	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>>>    		xfs_trans_set_sync(args.trans);
>>>> -	if ((flags & ATTR_KERNOTIME) == 0)
>>>> +	if ((name->type & ATTR_KERNOTIME) == 0)
>>>>    		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>>>>    	/*
>>>> @@ -444,9 +438,7 @@ xfs_attr_set(
>>>>    int
>>>>    xfs_attr_remove(
>>>>    	struct xfs_inode	*dp,
>>>> -	const unsigned char	*name,
>>>> -	size_t			namelen,
>>>> -	int			flags)
>>>> +	struct xfs_name		*name)
>>>>    {
>>>>    	struct xfs_mount	*mp = dp->i_mount;
>>>>    	struct xfs_da_args	args;
>>>> @@ -457,7 +449,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);
>>>>    	if (error)
>>>>    		return error;
>>>> @@ -478,7 +470,7 @@ xfs_attr_remove(
>>>>    	 */
>>>>    	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>>>>    			XFS_ATTRRM_SPACE_RES(mp), 0,
>>>> -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>>>> +			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>>>>    			&args.trans);
>>>>    	if (error)
>>>>    		return error;
>>>> @@ -501,7 +493,7 @@ xfs_attr_remove(
>>>>    	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>>>    		xfs_trans_set_sync(args.trans);
>>>> -	if ((flags & ATTR_KERNOTIME) == 0)
>>>> +	if ((name->type & ATTR_KERNOTIME) == 0)
>>>>    		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>>>>    	/*
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>> index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>>> +		 unsigned char *value, int valuelen);
>>>>    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 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..f8fb6e10 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);
>>>> +	name.type = ATTR_ALLOC | ATTR_ROOT;
>>>> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
>>>>    	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);
>>>> +		name.type = ATTR_ROOT;
>>>> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
>>>>    		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);
>>>>    		/*
>>>>    		 * 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 d440426..626420d 100644
>>>> --- a/fs/xfs/xfs_ioctl.c
>>>> +++ b/fs/xfs/xfs_ioctl.c
>>>> @@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
>>>>    {
>>>>    	unsigned char		*kbuf;
>>>>    	int			error = -EFAULT;
>>>> -	size_t			namelen;
>>>> +	struct xfs_name		xname = {
>>>> +		.name		= name,
>>>> +		.len		= strlen(name),
>>>> +		.type		= flags,
>>>> +	};
>>>>    	if (*len > XFS_XATTR_SIZE_MAX)
>>>>    		return -EINVAL;
>>>> @@ -439,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);
>>>>    	if (error)
>>>>    		goto out_kfree;
>>>> @@ -463,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;
>>>> @@ -474,8 +476,10 @@ 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);
>>>> +	xname.type = flags;
>>>> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
>>>>    	if (!error)
>>>>    		xfs_forget_acl(inode, name, flags);
>>>>    	kfree(kbuf);
>>>> @@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
>>>>    	uint32_t		flags)
>>>>    {
>>>>    	int			error;
>>>> -	size_t			namelen;
>>>> +	struct xfs_name		xname = {
>>>> +		.name		= name,
>>>> +		.len		= strlen(name),
>>>> +		.type		= flags,
>>>> +	};
>>>>    	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);
>>>>    	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 92de0a7..469e8e2 100644
>>>> --- a/fs/xfs/xfs_iops.c
>>>> +++ b/fs/xfs/xfs_iops.c
>>>> @@ -49,10 +49,14 @@ 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,
>>>> -				     ATTR_SECURE);
>>>> +		struct xfs_name	name = {
>>>> +			.name	= xattr->name,
>>>> +			.len	= strlen(xattr->name),
>>>> +			.type	= ATTR_SECURE,
>>>> +		};
>>>> +
>>>> +		error = xfs_attr_set(ip, &name,
>>>> +				     xattr->value, xattr->value_len);
>>>>    		if (error < 0)
>>>>    			break;
>>>>    	}
>>>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>>>> index 59ffe6c..6309da4 100644
>>>> --- a/fs/xfs/xfs_xattr.c
>>>> +++ b/fs/xfs/xfs_xattr.c
>>>> @@ -20,19 +20,21 @@ 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);
>>>> +	struct xfs_name xname = {
>>>> +		.name	= name,
>>>> +		.len	= strlen(name),
>>>> +		.type	= handler->flags
>>>> +	};
>>>>    	/* Convert Linux syscall to XFS internal ATTR flags */
>>>>    	if (!size) {
>>>> -		xflags |= ATTR_KERNOVAL;
>>>> +		xname.type |= ATTR_KERNOVAL;
>>>>    		value = NULL;
>>>>    	}
>>>> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
>>>> -			     &asize, xflags);
>>>> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
>>>>    	if (error)
>>>>    		return error;
>>>>    	return asize;
>>>> @@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>>>    		struct inode *inode, const char *name, const void *value,
>>>>    		size_t size, int flags)
>>>>    {
>>>> -	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),
>>>> +		.type		= handler->flags,
>>>> +	};
>>>>    	/* Convert Linux syscall to XFS internal ATTR flags */
>>>>    	if (flags & XATTR_CREATE)
>>>> -		xflags |= ATTR_CREATE;
>>>> +		xname.type |= ATTR_CREATE;
>>>>    	if (flags & XATTR_REPLACE)
>>>> -		xflags |= ATTR_REPLACE;
>>>> +		xname.type |= 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);
>>>> +	error = xfs_attr_set(ip, &xname, (void *)value, size);
>>>>    	if (!error)
>>>> -		xfs_forget_acl(inode, name, xflags);
>>>> +		xfs_forget_acl(inode, name, xname.type);
>>>>    	return error;
>>>>    }
>>>> -- 
>>>> 2.7.4
>>>>

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

* Re: [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name
  2019-09-18 18:48         ` Allison Collins
@ 2019-09-18 19:06           ` Darrick J. Wong
  0 siblings, 0 replies; 64+ messages in thread
From: Darrick J. Wong @ 2019-09-18 19:06 UTC (permalink / raw)
  To: Allison Collins; +Cc: Brian Foster, linux-xfs

On Wed, Sep 18, 2019 at 11:48:28AM -0700, Allison Collins wrote:
> On 9/18/19 11:14 AM, Brian Foster wrote:
> > On Wed, Sep 18, 2019 at 11:09:48AM -0700, Allison Collins wrote:
> > > 
> > > 
> > > On 9/18/19 9:43 AM, Brian Foster wrote:
> > > > On Thu, Sep 05, 2019 at 03:18:19PM -0700, Allison Collins wrote:
> > > > > This patch replaces the attribute name, length and flags 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 | 46 +++++++++++++++++++---------------------------
> > > > >    fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
> > > > >    fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
> > > > >    fs/xfs/xfs_ioctl.c       | 28 ++++++++++++++++++----------
> > > > >    fs/xfs/xfs_iops.c        | 12 ++++++++----
> > > > >    fs/xfs/xfs_xattr.c       | 30 +++++++++++++++++-------------
> > > > >    6 files changed, 80 insertions(+), 75 deletions(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > index 7589cb7..d0308d6 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > ...
> > > > > @@ -139,30 +137,28 @@ 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)
> > > > > +	int			*valuelenp)
> > > > >    {
> > > > >    	struct xfs_da_args	args;
> > > > >    	uint			lock_mode;
> > > > >    	int			error;
> > > > > -	ASSERT((flags & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> > > > > +	ASSERT((name->type & (ATTR_ALLOC | ATTR_KERNOVAL)) || *value);
> > > > 
> > > > While this looks like a nice cleanup, I'm not a huge fan of burying the
> > > > attr flags in the xfs_name like this. To me they are distinct parameters
> > > > and the interface isn't as clear for new callers. Other than that the
> > > > patch looks good.
> > > > 
> > > > BTW after looking at the next patch, a reasonable compromise might be to
> > > > leave the flags param for the top level xfs_attr_*() functions and then
> > > > bury the value in args->name.type for the rest of the lower level code
> > > > to use. Just a thought..
> > > > 
> > > > Brian
> > > 
> > > Yes, this was a sort of cleanup suggested in the last review.  While it is
> > > nice to have less parameters, I ended up having mixed feels about using type
> > > for flags.  Mostly just because a name of "type" generally implies that the
> > > field should be handled like an enumeration, and a "flag" implies that is
> > > should be handled like a bitmask.  So I found myself doing a lot of double
> > > takes just in looking at it.  I am fine with moving flags back out, but I
> > > would like folks to weigh in so that we have a consensus on what people are
> > > comfortable with.
> > > 
> > 
> > Sure..
> > 
> > > I'm not sure I like the idea of putting "value" in "type" though. Generally
> > > a "value" implies a sort of payload with a length (of which we have).  But
> > > but I think separating value and valuelen would look all sorts of weird.  I
> > > think either value should stay outside with valuelen, or we should probably
> > > bite the bullet and introduce a new struct for the purpose.  Thoughts?
> > > 
> > 
> > Note that I was referring to the flags value in a general sense, not the
> > actual attr value. I.e., leave the xfs_attr_() flags param, then store
> > flags in args->name.type if you really wanted to save the extra field
> > from args and remove the rest of the flags passing beneath the top level
> > functions.
> > 
> > Brian
> 
> Oh, I see, I misunderstood what you meant.  That makes more sense :-) Sure
> that seems like a reasonable compromise.  Lets see if we can get a consensus
> from folks though, because little stuff like this tends to pepper small
> changes up through the set, and it would be nice to get everyone settled on
> the same page.  :-)

/me agrees with Brian, the top level xfs_attr_[gs]et functions should
take a separate flags argument, even if internally it stuffs them into
the "type" argument of the name to save space in the args structure.

--D

> Allison
> 
> > 
> > > Allison
> > > 
> > > > 
> > > > >    	XFS_STATS_INC(ip->i_mount, xs_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);
> > > > >    	if (error)
> > > > >    		return error;
> > > > >    	/* Entirely possible to look up a name which doesn't exist */
> > > > >    	args.op_flags = XFS_DA_OP_OKNOENT;
> > > > > -	if (flags & ATTR_ALLOC)
> > > > > +	if (name->type & ATTR_ALLOC)
> > > > >    		args.op_flags |= XFS_DA_OP_ALLOCVAL;
> > > > >    	else
> > > > >    		args.value = *value;
> > > > > @@ -175,7 +171,7 @@ xfs_attr_get(
> > > > >    	/* on error, we have to clean up allocated value buffers */
> > > > >    	if (error) {
> > > > > -		if (flags & ATTR_ALLOC) {
> > > > > +		if (name->type & ATTR_ALLOC) {
> > > > >    			kmem_free(args.value);
> > > > >    			*value = NULL;
> > > > >    		}
> > > > > @@ -339,16 +335,14 @@ 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)
> > > > > +	int			valuelen)
> > > > >    {
> > > > >    	struct xfs_mount	*mp = dp->i_mount;
> > > > >    	struct xfs_da_args	args;
> > > > >    	struct xfs_trans_res	tres;
> > > > > -	int			rsvd = (flags & ATTR_ROOT) != 0;
> > > > > +	int			rsvd = (name->type & ATTR_ROOT) != 0;
> > > > >    	int			error, local;
> > > > >    	XFS_STATS_INC(mp, xs_attr_set);
> > > > > @@ -356,7 +350,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);
> > > > >    	if (error)
> > > > >    		return error;
> > > > > @@ -419,7 +413,7 @@ xfs_attr_set(
> > > > >    	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > > > >    		xfs_trans_set_sync(args.trans);
> > > > > -	if ((flags & ATTR_KERNOTIME) == 0)
> > > > > +	if ((name->type & ATTR_KERNOTIME) == 0)
> > > > >    		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
> > > > >    	/*
> > > > > @@ -444,9 +438,7 @@ xfs_attr_set(
> > > > >    int
> > > > >    xfs_attr_remove(
> > > > >    	struct xfs_inode	*dp,
> > > > > -	const unsigned char	*name,
> > > > > -	size_t			namelen,
> > > > > -	int			flags)
> > > > > +	struct xfs_name		*name)
> > > > >    {
> > > > >    	struct xfs_mount	*mp = dp->i_mount;
> > > > >    	struct xfs_da_args	args;
> > > > > @@ -457,7 +449,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);
> > > > >    	if (error)
> > > > >    		return error;
> > > > > @@ -478,7 +470,7 @@ xfs_attr_remove(
> > > > >    	 */
> > > > >    	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
> > > > >    			XFS_ATTRRM_SPACE_RES(mp), 0,
> > > > > -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> > > > > +			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> > > > >    			&args.trans);
> > > > >    	if (error)
> > > > >    		return error;
> > > > > @@ -501,7 +493,7 @@ xfs_attr_remove(
> > > > >    	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > > > >    		xfs_trans_set_sync(args.trans);
> > > > > -	if ((flags & ATTR_KERNOTIME) == 0)
> > > > > +	if ((name->type & ATTR_KERNOTIME) == 0)
> > > > >    		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
> > > > >    	/*
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > index 106a2f2..cedb4e2 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 xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> > > > > +		 unsigned char *value, int valuelen);
> > > > >    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 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..f8fb6e10 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);
> > > > > +	name.type = ATTR_ALLOC | ATTR_ROOT;
> > > > > +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len);
> > > > >    	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);
> > > > > +		name.type = ATTR_ROOT;
> > > > > +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
> > > > >    		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);
> > > > >    		/*
> > > > >    		 * 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 d440426..626420d 100644
> > > > > --- a/fs/xfs/xfs_ioctl.c
> > > > > +++ b/fs/xfs/xfs_ioctl.c
> > > > > @@ -431,7 +431,11 @@ xfs_attrmulti_attr_get(
> > > > >    {
> > > > >    	unsigned char		*kbuf;
> > > > >    	int			error = -EFAULT;
> > > > > -	size_t			namelen;
> > > > > +	struct xfs_name		xname = {
> > > > > +		.name		= name,
> > > > > +		.len		= strlen(name),
> > > > > +		.type		= flags,
> > > > > +	};
> > > > >    	if (*len > XFS_XATTR_SIZE_MAX)
> > > > >    		return -EINVAL;
> > > > > @@ -439,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);
> > > > >    	if (error)
> > > > >    		goto out_kfree;
> > > > > @@ -463,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;
> > > > > @@ -474,8 +476,10 @@ 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);
> > > > > +	xname.type = flags;
> > > > > +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
> > > > >    	if (!error)
> > > > >    		xfs_forget_acl(inode, name, flags);
> > > > >    	kfree(kbuf);
> > > > > @@ -489,12 +493,16 @@ xfs_attrmulti_attr_remove(
> > > > >    	uint32_t		flags)
> > > > >    {
> > > > >    	int			error;
> > > > > -	size_t			namelen;
> > > > > +	struct xfs_name		xname = {
> > > > > +		.name		= name,
> > > > > +		.len		= strlen(name),
> > > > > +		.type		= flags,
> > > > > +	};
> > > > >    	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);
> > > > >    	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 92de0a7..469e8e2 100644
> > > > > --- a/fs/xfs/xfs_iops.c
> > > > > +++ b/fs/xfs/xfs_iops.c
> > > > > @@ -49,10 +49,14 @@ 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,
> > > > > -				     ATTR_SECURE);
> > > > > +		struct xfs_name	name = {
> > > > > +			.name	= xattr->name,
> > > > > +			.len	= strlen(xattr->name),
> > > > > +			.type	= ATTR_SECURE,
> > > > > +		};
> > > > > +
> > > > > +		error = xfs_attr_set(ip, &name,
> > > > > +				     xattr->value, xattr->value_len);
> > > > >    		if (error < 0)
> > > > >    			break;
> > > > >    	}
> > > > > diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> > > > > index 59ffe6c..6309da4 100644
> > > > > --- a/fs/xfs/xfs_xattr.c
> > > > > +++ b/fs/xfs/xfs_xattr.c
> > > > > @@ -20,19 +20,21 @@ 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);
> > > > > +	struct xfs_name xname = {
> > > > > +		.name	= name,
> > > > > +		.len	= strlen(name),
> > > > > +		.type	= handler->flags
> > > > > +	};
> > > > >    	/* Convert Linux syscall to XFS internal ATTR flags */
> > > > >    	if (!size) {
> > > > > -		xflags |= ATTR_KERNOVAL;
> > > > > +		xname.type |= ATTR_KERNOVAL;
> > > > >    		value = NULL;
> > > > >    	}
> > > > > -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> > > > > -			     &asize, xflags);
> > > > > +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize);
> > > > >    	if (error)
> > > > >    		return error;
> > > > >    	return asize;
> > > > > @@ -65,23 +67,25 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
> > > > >    		struct inode *inode, const char *name, const void *value,
> > > > >    		size_t size, int flags)
> > > > >    {
> > > > > -	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),
> > > > > +		.type		= handler->flags,
> > > > > +	};
> > > > >    	/* Convert Linux syscall to XFS internal ATTR flags */
> > > > >    	if (flags & XATTR_CREATE)
> > > > > -		xflags |= ATTR_CREATE;
> > > > > +		xname.type |= ATTR_CREATE;
> > > > >    	if (flags & XATTR_REPLACE)
> > > > > -		xflags |= ATTR_REPLACE;
> > > > > +		xname.type |= 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);
> > > > > +	error = xfs_attr_set(ip, &xname, (void *)value, size);
> > > > >    	if (!error)
> > > > > -		xfs_forget_acl(inode, name, xflags);
> > > > > +		xfs_forget_acl(inode, name, xname.type);
> > > > >    	return error;
> > > > >    }
> > > > > -- 
> > > > > 2.7.4
> > > > > 

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

* Re: [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2019-09-18 16:44   ` Brian Foster
  2019-09-18 16:47     ` Christoph Hellwig
@ 2019-09-18 19:55     ` Allison Collins
  1 sibling, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-18 19:55 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs


On 9/18/19 9:44 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:20PM -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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        |  34 ++++++-------
>>   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        |  22 ++++-----
>>   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, 130 insertions(+), 125 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index d0308d6..50e099f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -71,13 +71,13 @@ xfs_attr_args_init(
>>   	args->geo = dp->i_mount->m_attr_geo;
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>> -	args->flags = name->type;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> -	if (args->namelen >= MAXNAMELEN)
>> +	args->name.type = name->type;
>> +	args->name.name = name->name;
>> +	args->name.len = name->len;
> 
> Looks like this could be a struct copy:
> 
> 	args->name = *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;
>>   }
>>   
> ...
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index 867c5de..e8d6721 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
> ...
>> @@ -259,8 +259,8 @@ xfs_dir_createname(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	args->name.name = name->name;
>> +	args->name.len = name->len;
>>   	args->filetype = name->type;
>>   	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>>   	args->inumber = inum;
>> @@ -355,8 +355,8 @@ 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;
>> +	args->name.name = name->name;
>> +	args->name.len = name->len;
>>   	args->filetype = name->type;
>>   	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>>   	args->dp = dp;
>> @@ -427,8 +427,8 @@ xfs_dir_removename(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	args->name.name = name->name;
>> +	args->name.len = name->len;
>>   	args->filetype = name->type;
>>   	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>>   	args->inumber = ino;
>> @@ -488,8 +488,8 @@ xfs_dir_replace(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	args->name.name = name->name;
>> +	args->name.len = name->len;
>>   	args->filetype = name->type;
>>   	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
>>   	args->inumber = inum;
> 
> More struct copy candidates above. Modulo that and the comments on the
> previous patch, the rest LGTM:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
i

Alrighty, will do.  Thanks for the review ;-)

Allison

> 
>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 9595ced..94269b9 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 85f14fc..fdc1431 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 eaae275..e0f524d 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -1669,7 +1669,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)
>> @@ -1678,9 +1678,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;
>> @@ -1733,7 +1734,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)
>> @@ -1743,12 +1744,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	[flat|nested] 64+ messages in thread

* Re: [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines
  2019-09-05 22:18 ` [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-09-19 17:47   ` Brian Foster
  2019-09-19 23:51     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-19 17:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:22PM -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 Henderson <allison.henderson@oracle.com>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Extra s-o-b tag?

> ---
>  fs/xfs/libxfs/xfs_attr.c      | 150 +++++++++++++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c |  92 +++++++++++++++++---------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>  4 files changed, 161 insertions(+), 84 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 50e099f..a297857 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_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp);
>  

The fact that this is not named xfs_attr_leaf_*() kind of stands out
here, particularly since the node variant uses the xfs_attr_* prefix.
Hm? (Same goes for xfs_shortform_has_attr() I suppose..).

>  /*
>   * 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);
>  
> @@ -309,6 +312,32 @@ 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_shortform_has_attr(args, NULL, NULL);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_leaf_has_attr(args, &bp);
> +		xfs_trans_brelse(args->trans, bp);
> +	} else {
> +		error = xfs_attr_node_hasname(args, NULL);
> +	}
> +
> +	return error;
> +}
> +

FWIW, I think it's preferable to include new functions like this with
the first user. I'm a bit curious about the use of error codes here as
opposed to returning a boolean. I could see being able to handle
unexpected errors as a good reason for doing that, but taking a quick
look ahead, it appears neither caller of xfs_has_attr() does so. ;)

(To be clear, I think keeping the function as is and fixing up the
eventual callers to handle unexpected errors is probably the right thing
to do.).

> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
> @@ -574,26 +603,17 @@ 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, -1, &bp);
> -	if (error)
> -		return error;
> -

It looks like we lose this unexpected error check here (i.e. suppose we
got -ENOMEM or -EFSCORRUPTED or something that indicates we shouldn't
continue). FWIW, this seems to repeat throughout this patch where we've
invoked the new helpers..

> -	/*
>  	 * 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_leaf_has_attr(args, &bp);
>  	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return retval;
> @@ -745,6 +765,25 @@ xfs_attr_leaf_addname(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +STATIC int
> +xfs_leaf_has_attr(
> +	struct xfs_da_args      *args,
> +	struct xfs_buf		**bp)
> +{
> +	int                     error = 0;
> +
> +	args->blkno = 0;

This seems misplaced for a helper, but I could be missing context.  Why
not just pass zero directly and leave the args->blkno assignment to the
caller?

> +	error = xfs_attr3_leaf_read(args->trans, args->dp,
> +			args->blkno, 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
> @@ -764,12 +803,8 @@ xfs_attr_leaf_removename(
>  	 * Remove the attribute.
>  	 */
>  	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> -	if (error)
> -		return error;

Lost error check.

>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
> +	error = xfs_leaf_has_attr(args, &bp);
>  	if (error == -ENOATTR) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -808,12 +843,7 @@ 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);
> -	if (error)
> -		return error;
> -

^ here too. Not sure if I caught them all, but you get the idea. ;)

> -	error = xfs_attr3_leaf_lookup_int(bp, args);
> +	error = xfs_leaf_has_attr(args, &bp);
>  	if (error != -EEXIST)  {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -823,6 +853,43 @@ 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;
> +	struct xfs_inode	*dp;
> +	int			retval, error;
> +
> +	/*
> +	 * 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;
> +

No real need for the dp local variable here if it's just to reference
->i_mount. Also I know that comment isn't introduced by this patch, but
any idea what it actually means? It doesn't make much sense to me at a
glance. :P

> +	/*
> +	 * 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
>   *========================================================================*/
> @@ -855,17 +922,14 @@ 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)

Error check again.

> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error == -EEXIST)
>  		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)) {
> @@ -1070,29 +1134,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.
> @@ -1314,20 +1364,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 cedb4e2..fb56d81 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 xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
> +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 07ce320..a501538 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -590,6 +590,53 @@ 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
> + * basep: If not null, pointer is set to the byte offset of the entry in the
> + *	  list
> + */
> +int
> +xfs_shortform_has_attr(
> +	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;

This function seems like it could just return a bool. Eh, I suppose it's
better to be consistent with the other variants if those ones can return
unrelated errors.

> +}
> +
> +/*
>   * Add a name/value pair to the shortform attribute list.
>   * Overflow from the inode has already been checked for.
>   */
> @@ -598,7 +645,7 @@ 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;
> +	int offset, size, error;
>  	xfs_mount_t *mp;
>  	xfs_inode_t *dp;

Nit: might be good to clean up the typedefs here since you do it in the
remove function as well.

>  	struct xfs_ifork *ifp;
> @@ -612,18 +659,10 @@ 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++) {
> +	error = xfs_shortform_has_attr(args, &sfe, NULL);
>  #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);
> +	ASSERT(error != -EEXIST);
>  #endif

Hmm, interesting. So basically this code walks to the end of the list
for the purpose of placement of the new attr and the debug code simply
asserts that we don't find an existing attr. The only thing that
concerns me is that nothing about xfs_shortform_has_attr() indicates
that the output values are important when the lookup fails. The comment
only explains what the values are when a lookup succeeds. Could we
update the comment to elaborate on this use case to prevent somebody
from unknowingly breaking it down the road?

Also, there's no need for the #ifdef DEBUG any more with just the assert
check in that block.

> -	}
>  
>  	offset = (char *)sfe - (char *)sf;
>  	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> @@ -668,33 +707,24 @@ 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;

This value of end is unused (end is immediately reassigned further down
in the function).

Brian

> -	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_shortform_has_attr(args, &sfe, &base);
> +	if (error == -ENOATTR)
> +		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 536a290..58e9327 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_shortform_has_attr(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] 64+ messages in thread

* Re: [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines
  2019-09-19 17:47   ` Brian Foster
@ 2019-09-19 23:51     ` Allison Collins
  2019-09-20 12:32       ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-19 23:51 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 9/19/19 10:47 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:22PM -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 Henderson <allison.henderson@oracle.com>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Extra s-o-b tag?
Oops, I thought I had caught all the old names.  Will clean out :-)

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 150 +++++++++++++++++++++++++++---------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  92 +++++++++++++++++---------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>>   4 files changed, 161 insertions(+), 84 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 50e099f..a297857 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_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp);
>>   
> 
> The fact that this is not named xfs_attr_leaf_*() kind of stands out
> here, particularly since the node variant uses the xfs_attr_* prefix.
> Hm? (Same goes for xfs_shortform_has_attr() I suppose..).
Sure, I can flip the prefixes around to look a little more consistent
> 
>>   /*
>>    * 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);
>>   
>> @@ -309,6 +312,32 @@ 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_shortform_has_attr(args, NULL, NULL);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_leaf_has_attr(args, &bp);
>> +		xfs_trans_brelse(args->trans, bp);
>> +	} else {
>> +		error = xfs_attr_node_hasname(args, NULL);
>> +	}
>> +
>> +	return error;
>> +}
>> +
> 
> FWIW, I think it's preferable to include new functions like this with
> the first user. I'm a bit curious about the use of error codes here as
> opposed to returning a boolean. I could see being able to handle
> unexpected errors as a good reason for doing that, but taking a quick
> look ahead, it appears neither caller of xfs_has_attr() does so. ;)
> 
> (To be clear, I think keeping the function as is and fixing up the
> eventual callers to handle unexpected errors is probably the right thing
> to do.).

The new top level function actually doesnt get used until patch 18, but 
I guess I try to keep the patch sizes small to make them easier for 
people to review.  Basically we use it to see if there is/isnt an 
attribute present, and then return the appropriate error code right 
away.  IE, trying to remove an attribute that isnt there immediately 
return EENOATTR rather than trying to start a delayed operation that 
isnt going to be successful.  The is because delayed operations are not 
supposed to return error codes.  If they do, they cause a shut down, 
which is not correct here.

Initially I think I had it returning booleans, but it means the top 
level function needs to do extra handling to translate the error codes, 
and I thought it looked messy.  So I decided to stick with the scheme 
that the rest of the code was using.

I skipped ahead about unexpected error codes and see what you mean, so I 
will add some extra handlers there.

> 
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
>> @@ -574,26 +603,17 @@ 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, -1, &bp);
>> -	if (error)
>> -		return error;
>> -
> 
> It looks like we lose this unexpected error check here (i.e. suppose we
> got -ENOMEM or -EFSCORRUPTED or something that indicates we shouldn't
> continue). FWIW, this seems to repeat throughout this patch where we've
> invoked the new helpers..

Ok, I'll add in an explicit check for (retval != -ENOATTR && retval != 
-EEXIST)


> 
>> -	/*
>>   	 * 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_leaf_has_attr(args, &bp);
>>   	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return retval;
>> @@ -745,6 +765,25 @@ xfs_attr_leaf_addname(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +STATIC int
>> +xfs_leaf_has_attr(
>> +	struct xfs_da_args      *args,
>> +	struct xfs_buf		**bp)
>> +{
>> +	int                     error = 0;
>> +
>> +	args->blkno = 0;
> 
> This seems misplaced for a helper, but I could be missing context.  Why
> not just pass zero directly and leave the args->blkno assignment to the
> caller?
I guess just I kept these two lines together since that's was how they 
initially appeared before factoring them out, but it does look a bit 
off.  It should be ok leave the assignment to the caller.  I can push it 
back up.

> 
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp,
>> +			args->blkno, 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
>> @@ -764,12 +803,8 @@ xfs_attr_leaf_removename(
>>   	 * Remove the attribute.
>>   	 */
>>   	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>> -	if (error)
>> -		return error;
> 
> Lost error check.
> 
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>> +	error = xfs_leaf_has_attr(args, &bp);
>>   	if (error == -ENOATTR) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -808,12 +843,7 @@ 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);
>> -	if (error)
>> -		return error;
>> -
> 
> ^ here too. Not sure if I caught them all, but you get the idea. ;)
Ok,I'll sweep through and find them :-)

> 
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>> +	error = xfs_leaf_has_attr(args, &bp);
>>   	if (error != -EEXIST)  {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -823,6 +853,43 @@ 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;
>> +	struct xfs_inode	*dp;
>> +	int			retval, error;
>> +
>> +	/*
>> +	 * 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;
>> +
> 
> No real need for the dp local variable here if it's just to reference
> ->i_mount. Also I know that comment isn't introduced by this patch, but
> any idea what it actually means? It doesn't make much sense to me at a
> glance. :P

Ok, will clean out assignment.  I'm actually not sure as to the comments 
origins either, I assumed it was in reference the the state?  I suppose 
state is used to keep track of a lot of things going on in the calling 
function.  But even in that context, I don't find the comment 
particularly descriptive.  Should I clean it out?

> 
>> +	/*
>> +	 * 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
>>    *========================================================================*/
>> @@ -855,17 +922,14 @@ 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)
> 
> Error check again.
> 
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error == -EEXIST)
>>   		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)) {
>> @@ -1070,29 +1134,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.
>> @@ -1314,20 +1364,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 cedb4e2..fb56d81 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 xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
>> +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 07ce320..a501538 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -590,6 +590,53 @@ 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
>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>> + *	  list
>> + */
>> +int
>> +xfs_shortform_has_attr(
>> +	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;
> 
> This function seems like it could just return a bool. Eh, I suppose it's
> better to be consistent with the other variants if those ones can return
> unrelated errors.
Ok, I prefer the consistency as well.

> 
>> +}
>> +
>> +/*
>>    * Add a name/value pair to the shortform attribute list.
>>    * Overflow from the inode has already been checked for.
>>    */
>> @@ -598,7 +645,7 @@ 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;
>> +	int offset, size, error;
>>   	xfs_mount_t *mp;
>>   	xfs_inode_t *dp;
> 
> Nit: might be good to clean up the typedefs here since you do it in the
> remove function as well.
Sure, will do.

> 
>>   	struct xfs_ifork *ifp;
>> @@ -612,18 +659,10 @@ 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++) {
>> +	error = xfs_shortform_has_attr(args, &sfe, NULL);
>>   #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);
>> +	ASSERT(error != -EEXIST);
>>   #endif
> 
> Hmm, interesting. So basically this code walks to the end of the list
> for the purpose of placement of the new attr and the debug code simply
> asserts that we don't find an existing attr. The only thing that
> concerns me is that nothing about xfs_shortform_has_attr() indicates
> that the output values are important when the lookup fails. The comment
> only explains what the values are when a lookup succeeds. Could we
> update the comment to elaborate on this use case to prevent somebody
> from unknowingly breaking it down the road?
> 
> Also, there's no need for the #ifdef DEBUG any more with just the assert
> check in that block.

Sure, I will clearify the comments and pull out the DEBUG

> 
>> -	}
>>   
>>   	offset = (char *)sfe - (char *)sf;
>>   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> @@ -668,33 +707,24 @@ 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;
> 
> This value of end is unused (end is immediately reassigned further down
> in the function).
> 
> Brian

Ok, I will pick that out. Thank you for the thorough reviews!

Allison

> 
>> -	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_shortform_has_attr(args, &sfe, &base);
>> +	if (error == -ENOATTR)
>> +		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 536a290..58e9327 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_shortform_has_attr(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] 64+ messages in thread

* Re: [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines
  2019-09-19 23:51     ` Allison Collins
@ 2019-09-20 12:32       ` Brian Foster
  0 siblings, 0 replies; 64+ messages in thread
From: Brian Foster @ 2019-09-20 12:32 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 19, 2019 at 04:51:02PM -0700, Allison Collins wrote:
> 
> 
> On 9/19/19 10:47 AM, Brian Foster wrote:
> > On Thu, Sep 05, 2019 at 03:18:22PM -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 Henderson <allison.henderson@oracle.com>
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > 
> > Extra s-o-b tag?
> Oops, I thought I had caught all the old names.  Will clean out :-)
> 
> > 
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c      | 150 +++++++++++++++++++++++++++---------------
> > >   fs/xfs/libxfs/xfs_attr.h      |   1 +
> > >   fs/xfs/libxfs/xfs_attr_leaf.c |  92 +++++++++++++++++---------
> > >   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
> > >   4 files changed, 161 insertions(+), 84 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 50e099f..a297857 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_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp);
> > 
> > The fact that this is not named xfs_attr_leaf_*() kind of stands out
> > here, particularly since the node variant uses the xfs_attr_* prefix.
> > Hm? (Same goes for xfs_shortform_has_attr() I suppose..).
> Sure, I can flip the prefixes around to look a little more consistent
> > 
> > >   /*
> > >    * 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);
> > > @@ -309,6 +312,32 @@ 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_shortform_has_attr(args, NULL, NULL);
> > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > +		error = xfs_leaf_has_attr(args, &bp);
> > > +		xfs_trans_brelse(args->trans, bp);
> > > +	} else {
> > > +		error = xfs_attr_node_hasname(args, NULL);
> > > +	}
> > > +
> > > +	return error;
> > > +}
> > > +
> > 
> > FWIW, I think it's preferable to include new functions like this with
> > the first user. I'm a bit curious about the use of error codes here as
> > opposed to returning a boolean. I could see being able to handle
> > unexpected errors as a good reason for doing that, but taking a quick
> > look ahead, it appears neither caller of xfs_has_attr() does so. ;)
> > 
> > (To be clear, I think keeping the function as is and fixing up the
> > eventual callers to handle unexpected errors is probably the right thing
> > to do.).
> 
> The new top level function actually doesnt get used until patch 18, but I
> guess I try to keep the patch sizes small to make them easier for people to
> review.  Basically we use it to see if there is/isnt an attribute present,
> and then return the appropriate error code right away.  IE, trying to remove
> an attribute that isnt there immediately return EENOATTR rather than trying
> to start a delayed operation that isnt going to be successful.  The is
> because delayed operations are not supposed to return error codes.  If they
> do, they cause a shut down, which is not correct here.
> 

Makes sense. It might be fine to leave the associated refactoring and
just defer the new helper to the later patch, fwiw.

> Initially I think I had it returning booleans, but it means the top level
> function needs to do extra handling to translate the error codes, and I
> thought it looked messy.  So I decided to stick with the scheme that the
> rest of the code was using.
> 

Yeah, it's strange at first, but seems prevalent throughout the xattr
code. Perhaps that's something we can clean up a bit down the road.

> I skipped ahead about unexpected error codes and see what you mean, so I
> will add some extra handlers there.
> 
> > 
> > > +/*
> > >    * Remove the attribute specified in @args.
> > >    */
> > >   int
> > > @@ -574,26 +603,17 @@ 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, -1, &bp);
> > > -	if (error)
> > > -		return error;
> > > -
> > 
> > It looks like we lose this unexpected error check here (i.e. suppose we
> > got -ENOMEM or -EFSCORRUPTED or something that indicates we shouldn't
> > continue). FWIW, this seems to repeat throughout this patch where we've
> > invoked the new helpers..
> 
> Ok, I'll add in an explicit check for (retval != -ENOATTR && retval !=
> -EEXIST)
> 
> 
> > 
> > > -	/*
> > >   	 * 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_leaf_has_attr(args, &bp);
> > >   	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return retval;
> > > @@ -745,6 +765,25 @@ xfs_attr_leaf_addname(
> > >   }
> > >   /*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + */
> > > +STATIC int
> > > +xfs_leaf_has_attr(
> > > +	struct xfs_da_args      *args,
> > > +	struct xfs_buf		**bp)
> > > +{
> > > +	int                     error = 0;
> > > +
> > > +	args->blkno = 0;
> > 
> > This seems misplaced for a helper, but I could be missing context.  Why
> > not just pass zero directly and leave the args->blkno assignment to the
> > caller?
> I guess just I kept these two lines together since that's was how they
> initially appeared before factoring them out, but it does look a bit off.
> It should be ok leave the assignment to the caller.  I can push it back up.
> 
> > 
> > > +	error = xfs_attr3_leaf_read(args->trans, args->dp,
> > > +			args->blkno, 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
> > > @@ -764,12 +803,8 @@ xfs_attr_leaf_removename(
> > >   	 * Remove the attribute.
> > >   	 */
> > >   	dp = args->dp;
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> > > -	if (error)
> > > -		return error;
> > 
> > Lost error check.
> > 
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > > +	error = xfs_leaf_has_attr(args, &bp);
> > >   	if (error == -ENOATTR) {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > > @@ -808,12 +843,7 @@ 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);
> > > -	if (error)
> > > -		return error;
> > > -
> > 
> > ^ here too. Not sure if I caught them all, but you get the idea. ;)
> Ok,I'll sweep through and find them :-)
> 
> > 
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > > +	error = xfs_leaf_has_attr(args, &bp);
> > >   	if (error != -EEXIST)  {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > > @@ -823,6 +853,43 @@ 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;
> > > +	struct xfs_inode	*dp;
> > > +	int			retval, error;
> > > +
> > > +	/*
> > > +	 * 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;
> > > +
> > 
> > No real need for the dp local variable here if it's just to reference
> > ->i_mount. Also I know that comment isn't introduced by this patch, but
> > any idea what it actually means? It doesn't make much sense to me at a
> > glance. :P
> 
> Ok, will clean out assignment.  I'm actually not sure as to the comments
> origins either, I assumed it was in reference the the state?  I suppose
> state is used to keep track of a lot of things going on in the calling
> function.  But even in that context, I don't find the comment particularly
> descriptive.  Should I clean it out?
> 

Unless somebody can chime in and explain what it means (so perhaps we
could reword it), I'd probably just remove it.

Brian

> > 
> > > +	/*
> > > +	 * 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
> > >    *========================================================================*/
> > > @@ -855,17 +922,14 @@ 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)
> > 
> > Error check again.
> > 
> > > +	error = xfs_attr_node_hasname(args, &state);
> > > +	if (error == -EEXIST)
> > >   		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)) {
> > > @@ -1070,29 +1134,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.
> > > @@ -1314,20 +1364,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 cedb4e2..fb56d81 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 xfs_attr_set_args(struct xfs_da_args *args);
> > >   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
> > > +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 07ce320..a501538 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > @@ -590,6 +590,53 @@ 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
> > > + * basep: If not null, pointer is set to the byte offset of the entry in the
> > > + *	  list
> > > + */
> > > +int
> > > +xfs_shortform_has_attr(
> > > +	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;
> > 
> > This function seems like it could just return a bool. Eh, I suppose it's
> > better to be consistent with the other variants if those ones can return
> > unrelated errors.
> Ok, I prefer the consistency as well.
> 
> > 
> > > +}
> > > +
> > > +/*
> > >    * Add a name/value pair to the shortform attribute list.
> > >    * Overflow from the inode has already been checked for.
> > >    */
> > > @@ -598,7 +645,7 @@ 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;
> > > +	int offset, size, error;
> > >   	xfs_mount_t *mp;
> > >   	xfs_inode_t *dp;
> > 
> > Nit: might be good to clean up the typedefs here since you do it in the
> > remove function as well.
> Sure, will do.
> 
> > 
> > >   	struct xfs_ifork *ifp;
> > > @@ -612,18 +659,10 @@ 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++) {
> > > +	error = xfs_shortform_has_attr(args, &sfe, NULL);
> > >   #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);
> > > +	ASSERT(error != -EEXIST);
> > >   #endif
> > 
> > Hmm, interesting. So basically this code walks to the end of the list
> > for the purpose of placement of the new attr and the debug code simply
> > asserts that we don't find an existing attr. The only thing that
> > concerns me is that nothing about xfs_shortform_has_attr() indicates
> > that the output values are important when the lookup fails. The comment
> > only explains what the values are when a lookup succeeds. Could we
> > update the comment to elaborate on this use case to prevent somebody
> > from unknowingly breaking it down the road?
> > 
> > Also, there's no need for the #ifdef DEBUG any more with just the assert
> > check in that block.
> 
> Sure, I will clearify the comments and pull out the DEBUG
> 
> > 
> > > -	}
> > >   	offset = (char *)sfe - (char *)sf;
> > >   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> > > @@ -668,33 +707,24 @@ 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;
> > 
> > This value of end is unused (end is immediately reassigned further down
> > in the function).
> > 
> > Brian
> 
> Ok, I will pick that out. Thank you for the thorough reviews!
> 
> Allison
> 
> > 
> > > -	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_shortform_has_attr(args, &sfe, &base);
> > > +	if (error == -ENOATTR)
> > > +		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 536a290..58e9327 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_shortform_has_attr(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] 64+ messages in thread

* Re: [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-09-05 22:18 ` [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-09-20 13:49   ` Brian Foster
  2019-09-21  7:29     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:23PM -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>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 72 +++++++++++++++++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
>  2 files changed, 57 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index db9247a..080a284 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
...
> @@ -500,6 +487,57 @@ xfs_attr_rmtval_set(
>  			return error;
>  	}
>  
> +	error = xfs_attr_rmtval_set_value(args);
> +	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 = args->rmtblkno;

The init of lfileoff looks a little strange here. It was originally
initialized to zero, passed into the call below and then assigned to
->rmtblkno. Is this change intentional?

With those nits fixed:

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

> +
> +	/*
> +	 * 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] 64+ messages in thread

* Re: [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-09-05 22:18 ` [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-09-20 13:49   ` Brian Foster
  2019-09-21  7:00     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:24PM -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>

>  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 a297857..7a6dd37 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -710,6 +710,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
> @@ -1046,6 +1053,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 a501538..3903e5c 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2919,10 +2919,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] 64+ messages in thread

* Re: [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2019-09-05 22:18 ` [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-09-20 13:49   ` Brian Foster
  2019-09-21  7:00     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:25PM -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 | 43 +++++++++++++++++++++++++++++--------------
>  1 file changed, 29 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7a6dd37..f27e2c6 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -593,19 +593,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;
> +	int			retval, error;

It looks like we could pick either retval or error and use it
consistently throughout the new function.

>  
>  	trace_xfs_attr_leaf_addname(args);
>  

I also wonder if this tracepoint should remain in the caller.

> @@ -650,13 +643,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.
>  		 */
>  		error = xfs_attr3_leaf_to_node(args);
>  		if (error)
>  			return error;
> +	}
> +	return retval;
> +}
> +
> +
> +/*
> + * 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			retval, error, forkoff;
> +	struct xfs_buf		*bp = NULL;
> +	struct xfs_inode	*dp = args->dp;
> +
> +	retval = xfs_attr_leaf_try_add(args, bp);
> +	if (retval == -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;

Hmm.. I find this bit of factoring a little strange. We do part of the
-ENOSPC handling (leaf to node) in one place and another part
(xfs_defer_finish()) in the caller. I'm assuming we intentionally don't
finish dfops in the new helper because the delayed attr bits shouldn't
do that, but I'm wondering whether the helper should just return -ENOSPC
and the caller should be responsible for whatever needs to happen based
on that in the associated context. Hm?

Brian

> -- 
> 2.7.4
> 

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

* Re: [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-09-05 22:18 ` [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-09-20 13:50   ` Brian Foster
  2019-09-21  1:25     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:50 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:26PM -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 | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index f27e2c6..318c543 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -227,7 +227,7 @@ xfs_attr_try_sf_addname(
>  {
>  
>  	struct xfs_mount	*mp = dp->i_mount;
> -	int			error, error2;
> +	int			error;
>  
>  	error = xfs_attr_shortform_addname(args);
>  	if (error == -ENOSPC)
> @@ -243,9 +243,7 @@ xfs_attr_try_sf_addname(
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args->trans);
>  

Perhaps the above check should stay along with the tx commit code..?

> -	error2 = xfs_trans_commit(args->trans);
> -	args->trans = NULL;
> -	return error ? error : error2;
> +	return error;
>  }
>  
>  /*
> @@ -257,7 +255,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,
> @@ -277,8 +275,11 @@ 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) {
> +			error2 = xfs_trans_commit(args->trans);
> +			args->trans = NULL;
> +			return error ? error : error2;

We've already checked that error == 0 here, so this can be simplified.
Hmm.. that said, the original code looks like it commits the transaction
on error != -ENOSPC, which means this slightly changes behavior when
(error && error != -ENOSPC) is true. So perhaps it is the error check
that should be fixed up and not the error2 logic..

Brian

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

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

* Re: [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-09-05 22:18 ` [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2019-09-20 13:50   ` Brian Foster
  0 siblings, 0 replies; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:50 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:27PM -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: 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 318c543..5e5b688 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1199,6 +1199,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 3903e5c..bcd86c3 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2801,10 +2801,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	[flat|nested] 64+ messages in thread

* Re: [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions
  2019-09-05 22:18 ` [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-09-20 13:50   ` Brian Foster
  2019-09-21  1:03     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:50 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:28PM -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 | 84 +++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
>  2 files changed, 86 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index bcd86c3..79650c9 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2757,6 +2757,36 @@ xfs_attr3_leaf_clearflag(
>  }
>  
>  /*
> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.
> + */
> +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;
> +
> +	trace_xfs_attr_leaf_setflag(args);
> +

Tracepoint seems misplaced.. This is just a flag checking helper, right?

> +	/*
> +	 * Set up the operation.
> +	 */

Not sure what the comment means. The code seems self-explanatory here
anyways, so you could probably just drop it.

> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);

Didn't you create a #define for this -1 earlier in the series?

> +	if (error)
> +		return error;
> +
> +	leaf = bp->b_addr;
> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
> +
> +	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
> +	return 0;

What about bp? Should we release it before returning? If not, the
comment above the function should elaborate.

> +}
> +
> +/*
>   * Set the INCOMPLETE flag on an entry in a leaf block.
>   */
>  int
> @@ -2918,3 +2948,57 @@ 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.
> + *

A sentence or two on what this check is for would be helpful. Relocation
of an xattr or something..?

> + * 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;
> +
> +	trace_xfs_attr_leaf_flipflags(args);
> +
> +	/*
> +	 * Read the block containing the "old" attr
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp1);
> +	if (error)
> +		return error;
> +

Similar comments about the tracepoint, -1 usage and buffers.

Brian

> +	/*
> +	 * 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));
> +
> +	return 0;
> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 58e9327..d82229b 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] 64+ messages in thread

* Re: [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-09-05 22:18 ` [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2019-09-20 13:51   ` Brian Foster
  2019-09-20 22:50     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:51 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:29PM -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.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 29 +++++++++++++++++++++--------
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 22 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 080a284..1b13795 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
...
> @@ -645,7 +638,27 @@ 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;

Nit: with done initialized here, you can remove the done = 0 further
down in the function. That aside:

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

> +
> +	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.
>  	 */
> 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] 64+ messages in thread

* Re: [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-09-05 22:18 ` [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-09-20 13:51   ` Brian Foster
  2019-09-20 22:49     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:51 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:30PM -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>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>  2 files changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5e5b688..781dd8a 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -783,6 +783,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);

Need an error check here now that this isn't the last call in the
function before we return.

Brian

> +
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	return error;
>  }
> @@ -1140,6 +1146,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 79650c9..786b851 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2750,10 +2750,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] 64+ messages in thread

* Re: [PATCH v3 13/19] xfs: Add delay context to xfs_da_args
  2019-09-05 22:18 ` [PATCH v3 13/19] xfs: Add delay context to xfs_da_args Allison Collins
@ 2019-09-20 13:51   ` Brian Foster
  2019-09-20 22:48     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 13:51 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:31PM -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 flags member 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>
> ---

Ok, I'll have to get further along in the usage of these bits to fully
grok this one. One quick note in the meantime...

>  fs/xfs/libxfs/xfs_da_btree.h | 23 +++++++++++++++++++++++
>  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, 35 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index bed4f40..ebe1295 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -42,6 +42,28 @@ enum xfs_dacmp {
>  	XFS_CMP_CASE		/* names are same but differ in case */
>  };
>  
> +#define		XFS_DC_INIT		0x01 /* Init delay info */
> +#define		XFS_DC_FOUND_LBLK	0x02 /* We found leaf blk for attr */
> +#define		XFS_DC_FOUND_NBLK	0x04 /* We found node blk for attr */
> +#define		XFS_DC_ALLOC_LEAF	0x08 /* We are allocating leaf blocks */
> +#define		XFS_DC_ALLOC_NODE	0x10 /* We are allocating node blocks */
> +#define		XFS_DC_RM_LEAF_BLKS	0x20 /* We are removing leaf blocks */
> +#define		XFS_DC_RM_NODE_BLKS	0x40 /* We are removing node blocks */
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delay_context {
> +	unsigned int		flags;
> +	struct xfs_buf		*leaf_bp;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	xfs_fileoff_t		lfileoff;
> +	int			blkcnt;
> +	struct xfs_da_state	*state;
> +	struct xfs_da_state_blk *blk;
> +};
> +

The mixed size of the various fields leaves some holes in the structure.
See 'pahole xfs.ko' output for how this struct could be reordered to
reduce the overall size a bit..

Brian

>  /*
>   * Structure to ease passing around component names.
>   */
> @@ -69,6 +91,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 f8fb6e10..4e85b38 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 00758fd..467c53c 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 626420d..2cabdc2 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 1e08bf7..7153780 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 469e8e2..57de5f1 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 6309da4..470e605 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-05 22:18 ` [PATCH v3 14/19] xfs: Add delayed attribute routines Allison Collins
@ 2019-09-20 15:28   ` Brian Foster
  2019-09-20 19:12     ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-20 15:28 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
> This patch adds new delayed attribute routines:
> 
> xfs_attr_set_later
> xfs_attr_remove_later
> xfs_leaf_addname_later
> xfs_node_addname_later
> xfs_node_removename_later
> 
> These routines are similar to their existing counter parts,
> but they do not roll or commit transactions.  They instead
> return -EAGAIN to allow the calling function to roll the
> transaction and recall the function.  This allows the
> attribute operations to be logged in multiple smaller
> transactions.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
>  fs/xfs/libxfs/xfs_attr.h |   2 +
>  2 files changed, 592 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 781dd8a..310f5b2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -313,6 +316,112 @@ xfs_attr_set_args(
>  }
>  
>  /*
> + * Set 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_set_later(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf          **leaf_bp)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	int			error = 0;
> +	int			sf_size;
> +
> +	/*
> +	 * 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,
> +	 * upgrade it to a single-leaf-block attribute list.
> +	 */
> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> +	     dp->i_d.di_anextents == 0)) {
> +		/*
> +		 * Build initial attribute list (if required).
> +		 */
> +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> +			xfs_attr_shortform_create(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;
> +
> +		/*
> +		 * 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);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * 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.
> +		 */
> +
> +		xfs_trans_bhold(args->trans, *leaf_bp);
> +		return -EAGAIN;
> +	}

I haven't actually reviewed the code in this patch yet, but rather I
skipped ahead to try and get an understanding of the design approach and
flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
of xattr code into these dfops oriented functions but instead of rolling
transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
reentrancy into the xfs_trans_attr() function.

If I'm following that correctly, I'm concerned about a couple things
with the general approach. First, I think the complexity is high and
maintainability is low/difficult for this kind of reentrant approach.
The state is managed/changed all throughout the call tree and so the
risk and complexity of changing one particular bit in the sequence
requires subtle consideration to make sure it doesn't cause problems if
the function is reentered. For example, I'd prefer to see something like
xfs_trans_attr() broken down into smaller granularity functions with
higher level state that is managed and readable in one place, if
possible. Perhaps we could do that based on attr fork format, but I need
to stare at the code and think about this some more (it might be that
some degree of reentrancy is inevitable, or we just need to break things
down to even smaller states...).

Second, it seems like a lot of this code duplication between deferred
and non-deferred operations should be unnecessary, particularly since
the only difference between the contexts is how transactions are
managed. For example, if you follow the xattr set code path in both
contexts, we can see that functions like xfs_attr_set_args() are
basically duplicated in the xfs_attr_set_later() deferred variant just
so we can change the xfs_defer_finish() call in the former to a return
-EAGAIN in the latter.

Instead, what I think we should strive for is a common xattr mechanism
that consists of the lowest common denominator between the two contexts
(or IOW, core infrastructure that can be invoked from either context).
For example, on a kernel without deferred xattr support, could we find a
way to call the deferred variants directly and just let the
context-specific caller do the transaction rolls on -EAGAIN instead of
relying on the dfops infrastructure? ISTM that should be possible, it
just requires further breaking down the existing/non-deferred mechanism
into smaller bits that uses the new state management logic and
implements -EAGAIN handling for when the lower level code requires a
transaction roll. At that point, deferred support should basically just
consist of the dfops and log (i.e. intents) code to plug into the associated
infrastructure. I think another side effect of that approach is that we
shouldn't need these patches that add a bunch of new xattr
infrastructure code, but rather we'd just continue refactoring the
existing code and eventually implement a new high level function that
returns -EAGAIN directly to the dfops code instead of rolling
transactions explicitly. Thoughts?

Brian

> +
> +	/*
> +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
> +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
> +	 * that it is not done yet, and need to be recalled to finish up from
> +	 * the last EAGAIN it returned
> +	 */
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
> +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
> +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
> +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +			args->dc.flags |= XFS_DC_FOUND_LBLK;
> +
> +			if (error && error != -ENOSPC)
> +				return error;
> +
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_leaf_addname_later(args);
> +		if (error && error != -ENOSPC)
> +			return error;
> +	} else {
> +		error = xfs_node_addname_later(args);
> +	}
> +
> +	return error;
> +}
> +
> +
> +
> +/*
>   * Return EEXIST if attr is found, or ENOATTR if not
>   */
>  int
> @@ -362,6 +471,57 @@ xfs_attr_remove_args(
>  	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;
> +	struct xfs_buf		*bp;
> +	int			forkoff, error = 0;
> +
> +	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_remove(args);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
> +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> +		/*
> +		 * If we fit in a block AND we are not in the middle of
> +		 * removing node blocks, remove the leaf attribute.
> +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
> +		 * signal that it is not done yet, and needs to be recalled to
> +		 * to finish up from the last -EAGAIN
> +		 */
> +		error = xfs_leaf_has_attr(args, &bp);
> +		if (error == -ENOATTR) {
> +			xfs_trans_brelse(args->trans, bp);
> +			return error;
> +		}
> +		error = 0;
> +
> +		xfs_attr3_leaf_remove(bp, args);
> +
> +		/* If the result is small enough, shrink it into the inode.*/
> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> +		if (forkoff)
> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> +	} else {
> +		error = xfs_node_removename_later(args);
> +	}
> +
> +	return error;
> +}
> +
> +
> +
>  int
>  xfs_attr_set(
>  	struct xfs_inode	*dp,
> @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
> + *
> + * 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.
> + */
> +STATIC int
> +xfs_leaf_addname_later(
> +	struct xfs_da_args	*args)
> +{
> +	int			error, nmap;
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_bmbt_irec	*map = &args->dc.map;
> +
> +	/*
> +	 * If there was an out-of-line value, allocate the blocks we
> +	 * identified for its storage and copy the value.  This is done
> +	 * after we create the attribute so that we don't overflow the
> +	 * maximum size of a transaction and/or hit a deadlock.
> +	 */
> +	if (args->rmtblkno > 0) {
> +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
> +			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));
> +
> +			error = xfs_attr_rmt_find_hole(args);
> +			if (error)
> +				return error;
> +
> +			args->dc.blkcnt = args->rmtblkcnt;
> +			args->dc.lblkno = args->rmtblkno;
> +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
> +		}
> +
> +		/*
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
> +		 */
> +		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));
> +
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
> +
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
> +		if (error)
> +			return error;
> +	}
> +
> +	if (args->rmtblkno > 0) {
> +		/*
> +		 * Added a "remote" value, just clear the incomplete flag.
> +		 */
> +		error = xfs_attr3_leaf_clearflag(args);
> +	}
> +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
> +	return error;
> +}
> +
> +/*
>   * Return EEXIST if attr is found, or ENOATTR if not
>   */
>  STATIC int
> @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
>  }
>  
>  /*
> + * Remove a name from a B-tree attribute list.
> + *
> + * 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
> + * -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.
> + */
> +STATIC int
> +xfs_node_removename_later(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_da_state	*state = NULL;
> +	struct xfs_da_state_blk	*blk;
> +	struct xfs_buf		*bp;
> +	int			error, forkoff, retval = 0;
> +	struct xfs_inode	*dp = args->dp;
> +	int			done = 0;
> +
> +	trace_xfs_attr_node_removename(args);
> +
> +	if (args->dc.state == NULL) {
> +		error = xfs_attr_node_hasname(args, &args->dc.state);
> +		if (error != -EEXIST)
> +			goto out;
> +		else
> +			error = 0;
> +
> +		/*
> +		 * If there is an out-of-line value, de-allocate the blocks.
> +		 * This is done before we remove the attribute so that we don't
> +		 * overflow the maximum size of a transaction and/or hit a
> +		 * deadlock.
> +		 */
> +		state = args->dc.state;
> +		args->dc.blk = &state->path.blk[state->path.active - 1];
> +		ASSERT(args->dc.blk->bp != NULL);
> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> +	}
> +	state = args->dc.state;
> +	blk = args->dc.blk;
> +
> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> +		bool isset;
> +
> +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
> +		if (error)
> +			goto out;
> +		if (!isset) {
> +			/*
> +			 * Fill in disk block numbers in the state structure
> +			 * so that we can get the buffers back after we commit
> +			 * several transactions in the following calls.
> +			 */
> +			error = xfs_attr_fillstate(state);
> +			if (error)
> +				goto out;
> +
> +			/*
> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> +			 * remote value.
> +			 */
> +			error = xfs_attr3_leaf_setflag(args);
> +			if (error)
> +				goto out;
> +
> +			return -EAGAIN;
> +		}
> +
> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> +			error = xfs_attr_rmtval_invalidate(args);
> +			if (error)
> +				goto out;
> +		}
> +
> +		/*
> +		 * 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;
> +
> +			if (!done)
> +				return -EAGAIN;
> +		}
> +
> +		if (error)
> +			goto out;
> +
> +		/*
> +		 * Refill the state structure with buffers, the prior calls
> +		 * released our buffers.
> +		 */
> +		error = xfs_attr_refillstate(state);
> +		if (error)
> +			goto out;
> +	}
> +
> +	/*
> +	 * Remove the name and update the hashvals in the tree.
> +	 */
> +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> +		blk = &state->path.blk[state->path.active - 1];
> +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +		retval = xfs_attr3_leaf_remove(blk->bp, args);
> +		xfs_da3_fixhashpath(state, &state->path);
> +
> +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
> +	}
> +
> +	/*
> +	 * Check to see if the tree needs to be collapsed.
> +	 */
> +	if (retval && (state->path.active > 1)) {
> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> +		error = xfs_da3_join(state);
> +		if (error)
> +			goto out;
> +
> +		return -EAGAIN;
> +	}
> +
> +	/*
> +	 * If the result is small enough, push it all into the inode.
> +	 */
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		/*
> +		 * Have to get rid of the copy of this dabuf in the state.
> +		 */
> +		ASSERT(state->path.active == 1);
> +		ASSERT(state->path.blk[0].bp);
> +		state->path.blk[0].bp = NULL;
> +
> +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
> +		if (error)
> +			goto out;
> +
> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> +		if (forkoff) {
> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> +			/* bp is gone due to xfs_da_shrink_inode */
> +			if (error)
> +				goto out;
> +		} else
> +			xfs_trans_brelse(args->trans, bp);
> +	}
> +out:
> +	if (state != NULL)
> +		xfs_da_state_free(state);
> +
> +	return error;
> +}
> +
> +/*
> + * Add a name to a Btree-format attribute list.
> + *
> + * This will involve walking down the Btree, and may involve splitting
> + * leaf nodes and even splitting intermediate nodes up to and including
> + * the root node (a special case of an intermediate node).
> + *
> + * "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
> + * -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.
> + */
> +STATIC int
> +xfs_node_addname_later(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_da_state	*state = NULL;
> +	struct xfs_da_state_blk	*blk;
> +	struct xfs_inode	*dp;
> +	int			retval, error = 0;
> +	int			nmap;
> +	struct xfs_bmbt_irec    *map = &args->dc.map;
> +
> +	trace_xfs_attr_node_addname(args);
> +
> +	/*
> +	 * Fill in bucket of arguments/results/context to carry around.
> +	 */
> +	dp = args->dp;
> +
> +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
> +		goto found_blk;
> +
> +	/*
> +	 * Search to see if name already exists, and get back a pointer
> +	 * to where it should go.
> +	 */
> +	retval = xfs_attr_node_hasname(args, &state);
> +	blk = &state->path.blk[state->path.active-1];
> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> +		goto out;
> +	} else if (retval == -EEXIST) {
> +		if (args->name.type & ATTR_CREATE)
> +			goto out;
> +
> +		trace_xfs_attr_node_replace(args);
> +
> +		/* save the attribute state for later removal*/
> +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
> +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> +		args->index2 = args->index;
> +		args->rmtblkno2 = args->rmtblkno;
> +		args->rmtblkcnt2 = args->rmtblkcnt;
> +		args->rmtvaluelen2 = args->rmtvaluelen;
> +
> +		/*
> +		 * clear the remote attr state now that it is saved so that the
> +		 * values reflect the state of the attribute we are about to
> +		 * add, not the attribute we just found and will remove later.
> +		 */
> +		args->rmtblkno = 0;
> +		args->rmtblkcnt = 0;
> +		args->rmtvaluelen = 0;
> +	}
> +
> +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
> +	if (retval == -ENOSPC) {
> +		if (state->path.active == 1) {
> +			/*
> +			 * Its really a single leaf node, but it had
> +			 * out-of-line values so it looked like it *might*
> +			 * have been a b-tree.
> +			 */
> +			xfs_da_state_free(state);
> +			state = NULL;
> +			error = xfs_attr3_leaf_to_node(args);
> +			if (error)
> +				goto out;
> +
> +			return -EAGAIN;
> +		}
> +
> +		/*
> +		 * Split as many Btree elements as required.
> +		 * This code tracks the new and old attr's location
> +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
> +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
> +		 */
> +		error = xfs_da3_split(state);
> +		if (error)
> +			goto out;
> +	} else {
> +		/*
> +		 * Addition succeeded, update Btree hashvals.
> +		 */
> +		xfs_da3_fixhashpath(state, &state->path);
> +	}
> +
> +	/*
> +	 * Kill the state structure, we're done with it and need to
> +	 * allow the buffers to come back later.
> +	 */
> +	xfs_da_state_free(state);
> +	state = NULL;
> +
> +	args->dc.flags |= XFS_DC_FOUND_NBLK;
> +	return -EAGAIN;
> +found_blk:
> +
> +	/*
> +	 * If there was an out-of-line value, allocate the blocks we
> +	 * identified for its storage and copy the value.  This is done
> +	 * after we create the attribute so that we don't overflow the
> +	 * maximum size of a transaction and/or hit a deadlock.
> +	 */
> +	if (args->rmtblkno > 0) {
> +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
> +			args->dc.flags |= XFS_DC_ALLOC_NODE;
> +			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));
> +
> +			error = xfs_attr_rmt_find_hole(args);
> +			if (error)
> +				return error;
> +
> +			args->dc.blkcnt = args->rmtblkcnt;
> +			args->dc.lblkno = args->rmtblkno;
> +		}
> +		/*
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
> +		 */
> +		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));
> +
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
> +
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
> +		if (error)
> +			return error;
> +	}
> +
> +	if (args->rmtblkno > 0) {
> +		/*
> +		 * Added a "remote" value, just clear the incomplete flag.
> +		 */
> +		error = xfs_attr3_leaf_clearflag(args);
> +		if (error)
> +			goto out;
> +	}
> +	retval = error = 0;
> +
> +out:
> +	if (state)
> +		xfs_da_state_free(state);
> +	if (error)
> +		return error;
> +
> +	return retval;
> +}
> +
> +
> +
> +/*
>   * Fill in the disk block numbers in the state structure for the buffers
>   * that are attached to the state structure.
>   * This is done so that we can quickly reattach ourselves to those buffers
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index fb56d81..6203766 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-20 15:28   ` Brian Foster
@ 2019-09-20 19:12     ` Allison Collins
  2019-09-23 12:04       ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-20 19:12 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 8:28 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
>> This patch adds new delayed attribute routines:
>>
>> xfs_attr_set_later
>> xfs_attr_remove_later
>> xfs_leaf_addname_later
>> xfs_node_addname_later
>> xfs_node_removename_later
>>
>> These routines are similar to their existing counter parts,
>> but they do not roll or commit transactions.  They instead
>> return -EAGAIN to allow the calling function to roll the
>> transaction and recall the function.  This allows the
>> attribute operations to be logged in multiple smaller
>> transactions.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
>>   fs/xfs/libxfs/xfs_attr.h |   2 +
>>   2 files changed, 592 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 781dd8a..310f5b2 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
> ...
>> @@ -313,6 +316,112 @@ xfs_attr_set_args(
>>   }
>>   
>>   /*
>> + * Set 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_set_later(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf          **leaf_bp)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	int			error = 0;
>> +	int			sf_size;
>> +
>> +	/*
>> +	 * 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,
>> +	 * upgrade it to a single-leaf-block attribute list.
>> +	 */
>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> +	     dp->i_d.di_anextents == 0)) {
>> +		/*
>> +		 * Build initial attribute list (if required).
>> +		 */
>> +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> +			xfs_attr_shortform_create(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;
>> +
>> +		/*
>> +		 * 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);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * 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.
>> +		 */
>> +
>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>> +		return -EAGAIN;
>> +	}
> 
> I haven't actually reviewed the code in this patch yet, but rather I
> skipped ahead to try and get an understanding of the design approach and
> flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
> of xattr code into these dfops oriented functions but instead of rolling
> transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
> reentrancy into the xfs_trans_attr() function.

Yes. If it helps to know a little more background about how it came into 
being...
Initially I had started out with the code paths merged, and had a 
boolean switch to control the alternate behavior (much like the 
"roll_trans" boolean from the prior sets, if you recall them).  In a 
way, the boolean acted like a sort of marker of where things needed to 
get factored up.  The goal being to pull the boolean into the higher 
level routines as much as possible and leaving behind all the little 
helpers which is what you see now in now patches 5 - 12.

After I got done with all the refactoring, the parts that still had the 
boolean were a sort of hybrid of the two paths you see now.  At one 
point I made a judgment that continuing to factor up the boolean would 
be more complicated than not.  I know people disliked the boolean toggle 
from the prior sets.  So the *_later routines we have now are a result 
of the hybrid having been gutted of the boolean and split then off into 
its separate path.


> 
> If I'm following that correctly, I'm concerned about a couple things
> with the general approach. First, I think the complexity is high and
> maintainability is low/difficult for this kind of reentrant approach.

Yes.  And I did very much anticipate a similar response.  Thats 
certainly not to imply that I did all this for giggles, but because I 
think sometimes it's easy for designs to sound like good ideas in 
theory, until people see them in practice.  And then the design takes a 
different direction.  In a way I think the prototypes are a sort of 
necessary step for the design to evolve, even if the prototypes are sort 
of ugly.  :-)

> The state is managed/changed all throughout the call tree and so the
> risk and complexity of changing one particular bit in the sequence
> requires subtle consideration to make sure it doesn't cause problems if
> the function is reentered. 
Yes, it's still very much a state machine in practice.  But I think we 
may be stuck with at least some variant of state machine if we still 
want to adhere to the EAGAIN interface which requires the stack to back 
out.  I have pondered the idea of introducing a call back to cycle out 
the transactions mid flight so that we dont need to stop and return. 
This would escape the state machine concept, but may require alternate 
surgery to the calling log routines too.  So that may just turn into a 
different type of monster

For example, I'd prefer to see something like
> xfs_trans_attr() broken down into smaller granularity functions with
> higher level state that is managed and readable in one place, if
> possible. Perhaps we could do that based on attr fork format, but I need
> to stare at the code and think about this some more (it might be that
> some degree of reentrancy is inevitable, or we just need to break things
> down to even smaller states...).
Yes, and I did go through a phase of trying to simplify the statemachine 
by trying to grab onto anything about the state of the fork that could 
be used instead.  But its not always enough particularly in the case of 
routines that are in the middle of allocating or removing blocks.  If 
you see any other mechanics that could help out, please call them out.


> 
> Second, it seems like a lot of this code duplication between deferred
> and non-deferred operations should be unnecessary, particularly since
> the only difference between the contexts is how transactions are
> managed. For example, if you follow the xattr set code path in both
> contexts, we can see that functions like xfs_attr_set_args() are
> basically duplicated in the xfs_attr_set_later() deferred variant just
> so we can change the xfs_defer_finish() call in the former to a return
> -EAGAIN in the latter.
Yes, they still carry some similarities.  I guess I reasoned that 
continuing to carve things up into smaller and smaller helpers with out 
a generalized purpose (other than de-dup reduction) was starting to look 
a little weird, and maybe leaving things in their appropriate context 
might have been preferred?  Folks are welcome to chime in with opinions 
though.

> 
> Instead, what I think we should strive for is a common xattr mechanism
> that consists of the lowest common denominator between the two contexts
> (or IOW, core infrastructure that can be invoked from either context).
> For example, on a kernel without deferred xattr support, could we find a
> way to call the deferred variants directly and just let the
> context-specific caller do the transaction rolls on -EAGAIN instead of
> relying on the dfops infrastructure? 
I think I did that somewhere in the older parent pointer sets.  At the 
time, we sort of forgot that we cant completely scrap non delayed attrs 
(because we need them for older versions).  But then protofiles needed 
to create pptrs with out the delay mechanic, so I opened coded a sort of 
loop to deal with the EAGAIN.  In fact, I ended up doing the same sort 
of loop in patch 15 for xfs_attri_recover, which has the same challenge. 
Maybe we could make a sort of general purpose wrapper?

ISTM that should be possible, it
> just requires further breaking down the existing/non-deferred mechanism
> into smaller bits that uses the new state management logic and
> implements -EAGAIN handling for when the lower level code requires a
> transaction roll. At that point, deferred support should basically just
> consist of the dfops and log (i.e. intents) code to plug into the associated
> infrastructure. I think another side effect of that approach is that we
> shouldn't need these patches that add a bunch of new xattr
> infrastructure code, but rather we'd just continue refactoring the
> existing code and eventually implement a new high level function that
> returns -EAGAIN directly to the dfops code instead of rolling
> transactions explicitly. Thoughts?
Ok, I think I understand what you're trying to describe here.  Maybe 
take a look at xfs_attri_recover in patch 15, and let me know if that 
was similar to what you were thinking?

Thank you for all the thorough reviewing here, I know it's a lot!
Allison

> 
> Brian
> 
>> +
>> +	/*
>> +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
>> +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
>> +	 * that it is not done yet, and need to be recalled to finish up from
>> +	 * the last EAGAIN it returned
>> +	 */
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
>> +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
>> +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
>> +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +			args->dc.flags |= XFS_DC_FOUND_LBLK;
>> +
>> +			if (error && error != -ENOSPC)
>> +				return error;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_leaf_addname_later(args);
>> +		if (error && error != -ENOSPC)
>> +			return error;
>> +	} else {
>> +		error = xfs_node_addname_later(args);
>> +	}
>> +
>> +	return error;
>> +}
>> +
>> +
>> +
>> +/*
>>    * Return EEXIST if attr is found, or ENOATTR if not
>>    */
>>   int
>> @@ -362,6 +471,57 @@ xfs_attr_remove_args(
>>   	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;
>> +	struct xfs_buf		*bp;
>> +	int			forkoff, error = 0;
>> +
>> +	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_remove(args);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
>> +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>> +		/*
>> +		 * If we fit in a block AND we are not in the middle of
>> +		 * removing node blocks, remove the leaf attribute.
>> +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
>> +		 * signal that it is not done yet, and needs to be recalled to
>> +		 * to finish up from the last -EAGAIN
>> +		 */
>> +		error = xfs_leaf_has_attr(args, &bp);
>> +		if (error == -ENOATTR) {
>> +			xfs_trans_brelse(args->trans, bp);
>> +			return error;
>> +		}
>> +		error = 0;
>> +
>> +		xfs_attr3_leaf_remove(bp, args);
>> +
>> +		/* If the result is small enough, shrink it into the inode.*/
>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>> +		if (forkoff)
>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> +	} else {
>> +		error = xfs_node_removename_later(args);
>> +	}
>> +
>> +	return error;
>> +}
>> +
>> +
>> +
>>   int
>>   xfs_attr_set(
>>   	struct xfs_inode	*dp,
>> @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
>> + *
>> + * 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.
>> + */
>> +STATIC int
>> +xfs_leaf_addname_later(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error, nmap;
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>> +
>> +	/*
>> +	 * If there was an out-of-line value, allocate the blocks we
>> +	 * identified for its storage and copy the value.  This is done
>> +	 * after we create the attribute so that we don't overflow the
>> +	 * maximum size of a transaction and/or hit a deadlock.
>> +	 */
>> +	if (args->rmtblkno > 0) {
>> +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
>> +			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));
>> +
>> +			error = xfs_attr_rmt_find_hole(args);
>> +			if (error)
>> +				return error;
>> +
>> +			args->dc.blkcnt = args->rmtblkcnt;
>> +			args->dc.lblkno = args->rmtblkno;
>> +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
>> +		}
>> +
>> +		/*
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>> +		 */
>> +		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));
>> +
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>> +		if (error)
>> +			return error;
>> +	}
>> +
>> +	if (args->rmtblkno > 0) {
>> +		/*
>> +		 * Added a "remote" value, just clear the incomplete flag.
>> +		 */
>> +		error = xfs_attr3_leaf_clearflag(args);
>> +	}
>> +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
>> +	return error;
>> +}
>> +
>> +/*
>>    * Return EEXIST if attr is found, or ENOATTR if not
>>    */
>>   STATIC int
>> @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
>>   }
>>   
>>   /*
>> + * Remove a name from a B-tree attribute list.
>> + *
>> + * 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
>> + * -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.
>> + */
>> +STATIC int
>> +xfs_node_removename_later(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_da_state	*state = NULL;
>> +	struct xfs_da_state_blk	*blk;
>> +	struct xfs_buf		*bp;
>> +	int			error, forkoff, retval = 0;
>> +	struct xfs_inode	*dp = args->dp;
>> +	int			done = 0;
>> +
>> +	trace_xfs_attr_node_removename(args);
>> +
>> +	if (args->dc.state == NULL) {
>> +		error = xfs_attr_node_hasname(args, &args->dc.state);
>> +		if (error != -EEXIST)
>> +			goto out;
>> +		else
>> +			error = 0;
>> +
>> +		/*
>> +		 * If there is an out-of-line value, de-allocate the blocks.
>> +		 * This is done before we remove the attribute so that we don't
>> +		 * overflow the maximum size of a transaction and/or hit a
>> +		 * deadlock.
>> +		 */
>> +		state = args->dc.state;
>> +		args->dc.blk = &state->path.blk[state->path.active - 1];
>> +		ASSERT(args->dc.blk->bp != NULL);
>> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +	}
>> +	state = args->dc.state;
>> +	blk = args->dc.blk;
>> +
>> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>> +		bool isset;
>> +
>> +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
>> +		if (error)
>> +			goto out;
>> +		if (!isset) {
>> +			/*
>> +			 * Fill in disk block numbers in the state structure
>> +			 * so that we can get the buffers back after we commit
>> +			 * several transactions in the following calls.
>> +			 */
>> +			error = xfs_attr_fillstate(state);
>> +			if (error)
>> +				goto out;
>> +
>> +			/*
>> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
>> +			 * remote value.
>> +			 */
>> +			error = xfs_attr3_leaf_setflag(args);
>> +			if (error)
>> +				goto out;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>> +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>> +			error = xfs_attr_rmtval_invalidate(args);
>> +			if (error)
>> +				goto out;
>> +		}
>> +
>> +		/*
>> +		 * 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;
>> +
>> +			if (!done)
>> +				return -EAGAIN;
>> +		}
>> +
>> +		if (error)
>> +			goto out;
>> +
>> +		/*
>> +		 * Refill the state structure with buffers, the prior calls
>> +		 * released our buffers.
>> +		 */
>> +		error = xfs_attr_refillstate(state);
>> +		if (error)
>> +			goto out;
>> +	}
>> +
>> +	/*
>> +	 * Remove the name and update the hashvals in the tree.
>> +	 */
>> +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>> +		blk = &state->path.blk[state->path.active - 1];
>> +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +		retval = xfs_attr3_leaf_remove(blk->bp, args);
>> +		xfs_da3_fixhashpath(state, &state->path);
>> +
>> +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
>> +	}
>> +
>> +	/*
>> +	 * Check to see if the tree needs to be collapsed.
>> +	 */
>> +	if (retval && (state->path.active > 1)) {
>> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>> +		error = xfs_da3_join(state);
>> +		if (error)
>> +			goto out;
>> +
>> +		return -EAGAIN;
>> +	}
>> +
>> +	/*
>> +	 * If the result is small enough, push it all into the inode.
>> +	 */
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		/*
>> +		 * Have to get rid of the copy of this dabuf in the state.
>> +		 */
>> +		ASSERT(state->path.active == 1);
>> +		ASSERT(state->path.blk[0].bp);
>> +		state->path.blk[0].bp = NULL;
>> +
>> +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
>> +		if (error)
>> +			goto out;
>> +
>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>> +		if (forkoff) {
>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> +			/* bp is gone due to xfs_da_shrink_inode */
>> +			if (error)
>> +				goto out;
>> +		} else
>> +			xfs_trans_brelse(args->trans, bp);
>> +	}
>> +out:
>> +	if (state != NULL)
>> +		xfs_da_state_free(state);
>> +
>> +	return error;
>> +}
>> +
>> +/*
>> + * Add a name to a Btree-format attribute list.
>> + *
>> + * This will involve walking down the Btree, and may involve splitting
>> + * leaf nodes and even splitting intermediate nodes up to and including
>> + * the root node (a special case of an intermediate node).
>> + *
>> + * "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
>> + * -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.
>> + */
>> +STATIC int
>> +xfs_node_addname_later(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_da_state	*state = NULL;
>> +	struct xfs_da_state_blk	*blk;
>> +	struct xfs_inode	*dp;
>> +	int			retval, error = 0;
>> +	int			nmap;
>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>> +
>> +	trace_xfs_attr_node_addname(args);
>> +
>> +	/*
>> +	 * Fill in bucket of arguments/results/context to carry around.
>> +	 */
>> +	dp = args->dp;
>> +
>> +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
>> +		goto found_blk;
>> +
>> +	/*
>> +	 * Search to see if name already exists, and get back a pointer
>> +	 * to where it should go.
>> +	 */
>> +	retval = xfs_attr_node_hasname(args, &state);
>> +	blk = &state->path.blk[state->path.active-1];
>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> +		goto out;
>> +	} else if (retval == -EEXIST) {
>> +		if (args->name.type & ATTR_CREATE)
>> +			goto out;
>> +
>> +		trace_xfs_attr_node_replace(args);
>> +
>> +		/* save the attribute state for later removal*/
>> +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
>> +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
>> +		args->index2 = args->index;
>> +		args->rmtblkno2 = args->rmtblkno;
>> +		args->rmtblkcnt2 = args->rmtblkcnt;
>> +		args->rmtvaluelen2 = args->rmtvaluelen;
>> +
>> +		/*
>> +		 * clear the remote attr state now that it is saved so that the
>> +		 * values reflect the state of the attribute we are about to
>> +		 * add, not the attribute we just found and will remove later.
>> +		 */
>> +		args->rmtblkno = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtvaluelen = 0;
>> +	}
>> +
>> +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
>> +	if (retval == -ENOSPC) {
>> +		if (state->path.active == 1) {
>> +			/*
>> +			 * Its really a single leaf node, but it had
>> +			 * out-of-line values so it looked like it *might*
>> +			 * have been a b-tree.
>> +			 */
>> +			xfs_da_state_free(state);
>> +			state = NULL;
>> +			error = xfs_attr3_leaf_to_node(args);
>> +			if (error)
>> +				goto out;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		/*
>> +		 * Split as many Btree elements as required.
>> +		 * This code tracks the new and old attr's location
>> +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
>> +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
>> +		 */
>> +		error = xfs_da3_split(state);
>> +		if (error)
>> +			goto out;
>> +	} else {
>> +		/*
>> +		 * Addition succeeded, update Btree hashvals.
>> +		 */
>> +		xfs_da3_fixhashpath(state, &state->path);
>> +	}
>> +
>> +	/*
>> +	 * Kill the state structure, we're done with it and need to
>> +	 * allow the buffers to come back later.
>> +	 */
>> +	xfs_da_state_free(state);
>> +	state = NULL;
>> +
>> +	args->dc.flags |= XFS_DC_FOUND_NBLK;
>> +	return -EAGAIN;
>> +found_blk:
>> +
>> +	/*
>> +	 * If there was an out-of-line value, allocate the blocks we
>> +	 * identified for its storage and copy the value.  This is done
>> +	 * after we create the attribute so that we don't overflow the
>> +	 * maximum size of a transaction and/or hit a deadlock.
>> +	 */
>> +	if (args->rmtblkno > 0) {
>> +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
>> +			args->dc.flags |= XFS_DC_ALLOC_NODE;
>> +			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));
>> +
>> +			error = xfs_attr_rmt_find_hole(args);
>> +			if (error)
>> +				return error;
>> +
>> +			args->dc.blkcnt = args->rmtblkcnt;
>> +			args->dc.lblkno = args->rmtblkno;
>> +		}
>> +		/*
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>> +		 */
>> +		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));
>> +
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>> +		if (error)
>> +			return error;
>> +	}
>> +
>> +	if (args->rmtblkno > 0) {
>> +		/*
>> +		 * Added a "remote" value, just clear the incomplete flag.
>> +		 */
>> +		error = xfs_attr3_leaf_clearflag(args);
>> +		if (error)
>> +			goto out;
>> +	}
>> +	retval = error = 0;
>> +
>> +out:
>> +	if (state)
>> +		xfs_da_state_free(state);
>> +	if (error)
>> +		return error;
>> +
>> +	return retval;
>> +}
>> +
>> +
>> +
>> +/*
>>    * Fill in the disk block numbers in the state structure for the buffers
>>    * that are attached to the state structure.
>>    * This is done so that we can quickly reattach ourselves to those buffers
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index fb56d81..6203766 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 13/19] xfs: Add delay context to xfs_da_args
  2019-09-20 13:51   ` Brian Foster
@ 2019-09-20 22:48     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-20 22:48 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 6:51 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:31PM -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 flags member 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>
>> ---
> 
> Ok, I'll have to get further along in the usage of these bits to fully
> grok this one. One quick note in the meantime...
Ok, yeah a lot of whats in here is dependent on what we decide in the 
next patch, but I will take a look through the pahole output.  Thanks!

Allison

> 
>>   fs/xfs/libxfs/xfs_da_btree.h | 23 +++++++++++++++++++++++
>>   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, 35 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index bed4f40..ebe1295 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -42,6 +42,28 @@ enum xfs_dacmp {
>>   	XFS_CMP_CASE		/* names are same but differ in case */
>>   };
>>   
>> +#define		XFS_DC_INIT		0x01 /* Init delay info */
>> +#define		XFS_DC_FOUND_LBLK	0x02 /* We found leaf blk for attr */
>> +#define		XFS_DC_FOUND_NBLK	0x04 /* We found node blk for attr */
>> +#define		XFS_DC_ALLOC_LEAF	0x08 /* We are allocating leaf blocks */
>> +#define		XFS_DC_ALLOC_NODE	0x10 /* We are allocating node blocks */
>> +#define		XFS_DC_RM_LEAF_BLKS	0x20 /* We are removing leaf blocks */
>> +#define		XFS_DC_RM_NODE_BLKS	0x40 /* We are removing node blocks */
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delay_context {
>> +	unsigned int		flags;
>> +	struct xfs_buf		*leaf_bp;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	xfs_fileoff_t		lfileoff;
>> +	int			blkcnt;
>> +	struct xfs_da_state	*state;
>> +	struct xfs_da_state_blk *blk;
>> +};
>> +
> 
> The mixed size of the various fields leaves some holes in the structure.
> See 'pahole xfs.ko' output for how this struct could be reordered to
> reduce the overall size a bit..
> 
> Brian
> 
>>   /*
>>    * Structure to ease passing around component names.
>>    */
>> @@ -69,6 +91,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 f8fb6e10..4e85b38 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 00758fd..467c53c 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 626420d..2cabdc2 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 1e08bf7..7153780 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 469e8e2..57de5f1 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 6309da4..470e605 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] 64+ messages in thread

* Re: [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-09-20 13:51   ` Brian Foster
@ 2019-09-20 22:49     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-20 22:49 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 6:51 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:30PM -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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>>   2 files changed, 15 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5e5b688..781dd8a 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -783,6 +783,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
> 
Alrighty, will fix.
Allison

> Need an error check here now that this isn't the last call in the
> function before we return.
> 
> Brian
> 
>> +
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   	}
>>   	return error;
>>   }
>> @@ -1140,6 +1146,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 79650c9..786b851 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2750,10 +2750,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] 64+ messages in thread

* Re: [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-09-20 13:51   ` Brian Foster
@ 2019-09-20 22:50     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-20 22:50 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 6:51 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:29PM -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.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 29 +++++++++++++++++++++--------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 22 insertions(+), 8 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 080a284..1b13795 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> ...
>> @@ -645,7 +638,27 @@ 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;
> 
> Nit: with done initialized here, you can remove the done = 0 further
> down in the function. That aside:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Ok, I will pick out that little bit.  Thank you for the reviews!

Allison

> 
>> +
>> +	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.
>>   	 */
>> 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] 64+ messages in thread

* Re: [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions
  2019-09-20 13:50   ` Brian Foster
@ 2019-09-21  1:03     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-21  1:03 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 9/20/19 6:50 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:28PM -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 | 84 +++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
>>   2 files changed, 86 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index bcd86c3..79650c9 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2757,6 +2757,36 @@ xfs_attr3_leaf_clearflag(
>>   }
>>   
>>   /*
>> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.
>> + */
>> +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;
>> +
>> +	trace_xfs_attr_leaf_setflag(args);
>> +
> 
> Tracepoint seems misplaced.. This is just a flag checking helper, right?
>
Yes, I likely scooped it up with the rest to consolidate code, but it 
probably should have stayed in setflag

>> +	/*
>> +	 * Set up the operation.
>> +	 */
> 
> Not sure what the comment means. The code seems self-explanatory here
> anyways, so you could probably just drop it.
Alrighty then, will clean out

> 
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);
> 
> Didn't you create a #define for this -1 earlier in the series?
Yes, I missed applying it here.  Will fix

> 
>> +	if (error)
>> +		return error;
>> +
>> +	leaf = bp->b_addr;
>> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
>> +
>> +	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
>> +	return 0;
> 
> What about bp? Should we release it before returning? If not, the
> comment above the function should elaborate.
I think you're probably right.  It's only used in the delayed code path 
and I think the logging routines may have done the release so I didn't 
notice

> 
>> +}
>> +
>> +/*
>>    * Set the INCOMPLETE flag on an entry in a leaf block.
>>    */
>>   int
>> @@ -2918,3 +2948,57 @@ 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.
>> + *
> 
> A sentence or two on what this check is for would be helpful. Relocation
> of an xattr or something..?
It's just a check to see if the two flags mentioned above have been 
swapped before proceeding to swap them with xfs_attr3_leaf_flipflags.  I 
believe it's used in attr renames.  I will add in some extra commentary 
to reference the other routine, that might help make a little more sense.

> 
>> + * 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;
>> +
>> +	trace_xfs_attr_leaf_flipflags(args);
>> +
>> +	/*
>> +	 * Read the block containing the "old" attr
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp1);
>> +	if (error)
>> +		return error;
>> +
> 
> Similar comments about the tracepoint, -1 usage and buffers.
Sure, will fix.  Thanks!

Allison
> 
> Brian
> 
>> +	/*
>> +	 * 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));
>> +
>> +	return 0;
>> +}
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 58e9327..d82229b 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] 64+ messages in thread

* Re: [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-09-20 13:50   ` Brian Foster
@ 2019-09-21  1:25     ` Allison Collins
  2019-09-23 12:04       ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-21  1:25 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 9/20/19 6:50 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:26PM -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 | 15 ++++++++-------
>>   1 file changed, 8 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index f27e2c6..318c543 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -227,7 +227,7 @@ xfs_attr_try_sf_addname(
>>   {
>>   
>>   	struct xfs_mount	*mp = dp->i_mount;
>> -	int			error, error2;
>> +	int			error;
>>   
>>   	error = xfs_attr_shortform_addname(args);
>>   	if (error == -ENOSPC)
>> @@ -243,9 +243,7 @@ xfs_attr_try_sf_addname(
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args->trans);
>>   
> 
> Perhaps the above check should stay along with the tx commit code..?
That makes sense, I will move it upwards
> 
>> -	error2 = xfs_trans_commit(args->trans);
>> -	args->trans = NULL;
>> -	return error ? error : error2;
>> +	return error;
>>   }
>>   
>>   /*
>> @@ -257,7 +255,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,
>> @@ -277,8 +275,11 @@ 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) {
>> +			error2 = xfs_trans_commit(args->trans);
>> +			args->trans = NULL;
>> +			return error ? error : error2;
> 
> We've already checked that error == 0 here, so this can be simplified.
> Hmm.. that said, the original code looks like it commits the transaction
> on error != -ENOSPC, which means this slightly changes behavior when
> (error && error != -ENOSPC) is true. So perhaps it is the error check
> that should be fixed up and not the error2 logic..

Yes, I believe this got some attention in the last review.  While it is 
different logic now, I think we reasoned that committing on say -EIO or 
some other such unexpected error didn't make much sense either, so we 
cleaned it up a bit.  Though you're probably right about the 
simplification now with the change.  Is there a reason we would want to 
commit in the case of unexpected errors?

Allison

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

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

* Re: [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2019-09-20 13:49   ` Brian Foster
@ 2019-09-21  7:00     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-21  7:00 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 6:49 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:25PM -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 | 43 +++++++++++++++++++++++++++++--------------
>>   1 file changed, 29 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7a6dd37..f27e2c6 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -593,19 +593,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;
>> +	int			retval, error;
> 
> It looks like we could pick either retval or error and use it
> consistently throughout the new function.
> 
>>   
>>   	trace_xfs_attr_leaf_addname(args);
>>   
> 
> I also wonder if this tracepoint should remain in the caller.

Alrihty, will clean out retval and move trace point

> 
>> @@ -650,13 +643,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.
>>   		 */
>>   		error = xfs_attr3_leaf_to_node(args);
>>   		if (error)
>>   			return error;
>> +	}
>> +	return retval;
>> +}
>> +
>> +
>> +/*
>> + * 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			retval, error, forkoff;
>> +	struct xfs_buf		*bp = NULL;
>> +	struct xfs_inode	*dp = args->dp;
>> +
>> +	retval = xfs_attr_leaf_try_add(args, bp);
>> +	if (retval == -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;
> 
> Hmm.. I find this bit of factoring a little strange. We do part of the
> -ENOSPC handling (leaf to node) in one place and another part
> (xfs_defer_finish()) in the caller. I'm assuming we intentionally don't
> finish dfops in the new helper because the delayed attr bits shouldn't
> do that, but I'm wondering whether the helper should just return -ENOSPC
> and the caller should be responsible for whatever needs to happen based
> on that in the associated context. Hm?
> 
> Brian

Yes, the idea is that the new helper function avoids anything with 
transactions.  We could factor up the ENOSPC handling into the caller, 
that may look cleaner.  I think there's really only one place it's called.

Thanks!
Allison

> 
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-09-20 13:49   ` Brian Foster
@ 2019-09-21  7:00     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-21  7:00 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 9/20/19 6:49 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:24PM -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>

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 a297857..7a6dd37 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -710,6 +710,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
>> @@ -1046,6 +1053,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 a501538..3903e5c 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2919,10 +2919,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] 64+ messages in thread

* Re: [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-09-20 13:49   ` Brian Foster
@ 2019-09-21  7:29     ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-21  7:29 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/20/19 6:49 AM, Brian Foster wrote:
> On Thu, Sep 05, 2019 at 03:18:23PM -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>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 72 +++++++++++++++++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
>>   2 files changed, 57 insertions(+), 18 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index db9247a..080a284 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> ...
>> @@ -500,6 +487,57 @@ xfs_attr_rmtval_set(
>>   			return error;
>>   	}
>>   
>> +	error = xfs_attr_rmtval_set_value(args);
>> +	return error;
> 
> 	return xfs_attr_rmtval_set_value(args);
Ok, will fix

> 
>> +}
>> +
>> +
>> +/*
>> + * 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 = args->rmtblkno;
> 
> The init of lfileoff looks a little strange here. It was originally
> initialized to zero, passed into the call below and then assigned to
> ->rmtblkno. Is this change intentional?
> 
I see, no I probably mistakenly adopted the assignment, but it's likely 
not needed.  Will clean out.

Thanks again for all the reviews!
Allison

> With those nits fixed:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
>> +
>> +	/*
>> +	 * 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] 64+ messages in thread

* Re: [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-09-21  1:25     ` Allison Collins
@ 2019-09-23 12:04       ` Brian Foster
  0 siblings, 0 replies; 64+ messages in thread
From: Brian Foster @ 2019-09-23 12:04 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Sep 20, 2019 at 06:25:04PM -0700, Allison Collins wrote:
> 
> 
> On 9/20/19 6:50 AM, Brian Foster wrote:
> > On Thu, Sep 05, 2019 at 03:18:26PM -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 | 15 ++++++++-------
> > >   1 file changed, 8 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index f27e2c6..318c543 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -227,7 +227,7 @@ xfs_attr_try_sf_addname(
> > >   {
> > >   	struct xfs_mount	*mp = dp->i_mount;
> > > -	int			error, error2;
> > > +	int			error;
> > >   	error = xfs_attr_shortform_addname(args);
> > >   	if (error == -ENOSPC)
> > > @@ -243,9 +243,7 @@ xfs_attr_try_sf_addname(
> > >   	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > >   		xfs_trans_set_sync(args->trans);
> > 
> > Perhaps the above check should stay along with the tx commit code..?
> That makes sense, I will move it upwards
> > 
> > > -	error2 = xfs_trans_commit(args->trans);
> > > -	args->trans = NULL;
> > > -	return error ? error : error2;
> > > +	return error;
> > >   }
> > >   /*
> > > @@ -257,7 +255,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,
> > > @@ -277,8 +275,11 @@ 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) {
> > > +			error2 = xfs_trans_commit(args->trans);
> > > +			args->trans = NULL;
> > > +			return error ? error : error2;
> > 
> > We've already checked that error == 0 here, so this can be simplified.
> > Hmm.. that said, the original code looks like it commits the transaction
> > on error != -ENOSPC, which means this slightly changes behavior when
> > (error && error != -ENOSPC) is true. So perhaps it is the error check
> > that should be fixed up and not the error2 logic..
> 
> Yes, I believe this got some attention in the last review.  While it is
> different logic now, I think we reasoned that committing on say -EIO or some
> other such unexpected error didn't make much sense either, so we cleaned it
> up a bit.  Though you're probably right about the simplification now with
> the change.  Is there a reason we would want to commit in the case of
> unexpected errors?
> 

I'm not 100% sure tbh. There is a comment that acknowledges unrelated
errors so it might be intentional, at least for some errors. I'd at
least suggest to preserve the existing logic in the refactoring patch
and if you think there's a bug, perhaps tack on a separate patch later
for independent review. That way if we find we broke something down the
line, it's easier to identify and test the logic change separately from
the broader rework.

Brian

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

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

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-20 19:12     ` Allison Collins
@ 2019-09-23 12:04       ` Brian Foster
  2019-09-24  5:53         ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-23 12:04 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
> On 9/20/19 8:28 AM, Brian Foster wrote:
> > On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
> > > This patch adds new delayed attribute routines:
> > > 
> > > xfs_attr_set_later
> > > xfs_attr_remove_later
> > > xfs_leaf_addname_later
> > > xfs_node_addname_later
> > > xfs_node_removename_later
> > > 
> > > These routines are similar to their existing counter parts,
> > > but they do not roll or commit transactions.  They instead
> > > return -EAGAIN to allow the calling function to roll the
> > > transaction and recall the function.  This allows the
> > > attribute operations to be logged in multiple smaller
> > > transactions.
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
> > >   fs/xfs/libxfs/xfs_attr.h |   2 +
> > >   2 files changed, 592 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 781dd8a..310f5b2 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > ...
> > > @@ -313,6 +316,112 @@ xfs_attr_set_args(
> > >   }
> > >   /*
> > > + * Set 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_set_later(
> > > +	struct xfs_da_args	*args,
> > > +	struct xfs_buf          **leaf_bp)
> > > +{
> > > +	struct xfs_inode	*dp = args->dp;
> > > +	int			error = 0;
> > > +	int			sf_size;
> > > +
> > > +	/*
> > > +	 * 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,
> > > +	 * upgrade it to a single-leaf-block attribute list.
> > > +	 */
> > > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> > > +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> > > +	     dp->i_d.di_anextents == 0)) {
> > > +		/*
> > > +		 * Build initial attribute list (if required).
> > > +		 */
> > > +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> > > +			xfs_attr_shortform_create(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;
> > > +
> > > +		/*
> > > +		 * 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);
> > > +		if (error)
> > > +			return error;
> > > +
> > > +		/*
> > > +		 * 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.
> > > +		 */
> > > +
> > > +		xfs_trans_bhold(args->trans, *leaf_bp);
> > > +		return -EAGAIN;
> > > +	}
> > 
> > I haven't actually reviewed the code in this patch yet, but rather I
> > skipped ahead to try and get an understanding of the design approach and
> > flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
> > of xattr code into these dfops oriented functions but instead of rolling
> > transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
> > reentrancy into the xfs_trans_attr() function.
> 
> Yes. If it helps to know a little more background about how it came into
> being...
> Initially I had started out with the code paths merged, and had a boolean
> switch to control the alternate behavior (much like the "roll_trans" boolean
> from the prior sets, if you recall them).  In a way, the boolean acted like
> a sort of marker of where things needed to get factored up.  The goal being
> to pull the boolean into the higher level routines as much as possible and
> leaving behind all the little helpers which is what you see now in now
> patches 5 - 12.
> 
> After I got done with all the refactoring, the parts that still had the
> boolean were a sort of hybrid of the two paths you see now.  At one point I
> made a judgment that continuing to factor up the boolean would be more
> complicated than not.  I know people disliked the boolean toggle from the
> prior sets.  So the *_later routines we have now are a result of the hybrid
> having been gutted of the boolean and split then off into its separate path.
> 
> 
> > 
> > If I'm following that correctly, I'm concerned about a couple things
> > with the general approach. First, I think the complexity is high and
> > maintainability is low/difficult for this kind of reentrant approach.
> 
> Yes.  And I did very much anticipate a similar response.  Thats certainly
> not to imply that I did all this for giggles, but because I think sometimes
> it's easy for designs to sound like good ideas in theory, until people see
> them in practice.  And then the design takes a different direction.  In a
> way I think the prototypes are a sort of necessary step for the design to
> evolve, even if the prototypes are sort of ugly.  :-)
> 

Yeah, tbh I suspect that anything we come up with at first is going to
have an ugliness factor due to the simple fact of how the code is
currently implemented. IMO, the right approach is to take the current
code apart as much as possible (without too much regard for aesthetic),
identify/isolate the smallest functional components required to support
both direct rolling and deferred operation rolling, and then from there
think about cleaning up the design for how to fit those pieces back
together.  We might be able to do that in one patch series, but I
wouldn't be surprised (or object to) doing it in several.

IOW, I think it would be reasonable to split off the effort of
refactoring the existing xattr code to be "deferred capable" as an
independent series if you didn't want to have to continue rebasing the
follow on deferred xattr bits and wanted to try and get more rapid
development+review cycles of the refactoring, but that's up to you. The
whole idea for the refactoring is to not change existing behavior, so I
don't see why that couldn't be a mergeable component on its own.

> > The state is managed/changed all throughout the call tree and so the
> > risk and complexity of changing one particular bit in the sequence
> > requires subtle consideration to make sure it doesn't cause problems if
> > the function is reentered.
> Yes, it's still very much a state machine in practice.  But I think we may
> be stuck with at least some variant of state machine if we still want to
> adhere to the EAGAIN interface which requires the stack to back out.  I have
> pondered the idea of introducing a call back to cycle out the transactions
> mid flight so that we dont need to stop and return. This would escape the
> state machine concept, but may require alternate surgery to the calling log
> routines too.  So that may just turn into a different type of monster
> 

To be clear, I'm pretty much expecting it to continue to be a state
machine. That seems to be the most simple way to break things down, I
think. I'd rather not get into things like callbacks or whatever until
we've broken down the functional components and have a more clear
picture of things.

BTW, I thought one of your previous series' had a start on this in terms
of just defining some quick and dirty states based on an enum or
something and sticking them in a switch statement..? The point I'm
trying to make is that while those kind of simple enumerated low level
states are probably not where we want to leave things at the end, it
might be a reasonable approach to break the existing code into those
states and then try and polish things from there. I definitely think it
would be easier to review from a design perspective...

> For example, I'd prefer to see something like
> > xfs_trans_attr() broken down into smaller granularity functions with
> > higher level state that is managed and readable in one place, if
> > possible. Perhaps we could do that based on attr fork format, but I need
> > to stare at the code and think about this some more (it might be that
> > some degree of reentrancy is inevitable, or we just need to break things
> > down to even smaller states...).
> Yes, and I did go through a phase of trying to simplify the statemachine by
> trying to grab onto anything about the state of the fork that could be used
> instead.  But its not always enough particularly in the case of routines
> that are in the middle of allocating or removing blocks.  If you see any
> other mechanics that could help out, please call them out.
> 

One of the things I'm wondering is if we'll be able to reduce the number
of unique (sub-)states required by reordering some of the existing logic
between the higher level states. For a quick example, the current series
uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
a state that can be reentered over and over. This raises the question to
me of whether that _ALLOC_LEAF thing could eventually just be folded
into the tail of the previous state.

To reiterate, for now I think it would be perfectly reasonable to make
_ALLOC_LEAF its own independent state so the flag management isn't
buried so deep in the xattr code...

> 
> > 
> > Second, it seems like a lot of this code duplication between deferred
> > and non-deferred operations should be unnecessary, particularly since
> > the only difference between the contexts is how transactions are
> > managed. For example, if you follow the xattr set code path in both
> > contexts, we can see that functions like xfs_attr_set_args() are
> > basically duplicated in the xfs_attr_set_later() deferred variant just
> > so we can change the xfs_defer_finish() call in the former to a return
> > -EAGAIN in the latter.
> Yes, they still carry some similarities.  I guess I reasoned that continuing
> to carve things up into smaller and smaller helpers with out a generalized
> purpose (other than de-dup reduction) was starting to look a little weird,
> and maybe leaving things in their appropriate context might have been
> preferred?  Folks are welcome to chime in with opinions though.
> 

As mentioned above, I think weird is to be expected, at least if we
break things down into an intermediary state. That's just my .02 though.
Maybe others have different ideas..

> > 
> > Instead, what I think we should strive for is a common xattr mechanism
> > that consists of the lowest common denominator between the two contexts
> > (or IOW, core infrastructure that can be invoked from either context).
> > For example, on a kernel without deferred xattr support, could we find a
> > way to call the deferred variants directly and just let the
> > context-specific caller do the transaction rolls on -EAGAIN instead of
> > relying on the dfops infrastructure?
> I think I did that somewhere in the older parent pointer sets.  At the time,
> we sort of forgot that we cant completely scrap non delayed attrs (because
> we need them for older versions).  But then protofiles needed to create
> pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
> with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
> 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
> a sort of general purpose wrapper?
> 
> ISTM that should be possible, it
> > just requires further breaking down the existing/non-deferred mechanism
> > into smaller bits that uses the new state management logic and
> > implements -EAGAIN handling for when the lower level code requires a
> > transaction roll. At that point, deferred support should basically just
> > consist of the dfops and log (i.e. intents) code to plug into the associated
> > infrastructure. I think another side effect of that approach is that we
> > shouldn't need these patches that add a bunch of new xattr
> > infrastructure code, but rather we'd just continue refactoring the
> > existing code and eventually implement a new high level function that
> > returns -EAGAIN directly to the dfops code instead of rolling
> > transactions explicitly. Thoughts?
> Ok, I think I understand what you're trying to describe here.  Maybe take a
> look at xfs_attri_recover in patch 15, and let me know if that was similar
> to what you were thinking?
> 

Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
expect the direct xattr path to have to do something very similar in
terms of invoking the xattr state machine and handling transaction rolls
where the dfops mechanism isn't there to do it for us.

Brian

> Thank you for all the thorough reviewing here, I know it's a lot!
> Allison
> 
> > 
> > Brian
> > 
> > > +
> > > +	/*
> > > +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
> > > +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
> > > +	 * that it is not done yet, and need to be recalled to finish up from
> > > +	 * the last EAGAIN it returned
> > > +	 */
> > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
> > > +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
> > > +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
> > > +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
> > > +			args->dc.flags |= XFS_DC_FOUND_LBLK;
> > > +
> > > +			if (error && error != -ENOSPC)
> > > +				return error;
> > > +
> > > +			return -EAGAIN;
> > > +		}
> > > +
> > > +		error = xfs_leaf_addname_later(args);
> > > +		if (error && error != -ENOSPC)
> > > +			return error;
> > > +	} else {
> > > +		error = xfs_node_addname_later(args);
> > > +	}
> > > +
> > > +	return error;
> > > +}
> > > +
> > > +
> > > +
> > > +/*
> > >    * Return EEXIST if attr is found, or ENOATTR if not
> > >    */
> > >   int
> > > @@ -362,6 +471,57 @@ xfs_attr_remove_args(
> > >   	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;
> > > +	struct xfs_buf		*bp;
> > > +	int			forkoff, error = 0;
> > > +
> > > +	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_remove(args);
> > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
> > > +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > +		/*
> > > +		 * If we fit in a block AND we are not in the middle of
> > > +		 * removing node blocks, remove the leaf attribute.
> > > +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
> > > +		 * signal that it is not done yet, and needs to be recalled to
> > > +		 * to finish up from the last -EAGAIN
> > > +		 */
> > > +		error = xfs_leaf_has_attr(args, &bp);
> > > +		if (error == -ENOATTR) {
> > > +			xfs_trans_brelse(args->trans, bp);
> > > +			return error;
> > > +		}
> > > +		error = 0;
> > > +
> > > +		xfs_attr3_leaf_remove(bp, args);
> > > +
> > > +		/* If the result is small enough, shrink it into the inode.*/
> > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > +		if (forkoff)
> > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > +	} else {
> > > +		error = xfs_node_removename_later(args);
> > > +	}
> > > +
> > > +	return error;
> > > +}
> > > +
> > > +
> > > +
> > >   int
> > >   xfs_attr_set(
> > >   	struct xfs_inode	*dp,
> > > @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
> > > + *
> > > + * 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.
> > > + */
> > > +STATIC int
> > > +xfs_leaf_addname_later(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error, nmap;
> > > +	struct xfs_inode	*dp = args->dp;
> > > +	struct xfs_bmbt_irec	*map = &args->dc.map;
> > > +
> > > +	/*
> > > +	 * If there was an out-of-line value, allocate the blocks we
> > > +	 * identified for its storage and copy the value.  This is done
> > > +	 * after we create the attribute so that we don't overflow the
> > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > +	 */
> > > +	if (args->rmtblkno > 0) {
> > > +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
> > > +			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));
> > > +
> > > +			error = xfs_attr_rmt_find_hole(args);
> > > +			if (error)
> > > +				return error;
> > > +
> > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > +			args->dc.lblkno = args->rmtblkno;
> > > +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
> > > +		}
> > > +
> > > +		/*
> > > +		 * Roll through the "value", allocating blocks on disk as
> > > +		 * required.
> > > +		 */
> > > +		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));
> > > +
> > > +			/* roll attribute extent map forwards */
> > > +			args->dc.lblkno += map->br_blockcount;
> > > +			args->dc.blkcnt -= map->br_blockcount;
> > > +
> > > +			return -EAGAIN;
> > > +		}
> > > +
> > > +		error = xfs_attr_rmtval_set_value(args);
> > > +		if (error)
> > > +			return error;
> > > +	}
> > > +
> > > +	if (args->rmtblkno > 0) {
> > > +		/*
> > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > +		 */
> > > +		error = xfs_attr3_leaf_clearflag(args);
> > > +	}
> > > +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > >    * Return EEXIST if attr is found, or ENOATTR if not
> > >    */
> > >   STATIC int
> > > @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
> > >   }
> > >   /*
> > > + * Remove a name from a B-tree attribute list.
> > > + *
> > > + * 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
> > > + * -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.
> > > + */
> > > +STATIC int
> > > +xfs_node_removename_later(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	struct xfs_da_state	*state = NULL;
> > > +	struct xfs_da_state_blk	*blk;
> > > +	struct xfs_buf		*bp;
> > > +	int			error, forkoff, retval = 0;
> > > +	struct xfs_inode	*dp = args->dp;
> > > +	int			done = 0;
> > > +
> > > +	trace_xfs_attr_node_removename(args);
> > > +
> > > +	if (args->dc.state == NULL) {
> > > +		error = xfs_attr_node_hasname(args, &args->dc.state);
> > > +		if (error != -EEXIST)
> > > +			goto out;
> > > +		else
> > > +			error = 0;
> > > +
> > > +		/*
> > > +		 * If there is an out-of-line value, de-allocate the blocks.
> > > +		 * This is done before we remove the attribute so that we don't
> > > +		 * overflow the maximum size of a transaction and/or hit a
> > > +		 * deadlock.
> > > +		 */
> > > +		state = args->dc.state;
> > > +		args->dc.blk = &state->path.blk[state->path.active - 1];
> > > +		ASSERT(args->dc.blk->bp != NULL);
> > > +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +	}
> > > +	state = args->dc.state;
> > > +	blk = args->dc.blk;
> > > +
> > > +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > +		bool isset;
> > > +
> > > +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
> > > +		if (error)
> > > +			goto out;
> > > +		if (!isset) {
> > > +			/*
> > > +			 * Fill in disk block numbers in the state structure
> > > +			 * so that we can get the buffers back after we commit
> > > +			 * several transactions in the following calls.
> > > +			 */
> > > +			error = xfs_attr_fillstate(state);
> > > +			if (error)
> > > +				goto out;
> > > +
> > > +			/*
> > > +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> > > +			 * remote value.
> > > +			 */
> > > +			error = xfs_attr3_leaf_setflag(args);
> > > +			if (error)
> > > +				goto out;
> > > +
> > > +			return -EAGAIN;
> > > +		}
> > > +
> > > +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > +			error = xfs_attr_rmtval_invalidate(args);
> > > +			if (error)
> > > +				goto out;
> > > +		}
> > > +
> > > +		/*
> > > +		 * 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;
> > > +
> > > +			if (!done)
> > > +				return -EAGAIN;
> > > +		}
> > > +
> > > +		if (error)
> > > +			goto out;
> > > +
> > > +		/*
> > > +		 * Refill the state structure with buffers, the prior calls
> > > +		 * released our buffers.
> > > +		 */
> > > +		error = xfs_attr_refillstate(state);
> > > +		if (error)
> > > +			goto out;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Remove the name and update the hashvals in the tree.
> > > +	 */
> > > +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > +		blk = &state->path.blk[state->path.active - 1];
> > > +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +		retval = xfs_attr3_leaf_remove(blk->bp, args);
> > > +		xfs_da3_fixhashpath(state, &state->path);
> > > +
> > > +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Check to see if the tree needs to be collapsed.
> > > +	 */
> > > +	if (retval && (state->path.active > 1)) {
> > > +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > +		error = xfs_da3_join(state);
> > > +		if (error)
> > > +			goto out;
> > > +
> > > +		return -EAGAIN;
> > > +	}
> > > +
> > > +	/*
> > > +	 * If the result is small enough, push it all into the inode.
> > > +	 */
> > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > +		/*
> > > +		 * Have to get rid of the copy of this dabuf in the state.
> > > +		 */
> > > +		ASSERT(state->path.active == 1);
> > > +		ASSERT(state->path.blk[0].bp);
> > > +		state->path.blk[0].bp = NULL;
> > > +
> > > +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
> > > +		if (error)
> > > +			goto out;
> > > +
> > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > +		if (forkoff) {
> > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > +			/* bp is gone due to xfs_da_shrink_inode */
> > > +			if (error)
> > > +				goto out;
> > > +		} else
> > > +			xfs_trans_brelse(args->trans, bp);
> > > +	}
> > > +out:
> > > +	if (state != NULL)
> > > +		xfs_da_state_free(state);
> > > +
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > > + * Add a name to a Btree-format attribute list.
> > > + *
> > > + * This will involve walking down the Btree, and may involve splitting
> > > + * leaf nodes and even splitting intermediate nodes up to and including
> > > + * the root node (a special case of an intermediate node).
> > > + *
> > > + * "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
> > > + * -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.
> > > + */
> > > +STATIC int
> > > +xfs_node_addname_later(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	struct xfs_da_state	*state = NULL;
> > > +	struct xfs_da_state_blk	*blk;
> > > +	struct xfs_inode	*dp;
> > > +	int			retval, error = 0;
> > > +	int			nmap;
> > > +	struct xfs_bmbt_irec    *map = &args->dc.map;
> > > +
> > > +	trace_xfs_attr_node_addname(args);
> > > +
> > > +	/*
> > > +	 * Fill in bucket of arguments/results/context to carry around.
> > > +	 */
> > > +	dp = args->dp;
> > > +
> > > +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
> > > +		goto found_blk;
> > > +
> > > +	/*
> > > +	 * Search to see if name already exists, and get back a pointer
> > > +	 * to where it should go.
> > > +	 */
> > > +	retval = xfs_attr_node_hasname(args, &state);
> > > +	blk = &state->path.blk[state->path.active-1];
> > > +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > > +		goto out;
> > > +	} else if (retval == -EEXIST) {
> > > +		if (args->name.type & ATTR_CREATE)
> > > +			goto out;
> > > +
> > > +		trace_xfs_attr_node_replace(args);
> > > +
> > > +		/* save the attribute state for later removal*/
> > > +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
> > > +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> > > +		args->index2 = args->index;
> > > +		args->rmtblkno2 = args->rmtblkno;
> > > +		args->rmtblkcnt2 = args->rmtblkcnt;
> > > +		args->rmtvaluelen2 = args->rmtvaluelen;
> > > +
> > > +		/*
> > > +		 * clear the remote attr state now that it is saved so that the
> > > +		 * values reflect the state of the attribute we are about to
> > > +		 * add, not the attribute we just found and will remove later.
> > > +		 */
> > > +		args->rmtblkno = 0;
> > > +		args->rmtblkcnt = 0;
> > > +		args->rmtvaluelen = 0;
> > > +	}
> > > +
> > > +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
> > > +	if (retval == -ENOSPC) {
> > > +		if (state->path.active == 1) {
> > > +			/*
> > > +			 * Its really a single leaf node, but it had
> > > +			 * out-of-line values so it looked like it *might*
> > > +			 * have been a b-tree.
> > > +			 */
> > > +			xfs_da_state_free(state);
> > > +			state = NULL;
> > > +			error = xfs_attr3_leaf_to_node(args);
> > > +			if (error)
> > > +				goto out;
> > > +
> > > +			return -EAGAIN;
> > > +		}
> > > +
> > > +		/*
> > > +		 * Split as many Btree elements as required.
> > > +		 * This code tracks the new and old attr's location
> > > +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
> > > +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
> > > +		 */
> > > +		error = xfs_da3_split(state);
> > > +		if (error)
> > > +			goto out;
> > > +	} else {
> > > +		/*
> > > +		 * Addition succeeded, update Btree hashvals.
> > > +		 */
> > > +		xfs_da3_fixhashpath(state, &state->path);
> > > +	}
> > > +
> > > +	/*
> > > +	 * Kill the state structure, we're done with it and need to
> > > +	 * allow the buffers to come back later.
> > > +	 */
> > > +	xfs_da_state_free(state);
> > > +	state = NULL;
> > > +
> > > +	args->dc.flags |= XFS_DC_FOUND_NBLK;
> > > +	return -EAGAIN;
> > > +found_blk:
> > > +
> > > +	/*
> > > +	 * If there was an out-of-line value, allocate the blocks we
> > > +	 * identified for its storage and copy the value.  This is done
> > > +	 * after we create the attribute so that we don't overflow the
> > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > +	 */
> > > +	if (args->rmtblkno > 0) {
> > > +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
> > > +			args->dc.flags |= XFS_DC_ALLOC_NODE;
> > > +			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));
> > > +
> > > +			error = xfs_attr_rmt_find_hole(args);
> > > +			if (error)
> > > +				return error;
> > > +
> > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > +			args->dc.lblkno = args->rmtblkno;
> > > +		}
> > > +		/*
> > > +		 * Roll through the "value", allocating blocks on disk as
> > > +		 * required.
> > > +		 */
> > > +		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));
> > > +
> > > +			/* roll attribute extent map forwards */
> > > +			args->dc.lblkno += map->br_blockcount;
> > > +			args->dc.blkcnt -= map->br_blockcount;
> > > +
> > > +			return -EAGAIN;
> > > +		}
> > > +
> > > +		error = xfs_attr_rmtval_set_value(args);
> > > +		if (error)
> > > +			return error;
> > > +	}
> > > +
> > > +	if (args->rmtblkno > 0) {
> > > +		/*
> > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > +		 */
> > > +		error = xfs_attr3_leaf_clearflag(args);
> > > +		if (error)
> > > +			goto out;
> > > +	}
> > > +	retval = error = 0;
> > > +
> > > +out:
> > > +	if (state)
> > > +		xfs_da_state_free(state);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	return retval;
> > > +}
> > > +
> > > +
> > > +
> > > +/*
> > >    * Fill in the disk block numbers in the state structure for the buffers
> > >    * that are attached to the state structure.
> > >    * This is done so that we can quickly reattach ourselves to those buffers
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index fb56d81..6203766 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-23 12:04       ` Brian Foster
@ 2019-09-24  5:53         ` Allison Collins
  2019-09-24 10:05           ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Allison Collins @ 2019-09-24  5:53 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 9/23/19 5:04 AM, Brian Foster wrote:
> On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
>> On 9/20/19 8:28 AM, Brian Foster wrote:
>>> On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
>>>> This patch adds new delayed attribute routines:
>>>>
>>>> xfs_attr_set_later
>>>> xfs_attr_remove_later
>>>> xfs_leaf_addname_later
>>>> xfs_node_addname_later
>>>> xfs_node_removename_later
>>>>
>>>> These routines are similar to their existing counter parts,
>>>> but they do not roll or commit transactions.  They instead
>>>> return -EAGAIN to allow the calling function to roll the
>>>> transaction and recall the function.  This allows the
>>>> attribute operations to be logged in multiple smaller
>>>> transactions.
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
>>>>    fs/xfs/libxfs/xfs_attr.h |   2 +
>>>>    2 files changed, 592 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 781dd8a..310f5b2 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> ...
>>>> @@ -313,6 +316,112 @@ xfs_attr_set_args(
>>>>    }
>>>>    /*
>>>> + * Set 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_set_later(
>>>> +	struct xfs_da_args	*args,
>>>> +	struct xfs_buf          **leaf_bp)
>>>> +{
>>>> +	struct xfs_inode	*dp = args->dp;
>>>> +	int			error = 0;
>>>> +	int			sf_size;
>>>> +
>>>> +	/*
>>>> +	 * 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,
>>>> +	 * upgrade it to a single-leaf-block attribute list.
>>>> +	 */
>>>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>>>> +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>>>> +	     dp->i_d.di_anextents == 0)) {
>>>> +		/*
>>>> +		 * Build initial attribute list (if required).
>>>> +		 */
>>>> +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>>>> +			xfs_attr_shortform_create(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;
>>>> +
>>>> +		/*
>>>> +		 * 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);
>>>> +		if (error)
>>>> +			return error;
>>>> +
>>>> +		/*
>>>> +		 * 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.
>>>> +		 */
>>>> +
>>>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>>>> +		return -EAGAIN;
>>>> +	}
>>>
>>> I haven't actually reviewed the code in this patch yet, but rather I
>>> skipped ahead to try and get an understanding of the design approach and
>>> flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
>>> of xattr code into these dfops oriented functions but instead of rolling
>>> transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
>>> reentrancy into the xfs_trans_attr() function.
>>
>> Yes. If it helps to know a little more background about how it came into
>> being...
>> Initially I had started out with the code paths merged, and had a boolean
>> switch to control the alternate behavior (much like the "roll_trans" boolean
>> from the prior sets, if you recall them).  In a way, the boolean acted like
>> a sort of marker of where things needed to get factored up.  The goal being
>> to pull the boolean into the higher level routines as much as possible and
>> leaving behind all the little helpers which is what you see now in now
>> patches 5 - 12.
>>
>> After I got done with all the refactoring, the parts that still had the
>> boolean were a sort of hybrid of the two paths you see now.  At one point I
>> made a judgment that continuing to factor up the boolean would be more
>> complicated than not.  I know people disliked the boolean toggle from the
>> prior sets.  So the *_later routines we have now are a result of the hybrid
>> having been gutted of the boolean and split then off into its separate path.
>>
>>
>>>
>>> If I'm following that correctly, I'm concerned about a couple things
>>> with the general approach. First, I think the complexity is high and
>>> maintainability is low/difficult for this kind of reentrant approach.
>>
>> Yes.  And I did very much anticipate a similar response.  Thats certainly
>> not to imply that I did all this for giggles, but because I think sometimes
>> it's easy for designs to sound like good ideas in theory, until people see
>> them in practice.  And then the design takes a different direction.  In a
>> way I think the prototypes are a sort of necessary step for the design to
>> evolve, even if the prototypes are sort of ugly.  :-)
>>
> 
> Yeah, tbh I suspect that anything we come up with at first is going to
> have an ugliness factor due to the simple fact of how the code is
> currently implemented. IMO, the right approach is to take the current
> code apart as much as possible (without too much regard for aesthetic),
> identify/isolate the smallest functional components required to support
> both direct rolling and deferred operation rolling, and then from there
> think about cleaning up the design for how to fit those pieces back
> together.  We might be able to do that in one patch series, but I
> wouldn't be surprised (or object to) doing it in several.
> 
> IOW, I think it would be reasonable to split off the effort of
> refactoring the existing xattr code to be "deferred capable" as an
> independent series if you didn't want to have to continue rebasing the
> follow on deferred xattr bits and wanted to try and get more rapid
> development+review cycles of the refactoring, but that's up to you. The
> whole idea for the refactoring is to not change existing behavior, so I
> don't see why that couldn't be a mergeable component on its own.

Ok, maybe I could break up the set after patch 14, and add a wrapper 
loop like the one we have in the recover routine.  That might be a good 
way to introduce some of the set in smaller pieces.

> 
>>> The state is managed/changed all throughout the call tree and so the
>>> risk and complexity of changing one particular bit in the sequence
>>> requires subtle consideration to make sure it doesn't cause problems if
>>> the function is reentered.
>> Yes, it's still very much a state machine in practice.  But I think we may
>> be stuck with at least some variant of state machine if we still want to
>> adhere to the EAGAIN interface which requires the stack to back out.  I have
>> pondered the idea of introducing a call back to cycle out the transactions
>> mid flight so that we dont need to stop and return. This would escape the
>> state machine concept, but may require alternate surgery to the calling log
>> routines too.  So that may just turn into a different type of monster
>>
> 
> To be clear, I'm pretty much expecting it to continue to be a state
> machine. That seems to be the most simple way to break things down, I
> think. I'd rather not get into things like callbacks or whatever until
> we've broken down the functional components and have a more clear
> picture of things.
> 
> BTW, I thought one of your previous series' had a start on this in terms
> of just defining some quick and dirty states based on an enum or
> something and sticking them in a switch statement..? The point I'm
> trying to make is that while those kind of simple enumerated low level
> states are probably not where we want to leave things at the end, it
> might be a reasonable approach to break the existing code into those
> states and then try and polish things from there. I definitely think it
> would be easier to review from a design perspective...

Sure, I can bring back the state switch if people prefer.  I got the 
impression that people thought it was odd, so I replaced it with the 
XFS_DC_* flags in this one.  I figured that might be a little more like 
what people are used to seeing.  IMHO I think the state switch might 
have been little cleaner in that it doesn't have to re-run over the same 
block of code multiple times to achieve the same end goal of getting 
back to where it was.  If people have other opinions though please feel 
free to chime in.

> 
>> For example, I'd prefer to see something like
>>> xfs_trans_attr() broken down into smaller granularity functions with
>>> higher level state that is managed and readable in one place, if
>>> possible. Perhaps we could do that based on attr fork format, but I need
>>> to stare at the code and think about this some more (it might be that
>>> some degree of reentrancy is inevitable, or we just need to break things
>>> down to even smaller states...).
>> Yes, and I did go through a phase of trying to simplify the statemachine by
>> trying to grab onto anything about the state of the fork that could be used
>> instead.  But its not always enough particularly in the case of routines
>> that are in the middle of allocating or removing blocks.  If you see any
>> other mechanics that could help out, please call them out.
>>
> 
> One of the things I'm wondering is if we'll be able to reduce the number
> of unique (sub-)states required by reordering some of the existing logic
> between the higher level states. For a quick example, the current series
> uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
> a state that can be reentered over and over. This raises the question to
> me of whether that _ALLOC_LEAF thing could eventually just be folded
> into the tail of the previous state.
> 
> To reiterate, for now I think it would be perfectly reasonable to make
> _ALLOC_LEAF its own independent state so the flag management isn't
> buried so deep in the xattr code...

Yes, it is one of the examples where trying to use the fork to control 
the state does not work out so well because we're in the middle of 
altering things.  So in those cases, using the state machine to give it 
its own state starts to make more sense.

> 
>>
>>>
>>> Second, it seems like a lot of this code duplication between deferred
>>> and non-deferred operations should be unnecessary, particularly since
>>> the only difference between the contexts is how transactions are
>>> managed. For example, if you follow the xattr set code path in both
>>> contexts, we can see that functions like xfs_attr_set_args() are
>>> basically duplicated in the xfs_attr_set_later() deferred variant just
>>> so we can change the xfs_defer_finish() call in the former to a return
>>> -EAGAIN in the latter.
>> Yes, they still carry some similarities.  I guess I reasoned that continuing
>> to carve things up into smaller and smaller helpers with out a generalized
>> purpose (other than de-dup reduction) was starting to look a little weird,
>> and maybe leaving things in their appropriate context might have been
>> preferred?  Folks are welcome to chime in with opinions though.
>>
> 
> As mentioned above, I think weird is to be expected, at least if we
> break things down into an intermediary state. That's just my .02 though.
> Maybe others have different ideas..
> 
>>>
>>> Instead, what I think we should strive for is a common xattr mechanism
>>> that consists of the lowest common denominator between the two contexts
>>> (or IOW, core infrastructure that can be invoked from either context).
>>> For example, on a kernel without deferred xattr support, could we find a
>>> way to call the deferred variants directly and just let the
>>> context-specific caller do the transaction rolls on -EAGAIN instead of
>>> relying on the dfops infrastructure?
>> I think I did that somewhere in the older parent pointer sets.  At the time,
>> we sort of forgot that we cant completely scrap non delayed attrs (because
>> we need them for older versions).  But then protofiles needed to create
>> pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
>> with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
>> 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
>> a sort of general purpose wrapper?
>>
>> ISTM that should be possible, it
>>> just requires further breaking down the existing/non-deferred mechanism
>>> into smaller bits that uses the new state management logic and
>>> implements -EAGAIN handling for when the lower level code requires a
>>> transaction roll. At that point, deferred support should basically just
>>> consist of the dfops and log (i.e. intents) code to plug into the associated
>>> infrastructure. I think another side effect of that approach is that we
>>> shouldn't need these patches that add a bunch of new xattr
>>> infrastructure code, but rather we'd just continue refactoring the
>>> existing code and eventually implement a new high level function that
>>> returns -EAGAIN directly to the dfops code instead of rolling
>>> transactions explicitly. Thoughts?
>> Ok, I think I understand what you're trying to describe here.  Maybe take a
>> look at xfs_attri_recover in patch 15, and let me know if that was similar
>> to what you were thinking?
>>
> 
> Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
> expect the direct xattr path to have to do something very similar in
> terms of invoking the xattr state machine and handling transaction rolls
> where the dfops mechanism isn't there to do it for us.
> 
> Brian
Sure, that shouldn't be to hard to make a high level wrapper like that. 
Then we can let go of the old code path.

Thanks again for the all the reviewing!  :-)

Allison

> 
>> Thank you for all the thorough reviewing here, I know it's a lot!
>> Allison
>>
>>>
>>> Brian
>>>
>>>> +
>>>> +	/*
>>>> +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
>>>> +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
>>>> +	 * that it is not done yet, and need to be recalled to finish up from
>>>> +	 * the last EAGAIN it returned
>>>> +	 */
>>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
>>>> +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
>>>> +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
>>>> +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
>>>> +			args->dc.flags |= XFS_DC_FOUND_LBLK;
>>>> +
>>>> +			if (error && error != -ENOSPC)
>>>> +				return error;
>>>> +
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		error = xfs_leaf_addname_later(args);
>>>> +		if (error && error != -ENOSPC)
>>>> +			return error;
>>>> +	} else {
>>>> +		error = xfs_node_addname_later(args);
>>>> +	}
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>> +
>>>> +
>>>> +/*
>>>>     * Return EEXIST if attr is found, or ENOATTR if not
>>>>     */
>>>>    int
>>>> @@ -362,6 +471,57 @@ xfs_attr_remove_args(
>>>>    	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;
>>>> +	struct xfs_buf		*bp;
>>>> +	int			forkoff, error = 0;
>>>> +
>>>> +	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_remove(args);
>>>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
>>>> +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>>>> +		/*
>>>> +		 * If we fit in a block AND we are not in the middle of
>>>> +		 * removing node blocks, remove the leaf attribute.
>>>> +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
>>>> +		 * signal that it is not done yet, and needs to be recalled to
>>>> +		 * to finish up from the last -EAGAIN
>>>> +		 */
>>>> +		error = xfs_leaf_has_attr(args, &bp);
>>>> +		if (error == -ENOATTR) {
>>>> +			xfs_trans_brelse(args->trans, bp);
>>>> +			return error;
>>>> +		}
>>>> +		error = 0;
>>>> +
>>>> +		xfs_attr3_leaf_remove(bp, args);
>>>> +
>>>> +		/* If the result is small enough, shrink it into the inode.*/
>>>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>>>> +		if (forkoff)
>>>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>>>> +	} else {
>>>> +		error = xfs_node_removename_later(args);
>>>> +	}
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>> +
>>>> +
>>>>    int
>>>>    xfs_attr_set(
>>>>    	struct xfs_inode	*dp,
>>>> @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +STATIC int
>>>> +xfs_leaf_addname_later(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int			error, nmap;
>>>> +	struct xfs_inode	*dp = args->dp;
>>>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>>>> +
>>>> +	/*
>>>> +	 * If there was an out-of-line value, allocate the blocks we
>>>> +	 * identified for its storage and copy the value.  This is done
>>>> +	 * after we create the attribute so that we don't overflow the
>>>> +	 * maximum size of a transaction and/or hit a deadlock.
>>>> +	 */
>>>> +	if (args->rmtblkno > 0) {
>>>> +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
>>>> +			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));
>>>> +
>>>> +			error = xfs_attr_rmt_find_hole(args);
>>>> +			if (error)
>>>> +				return error;
>>>> +
>>>> +			args->dc.blkcnt = args->rmtblkcnt;
>>>> +			args->dc.lblkno = args->rmtblkno;
>>>> +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
>>>> +		}
>>>> +
>>>> +		/*
>>>> +		 * Roll through the "value", allocating blocks on disk as
>>>> +		 * required.
>>>> +		 */
>>>> +		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));
>>>> +
>>>> +			/* roll attribute extent map forwards */
>>>> +			args->dc.lblkno += map->br_blockcount;
>>>> +			args->dc.blkcnt -= map->br_blockcount;
>>>> +
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		error = xfs_attr_rmtval_set_value(args);
>>>> +		if (error)
>>>> +			return error;
>>>> +	}
>>>> +
>>>> +	if (args->rmtblkno > 0) {
>>>> +		/*
>>>> +		 * Added a "remote" value, just clear the incomplete flag.
>>>> +		 */
>>>> +		error = xfs_attr3_leaf_clearflag(args);
>>>> +	}
>>>> +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
>>>> +	return error;
>>>> +}
>>>> +
>>>> +/*
>>>>     * Return EEXIST if attr is found, or ENOATTR if not
>>>>     */
>>>>    STATIC int
>>>> @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
>>>>    }
>>>>    /*
>>>> + * Remove a name from a B-tree attribute list.
>>>> + *
>>>> + * 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
>>>> + * -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.
>>>> + */
>>>> +STATIC int
>>>> +xfs_node_removename_later(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	struct xfs_da_state	*state = NULL;
>>>> +	struct xfs_da_state_blk	*blk;
>>>> +	struct xfs_buf		*bp;
>>>> +	int			error, forkoff, retval = 0;
>>>> +	struct xfs_inode	*dp = args->dp;
>>>> +	int			done = 0;
>>>> +
>>>> +	trace_xfs_attr_node_removename(args);
>>>> +
>>>> +	if (args->dc.state == NULL) {
>>>> +		error = xfs_attr_node_hasname(args, &args->dc.state);
>>>> +		if (error != -EEXIST)
>>>> +			goto out;
>>>> +		else
>>>> +			error = 0;
>>>> +
>>>> +		/*
>>>> +		 * If there is an out-of-line value, de-allocate the blocks.
>>>> +		 * This is done before we remove the attribute so that we don't
>>>> +		 * overflow the maximum size of a transaction and/or hit a
>>>> +		 * deadlock.
>>>> +		 */
>>>> +		state = args->dc.state;
>>>> +		args->dc.blk = &state->path.blk[state->path.active - 1];
>>>> +		ASSERT(args->dc.blk->bp != NULL);
>>>> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> +	}
>>>> +	state = args->dc.state;
>>>> +	blk = args->dc.blk;
>>>> +
>>>> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>>>> +		bool isset;
>>>> +
>>>> +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
>>>> +		if (error)
>>>> +			goto out;
>>>> +		if (!isset) {
>>>> +			/*
>>>> +			 * Fill in disk block numbers in the state structure
>>>> +			 * so that we can get the buffers back after we commit
>>>> +			 * several transactions in the following calls.
>>>> +			 */
>>>> +			error = xfs_attr_fillstate(state);
>>>> +			if (error)
>>>> +				goto out;
>>>> +
>>>> +			/*
>>>> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
>>>> +			 * remote value.
>>>> +			 */
>>>> +			error = xfs_attr3_leaf_setflag(args);
>>>> +			if (error)
>>>> +				goto out;
>>>> +
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>>>> +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>>>> +			error = xfs_attr_rmtval_invalidate(args);
>>>> +			if (error)
>>>> +				goto out;
>>>> +		}
>>>> +
>>>> +		/*
>>>> +		 * 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;
>>>> +
>>>> +			if (!done)
>>>> +				return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		if (error)
>>>> +			goto out;
>>>> +
>>>> +		/*
>>>> +		 * Refill the state structure with buffers, the prior calls
>>>> +		 * released our buffers.
>>>> +		 */
>>>> +		error = xfs_attr_refillstate(state);
>>>> +		if (error)
>>>> +			goto out;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * Remove the name and update the hashvals in the tree.
>>>> +	 */
>>>> +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>>>> +		blk = &state->path.blk[state->path.active - 1];
>>>> +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> +		retval = xfs_attr3_leaf_remove(blk->bp, args);
>>>> +		xfs_da3_fixhashpath(state, &state->path);
>>>> +
>>>> +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * Check to see if the tree needs to be collapsed.
>>>> +	 */
>>>> +	if (retval && (state->path.active > 1)) {
>>>> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>>>> +		error = xfs_da3_join(state);
>>>> +		if (error)
>>>> +			goto out;
>>>> +
>>>> +		return -EAGAIN;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * If the result is small enough, push it all into the inode.
>>>> +	 */
>>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>> +		/*
>>>> +		 * Have to get rid of the copy of this dabuf in the state.
>>>> +		 */
>>>> +		ASSERT(state->path.active == 1);
>>>> +		ASSERT(state->path.blk[0].bp);
>>>> +		state->path.blk[0].bp = NULL;
>>>> +
>>>> +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
>>>> +		if (error)
>>>> +			goto out;
>>>> +
>>>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>>>> +		if (forkoff) {
>>>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>>>> +			/* bp is gone due to xfs_da_shrink_inode */
>>>> +			if (error)
>>>> +				goto out;
>>>> +		} else
>>>> +			xfs_trans_brelse(args->trans, bp);
>>>> +	}
>>>> +out:
>>>> +	if (state != NULL)
>>>> +		xfs_da_state_free(state);
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Add a name to a Btree-format attribute list.
>>>> + *
>>>> + * This will involve walking down the Btree, and may involve splitting
>>>> + * leaf nodes and even splitting intermediate nodes up to and including
>>>> + * the root node (a special case of an intermediate node).
>>>> + *
>>>> + * "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
>>>> + * -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.
>>>> + */
>>>> +STATIC int
>>>> +xfs_node_addname_later(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	struct xfs_da_state	*state = NULL;
>>>> +	struct xfs_da_state_blk	*blk;
>>>> +	struct xfs_inode	*dp;
>>>> +	int			retval, error = 0;
>>>> +	int			nmap;
>>>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>>>> +
>>>> +	trace_xfs_attr_node_addname(args);
>>>> +
>>>> +	/*
>>>> +	 * Fill in bucket of arguments/results/context to carry around.
>>>> +	 */
>>>> +	dp = args->dp;
>>>> +
>>>> +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
>>>> +		goto found_blk;
>>>> +
>>>> +	/*
>>>> +	 * Search to see if name already exists, and get back a pointer
>>>> +	 * to where it should go.
>>>> +	 */
>>>> +	retval = xfs_attr_node_hasname(args, &state);
>>>> +	blk = &state->path.blk[state->path.active-1];
>>>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>>> +		goto out;
>>>> +	} else if (retval == -EEXIST) {
>>>> +		if (args->name.type & ATTR_CREATE)
>>>> +			goto out;
>>>> +
>>>> +		trace_xfs_attr_node_replace(args);
>>>> +
>>>> +		/* save the attribute state for later removal*/
>>>> +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
>>>> +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
>>>> +		args->index2 = args->index;
>>>> +		args->rmtblkno2 = args->rmtblkno;
>>>> +		args->rmtblkcnt2 = args->rmtblkcnt;
>>>> +		args->rmtvaluelen2 = args->rmtvaluelen;
>>>> +
>>>> +		/*
>>>> +		 * clear the remote attr state now that it is saved so that the
>>>> +		 * values reflect the state of the attribute we are about to
>>>> +		 * add, not the attribute we just found and will remove later.
>>>> +		 */
>>>> +		args->rmtblkno = 0;
>>>> +		args->rmtblkcnt = 0;
>>>> +		args->rmtvaluelen = 0;
>>>> +	}
>>>> +
>>>> +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
>>>> +	if (retval == -ENOSPC) {
>>>> +		if (state->path.active == 1) {
>>>> +			/*
>>>> +			 * Its really a single leaf node, but it had
>>>> +			 * out-of-line values so it looked like it *might*
>>>> +			 * have been a b-tree.
>>>> +			 */
>>>> +			xfs_da_state_free(state);
>>>> +			state = NULL;
>>>> +			error = xfs_attr3_leaf_to_node(args);
>>>> +			if (error)
>>>> +				goto out;
>>>> +
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		/*
>>>> +		 * Split as many Btree elements as required.
>>>> +		 * This code tracks the new and old attr's location
>>>> +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
>>>> +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
>>>> +		 */
>>>> +		error = xfs_da3_split(state);
>>>> +		if (error)
>>>> +			goto out;
>>>> +	} else {
>>>> +		/*
>>>> +		 * Addition succeeded, update Btree hashvals.
>>>> +		 */
>>>> +		xfs_da3_fixhashpath(state, &state->path);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * Kill the state structure, we're done with it and need to
>>>> +	 * allow the buffers to come back later.
>>>> +	 */
>>>> +	xfs_da_state_free(state);
>>>> +	state = NULL;
>>>> +
>>>> +	args->dc.flags |= XFS_DC_FOUND_NBLK;
>>>> +	return -EAGAIN;
>>>> +found_blk:
>>>> +
>>>> +	/*
>>>> +	 * If there was an out-of-line value, allocate the blocks we
>>>> +	 * identified for its storage and copy the value.  This is done
>>>> +	 * after we create the attribute so that we don't overflow the
>>>> +	 * maximum size of a transaction and/or hit a deadlock.
>>>> +	 */
>>>> +	if (args->rmtblkno > 0) {
>>>> +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
>>>> +			args->dc.flags |= XFS_DC_ALLOC_NODE;
>>>> +			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));
>>>> +
>>>> +			error = xfs_attr_rmt_find_hole(args);
>>>> +			if (error)
>>>> +				return error;
>>>> +
>>>> +			args->dc.blkcnt = args->rmtblkcnt;
>>>> +			args->dc.lblkno = args->rmtblkno;
>>>> +		}
>>>> +		/*
>>>> +		 * Roll through the "value", allocating blocks on disk as
>>>> +		 * required.
>>>> +		 */
>>>> +		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));
>>>> +
>>>> +			/* roll attribute extent map forwards */
>>>> +			args->dc.lblkno += map->br_blockcount;
>>>> +			args->dc.blkcnt -= map->br_blockcount;
>>>> +
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +
>>>> +		error = xfs_attr_rmtval_set_value(args);
>>>> +		if (error)
>>>> +			return error;
>>>> +	}
>>>> +
>>>> +	if (args->rmtblkno > 0) {
>>>> +		/*
>>>> +		 * Added a "remote" value, just clear the incomplete flag.
>>>> +		 */
>>>> +		error = xfs_attr3_leaf_clearflag(args);
>>>> +		if (error)
>>>> +			goto out;
>>>> +	}
>>>> +	retval = error = 0;
>>>> +
>>>> +out:
>>>> +	if (state)
>>>> +		xfs_da_state_free(state);
>>>> +	if (error)
>>>> +		return error;
>>>> +
>>>> +	return retval;
>>>> +}
>>>> +
>>>> +
>>>> +
>>>> +/*
>>>>     * Fill in the disk block numbers in the state structure for the buffers
>>>>     * that are attached to the state structure.
>>>>     * This is done so that we can quickly reattach ourselves to those buffers
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>> index fb56d81..6203766 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>> @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-24  5:53         ` Allison Collins
@ 2019-09-24 10:05           ` Brian Foster
  2019-09-25  4:36             ` Darrick J. Wong
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-24 10:05 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Sep 23, 2019 at 10:53:42PM -0700, Allison Collins wrote:
> On 9/23/19 5:04 AM, Brian Foster wrote:
> > On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
> > > On 9/20/19 8:28 AM, Brian Foster wrote:
> > > > On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
> > > > > This patch adds new delayed attribute routines:
> > > > > 
> > > > > xfs_attr_set_later
> > > > > xfs_attr_remove_later
> > > > > xfs_leaf_addname_later
> > > > > xfs_node_addname_later
> > > > > xfs_node_removename_later
> > > > > 
> > > > > These routines are similar to their existing counter parts,
> > > > > but they do not roll or commit transactions.  They instead
> > > > > return -EAGAIN to allow the calling function to roll the
> > > > > transaction and recall the function.  This allows the
> > > > > attribute operations to be logged in multiple smaller
> > > > > transactions.
> > > > > 
> > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > ---
> > > > >    fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
> > > > >    fs/xfs/libxfs/xfs_attr.h |   2 +
> > > > >    2 files changed, 592 insertions(+), 1 deletion(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > index 781dd8a..310f5b2 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > ...
> > > > > @@ -313,6 +316,112 @@ xfs_attr_set_args(
> > > > >    }
> > > > >    /*
> > > > > + * Set 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_set_later(
> > > > > +	struct xfs_da_args	*args,
> > > > > +	struct xfs_buf          **leaf_bp)
> > > > > +{
> > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > +	int			error = 0;
> > > > > +	int			sf_size;
> > > > > +
> > > > > +	/*
> > > > > +	 * 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,
> > > > > +	 * upgrade it to a single-leaf-block attribute list.
> > > > > +	 */
> > > > > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> > > > > +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> > > > > +	     dp->i_d.di_anextents == 0)) {
> > > > > +		/*
> > > > > +		 * Build initial attribute list (if required).
> > > > > +		 */
> > > > > +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> > > > > +			xfs_attr_shortform_create(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;
> > > > > +
> > > > > +		/*
> > > > > +		 * 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);
> > > > > +		if (error)
> > > > > +			return error;
> > > > > +
> > > > > +		/*
> > > > > +		 * 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.
> > > > > +		 */
> > > > > +
> > > > > +		xfs_trans_bhold(args->trans, *leaf_bp);
> > > > > +		return -EAGAIN;
> > > > > +	}
> > > > 
> > > > I haven't actually reviewed the code in this patch yet, but rather I
> > > > skipped ahead to try and get an understanding of the design approach and
> > > > flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
> > > > of xattr code into these dfops oriented functions but instead of rolling
> > > > transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
> > > > reentrancy into the xfs_trans_attr() function.
> > > 
> > > Yes. If it helps to know a little more background about how it came into
> > > being...
> > > Initially I had started out with the code paths merged, and had a boolean
> > > switch to control the alternate behavior (much like the "roll_trans" boolean
> > > from the prior sets, if you recall them).  In a way, the boolean acted like
> > > a sort of marker of where things needed to get factored up.  The goal being
> > > to pull the boolean into the higher level routines as much as possible and
> > > leaving behind all the little helpers which is what you see now in now
> > > patches 5 - 12.
> > > 
> > > After I got done with all the refactoring, the parts that still had the
> > > boolean were a sort of hybrid of the two paths you see now.  At one point I
> > > made a judgment that continuing to factor up the boolean would be more
> > > complicated than not.  I know people disliked the boolean toggle from the
> > > prior sets.  So the *_later routines we have now are a result of the hybrid
> > > having been gutted of the boolean and split then off into its separate path.
> > > 
> > > 
> > > > 
> > > > If I'm following that correctly, I'm concerned about a couple things
> > > > with the general approach. First, I think the complexity is high and
> > > > maintainability is low/difficult for this kind of reentrant approach.
> > > 
> > > Yes.  And I did very much anticipate a similar response.  Thats certainly
> > > not to imply that I did all this for giggles, but because I think sometimes
> > > it's easy for designs to sound like good ideas in theory, until people see
> > > them in practice.  And then the design takes a different direction.  In a
> > > way I think the prototypes are a sort of necessary step for the design to
> > > evolve, even if the prototypes are sort of ugly.  :-)
> > > 
> > 
> > Yeah, tbh I suspect that anything we come up with at first is going to
> > have an ugliness factor due to the simple fact of how the code is
> > currently implemented. IMO, the right approach is to take the current
> > code apart as much as possible (without too much regard for aesthetic),
> > identify/isolate the smallest functional components required to support
> > both direct rolling and deferred operation rolling, and then from there
> > think about cleaning up the design for how to fit those pieces back
> > together.  We might be able to do that in one patch series, but I
> > wouldn't be surprised (or object to) doing it in several.
> > 
> > IOW, I think it would be reasonable to split off the effort of
> > refactoring the existing xattr code to be "deferred capable" as an
> > independent series if you didn't want to have to continue rebasing the
> > follow on deferred xattr bits and wanted to try and get more rapid
> > development+review cycles of the refactoring, but that's up to you. The
> > whole idea for the refactoring is to not change existing behavior, so I
> > don't see why that couldn't be a mergeable component on its own.
> 
> Ok, maybe I could break up the set after patch 14, and add a wrapper loop
> like the one we have in the recover routine.  That might be a good way to
> introduce some of the set in smaller pieces.
> 
> > 
> > > > The state is managed/changed all throughout the call tree and so the
> > > > risk and complexity of changing one particular bit in the sequence
> > > > requires subtle consideration to make sure it doesn't cause problems if
> > > > the function is reentered.
> > > Yes, it's still very much a state machine in practice.  But I think we may
> > > be stuck with at least some variant of state machine if we still want to
> > > adhere to the EAGAIN interface which requires the stack to back out.  I have
> > > pondered the idea of introducing a call back to cycle out the transactions
> > > mid flight so that we dont need to stop and return. This would escape the
> > > state machine concept, but may require alternate surgery to the calling log
> > > routines too.  So that may just turn into a different type of monster
> > > 
> > 
> > To be clear, I'm pretty much expecting it to continue to be a state
> > machine. That seems to be the most simple way to break things down, I
> > think. I'd rather not get into things like callbacks or whatever until
> > we've broken down the functional components and have a more clear
> > picture of things.
> > 
> > BTW, I thought one of your previous series' had a start on this in terms
> > of just defining some quick and dirty states based on an enum or
> > something and sticking them in a switch statement..? The point I'm
> > trying to make is that while those kind of simple enumerated low level
> > states are probably not where we want to leave things at the end, it
> > might be a reasonable approach to break the existing code into those
> > states and then try and polish things from there. I definitely think it
> > would be easier to review from a design perspective...
> 
> Sure, I can bring back the state switch if people prefer.  I got the
> impression that people thought it was odd, so I replaced it with the
> XFS_DC_* flags in this one.  I figured that might be a little more like what
> people are used to seeing.  IMHO I think the state switch might have been
> little cleaner in that it doesn't have to re-run over the same block of code
> multiple times to achieve the same end goal of getting back to where it was.
> If people have other opinions though please feel free to chime in.
> 

To me, it's not so much preference as it is just thinking that's the
best approach to get the code refactored and reviewed. I agree that the
state machine approach is a bit more straightforward, even if crude, due
to the elimination of the repeated function calls and flags controlling
random blocks of code. As noted previously, my hope is that once we
break things down mechanically into the crude states that exist in the
current code, we'll come up with some nice ways to continue refactoring
things, reduce the number of states required and/or maybe even think of
a way to eliminate the state machine entirely.

It's definitely worth soliciting other opinions, though, before
significantly refactoring things one way or the other..

> > 
> > > For example, I'd prefer to see something like
> > > > xfs_trans_attr() broken down into smaller granularity functions with
> > > > higher level state that is managed and readable in one place, if
> > > > possible. Perhaps we could do that based on attr fork format, but I need
> > > > to stare at the code and think about this some more (it might be that
> > > > some degree of reentrancy is inevitable, or we just need to break things
> > > > down to even smaller states...).
> > > Yes, and I did go through a phase of trying to simplify the statemachine by
> > > trying to grab onto anything about the state of the fork that could be used
> > > instead.  But its not always enough particularly in the case of routines
> > > that are in the middle of allocating or removing blocks.  If you see any
> > > other mechanics that could help out, please call them out.
> > > 
> > 
> > One of the things I'm wondering is if we'll be able to reduce the number
> > of unique (sub-)states required by reordering some of the existing logic
> > between the higher level states. For a quick example, the current series
> > uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
> > a state that can be reentered over and over. This raises the question to
> > me of whether that _ALLOC_LEAF thing could eventually just be folded
> > into the tail of the previous state.
> > 
> > To reiterate, for now I think it would be perfectly reasonable to make
> > _ALLOC_LEAF its own independent state so the flag management isn't
> > buried so deep in the xattr code...
> 
> Yes, it is one of the examples where trying to use the fork to control the
> state does not work out so well because we're in the middle of altering
> things.  So in those cases, using the state machine to give it its own state
> starts to make more sense.
> 
> > 
> > > 
> > > > 
> > > > Second, it seems like a lot of this code duplication between deferred
> > > > and non-deferred operations should be unnecessary, particularly since
> > > > the only difference between the contexts is how transactions are
> > > > managed. For example, if you follow the xattr set code path in both
> > > > contexts, we can see that functions like xfs_attr_set_args() are
> > > > basically duplicated in the xfs_attr_set_later() deferred variant just
> > > > so we can change the xfs_defer_finish() call in the former to a return
> > > > -EAGAIN in the latter.
> > > Yes, they still carry some similarities.  I guess I reasoned that continuing
> > > to carve things up into smaller and smaller helpers with out a generalized
> > > purpose (other than de-dup reduction) was starting to look a little weird,
> > > and maybe leaving things in their appropriate context might have been
> > > preferred?  Folks are welcome to chime in with opinions though.
> > > 
> > 
> > As mentioned above, I think weird is to be expected, at least if we
> > break things down into an intermediary state. That's just my .02 though.
> > Maybe others have different ideas..
> > 
> > > > 
> > > > Instead, what I think we should strive for is a common xattr mechanism
> > > > that consists of the lowest common denominator between the two contexts
> > > > (or IOW, core infrastructure that can be invoked from either context).
> > > > For example, on a kernel without deferred xattr support, could we find a
> > > > way to call the deferred variants directly and just let the
> > > > context-specific caller do the transaction rolls on -EAGAIN instead of
> > > > relying on the dfops infrastructure?
> > > I think I did that somewhere in the older parent pointer sets.  At the time,
> > > we sort of forgot that we cant completely scrap non delayed attrs (because
> > > we need them for older versions).  But then protofiles needed to create
> > > pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
> > > with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
> > > 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
> > > a sort of general purpose wrapper?
> > > 
> > > ISTM that should be possible, it
> > > > just requires further breaking down the existing/non-deferred mechanism
> > > > into smaller bits that uses the new state management logic and
> > > > implements -EAGAIN handling for when the lower level code requires a
> > > > transaction roll. At that point, deferred support should basically just
> > > > consist of the dfops and log (i.e. intents) code to plug into the associated
> > > > infrastructure. I think another side effect of that approach is that we
> > > > shouldn't need these patches that add a bunch of new xattr
> > > > infrastructure code, but rather we'd just continue refactoring the
> > > > existing code and eventually implement a new high level function that
> > > > returns -EAGAIN directly to the dfops code instead of rolling
> > > > transactions explicitly. Thoughts?
> > > Ok, I think I understand what you're trying to describe here.  Maybe take a
> > > look at xfs_attri_recover in patch 15, and let me know if that was similar
> > > to what you were thinking?
> > > 
> > 
> > Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
> > expect the direct xattr path to have to do something very similar in
> > terms of invoking the xattr state machine and handling transaction rolls
> > where the dfops mechanism isn't there to do it for us.
> > 
> > Brian
> Sure, that shouldn't be to hard to make a high level wrapper like that. Then
> we can let go of the old code path.
> 

I view it as more like reorganizing and reusing the old code path. ;)

Brian

> Thanks again for the all the reviewing!  :-)
> 
> Allison
> 
> > 
> > > Thank you for all the thorough reviewing here, I know it's a lot!
> > > Allison
> > > 
> > > > 
> > > > Brian
> > > > 
> > > > > +
> > > > > +	/*
> > > > > +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
> > > > > +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
> > > > > +	 * that it is not done yet, and need to be recalled to finish up from
> > > > > +	 * the last EAGAIN it returned
> > > > > +	 */
> > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
> > > > > +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
> > > > > +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
> > > > > +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
> > > > > +			args->dc.flags |= XFS_DC_FOUND_LBLK;
> > > > > +
> > > > > +			if (error && error != -ENOSPC)
> > > > > +				return error;
> > > > > +
> > > > > +			return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		error = xfs_leaf_addname_later(args);
> > > > > +		if (error && error != -ENOSPC)
> > > > > +			return error;
> > > > > +	} else {
> > > > > +		error = xfs_node_addname_later(args);
> > > > > +	}
> > > > > +
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +
> > > > > +/*
> > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > >     */
> > > > >    int
> > > > > @@ -362,6 +471,57 @@ xfs_attr_remove_args(
> > > > >    	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;
> > > > > +	struct xfs_buf		*bp;
> > > > > +	int			forkoff, error = 0;
> > > > > +
> > > > > +	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_remove(args);
> > > > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
> > > > > +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > +		/*
> > > > > +		 * If we fit in a block AND we are not in the middle of
> > > > > +		 * removing node blocks, remove the leaf attribute.
> > > > > +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
> > > > > +		 * signal that it is not done yet, and needs to be recalled to
> > > > > +		 * to finish up from the last -EAGAIN
> > > > > +		 */
> > > > > +		error = xfs_leaf_has_attr(args, &bp);
> > > > > +		if (error == -ENOATTR) {
> > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > +			return error;
> > > > > +		}
> > > > > +		error = 0;
> > > > > +
> > > > > +		xfs_attr3_leaf_remove(bp, args);
> > > > > +
> > > > > +		/* If the result is small enough, shrink it into the inode.*/
> > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > +		if (forkoff)
> > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > +	} else {
> > > > > +		error = xfs_node_removename_later(args);
> > > > > +	}
> > > > > +
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +
> > > > >    int
> > > > >    xfs_attr_set(
> > > > >    	struct xfs_inode	*dp,
> > > > > @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
> > > > > + *
> > > > > + * 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.
> > > > > + */
> > > > > +STATIC int
> > > > > +xfs_leaf_addname_later(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	int			error, nmap;
> > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > +	struct xfs_bmbt_irec	*map = &args->dc.map;
> > > > > +
> > > > > +	/*
> > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > +	 */
> > > > > +	if (args->rmtblkno > 0) {
> > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
> > > > > +			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));
> > > > > +
> > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > +			if (error)
> > > > > +				return error;
> > > > > +
> > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
> > > > > +		}
> > > > > +
> > > > > +		/*
> > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > +		 * required.
> > > > > +		 */
> > > > > +		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));
> > > > > +
> > > > > +			/* roll attribute extent map forwards */
> > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > +
> > > > > +			return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > +		if (error)
> > > > > +			return error;
> > > > > +	}
> > > > > +
> > > > > +	if (args->rmtblkno > 0) {
> > > > > +		/*
> > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > +		 */
> > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > +	}
> > > > > +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +/*
> > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > >     */
> > > > >    STATIC int
> > > > > @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
> > > > >    }
> > > > >    /*
> > > > > + * Remove a name from a B-tree attribute list.
> > > > > + *
> > > > > + * 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
> > > > > + * -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.
> > > > > + */
> > > > > +STATIC int
> > > > > +xfs_node_removename_later(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	struct xfs_da_state	*state = NULL;
> > > > > +	struct xfs_da_state_blk	*blk;
> > > > > +	struct xfs_buf		*bp;
> > > > > +	int			error, forkoff, retval = 0;
> > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > +	int			done = 0;
> > > > > +
> > > > > +	trace_xfs_attr_node_removename(args);
> > > > > +
> > > > > +	if (args->dc.state == NULL) {
> > > > > +		error = xfs_attr_node_hasname(args, &args->dc.state);
> > > > > +		if (error != -EEXIST)
> > > > > +			goto out;
> > > > > +		else
> > > > > +			error = 0;
> > > > > +
> > > > > +		/*
> > > > > +		 * If there is an out-of-line value, de-allocate the blocks.
> > > > > +		 * This is done before we remove the attribute so that we don't
> > > > > +		 * overflow the maximum size of a transaction and/or hit a
> > > > > +		 * deadlock.
> > > > > +		 */
> > > > > +		state = args->dc.state;
> > > > > +		args->dc.blk = &state->path.blk[state->path.active - 1];
> > > > > +		ASSERT(args->dc.blk->bp != NULL);
> > > > > +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > +	}
> > > > > +	state = args->dc.state;
> > > > > +	blk = args->dc.blk;
> > > > > +
> > > > > +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > +		bool isset;
> > > > > +
> > > > > +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +		if (!isset) {
> > > > > +			/*
> > > > > +			 * Fill in disk block numbers in the state structure
> > > > > +			 * so that we can get the buffers back after we commit
> > > > > +			 * several transactions in the following calls.
> > > > > +			 */
> > > > > +			error = xfs_attr_fillstate(state);
> > > > > +			if (error)
> > > > > +				goto out;
> > > > > +
> > > > > +			/*
> > > > > +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> > > > > +			 * remote value.
> > > > > +			 */
> > > > > +			error = xfs_attr3_leaf_setflag(args);
> > > > > +			if (error)
> > > > > +				goto out;
> > > > > +
> > > > > +			return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > +			error = xfs_attr_rmtval_invalidate(args);
> > > > > +			if (error)
> > > > > +				goto out;
> > > > > +		}
> > > > > +
> > > > > +		/*
> > > > > +		 * 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;
> > > > > +
> > > > > +			if (!done)
> > > > > +				return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +
> > > > > +		/*
> > > > > +		 * Refill the state structure with buffers, the prior calls
> > > > > +		 * released our buffers.
> > > > > +		 */
> > > > > +		error = xfs_attr_refillstate(state);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * Remove the name and update the hashvals in the tree.
> > > > > +	 */
> > > > > +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > +		blk = &state->path.blk[state->path.active - 1];
> > > > > +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > +		retval = xfs_attr3_leaf_remove(blk->bp, args);
> > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > +
> > > > > +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * Check to see if the tree needs to be collapsed.
> > > > > +	 */
> > > > > +	if (retval && (state->path.active > 1)) {
> > > > > +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > +		error = xfs_da3_join(state);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +
> > > > > +		return -EAGAIN;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * If the result is small enough, push it all into the inode.
> > > > > +	 */
> > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > > > +		/*
> > > > > +		 * Have to get rid of the copy of this dabuf in the state.
> > > > > +		 */
> > > > > +		ASSERT(state->path.active == 1);
> > > > > +		ASSERT(state->path.blk[0].bp);
> > > > > +		state->path.blk[0].bp = NULL;
> > > > > +
> > > > > +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +
> > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > +		if (forkoff) {
> > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > +			/* bp is gone due to xfs_da_shrink_inode */
> > > > > +			if (error)
> > > > > +				goto out;
> > > > > +		} else
> > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > +	}
> > > > > +out:
> > > > > +	if (state != NULL)
> > > > > +		xfs_da_state_free(state);
> > > > > +
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +/*
> > > > > + * Add a name to a Btree-format attribute list.
> > > > > + *
> > > > > + * This will involve walking down the Btree, and may involve splitting
> > > > > + * leaf nodes and even splitting intermediate nodes up to and including
> > > > > + * the root node (a special case of an intermediate node).
> > > > > + *
> > > > > + * "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
> > > > > + * -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.
> > > > > + */
> > > > > +STATIC int
> > > > > +xfs_node_addname_later(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	struct xfs_da_state	*state = NULL;
> > > > > +	struct xfs_da_state_blk	*blk;
> > > > > +	struct xfs_inode	*dp;
> > > > > +	int			retval, error = 0;
> > > > > +	int			nmap;
> > > > > +	struct xfs_bmbt_irec    *map = &args->dc.map;
> > > > > +
> > > > > +	trace_xfs_attr_node_addname(args);
> > > > > +
> > > > > +	/*
> > > > > +	 * Fill in bucket of arguments/results/context to carry around.
> > > > > +	 */
> > > > > +	dp = args->dp;
> > > > > +
> > > > > +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
> > > > > +		goto found_blk;
> > > > > +
> > > > > +	/*
> > > > > +	 * Search to see if name already exists, and get back a pointer
> > > > > +	 * to where it should go.
> > > > > +	 */
> > > > > +	retval = xfs_attr_node_hasname(args, &state);
> > > > > +	blk = &state->path.blk[state->path.active-1];
> > > > > +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > > > > +		goto out;
> > > > > +	} else if (retval == -EEXIST) {
> > > > > +		if (args->name.type & ATTR_CREATE)
> > > > > +			goto out;
> > > > > +
> > > > > +		trace_xfs_attr_node_replace(args);
> > > > > +
> > > > > +		/* save the attribute state for later removal*/
> > > > > +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
> > > > > +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> > > > > +		args->index2 = args->index;
> > > > > +		args->rmtblkno2 = args->rmtblkno;
> > > > > +		args->rmtblkcnt2 = args->rmtblkcnt;
> > > > > +		args->rmtvaluelen2 = args->rmtvaluelen;
> > > > > +
> > > > > +		/*
> > > > > +		 * clear the remote attr state now that it is saved so that the
> > > > > +		 * values reflect the state of the attribute we are about to
> > > > > +		 * add, not the attribute we just found and will remove later.
> > > > > +		 */
> > > > > +		args->rmtblkno = 0;
> > > > > +		args->rmtblkcnt = 0;
> > > > > +		args->rmtvaluelen = 0;
> > > > > +	}
> > > > > +
> > > > > +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
> > > > > +	if (retval == -ENOSPC) {
> > > > > +		if (state->path.active == 1) {
> > > > > +			/*
> > > > > +			 * Its really a single leaf node, but it had
> > > > > +			 * out-of-line values so it looked like it *might*
> > > > > +			 * have been a b-tree.
> > > > > +			 */
> > > > > +			xfs_da_state_free(state);
> > > > > +			state = NULL;
> > > > > +			error = xfs_attr3_leaf_to_node(args);
> > > > > +			if (error)
> > > > > +				goto out;
> > > > > +
> > > > > +			return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		/*
> > > > > +		 * Split as many Btree elements as required.
> > > > > +		 * This code tracks the new and old attr's location
> > > > > +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
> > > > > +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
> > > > > +		 */
> > > > > +		error = xfs_da3_split(state);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +	} else {
> > > > > +		/*
> > > > > +		 * Addition succeeded, update Btree hashvals.
> > > > > +		 */
> > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * Kill the state structure, we're done with it and need to
> > > > > +	 * allow the buffers to come back later.
> > > > > +	 */
> > > > > +	xfs_da_state_free(state);
> > > > > +	state = NULL;
> > > > > +
> > > > > +	args->dc.flags |= XFS_DC_FOUND_NBLK;
> > > > > +	return -EAGAIN;
> > > > > +found_blk:
> > > > > +
> > > > > +	/*
> > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > +	 */
> > > > > +	if (args->rmtblkno > 0) {
> > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
> > > > > +			args->dc.flags |= XFS_DC_ALLOC_NODE;
> > > > > +			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));
> > > > > +
> > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > +			if (error)
> > > > > +				return error;
> > > > > +
> > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > +		}
> > > > > +		/*
> > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > +		 * required.
> > > > > +		 */
> > > > > +		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));
> > > > > +
> > > > > +			/* roll attribute extent map forwards */
> > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > +
> > > > > +			return -EAGAIN;
> > > > > +		}
> > > > > +
> > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > +		if (error)
> > > > > +			return error;
> > > > > +	}
> > > > > +
> > > > > +	if (args->rmtblkno > 0) {
> > > > > +		/*
> > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > +		 */
> > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > +		if (error)
> > > > > +			goto out;
> > > > > +	}
> > > > > +	retval = error = 0;
> > > > > +
> > > > > +out:
> > > > > +	if (state)
> > > > > +		xfs_da_state_free(state);
> > > > > +	if (error)
> > > > > +		return error;
> > > > > +
> > > > > +	return retval;
> > > > > +}
> > > > > +
> > > > > +
> > > > > +
> > > > > +/*
> > > > >     * Fill in the disk block numbers in the state structure for the buffers
> > > > >     * that are attached to the state structure.
> > > > >     * This is done so that we can quickly reattach ourselves to those buffers
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > index fb56d81..6203766 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > > > @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-24 10:05           ` Brian Foster
@ 2019-09-25  4:36             ` Darrick J. Wong
  2019-09-25 11:53               ` Brian Foster
  0 siblings, 1 reply; 64+ messages in thread
From: Darrick J. Wong @ 2019-09-25  4:36 UTC (permalink / raw)
  To: Brian Foster; +Cc: Allison Collins, linux-xfs

On Tue, Sep 24, 2019 at 06:05:16AM -0400, Brian Foster wrote:
> On Mon, Sep 23, 2019 at 10:53:42PM -0700, Allison Collins wrote:
> > On 9/23/19 5:04 AM, Brian Foster wrote:
> > > On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
> > > > On 9/20/19 8:28 AM, Brian Foster wrote:
> > > > > On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
> > > > > > This patch adds new delayed attribute routines:
> > > > > > 
> > > > > > xfs_attr_set_later
> > > > > > xfs_attr_remove_later
> > > > > > xfs_leaf_addname_later
> > > > > > xfs_node_addname_later
> > > > > > xfs_node_removename_later
> > > > > > 
> > > > > > These routines are similar to their existing counter parts,
> > > > > > but they do not roll or commit transactions.  They instead
> > > > > > return -EAGAIN to allow the calling function to roll the
> > > > > > transaction and recall the function.  This allows the
> > > > > > attribute operations to be logged in multiple smaller
> > > > > > transactions.
> > > > > > 
> > > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > > ---
> > > > > >    fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
> > > > > >    fs/xfs/libxfs/xfs_attr.h |   2 +
> > > > > >    2 files changed, 592 insertions(+), 1 deletion(-)
> > > > > > 
> > > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > > index 781dd8a..310f5b2 100644
> > > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > > ...
> > > > > > @@ -313,6 +316,112 @@ xfs_attr_set_args(
> > > > > >    }
> > > > > >    /*
> > > > > > + * Set 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_set_later(
> > > > > > +	struct xfs_da_args	*args,
> > > > > > +	struct xfs_buf          **leaf_bp)
> > > > > > +{
> > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > +	int			error = 0;
> > > > > > +	int			sf_size;
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * 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,
> > > > > > +	 * upgrade it to a single-leaf-block attribute list.
> > > > > > +	 */
> > > > > > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> > > > > > +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> > > > > > +	     dp->i_d.di_anextents == 0)) {
> > > > > > +		/*
> > > > > > +		 * Build initial attribute list (if required).
> > > > > > +		 */
> > > > > > +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> > > > > > +			xfs_attr_shortform_create(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;
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * 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);
> > > > > > +		if (error)
> > > > > > +			return error;
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * 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.
> > > > > > +		 */
> > > > > > +
> > > > > > +		xfs_trans_bhold(args->trans, *leaf_bp);
> > > > > > +		return -EAGAIN;
> > > > > > +	}
> > > > > 
> > > > > I haven't actually reviewed the code in this patch yet, but rather I
> > > > > skipped ahead to try and get an understanding of the design approach and
> > > > > flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
> > > > > of xattr code into these dfops oriented functions but instead of rolling
> > > > > transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
> > > > > reentrancy into the xfs_trans_attr() function.
> > > > 
> > > > Yes. If it helps to know a little more background about how it came into
> > > > being...
> > > > Initially I had started out with the code paths merged, and had a boolean
> > > > switch to control the alternate behavior (much like the "roll_trans" boolean
> > > > from the prior sets, if you recall them).  In a way, the boolean acted like
> > > > a sort of marker of where things needed to get factored up.  The goal being
> > > > to pull the boolean into the higher level routines as much as possible and
> > > > leaving behind all the little helpers which is what you see now in now
> > > > patches 5 - 12.
> > > > 
> > > > After I got done with all the refactoring, the parts that still had the
> > > > boolean were a sort of hybrid of the two paths you see now.  At one point I
> > > > made a judgment that continuing to factor up the boolean would be more
> > > > complicated than not.  I know people disliked the boolean toggle from the
> > > > prior sets.  So the *_later routines we have now are a result of the hybrid
> > > > having been gutted of the boolean and split then off into its separate path.
> > > > 
> > > > 
> > > > > 
> > > > > If I'm following that correctly, I'm concerned about a couple things
> > > > > with the general approach. First, I think the complexity is high and
> > > > > maintainability is low/difficult for this kind of reentrant approach.
> > > > 
> > > > Yes.  And I did very much anticipate a similar response.  Thats certainly
> > > > not to imply that I did all this for giggles, but because I think sometimes
> > > > it's easy for designs to sound like good ideas in theory, until people see
> > > > them in practice.  And then the design takes a different direction.  In a
> > > > way I think the prototypes are a sort of necessary step for the design to
> > > > evolve, even if the prototypes are sort of ugly.  :-)
> > > > 
> > > 
> > > Yeah, tbh I suspect that anything we come up with at first is going to
> > > have an ugliness factor due to the simple fact of how the code is
> > > currently implemented. IMO, the right approach is to take the current
> > > code apart as much as possible (without too much regard for aesthetic),
> > > identify/isolate the smallest functional components required to support
> > > both direct rolling and deferred operation rolling, and then from there
> > > think about cleaning up the design for how to fit those pieces back
> > > together.  We might be able to do that in one patch series, but I
> > > wouldn't be surprised (or object to) doing it in several.
> > > 
> > > IOW, I think it would be reasonable to split off the effort of
> > > refactoring the existing xattr code to be "deferred capable" as an
> > > independent series if you didn't want to have to continue rebasing the
> > > follow on deferred xattr bits and wanted to try and get more rapid
> > > development+review cycles of the refactoring, but that's up to you. The
> > > whole idea for the refactoring is to not change existing behavior, so I
> > > don't see why that couldn't be a mergeable component on its own.
> > 
> > Ok, maybe I could break up the set after patch 14, and add a wrapper loop
> > like the one we have in the recover routine.  That might be a good way to
> > introduce some of the set in smaller pieces.
> > 
> > > 
> > > > > The state is managed/changed all throughout the call tree and so the
> > > > > risk and complexity of changing one particular bit in the sequence
> > > > > requires subtle consideration to make sure it doesn't cause problems if
> > > > > the function is reentered.
> > > > Yes, it's still very much a state machine in practice.  But I think we may
> > > > be stuck with at least some variant of state machine if we still want to
> > > > adhere to the EAGAIN interface which requires the stack to back out.  I have
> > > > pondered the idea of introducing a call back to cycle out the transactions
> > > > mid flight so that we dont need to stop and return. This would escape the
> > > > state machine concept, but may require alternate surgery to the calling log
> > > > routines too.  So that may just turn into a different type of monster
> > > > 
> > > 
> > > To be clear, I'm pretty much expecting it to continue to be a state
> > > machine. That seems to be the most simple way to break things down, I
> > > think. I'd rather not get into things like callbacks or whatever until
> > > we've broken down the functional components and have a more clear
> > > picture of things.
> > > 
> > > BTW, I thought one of your previous series' had a start on this in terms
> > > of just defining some quick and dirty states based on an enum or
> > > something and sticking them in a switch statement..? The point I'm
> > > trying to make is that while those kind of simple enumerated low level
> > > states are probably not where we want to leave things at the end, it
> > > might be a reasonable approach to break the existing code into those
> > > states and then try and polish things from there. I definitely think it
> > > would be easier to review from a design perspective...
> > 
> > Sure, I can bring back the state switch if people prefer.  I got the
> > impression that people thought it was odd, so I replaced it with the
> > XFS_DC_* flags in this one.  I figured that might be a little more like what
> > people are used to seeing.  IMHO I think the state switch might have been
> > little cleaner in that it doesn't have to re-run over the same block of code
> > multiple times to achieve the same end goal of getting back to where it was.
> > If people have other opinions though please feel free to chime in.
> > 
> 
> To me, it's not so much preference as it is just thinking that's the
> best approach to get the code refactored and reviewed. I agree that the
> state machine approach is a bit more straightforward, even if crude, due
> to the elimination of the repeated function calls and flags controlling

Hmm.  The downside of reviewing a lot of patches is that I have a hard
time remembering what I've said before.  Specifically, I don't remember
if I was the one who complained about that... :/

So right now, xfs_attr_set_args encodes the sequence of "ensure attr
fork" -> "try to add sf attr" -> "convert to leaf" -> "try to add leaf".
Maybe each of those pieces should be separate functions, and each
separate function is in charge of updating the @args with whichever
function comes next in the sequence.  With that, xfs_attr_set_args
becomes:

	while (args->nextfunc) {
		error = args->nextfunc(args);
		if (error && error != -EAGAIN)
			return error;
		xfs_trans_roll_inode(...);
	}

and then xfs_trans_attr (i.e. the deferred version) becomes:

	while (args->nextfunc) {
		args->nextfunc(args);
		/*
		 * If error == -EAGAIN, we'll end up back here with a
		 * fresh transaction.
		 */
		if (error)
			return error;
	}

Though I guess a nice property of this current version is that it does
all the checks every time, which means that at least in theory you could
drop the ILOCK between rolls.  The only reason I mention /that/ is due
to our recent discovery that while most code blocks for transaction
reservation before blocking on an ILOCK, xfs_trans_roll_inode holds the
ILOCK and can block waiting for more transaction reservation, which can
lead to trouble.

One other thing I noticed while walking through the attr code is that
xfs_da_shrink_inode calls bunmapi to remove empty blocks.  I don't know
if the deferred code does this, but it seems like it could be promising
to use the deferred bmap unmap operation instead.  Dunno.

> random blocks of code. As noted previously, my hope is that once we
> break things down mechanically into the crude states that exist in the
> current code, we'll come up with some nice ways to continue refactoring
> things, reduce the number of states required and/or maybe even think of
> a way to eliminate the state machine entirely.

(Hopefully the above was what Brian was getting at?)

--D

> It's definitely worth soliciting other opinions, though, before
> significantly refactoring things one way or the other..
> 
> > > 
> > > > For example, I'd prefer to see something like
> > > > > xfs_trans_attr() broken down into smaller granularity functions with
> > > > > higher level state that is managed and readable in one place, if
> > > > > possible. Perhaps we could do that based on attr fork format, but I need
> > > > > to stare at the code and think about this some more (it might be that
> > > > > some degree of reentrancy is inevitable, or we just need to break things
> > > > > down to even smaller states...).
> > > > Yes, and I did go through a phase of trying to simplify the statemachine by
> > > > trying to grab onto anything about the state of the fork that could be used
> > > > instead.  But its not always enough particularly in the case of routines
> > > > that are in the middle of allocating or removing blocks.  If you see any
> > > > other mechanics that could help out, please call them out.
> > > > 
> > > 
> > > One of the things I'm wondering is if we'll be able to reduce the number
> > > of unique (sub-)states required by reordering some of the existing logic
> > > between the higher level states. For a quick example, the current series
> > > uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
> > > a state that can be reentered over and over. This raises the question to
> > > me of whether that _ALLOC_LEAF thing could eventually just be folded
> > > into the tail of the previous state.
> > > 
> > > To reiterate, for now I think it would be perfectly reasonable to make
> > > _ALLOC_LEAF its own independent state so the flag management isn't
> > > buried so deep in the xattr code...
> > 
> > Yes, it is one of the examples where trying to use the fork to control the
> > state does not work out so well because we're in the middle of altering
> > things.  So in those cases, using the state machine to give it its own state
> > starts to make more sense.
> > 
> > > 
> > > > 
> > > > > 
> > > > > Second, it seems like a lot of this code duplication between deferred
> > > > > and non-deferred operations should be unnecessary, particularly since
> > > > > the only difference between the contexts is how transactions are
> > > > > managed. For example, if you follow the xattr set code path in both
> > > > > contexts, we can see that functions like xfs_attr_set_args() are
> > > > > basically duplicated in the xfs_attr_set_later() deferred variant just
> > > > > so we can change the xfs_defer_finish() call in the former to a return
> > > > > -EAGAIN in the latter.
> > > > Yes, they still carry some similarities.  I guess I reasoned that continuing
> > > > to carve things up into smaller and smaller helpers with out a generalized
> > > > purpose (other than de-dup reduction) was starting to look a little weird,
> > > > and maybe leaving things in their appropriate context might have been
> > > > preferred?  Folks are welcome to chime in with opinions though.
> > > > 
> > > 
> > > As mentioned above, I think weird is to be expected, at least if we
> > > break things down into an intermediary state. That's just my .02 though.
> > > Maybe others have different ideas..
> > > 
> > > > > 
> > > > > Instead, what I think we should strive for is a common xattr mechanism
> > > > > that consists of the lowest common denominator between the two contexts
> > > > > (or IOW, core infrastructure that can be invoked from either context).
> > > > > For example, on a kernel without deferred xattr support, could we find a
> > > > > way to call the deferred variants directly and just let the
> > > > > context-specific caller do the transaction rolls on -EAGAIN instead of
> > > > > relying on the dfops infrastructure?
> > > > I think I did that somewhere in the older parent pointer sets.  At the time,
> > > > we sort of forgot that we cant completely scrap non delayed attrs (because
> > > > we need them for older versions).  But then protofiles needed to create
> > > > pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
> > > > with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
> > > > 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
> > > > a sort of general purpose wrapper?
> > > > 
> > > > ISTM that should be possible, it
> > > > > just requires further breaking down the existing/non-deferred mechanism
> > > > > into smaller bits that uses the new state management logic and
> > > > > implements -EAGAIN handling for when the lower level code requires a
> > > > > transaction roll. At that point, deferred support should basically just
> > > > > consist of the dfops and log (i.e. intents) code to plug into the associated
> > > > > infrastructure. I think another side effect of that approach is that we
> > > > > shouldn't need these patches that add a bunch of new xattr
> > > > > infrastructure code, but rather we'd just continue refactoring the
> > > > > existing code and eventually implement a new high level function that
> > > > > returns -EAGAIN directly to the dfops code instead of rolling
> > > > > transactions explicitly. Thoughts?
> > > > Ok, I think I understand what you're trying to describe here.  Maybe take a
> > > > look at xfs_attri_recover in patch 15, and let me know if that was similar
> > > > to what you were thinking?
> > > > 
> > > 
> > > Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
> > > expect the direct xattr path to have to do something very similar in
> > > terms of invoking the xattr state machine and handling transaction rolls
> > > where the dfops mechanism isn't there to do it for us.
> > > 
> > > Brian
> > Sure, that shouldn't be to hard to make a high level wrapper like that. Then
> > we can let go of the old code path.
> > 
> 
> I view it as more like reorganizing and reusing the old code path. ;)
> 
> Brian
> 
> > Thanks again for the all the reviewing!  :-)
> > 
> > Allison
> > 
> > > 
> > > > Thank you for all the thorough reviewing here, I know it's a lot!
> > > > Allison
> > > > 
> > > > > 
> > > > > Brian
> > > > > 
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
> > > > > > +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
> > > > > > +	 * that it is not done yet, and need to be recalled to finish up from
> > > > > > +	 * the last EAGAIN it returned
> > > > > > +	 */
> > > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
> > > > > > +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
> > > > > > +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
> > > > > > +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
> > > > > > +			args->dc.flags |= XFS_DC_FOUND_LBLK;
> > > > > > +
> > > > > > +			if (error && error != -ENOSPC)
> > > > > > +				return error;
> > > > > > +
> > > > > > +			return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		error = xfs_leaf_addname_later(args);
> > > > > > +		if (error && error != -ENOSPC)
> > > > > > +			return error;
> > > > > > +	} else {
> > > > > > +		error = xfs_node_addname_later(args);
> > > > > > +	}
> > > > > > +
> > > > > > +	return error;
> > > > > > +}
> > > > > > +
> > > > > > +
> > > > > > +
> > > > > > +/*
> > > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > > >     */
> > > > > >    int
> > > > > > @@ -362,6 +471,57 @@ xfs_attr_remove_args(
> > > > > >    	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;
> > > > > > +	struct xfs_buf		*bp;
> > > > > > +	int			forkoff, error = 0;
> > > > > > +
> > > > > > +	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_remove(args);
> > > > > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
> > > > > > +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > > +		/*
> > > > > > +		 * If we fit in a block AND we are not in the middle of
> > > > > > +		 * removing node blocks, remove the leaf attribute.
> > > > > > +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
> > > > > > +		 * signal that it is not done yet, and needs to be recalled to
> > > > > > +		 * to finish up from the last -EAGAIN
> > > > > > +		 */
> > > > > > +		error = xfs_leaf_has_attr(args, &bp);
> > > > > > +		if (error == -ENOATTR) {
> > > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > > +			return error;
> > > > > > +		}
> > > > > > +		error = 0;
> > > > > > +
> > > > > > +		xfs_attr3_leaf_remove(bp, args);
> > > > > > +
> > > > > > +		/* If the result is small enough, shrink it into the inode.*/
> > > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > > +		if (forkoff)
> > > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > > +	} else {
> > > > > > +		error = xfs_node_removename_later(args);
> > > > > > +	}
> > > > > > +
> > > > > > +	return error;
> > > > > > +}
> > > > > > +
> > > > > > +
> > > > > > +
> > > > > >    int
> > > > > >    xfs_attr_set(
> > > > > >    	struct xfs_inode	*dp,
> > > > > > @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
> > > > > > + *
> > > > > > + * 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.
> > > > > > + */
> > > > > > +STATIC int
> > > > > > +xfs_leaf_addname_later(
> > > > > > +	struct xfs_da_args	*args)
> > > > > > +{
> > > > > > +	int			error, nmap;
> > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > +	struct xfs_bmbt_irec	*map = &args->dc.map;
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > > +	 */
> > > > > > +	if (args->rmtblkno > 0) {
> > > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
> > > > > > +			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));
> > > > > > +
> > > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > > +			if (error)
> > > > > > +				return error;
> > > > > > +
> > > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > > +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
> > > > > > +		}
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > > +		 * required.
> > > > > > +		 */
> > > > > > +		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));
> > > > > > +
> > > > > > +			/* roll attribute extent map forwards */
> > > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > > +
> > > > > > +			return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > > +		if (error)
> > > > > > +			return error;
> > > > > > +	}
> > > > > > +
> > > > > > +	if (args->rmtblkno > 0) {
> > > > > > +		/*
> > > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > > +		 */
> > > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > > +	}
> > > > > > +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
> > > > > > +	return error;
> > > > > > +}
> > > > > > +
> > > > > > +/*
> > > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > > >     */
> > > > > >    STATIC int
> > > > > > @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
> > > > > >    }
> > > > > >    /*
> > > > > > + * Remove a name from a B-tree attribute list.
> > > > > > + *
> > > > > > + * 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
> > > > > > + * -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.
> > > > > > + */
> > > > > > +STATIC int
> > > > > > +xfs_node_removename_later(
> > > > > > +	struct xfs_da_args	*args)
> > > > > > +{
> > > > > > +	struct xfs_da_state	*state = NULL;
> > > > > > +	struct xfs_da_state_blk	*blk;
> > > > > > +	struct xfs_buf		*bp;
> > > > > > +	int			error, forkoff, retval = 0;
> > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > +	int			done = 0;
> > > > > > +
> > > > > > +	trace_xfs_attr_node_removename(args);
> > > > > > +
> > > > > > +	if (args->dc.state == NULL) {
> > > > > > +		error = xfs_attr_node_hasname(args, &args->dc.state);
> > > > > > +		if (error != -EEXIST)
> > > > > > +			goto out;
> > > > > > +		else
> > > > > > +			error = 0;
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * If there is an out-of-line value, de-allocate the blocks.
> > > > > > +		 * This is done before we remove the attribute so that we don't
> > > > > > +		 * overflow the maximum size of a transaction and/or hit a
> > > > > > +		 * deadlock.
> > > > > > +		 */
> > > > > > +		state = args->dc.state;
> > > > > > +		args->dc.blk = &state->path.blk[state->path.active - 1];
> > > > > > +		ASSERT(args->dc.blk->bp != NULL);
> > > > > > +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > +	}
> > > > > > +	state = args->dc.state;
> > > > > > +	blk = args->dc.blk;
> > > > > > +
> > > > > > +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > > +		bool isset;
> > > > > > +
> > > > > > +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +		if (!isset) {
> > > > > > +			/*
> > > > > > +			 * Fill in disk block numbers in the state structure
> > > > > > +			 * so that we can get the buffers back after we commit
> > > > > > +			 * several transactions in the following calls.
> > > > > > +			 */
> > > > > > +			error = xfs_attr_fillstate(state);
> > > > > > +			if (error)
> > > > > > +				goto out;
> > > > > > +
> > > > > > +			/*
> > > > > > +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> > > > > > +			 * remote value.
> > > > > > +			 */
> > > > > > +			error = xfs_attr3_leaf_setflag(args);
> > > > > > +			if (error)
> > > > > > +				goto out;
> > > > > > +
> > > > > > +			return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > > +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > > +			error = xfs_attr_rmtval_invalidate(args);
> > > > > > +			if (error)
> > > > > > +				goto out;
> > > > > > +		}
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * 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;
> > > > > > +
> > > > > > +			if (!done)
> > > > > > +				return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * Refill the state structure with buffers, the prior calls
> > > > > > +		 * released our buffers.
> > > > > > +		 */
> > > > > > +		error = xfs_attr_refillstate(state);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Remove the name and update the hashvals in the tree.
> > > > > > +	 */
> > > > > > +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > > +		blk = &state->path.blk[state->path.active - 1];
> > > > > > +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > +		retval = xfs_attr3_leaf_remove(blk->bp, args);
> > > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > > +
> > > > > > +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Check to see if the tree needs to be collapsed.
> > > > > > +	 */
> > > > > > +	if (retval && (state->path.active > 1)) {
> > > > > > +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > > +		error = xfs_da3_join(state);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +
> > > > > > +		return -EAGAIN;
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * If the result is small enough, push it all into the inode.
> > > > > > +	 */
> > > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > > > > +		/*
> > > > > > +		 * Have to get rid of the copy of this dabuf in the state.
> > > > > > +		 */
> > > > > > +		ASSERT(state->path.active == 1);
> > > > > > +		ASSERT(state->path.blk[0].bp);
> > > > > > +		state->path.blk[0].bp = NULL;
> > > > > > +
> > > > > > +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +
> > > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > > +		if (forkoff) {
> > > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > > +			/* bp is gone due to xfs_da_shrink_inode */
> > > > > > +			if (error)
> > > > > > +				goto out;
> > > > > > +		} else
> > > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > > +	}
> > > > > > +out:
> > > > > > +	if (state != NULL)
> > > > > > +		xfs_da_state_free(state);
> > > > > > +
> > > > > > +	return error;
> > > > > > +}
> > > > > > +
> > > > > > +/*
> > > > > > + * Add a name to a Btree-format attribute list.
> > > > > > + *
> > > > > > + * This will involve walking down the Btree, and may involve splitting
> > > > > > + * leaf nodes and even splitting intermediate nodes up to and including
> > > > > > + * the root node (a special case of an intermediate node).
> > > > > > + *
> > > > > > + * "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
> > > > > > + * -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.
> > > > > > + */
> > > > > > +STATIC int
> > > > > > +xfs_node_addname_later(
> > > > > > +	struct xfs_da_args	*args)
> > > > > > +{
> > > > > > +	struct xfs_da_state	*state = NULL;
> > > > > > +	struct xfs_da_state_blk	*blk;
> > > > > > +	struct xfs_inode	*dp;
> > > > > > +	int			retval, error = 0;
> > > > > > +	int			nmap;
> > > > > > +	struct xfs_bmbt_irec    *map = &args->dc.map;
> > > > > > +
> > > > > > +	trace_xfs_attr_node_addname(args);
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Fill in bucket of arguments/results/context to carry around.
> > > > > > +	 */
> > > > > > +	dp = args->dp;
> > > > > > +
> > > > > > +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
> > > > > > +		goto found_blk;
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Search to see if name already exists, and get back a pointer
> > > > > > +	 * to where it should go.
> > > > > > +	 */
> > > > > > +	retval = xfs_attr_node_hasname(args, &state);
> > > > > > +	blk = &state->path.blk[state->path.active-1];
> > > > > > +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > > > > > +		goto out;
> > > > > > +	} else if (retval == -EEXIST) {
> > > > > > +		if (args->name.type & ATTR_CREATE)
> > > > > > +			goto out;
> > > > > > +
> > > > > > +		trace_xfs_attr_node_replace(args);
> > > > > > +
> > > > > > +		/* save the attribute state for later removal*/
> > > > > > +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
> > > > > > +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> > > > > > +		args->index2 = args->index;
> > > > > > +		args->rmtblkno2 = args->rmtblkno;
> > > > > > +		args->rmtblkcnt2 = args->rmtblkcnt;
> > > > > > +		args->rmtvaluelen2 = args->rmtvaluelen;
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * clear the remote attr state now that it is saved so that the
> > > > > > +		 * values reflect the state of the attribute we are about to
> > > > > > +		 * add, not the attribute we just found and will remove later.
> > > > > > +		 */
> > > > > > +		args->rmtblkno = 0;
> > > > > > +		args->rmtblkcnt = 0;
> > > > > > +		args->rmtvaluelen = 0;
> > > > > > +	}
> > > > > > +
> > > > > > +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
> > > > > > +	if (retval == -ENOSPC) {
> > > > > > +		if (state->path.active == 1) {
> > > > > > +			/*
> > > > > > +			 * Its really a single leaf node, but it had
> > > > > > +			 * out-of-line values so it looked like it *might*
> > > > > > +			 * have been a b-tree.
> > > > > > +			 */
> > > > > > +			xfs_da_state_free(state);
> > > > > > +			state = NULL;
> > > > > > +			error = xfs_attr3_leaf_to_node(args);
> > > > > > +			if (error)
> > > > > > +				goto out;
> > > > > > +
> > > > > > +			return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		/*
> > > > > > +		 * Split as many Btree elements as required.
> > > > > > +		 * This code tracks the new and old attr's location
> > > > > > +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
> > > > > > +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
> > > > > > +		 */
> > > > > > +		error = xfs_da3_split(state);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +	} else {
> > > > > > +		/*
> > > > > > +		 * Addition succeeded, update Btree hashvals.
> > > > > > +		 */
> > > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Kill the state structure, we're done with it and need to
> > > > > > +	 * allow the buffers to come back later.
> > > > > > +	 */
> > > > > > +	xfs_da_state_free(state);
> > > > > > +	state = NULL;
> > > > > > +
> > > > > > +	args->dc.flags |= XFS_DC_FOUND_NBLK;
> > > > > > +	return -EAGAIN;
> > > > > > +found_blk:
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > > +	 */
> > > > > > +	if (args->rmtblkno > 0) {
> > > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
> > > > > > +			args->dc.flags |= XFS_DC_ALLOC_NODE;
> > > > > > +			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));
> > > > > > +
> > > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > > +			if (error)
> > > > > > +				return error;
> > > > > > +
> > > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > > +		}
> > > > > > +		/*
> > > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > > +		 * required.
> > > > > > +		 */
> > > > > > +		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));
> > > > > > +
> > > > > > +			/* roll attribute extent map forwards */
> > > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > > +
> > > > > > +			return -EAGAIN;
> > > > > > +		}
> > > > > > +
> > > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > > +		if (error)
> > > > > > +			return error;
> > > > > > +	}
> > > > > > +
> > > > > > +	if (args->rmtblkno > 0) {
> > > > > > +		/*
> > > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > > +		 */
> > > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > > +		if (error)
> > > > > > +			goto out;
> > > > > > +	}
> > > > > > +	retval = error = 0;
> > > > > > +
> > > > > > +out:
> > > > > > +	if (state)
> > > > > > +		xfs_da_state_free(state);
> > > > > > +	if (error)
> > > > > > +		return error;
> > > > > > +
> > > > > > +	return retval;
> > > > > > +}
> > > > > > +
> > > > > > +
> > > > > > +
> > > > > > +/*
> > > > > >     * Fill in the disk block numbers in the state structure for the buffers
> > > > > >     * that are attached to the state structure.
> > > > > >     * This is done so that we can quickly reattach ourselves to those buffers
> > > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > > index fb56d81..6203766 100644
> > > > > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > > > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > > > > @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-25  4:36             ` Darrick J. Wong
@ 2019-09-25 11:53               ` Brian Foster
  2019-09-25 20:28                 ` Allison Collins
  0 siblings, 1 reply; 64+ messages in thread
From: Brian Foster @ 2019-09-25 11:53 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Collins, linux-xfs

On Tue, Sep 24, 2019 at 09:36:45PM -0700, Darrick J. Wong wrote:
> On Tue, Sep 24, 2019 at 06:05:16AM -0400, Brian Foster wrote:
> > On Mon, Sep 23, 2019 at 10:53:42PM -0700, Allison Collins wrote:
> > > On 9/23/19 5:04 AM, Brian Foster wrote:
> > > > On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
> > > > > On 9/20/19 8:28 AM, Brian Foster wrote:
> > > > > > On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
> > > > > > > This patch adds new delayed attribute routines:
> > > > > > > 
> > > > > > > xfs_attr_set_later
> > > > > > > xfs_attr_remove_later
> > > > > > > xfs_leaf_addname_later
> > > > > > > xfs_node_addname_later
> > > > > > > xfs_node_removename_later
> > > > > > > 
> > > > > > > These routines are similar to their existing counter parts,
> > > > > > > but they do not roll or commit transactions.  They instead
> > > > > > > return -EAGAIN to allow the calling function to roll the
> > > > > > > transaction and recall the function.  This allows the
> > > > > > > attribute operations to be logged in multiple smaller
> > > > > > > transactions.
> > > > > > > 
> > > > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > > > ---
> > > > > > >    fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
> > > > > > >    fs/xfs/libxfs/xfs_attr.h |   2 +
> > > > > > >    2 files changed, 592 insertions(+), 1 deletion(-)
> > > > > > > 
> > > > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > > > index 781dd8a..310f5b2 100644
> > > > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > > > ...
> > > > > > > @@ -313,6 +316,112 @@ xfs_attr_set_args(
> > > > > > >    }
> > > > > > >    /*
> > > > > > > + * Set 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_set_later(
> > > > > > > +	struct xfs_da_args	*args,
> > > > > > > +	struct xfs_buf          **leaf_bp)
> > > > > > > +{
> > > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > > +	int			error = 0;
> > > > > > > +	int			sf_size;
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * 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,
> > > > > > > +	 * upgrade it to a single-leaf-block attribute list.
> > > > > > > +	 */
> > > > > > > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> > > > > > > +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> > > > > > > +	     dp->i_d.di_anextents == 0)) {
> > > > > > > +		/*
> > > > > > > +		 * Build initial attribute list (if required).
> > > > > > > +		 */
> > > > > > > +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> > > > > > > +			xfs_attr_shortform_create(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;
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * 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);
> > > > > > > +		if (error)
> > > > > > > +			return error;
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * 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.
> > > > > > > +		 */
> > > > > > > +
> > > > > > > +		xfs_trans_bhold(args->trans, *leaf_bp);
> > > > > > > +		return -EAGAIN;
> > > > > > > +	}
> > > > > > 
> > > > > > I haven't actually reviewed the code in this patch yet, but rather I
> > > > > > skipped ahead to try and get an understanding of the design approach and
> > > > > > flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
> > > > > > of xattr code into these dfops oriented functions but instead of rolling
> > > > > > transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
> > > > > > reentrancy into the xfs_trans_attr() function.
> > > > > 
> > > > > Yes. If it helps to know a little more background about how it came into
> > > > > being...
> > > > > Initially I had started out with the code paths merged, and had a boolean
> > > > > switch to control the alternate behavior (much like the "roll_trans" boolean
> > > > > from the prior sets, if you recall them).  In a way, the boolean acted like
> > > > > a sort of marker of where things needed to get factored up.  The goal being
> > > > > to pull the boolean into the higher level routines as much as possible and
> > > > > leaving behind all the little helpers which is what you see now in now
> > > > > patches 5 - 12.
> > > > > 
> > > > > After I got done with all the refactoring, the parts that still had the
> > > > > boolean were a sort of hybrid of the two paths you see now.  At one point I
> > > > > made a judgment that continuing to factor up the boolean would be more
> > > > > complicated than not.  I know people disliked the boolean toggle from the
> > > > > prior sets.  So the *_later routines we have now are a result of the hybrid
> > > > > having been gutted of the boolean and split then off into its separate path.
> > > > > 
> > > > > 
> > > > > > 
> > > > > > If I'm following that correctly, I'm concerned about a couple things
> > > > > > with the general approach. First, I think the complexity is high and
> > > > > > maintainability is low/difficult for this kind of reentrant approach.
> > > > > 
> > > > > Yes.  And I did very much anticipate a similar response.  Thats certainly
> > > > > not to imply that I did all this for giggles, but because I think sometimes
> > > > > it's easy for designs to sound like good ideas in theory, until people see
> > > > > them in practice.  And then the design takes a different direction.  In a
> > > > > way I think the prototypes are a sort of necessary step for the design to
> > > > > evolve, even if the prototypes are sort of ugly.  :-)
> > > > > 
> > > > 
> > > > Yeah, tbh I suspect that anything we come up with at first is going to
> > > > have an ugliness factor due to the simple fact of how the code is
> > > > currently implemented. IMO, the right approach is to take the current
> > > > code apart as much as possible (without too much regard for aesthetic),
> > > > identify/isolate the smallest functional components required to support
> > > > both direct rolling and deferred operation rolling, and then from there
> > > > think about cleaning up the design for how to fit those pieces back
> > > > together.  We might be able to do that in one patch series, but I
> > > > wouldn't be surprised (or object to) doing it in several.
> > > > 
> > > > IOW, I think it would be reasonable to split off the effort of
> > > > refactoring the existing xattr code to be "deferred capable" as an
> > > > independent series if you didn't want to have to continue rebasing the
> > > > follow on deferred xattr bits and wanted to try and get more rapid
> > > > development+review cycles of the refactoring, but that's up to you. The
> > > > whole idea for the refactoring is to not change existing behavior, so I
> > > > don't see why that couldn't be a mergeable component on its own.
> > > 
> > > Ok, maybe I could break up the set after patch 14, and add a wrapper loop
> > > like the one we have in the recover routine.  That might be a good way to
> > > introduce some of the set in smaller pieces.
> > > 
> > > > 
> > > > > > The state is managed/changed all throughout the call tree and so the
> > > > > > risk and complexity of changing one particular bit in the sequence
> > > > > > requires subtle consideration to make sure it doesn't cause problems if
> > > > > > the function is reentered.
> > > > > Yes, it's still very much a state machine in practice.  But I think we may
> > > > > be stuck with at least some variant of state machine if we still want to
> > > > > adhere to the EAGAIN interface which requires the stack to back out.  I have
> > > > > pondered the idea of introducing a call back to cycle out the transactions
> > > > > mid flight so that we dont need to stop and return. This would escape the
> > > > > state machine concept, but may require alternate surgery to the calling log
> > > > > routines too.  So that may just turn into a different type of monster
> > > > > 
> > > > 
> > > > To be clear, I'm pretty much expecting it to continue to be a state
> > > > machine. That seems to be the most simple way to break things down, I
> > > > think. I'd rather not get into things like callbacks or whatever until
> > > > we've broken down the functional components and have a more clear
> > > > picture of things.
> > > > 
> > > > BTW, I thought one of your previous series' had a start on this in terms
> > > > of just defining some quick and dirty states based on an enum or
> > > > something and sticking them in a switch statement..? The point I'm
> > > > trying to make is that while those kind of simple enumerated low level
> > > > states are probably not where we want to leave things at the end, it
> > > > might be a reasonable approach to break the existing code into those
> > > > states and then try and polish things from there. I definitely think it
> > > > would be easier to review from a design perspective...
> > > 
> > > Sure, I can bring back the state switch if people prefer.  I got the
> > > impression that people thought it was odd, so I replaced it with the
> > > XFS_DC_* flags in this one.  I figured that might be a little more like what
> > > people are used to seeing.  IMHO I think the state switch might have been
> > > little cleaner in that it doesn't have to re-run over the same block of code
> > > multiple times to achieve the same end goal of getting back to where it was.
> > > If people have other opinions though please feel free to chime in.
> > > 
> > 
> > To me, it's not so much preference as it is just thinking that's the
> > best approach to get the code refactored and reviewed. I agree that the
> > state machine approach is a bit more straightforward, even if crude, due
> > to the elimination of the repeated function calls and flags controlling
> 
> Hmm.  The downside of reviewing a lot of patches is that I have a hard
> time remembering what I've said before.  Specifically, I don't remember
> if I was the one who complained about that... :/
> 

Heh. I don't recall complaining about it, but I've agreed that it looks
funny so who knows. In any event, it's probably best that we agree on an
approach from here so we all know what to expect and don't waste
development and review time...

> So right now, xfs_attr_set_args encodes the sequence of "ensure attr
> fork" -> "try to add sf attr" -> "convert to leaf" -> "try to add leaf".
> Maybe each of those pieces should be separate functions, and each
> separate function is in charge of updating the @args with whichever
> function comes next in the sequence.  With that, xfs_attr_set_args
> becomes:
> 
> 	while (args->nextfunc) {
> 		error = args->nextfunc(args);
> 		if (error && error != -EAGAIN)
> 			return error;
> 		xfs_trans_roll_inode(...);
> 	}
> 
> and then xfs_trans_attr (i.e. the deferred version) becomes:
> 
> 	while (args->nextfunc) {
> 		args->nextfunc(args);
> 		/*
> 		 * If error == -EAGAIN, we'll end up back here with a
> 		 * fresh transaction.
> 		 */
> 		if (error)
> 			return error;
> 	}
> 

This seems like a potential final option to me, but I still think
breaking things down into the most basic states (as one of the previous
versions sort of did with a switch statement) is the most
straightforward approach because it facilitates pure refactoring. Note
that I'm definitely not trying to make the argument that we refactor
everything as such and then be done with it, but rather that we evaluate
next direction from that point.

Next direction includes consideration of things like whether the
intermediate state is aesthetically reasonable enough to be mergeable
(so we can make some development progress and stop holding up some of
these earlier patches), whether we can combine/reorder code to reduce
states, and if/how to actually redesign the broader mechanism to
facilitate deferred operations and potentially deal with some of the
things you call out below (transaction reservation/rolling and locking,
etc). I find the current approach of trying to solve all of this at once
unwieldy simply due to the big clump of code that the xattr mechanism
happens to be. We know we have to factor out the transaction processing
for deferred operations and take this thing apart, so why not just get
that part done?

> Though I guess a nice property of this current version is that it does
> all the checks every time, which means that at least in theory you could
> drop the ILOCK between rolls.  The only reason I mention /that/ is due
> to our recent discovery that while most code blocks for transaction
> reservation before blocking on an ILOCK, xfs_trans_roll_inode holds the
> ILOCK and can block waiting for more transaction reservation, which can
> lead to trouble.
> 

Indeed, though this is a problem with the current code too, right?

> One other thing I noticed while walking through the attr code is that
> xfs_da_shrink_inode calls bunmapi to remove empty blocks.  I don't know
> if the deferred code does this, but it seems like it could be promising
> to use the deferred bmap unmap operation instead.  Dunno.
> 

Another potential cleanup to consider. ;)

> > random blocks of code. As noted previously, my hope is that once we
> > break things down mechanically into the crude states that exist in the
> > current code, we'll come up with some nice ways to continue refactoring
> > things, reduce the number of states required and/or maybe even think of
> > a way to eliminate the state machine entirely.
> 
> (Hopefully the above was what Brian was getting at?)
> 

It's definitely along the lines of what I was hoping for as a final
result. I'm just arguing for a more deliberate approach to get to that
point:

1.) Refactor existing code to lift out transaction processing using as
simple and unclever programming constructs as possible (i.e., switch
statements) and no functional changes.
2.) Simplify/refine what falls out from that as appropriate.
3.) Rework into a legitimate design (perhaps like what you propose above
with function pointers).
4.) Plumb in deferred/intent item infrastructure such that the same
xattr mechanism is used for direct and deferred xattrs.
5.) Profit.

Thoughts?

Brian

> --D
> 
> > It's definitely worth soliciting other opinions, though, before
> > significantly refactoring things one way or the other..
> > 
> > > > 
> > > > > For example, I'd prefer to see something like
> > > > > > xfs_trans_attr() broken down into smaller granularity functions with
> > > > > > higher level state that is managed and readable in one place, if
> > > > > > possible. Perhaps we could do that based on attr fork format, but I need
> > > > > > to stare at the code and think about this some more (it might be that
> > > > > > some degree of reentrancy is inevitable, or we just need to break things
> > > > > > down to even smaller states...).
> > > > > Yes, and I did go through a phase of trying to simplify the statemachine by
> > > > > trying to grab onto anything about the state of the fork that could be used
> > > > > instead.  But its not always enough particularly in the case of routines
> > > > > that are in the middle of allocating or removing blocks.  If you see any
> > > > > other mechanics that could help out, please call them out.
> > > > > 
> > > > 
> > > > One of the things I'm wondering is if we'll be able to reduce the number
> > > > of unique (sub-)states required by reordering some of the existing logic
> > > > between the higher level states. For a quick example, the current series
> > > > uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
> > > > a state that can be reentered over and over. This raises the question to
> > > > me of whether that _ALLOC_LEAF thing could eventually just be folded
> > > > into the tail of the previous state.
> > > > 
> > > > To reiterate, for now I think it would be perfectly reasonable to make
> > > > _ALLOC_LEAF its own independent state so the flag management isn't
> > > > buried so deep in the xattr code...
> > > 
> > > Yes, it is one of the examples where trying to use the fork to control the
> > > state does not work out so well because we're in the middle of altering
> > > things.  So in those cases, using the state machine to give it its own state
> > > starts to make more sense.
> > > 
> > > > 
> > > > > 
> > > > > > 
> > > > > > Second, it seems like a lot of this code duplication between deferred
> > > > > > and non-deferred operations should be unnecessary, particularly since
> > > > > > the only difference between the contexts is how transactions are
> > > > > > managed. For example, if you follow the xattr set code path in both
> > > > > > contexts, we can see that functions like xfs_attr_set_args() are
> > > > > > basically duplicated in the xfs_attr_set_later() deferred variant just
> > > > > > so we can change the xfs_defer_finish() call in the former to a return
> > > > > > -EAGAIN in the latter.
> > > > > Yes, they still carry some similarities.  I guess I reasoned that continuing
> > > > > to carve things up into smaller and smaller helpers with out a generalized
> > > > > purpose (other than de-dup reduction) was starting to look a little weird,
> > > > > and maybe leaving things in their appropriate context might have been
> > > > > preferred?  Folks are welcome to chime in with opinions though.
> > > > > 
> > > > 
> > > > As mentioned above, I think weird is to be expected, at least if we
> > > > break things down into an intermediary state. That's just my .02 though.
> > > > Maybe others have different ideas..
> > > > 
> > > > > > 
> > > > > > Instead, what I think we should strive for is a common xattr mechanism
> > > > > > that consists of the lowest common denominator between the two contexts
> > > > > > (or IOW, core infrastructure that can be invoked from either context).
> > > > > > For example, on a kernel without deferred xattr support, could we find a
> > > > > > way to call the deferred variants directly and just let the
> > > > > > context-specific caller do the transaction rolls on -EAGAIN instead of
> > > > > > relying on the dfops infrastructure?
> > > > > I think I did that somewhere in the older parent pointer sets.  At the time,
> > > > > we sort of forgot that we cant completely scrap non delayed attrs (because
> > > > > we need them for older versions).  But then protofiles needed to create
> > > > > pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
> > > > > with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
> > > > > 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
> > > > > a sort of general purpose wrapper?
> > > > > 
> > > > > ISTM that should be possible, it
> > > > > > just requires further breaking down the existing/non-deferred mechanism
> > > > > > into smaller bits that uses the new state management logic and
> > > > > > implements -EAGAIN handling for when the lower level code requires a
> > > > > > transaction roll. At that point, deferred support should basically just
> > > > > > consist of the dfops and log (i.e. intents) code to plug into the associated
> > > > > > infrastructure. I think another side effect of that approach is that we
> > > > > > shouldn't need these patches that add a bunch of new xattr
> > > > > > infrastructure code, but rather we'd just continue refactoring the
> > > > > > existing code and eventually implement a new high level function that
> > > > > > returns -EAGAIN directly to the dfops code instead of rolling
> > > > > > transactions explicitly. Thoughts?
> > > > > Ok, I think I understand what you're trying to describe here.  Maybe take a
> > > > > look at xfs_attri_recover in patch 15, and let me know if that was similar
> > > > > to what you were thinking?
> > > > > 
> > > > 
> > > > Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
> > > > expect the direct xattr path to have to do something very similar in
> > > > terms of invoking the xattr state machine and handling transaction rolls
> > > > where the dfops mechanism isn't there to do it for us.
> > > > 
> > > > Brian
> > > Sure, that shouldn't be to hard to make a high level wrapper like that. Then
> > > we can let go of the old code path.
> > > 
> > 
> > I view it as more like reorganizing and reusing the old code path. ;)
> > 
> > Brian
> > 
> > > Thanks again for the all the reviewing!  :-)
> > > 
> > > Allison
> > > 
> > > > 
> > > > > Thank you for all the thorough reviewing here, I know it's a lot!
> > > > > Allison
> > > > > 
> > > > > > 
> > > > > > Brian
> > > > > > 
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
> > > > > > > +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
> > > > > > > +	 * that it is not done yet, and need to be recalled to finish up from
> > > > > > > +	 * the last EAGAIN it returned
> > > > > > > +	 */
> > > > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
> > > > > > > +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
> > > > > > > +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
> > > > > > > +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
> > > > > > > +			args->dc.flags |= XFS_DC_FOUND_LBLK;
> > > > > > > +
> > > > > > > +			if (error && error != -ENOSPC)
> > > > > > > +				return error;
> > > > > > > +
> > > > > > > +			return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		error = xfs_leaf_addname_later(args);
> > > > > > > +		if (error && error != -ENOSPC)
> > > > > > > +			return error;
> > > > > > > +	} else {
> > > > > > > +		error = xfs_node_addname_later(args);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	return error;
> > > > > > > +}
> > > > > > > +
> > > > > > > +
> > > > > > > +
> > > > > > > +/*
> > > > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > > > >     */
> > > > > > >    int
> > > > > > > @@ -362,6 +471,57 @@ xfs_attr_remove_args(
> > > > > > >    	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;
> > > > > > > +	struct xfs_buf		*bp;
> > > > > > > +	int			forkoff, error = 0;
> > > > > > > +
> > > > > > > +	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_remove(args);
> > > > > > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
> > > > > > > +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > > > +		/*
> > > > > > > +		 * If we fit in a block AND we are not in the middle of
> > > > > > > +		 * removing node blocks, remove the leaf attribute.
> > > > > > > +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
> > > > > > > +		 * signal that it is not done yet, and needs to be recalled to
> > > > > > > +		 * to finish up from the last -EAGAIN
> > > > > > > +		 */
> > > > > > > +		error = xfs_leaf_has_attr(args, &bp);
> > > > > > > +		if (error == -ENOATTR) {
> > > > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > > > +			return error;
> > > > > > > +		}
> > > > > > > +		error = 0;
> > > > > > > +
> > > > > > > +		xfs_attr3_leaf_remove(bp, args);
> > > > > > > +
> > > > > > > +		/* If the result is small enough, shrink it into the inode.*/
> > > > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > > > +		if (forkoff)
> > > > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > > > +	} else {
> > > > > > > +		error = xfs_node_removename_later(args);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	return error;
> > > > > > > +}
> > > > > > > +
> > > > > > > +
> > > > > > > +
> > > > > > >    int
> > > > > > >    xfs_attr_set(
> > > > > > >    	struct xfs_inode	*dp,
> > > > > > > @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
> > > > > > > + *
> > > > > > > + * 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.
> > > > > > > + */
> > > > > > > +STATIC int
> > > > > > > +xfs_leaf_addname_later(
> > > > > > > +	struct xfs_da_args	*args)
> > > > > > > +{
> > > > > > > +	int			error, nmap;
> > > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > > +	struct xfs_bmbt_irec	*map = &args->dc.map;
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > > > +	 */
> > > > > > > +	if (args->rmtblkno > 0) {
> > > > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
> > > > > > > +			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));
> > > > > > > +
> > > > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > > > +			if (error)
> > > > > > > +				return error;
> > > > > > > +
> > > > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > > > +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > > > +		 * required.
> > > > > > > +		 */
> > > > > > > +		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));
> > > > > > > +
> > > > > > > +			/* roll attribute extent map forwards */
> > > > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > > > +
> > > > > > > +			return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > > > +		if (error)
> > > > > > > +			return error;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if (args->rmtblkno > 0) {
> > > > > > > +		/*
> > > > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > > > +		 */
> > > > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > > > +	}
> > > > > > > +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
> > > > > > > +	return error;
> > > > > > > +}
> > > > > > > +
> > > > > > > +/*
> > > > > > >     * Return EEXIST if attr is found, or ENOATTR if not
> > > > > > >     */
> > > > > > >    STATIC int
> > > > > > > @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
> > > > > > >    }
> > > > > > >    /*
> > > > > > > + * Remove a name from a B-tree attribute list.
> > > > > > > + *
> > > > > > > + * 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
> > > > > > > + * -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.
> > > > > > > + */
> > > > > > > +STATIC int
> > > > > > > +xfs_node_removename_later(
> > > > > > > +	struct xfs_da_args	*args)
> > > > > > > +{
> > > > > > > +	struct xfs_da_state	*state = NULL;
> > > > > > > +	struct xfs_da_state_blk	*blk;
> > > > > > > +	struct xfs_buf		*bp;
> > > > > > > +	int			error, forkoff, retval = 0;
> > > > > > > +	struct xfs_inode	*dp = args->dp;
> > > > > > > +	int			done = 0;
> > > > > > > +
> > > > > > > +	trace_xfs_attr_node_removename(args);
> > > > > > > +
> > > > > > > +	if (args->dc.state == NULL) {
> > > > > > > +		error = xfs_attr_node_hasname(args, &args->dc.state);
> > > > > > > +		if (error != -EEXIST)
> > > > > > > +			goto out;
> > > > > > > +		else
> > > > > > > +			error = 0;
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * If there is an out-of-line value, de-allocate the blocks.
> > > > > > > +		 * This is done before we remove the attribute so that we don't
> > > > > > > +		 * overflow the maximum size of a transaction and/or hit a
> > > > > > > +		 * deadlock.
> > > > > > > +		 */
> > > > > > > +		state = args->dc.state;
> > > > > > > +		args->dc.blk = &state->path.blk[state->path.active - 1];
> > > > > > > +		ASSERT(args->dc.blk->bp != NULL);
> > > > > > > +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > > +	}
> > > > > > > +	state = args->dc.state;
> > > > > > > +	blk = args->dc.blk;
> > > > > > > +
> > > > > > > +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > > > +		bool isset;
> > > > > > > +
> > > > > > > +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +		if (!isset) {
> > > > > > > +			/*
> > > > > > > +			 * Fill in disk block numbers in the state structure
> > > > > > > +			 * so that we can get the buffers back after we commit
> > > > > > > +			 * several transactions in the following calls.
> > > > > > > +			 */
> > > > > > > +			error = xfs_attr_fillstate(state);
> > > > > > > +			if (error)
> > > > > > > +				goto out;
> > > > > > > +
> > > > > > > +			/*
> > > > > > > +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> > > > > > > +			 * remote value.
> > > > > > > +			 */
> > > > > > > +			error = xfs_attr3_leaf_setflag(args);
> > > > > > > +			if (error)
> > > > > > > +				goto out;
> > > > > > > +
> > > > > > > +			return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> > > > > > > +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > > > +			error = xfs_attr_rmtval_invalidate(args);
> > > > > > > +			if (error)
> > > > > > > +				goto out;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * 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;
> > > > > > > +
> > > > > > > +			if (!done)
> > > > > > > +				return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * Refill the state structure with buffers, the prior calls
> > > > > > > +		 * released our buffers.
> > > > > > > +		 */
> > > > > > > +		error = xfs_attr_refillstate(state);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Remove the name and update the hashvals in the tree.
> > > > > > > +	 */
> > > > > > > +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> > > > > > > +		blk = &state->path.blk[state->path.active - 1];
> > > > > > > +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > > +		retval = xfs_attr3_leaf_remove(blk->bp, args);
> > > > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > > > +
> > > > > > > +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Check to see if the tree needs to be collapsed.
> > > > > > > +	 */
> > > > > > > +	if (retval && (state->path.active > 1)) {
> > > > > > > +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> > > > > > > +		error = xfs_da3_join(state);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +
> > > > > > > +		return -EAGAIN;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * If the result is small enough, push it all into the inode.
> > > > > > > +	 */
> > > > > > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > > > > > +		/*
> > > > > > > +		 * Have to get rid of the copy of this dabuf in the state.
> > > > > > > +		 */
> > > > > > > +		ASSERT(state->path.active == 1);
> > > > > > > +		ASSERT(state->path.blk[0].bp);
> > > > > > > +		state->path.blk[0].bp = NULL;
> > > > > > > +
> > > > > > > +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +
> > > > > > > +		forkoff = xfs_attr_shortform_allfit(bp, dp);
> > > > > > > +		if (forkoff) {
> > > > > > > +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> > > > > > > +			/* bp is gone due to xfs_da_shrink_inode */
> > > > > > > +			if (error)
> > > > > > > +				goto out;
> > > > > > > +		} else
> > > > > > > +			xfs_trans_brelse(args->trans, bp);
> > > > > > > +	}
> > > > > > > +out:
> > > > > > > +	if (state != NULL)
> > > > > > > +		xfs_da_state_free(state);
> > > > > > > +
> > > > > > > +	return error;
> > > > > > > +}
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * Add a name to a Btree-format attribute list.
> > > > > > > + *
> > > > > > > + * This will involve walking down the Btree, and may involve splitting
> > > > > > > + * leaf nodes and even splitting intermediate nodes up to and including
> > > > > > > + * the root node (a special case of an intermediate node).
> > > > > > > + *
> > > > > > > + * "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
> > > > > > > + * -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.
> > > > > > > + */
> > > > > > > +STATIC int
> > > > > > > +xfs_node_addname_later(
> > > > > > > +	struct xfs_da_args	*args)
> > > > > > > +{
> > > > > > > +	struct xfs_da_state	*state = NULL;
> > > > > > > +	struct xfs_da_state_blk	*blk;
> > > > > > > +	struct xfs_inode	*dp;
> > > > > > > +	int			retval, error = 0;
> > > > > > > +	int			nmap;
> > > > > > > +	struct xfs_bmbt_irec    *map = &args->dc.map;
> > > > > > > +
> > > > > > > +	trace_xfs_attr_node_addname(args);
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Fill in bucket of arguments/results/context to carry around.
> > > > > > > +	 */
> > > > > > > +	dp = args->dp;
> > > > > > > +
> > > > > > > +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
> > > > > > > +		goto found_blk;
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Search to see if name already exists, and get back a pointer
> > > > > > > +	 * to where it should go.
> > > > > > > +	 */
> > > > > > > +	retval = xfs_attr_node_hasname(args, &state);
> > > > > > > +	blk = &state->path.blk[state->path.active-1];
> > > > > > > +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > > > +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > > > > > > +		goto out;
> > > > > > > +	} else if (retval == -EEXIST) {
> > > > > > > +		if (args->name.type & ATTR_CREATE)
> > > > > > > +			goto out;
> > > > > > > +
> > > > > > > +		trace_xfs_attr_node_replace(args);
> > > > > > > +
> > > > > > > +		/* save the attribute state for later removal*/
> > > > > > > +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
> > > > > > > +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> > > > > > > +		args->index2 = args->index;
> > > > > > > +		args->rmtblkno2 = args->rmtblkno;
> > > > > > > +		args->rmtblkcnt2 = args->rmtblkcnt;
> > > > > > > +		args->rmtvaluelen2 = args->rmtvaluelen;
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * clear the remote attr state now that it is saved so that the
> > > > > > > +		 * values reflect the state of the attribute we are about to
> > > > > > > +		 * add, not the attribute we just found and will remove later.
> > > > > > > +		 */
> > > > > > > +		args->rmtblkno = 0;
> > > > > > > +		args->rmtblkcnt = 0;
> > > > > > > +		args->rmtvaluelen = 0;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
> > > > > > > +	if (retval == -ENOSPC) {
> > > > > > > +		if (state->path.active == 1) {
> > > > > > > +			/*
> > > > > > > +			 * Its really a single leaf node, but it had
> > > > > > > +			 * out-of-line values so it looked like it *might*
> > > > > > > +			 * have been a b-tree.
> > > > > > > +			 */
> > > > > > > +			xfs_da_state_free(state);
> > > > > > > +			state = NULL;
> > > > > > > +			error = xfs_attr3_leaf_to_node(args);
> > > > > > > +			if (error)
> > > > > > > +				goto out;
> > > > > > > +
> > > > > > > +			return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		/*
> > > > > > > +		 * Split as many Btree elements as required.
> > > > > > > +		 * This code tracks the new and old attr's location
> > > > > > > +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
> > > > > > > +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
> > > > > > > +		 */
> > > > > > > +		error = xfs_da3_split(state);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +	} else {
> > > > > > > +		/*
> > > > > > > +		 * Addition succeeded, update Btree hashvals.
> > > > > > > +		 */
> > > > > > > +		xfs_da3_fixhashpath(state, &state->path);
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Kill the state structure, we're done with it and need to
> > > > > > > +	 * allow the buffers to come back later.
> > > > > > > +	 */
> > > > > > > +	xfs_da_state_free(state);
> > > > > > > +	state = NULL;
> > > > > > > +
> > > > > > > +	args->dc.flags |= XFS_DC_FOUND_NBLK;
> > > > > > > +	return -EAGAIN;
> > > > > > > +found_blk:
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * If there was an out-of-line value, allocate the blocks we
> > > > > > > +	 * identified for its storage and copy the value.  This is done
> > > > > > > +	 * after we create the attribute so that we don't overflow the
> > > > > > > +	 * maximum size of a transaction and/or hit a deadlock.
> > > > > > > +	 */
> > > > > > > +	if (args->rmtblkno > 0) {
> > > > > > > +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
> > > > > > > +			args->dc.flags |= XFS_DC_ALLOC_NODE;
> > > > > > > +			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));
> > > > > > > +
> > > > > > > +			error = xfs_attr_rmt_find_hole(args);
> > > > > > > +			if (error)
> > > > > > > +				return error;
> > > > > > > +
> > > > > > > +			args->dc.blkcnt = args->rmtblkcnt;
> > > > > > > +			args->dc.lblkno = args->rmtblkno;
> > > > > > > +		}
> > > > > > > +		/*
> > > > > > > +		 * Roll through the "value", allocating blocks on disk as
> > > > > > > +		 * required.
> > > > > > > +		 */
> > > > > > > +		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));
> > > > > > > +
> > > > > > > +			/* roll attribute extent map forwards */
> > > > > > > +			args->dc.lblkno += map->br_blockcount;
> > > > > > > +			args->dc.blkcnt -= map->br_blockcount;
> > > > > > > +
> > > > > > > +			return -EAGAIN;
> > > > > > > +		}
> > > > > > > +
> > > > > > > +		error = xfs_attr_rmtval_set_value(args);
> > > > > > > +		if (error)
> > > > > > > +			return error;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	if (args->rmtblkno > 0) {
> > > > > > > +		/*
> > > > > > > +		 * Added a "remote" value, just clear the incomplete flag.
> > > > > > > +		 */
> > > > > > > +		error = xfs_attr3_leaf_clearflag(args);
> > > > > > > +		if (error)
> > > > > > > +			goto out;
> > > > > > > +	}
> > > > > > > +	retval = error = 0;
> > > > > > > +
> > > > > > > +out:
> > > > > > > +	if (state)
> > > > > > > +		xfs_da_state_free(state);
> > > > > > > +	if (error)
> > > > > > > +		return error;
> > > > > > > +
> > > > > > > +	return retval;
> > > > > > > +}
> > > > > > > +
> > > > > > > +
> > > > > > > +
> > > > > > > +/*
> > > > > > >     * Fill in the disk block numbers in the state structure for the buffers
> > > > > > >     * that are attached to the state structure.
> > > > > > >     * This is done so that we can quickly reattach ourselves to those buffers
> > > > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > > > index fb56d81..6203766 100644
> > > > > > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > > > > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > > > > > @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

* Re: [PATCH v3 14/19] xfs: Add delayed attribute routines
  2019-09-25 11:53               ` Brian Foster
@ 2019-09-25 20:28                 ` Allison Collins
  0 siblings, 0 replies; 64+ messages in thread
From: Allison Collins @ 2019-09-25 20:28 UTC (permalink / raw)
  To: Brian Foster, Darrick J. Wong; +Cc: linux-xfs



On 9/25/19 4:53 AM, Brian Foster wrote:
> On Tue, Sep 24, 2019 at 09:36:45PM -0700, Darrick J. Wong wrote:
>> On Tue, Sep 24, 2019 at 06:05:16AM -0400, Brian Foster wrote:
>>> On Mon, Sep 23, 2019 at 10:53:42PM -0700, Allison Collins wrote:
>>>> On 9/23/19 5:04 AM, Brian Foster wrote:
>>>>> On Fri, Sep 20, 2019 at 12:12:51PM -0700, Allison Collins wrote:
>>>>>> On 9/20/19 8:28 AM, Brian Foster wrote:
>>>>>>> On Thu, Sep 05, 2019 at 03:18:32PM -0700, Allison Collins wrote:
>>>>>>>> This patch adds new delayed attribute routines:
>>>>>>>>
>>>>>>>> xfs_attr_set_later
>>>>>>>> xfs_attr_remove_later
>>>>>>>> xfs_leaf_addname_later
>>>>>>>> xfs_node_addname_later
>>>>>>>> xfs_node_removename_later
>>>>>>>>
>>>>>>>> These routines are similar to their existing counter parts,
>>>>>>>> but they do not roll or commit transactions.  They instead
>>>>>>>> return -EAGAIN to allow the calling function to roll the
>>>>>>>> transaction and recall the function.  This allows the
>>>>>>>> attribute operations to be logged in multiple smaller
>>>>>>>> transactions.
>>>>>>>>
>>>>>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>>>>>> ---
>>>>>>>>     fs/xfs/libxfs/xfs_attr.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>>>>     fs/xfs/libxfs/xfs_attr.h |   2 +
>>>>>>>>     2 files changed, 592 insertions(+), 1 deletion(-)
>>>>>>>>
>>>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>>>>>> index 781dd8a..310f5b2 100644
>>>>>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>>>>> ...
>>>>>>>> @@ -313,6 +316,112 @@ xfs_attr_set_args(
>>>>>>>>     }
>>>>>>>>     /*
>>>>>>>> + * Set 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_set_later(
>>>>>>>> +	struct xfs_da_args	*args,
>>>>>>>> +	struct xfs_buf          **leaf_bp)
>>>>>>>> +{
>>>>>>>> +	struct xfs_inode	*dp = args->dp;
>>>>>>>> +	int			error = 0;
>>>>>>>> +	int			sf_size;
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * 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,
>>>>>>>> +	 * upgrade it to a single-leaf-block attribute list.
>>>>>>>> +	 */
>>>>>>>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>>>>>>>> +	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>>>>>>>> +	     dp->i_d.di_anextents == 0)) {
>>>>>>>> +		/*
>>>>>>>> +		 * Build initial attribute list (if required).
>>>>>>>> +		 */
>>>>>>>> +		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>>>>>>>> +			xfs_attr_shortform_create(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;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * 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);
>>>>>>>> +		if (error)
>>>>>>>> +			return error;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * 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.
>>>>>>>> +		 */
>>>>>>>> +
>>>>>>>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>>>>>>>> +		return -EAGAIN;
>>>>>>>> +	}
>>>>>>>
>>>>>>> I haven't actually reviewed the code in this patch yet, but rather I
>>>>>>> skipped ahead to try and get an understanding of the design approach and
>>>>>>> flow of a deferred xattr operation. IIUC, we basically duplicate a bunch
>>>>>>> of xattr code into these dfops oriented functions but instead of rolling
>>>>>>> transactions, return -EAGAIN and use the XFS_DC_ state flags to manage
>>>>>>> reentrancy into the xfs_trans_attr() function.
>>>>>>
>>>>>> Yes. If it helps to know a little more background about how it came into
>>>>>> being...
>>>>>> Initially I had started out with the code paths merged, and had a boolean
>>>>>> switch to control the alternate behavior (much like the "roll_trans" boolean
>>>>>> from the prior sets, if you recall them).  In a way, the boolean acted like
>>>>>> a sort of marker of where things needed to get factored up.  The goal being
>>>>>> to pull the boolean into the higher level routines as much as possible and
>>>>>> leaving behind all the little helpers which is what you see now in now
>>>>>> patches 5 - 12.
>>>>>>
>>>>>> After I got done with all the refactoring, the parts that still had the
>>>>>> boolean were a sort of hybrid of the two paths you see now.  At one point I
>>>>>> made a judgment that continuing to factor up the boolean would be more
>>>>>> complicated than not.  I know people disliked the boolean toggle from the
>>>>>> prior sets.  So the *_later routines we have now are a result of the hybrid
>>>>>> having been gutted of the boolean and split then off into its separate path.
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> If I'm following that correctly, I'm concerned about a couple things
>>>>>>> with the general approach. First, I think the complexity is high and
>>>>>>> maintainability is low/difficult for this kind of reentrant approach.
>>>>>>
>>>>>> Yes.  And I did very much anticipate a similar response.  Thats certainly
>>>>>> not to imply that I did all this for giggles, but because I think sometimes
>>>>>> it's easy for designs to sound like good ideas in theory, until people see
>>>>>> them in practice.  And then the design takes a different direction.  In a
>>>>>> way I think the prototypes are a sort of necessary step for the design to
>>>>>> evolve, even if the prototypes are sort of ugly.  :-)
>>>>>>
>>>>>
>>>>> Yeah, tbh I suspect that anything we come up with at first is going to
>>>>> have an ugliness factor due to the simple fact of how the code is
>>>>> currently implemented. IMO, the right approach is to take the current
>>>>> code apart as much as possible (without too much regard for aesthetic),
>>>>> identify/isolate the smallest functional components required to support
>>>>> both direct rolling and deferred operation rolling, and then from there
>>>>> think about cleaning up the design for how to fit those pieces back
>>>>> together.  We might be able to do that in one patch series, but I
>>>>> wouldn't be surprised (or object to) doing it in several.
>>>>>
>>>>> IOW, I think it would be reasonable to split off the effort of
>>>>> refactoring the existing xattr code to be "deferred capable" as an
>>>>> independent series if you didn't want to have to continue rebasing the
>>>>> follow on deferred xattr bits and wanted to try and get more rapid
>>>>> development+review cycles of the refactoring, but that's up to you. The
>>>>> whole idea for the refactoring is to not change existing behavior, so I
>>>>> don't see why that couldn't be a mergeable component on its own.
>>>>
>>>> Ok, maybe I could break up the set after patch 14, and add a wrapper loop
>>>> like the one we have in the recover routine.  That might be a good way to
>>>> introduce some of the set in smaller pieces.
>>>>
>>>>>
>>>>>>> The state is managed/changed all throughout the call tree and so the
>>>>>>> risk and complexity of changing one particular bit in the sequence
>>>>>>> requires subtle consideration to make sure it doesn't cause problems if
>>>>>>> the function is reentered.
>>>>>> Yes, it's still very much a state machine in practice.  But I think we may
>>>>>> be stuck with at least some variant of state machine if we still want to
>>>>>> adhere to the EAGAIN interface which requires the stack to back out.  I have
>>>>>> pondered the idea of introducing a call back to cycle out the transactions
>>>>>> mid flight so that we dont need to stop and return. This would escape the
>>>>>> state machine concept, but may require alternate surgery to the calling log
>>>>>> routines too.  So that may just turn into a different type of monster
>>>>>>
>>>>>
>>>>> To be clear, I'm pretty much expecting it to continue to be a state
>>>>> machine. That seems to be the most simple way to break things down, I
>>>>> think. I'd rather not get into things like callbacks or whatever until
>>>>> we've broken down the functional components and have a more clear
>>>>> picture of things.
>>>>>
>>>>> BTW, I thought one of your previous series' had a start on this in terms
>>>>> of just defining some quick and dirty states based on an enum or
>>>>> something and sticking them in a switch statement..? The point I'm
>>>>> trying to make is that while those kind of simple enumerated low level
>>>>> states are probably not where we want to leave things at the end, it
>>>>> might be a reasonable approach to break the existing code into those
>>>>> states and then try and polish things from there. I definitely think it
>>>>> would be easier to review from a design perspective...
>>>>
>>>> Sure, I can bring back the state switch if people prefer.  I got the
>>>> impression that people thought it was odd, so I replaced it with the
>>>> XFS_DC_* flags in this one.  I figured that might be a little more like what
>>>> people are used to seeing.  IMHO I think the state switch might have been
>>>> little cleaner in that it doesn't have to re-run over the same block of code
>>>> multiple times to achieve the same end goal of getting back to where it was.
>>>> If people have other opinions though please feel free to chime in.
>>>>
>>>
>>> To me, it's not so much preference as it is just thinking that's the
>>> best approach to get the code refactored and reviewed. I agree that the
>>> state machine approach is a bit more straightforward, even if crude, due
>>> to the elimination of the repeated function calls and flags controlling
>>
>> Hmm.  The downside of reviewing a lot of patches is that I have a hard
>> time remembering what I've said before.  Specifically, I don't remember
>> if I was the one who complained about that... :/
>>
> 
> Heh. I don't recall complaining about it, but I've agreed that it looks
> funny so who knows. In any event, it's probably best that we agree on an
> approach from here so we all know what to expect and don't waste
> development and review time...
> 
>> So right now, xfs_attr_set_args encodes the sequence of "ensure attr
>> fork" -> "try to add sf attr" -> "convert to leaf" -> "try to add leaf".
>> Maybe each of those pieces should be separate functions, and each
>> separate function is in charge of updating the @args with whichever
>> function comes next in the sequence.  With that, xfs_attr_set_args
>> becomes:
>>
>> 	while (args->nextfunc) {
>> 		error = args->nextfunc(args);
>> 		if (error && error != -EAGAIN)
>> 			return error;
>> 		xfs_trans_roll_inode(...);
>> 	}
>>
>> and then xfs_trans_attr (i.e. the deferred version) becomes:
>>
>> 	while (args->nextfunc) {
>> 		args->nextfunc(args);
>> 		/*
>> 		 * If error == -EAGAIN, we'll end up back here with a
>> 		 * fresh transaction.
>> 		 */
>> 		if (error)
>> 			return error;
>> 	}
>>
> 
> This seems like a potential final option to me, but I still think
> breaking things down into the most basic states (as one of the previous
> versions sort of did with a switch statement) is the most
> straightforward approach because it facilitates pure refactoring. Note
> that I'm definitely not trying to make the argument that we refactor
> everything as such and then be done with it, but rather that we evaluate
> next direction from that point.
> 
> Next direction includes consideration of things like whether the
> intermediate state is aesthetically reasonable enough to be mergeable
> (so we can make some development progress and stop holding up some of
> these earlier patches), whether we can combine/reorder code to reduce
> states, and if/how to actually redesign the broader mechanism to
> facilitate deferred operations and potentially deal with some of the
> things you call out below (transaction reservation/rolling and locking,
> etc). I find the current approach of trying to solve all of this at once
> unwieldy simply due to the big clump of code that the xattr mechanism
> happens to be. We know we have to factor out the transaction processing
> for deferred operations and take this thing apart, so why not just get
> that part done?
> 
>> Though I guess a nice property of this current version is that it does
>> all the checks every time, which means that at least in theory you could
>> drop the ILOCK between rolls.  The only reason I mention /that/ is due
>> to our recent discovery that while most code blocks for transaction
>> reservation before blocking on an ILOCK, xfs_trans_roll_inode holds the
>> ILOCK and can block waiting for more transaction reservation, which can
>> lead to trouble.
>>
> 
> Indeed, though this is a problem with the current code too, right?
> 
>> One other thing I noticed while walking through the attr code is that
>> xfs_da_shrink_inode calls bunmapi to remove empty blocks.  I don't know
>> if the deferred code does this, but it seems like it could be promising
>> to use the deferred bmap unmap operation instead.  Dunno.
>>
> 
> Another potential cleanup to consider. ;)
> 
>>> random blocks of code. As noted previously, my hope is that once we
>>> break things down mechanically into the crude states that exist in the
>>> current code, we'll come up with some nice ways to continue refactoring
>>> things, reduce the number of states required and/or maybe even think of
>>> a way to eliminate the state machine entirely.
>>
>> (Hopefully the above was what Brian was getting at?)
>>
> 
> It's definitely along the lines of what I was hoping for as a final
> result. I'm just arguing for a more deliberate approach to get to that
> point:
> 
> 1.) Refactor existing code to lift out transaction processing using as
> simple and unclever programming constructs as possible (i.e., switch
> statements) and no functional changes.
> 2.) Simplify/refine what falls out from that as appropriate.
> 3.) Rework into a legitimate design (perhaps like what you propose above
> with function pointers).
> 4.) Plumb in deferred/intent item infrastructure such that the same
> xattr mechanism is used for direct and deferred xattrs.
> 5.) Profit.
> 
> Thoughts?
> 
> Brian
That seems like a reasonable plan to me.  I think the set has gone 
around enough times that if there was something more obvious missed, 
there would have been more opinions voiced.  So I think this would be a 
good way to proceed with caution and in small steps.  :-)

Allison

> 
>> --D
>>
>>> It's definitely worth soliciting other opinions, though, before
>>> significantly refactoring things one way or the other..
>>>
>>>>>
>>>>>> For example, I'd prefer to see something like
>>>>>>> xfs_trans_attr() broken down into smaller granularity functions with
>>>>>>> higher level state that is managed and readable in one place, if
>>>>>>> possible. Perhaps we could do that based on attr fork format, but I need
>>>>>>> to stare at the code and think about this some more (it might be that
>>>>>>> some degree of reentrancy is inevitable, or we just need to break things
>>>>>>> down to even smaller states...).
>>>>>> Yes, and I did go through a phase of trying to simplify the statemachine by
>>>>>> trying to grab onto anything about the state of the fork that could be used
>>>>>> instead.  But its not always enough particularly in the case of routines
>>>>>> that are in the middle of allocating or removing blocks.  If you see any
>>>>>> other mechanics that could help out, please call them out.
>>>>>>
>>>>>
>>>>> One of the things I'm wondering is if we'll be able to reduce the number
>>>>> of unique (sub-)states required by reordering some of the existing logic
>>>>> between the higher level states. For a quick example, the current series
>>>>> uses the XFS_DC_ALLOC_LEAF state for a one-time operation that's part of
>>>>> a state that can be reentered over and over. This raises the question to
>>>>> me of whether that _ALLOC_LEAF thing could eventually just be folded
>>>>> into the tail of the previous state.
>>>>>
>>>>> To reiterate, for now I think it would be perfectly reasonable to make
>>>>> _ALLOC_LEAF its own independent state so the flag management isn't
>>>>> buried so deep in the xattr code...
>>>>
>>>> Yes, it is one of the examples where trying to use the fork to control the
>>>> state does not work out so well because we're in the middle of altering
>>>> things.  So in those cases, using the state machine to give it its own state
>>>> starts to make more sense.
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>> Second, it seems like a lot of this code duplication between deferred
>>>>>>> and non-deferred operations should be unnecessary, particularly since
>>>>>>> the only difference between the contexts is how transactions are
>>>>>>> managed. For example, if you follow the xattr set code path in both
>>>>>>> contexts, we can see that functions like xfs_attr_set_args() are
>>>>>>> basically duplicated in the xfs_attr_set_later() deferred variant just
>>>>>>> so we can change the xfs_defer_finish() call in the former to a return
>>>>>>> -EAGAIN in the latter.
>>>>>> Yes, they still carry some similarities.  I guess I reasoned that continuing
>>>>>> to carve things up into smaller and smaller helpers with out a generalized
>>>>>> purpose (other than de-dup reduction) was starting to look a little weird,
>>>>>> and maybe leaving things in their appropriate context might have been
>>>>>> preferred?  Folks are welcome to chime in with opinions though.
>>>>>>
>>>>>
>>>>> As mentioned above, I think weird is to be expected, at least if we
>>>>> break things down into an intermediary state. That's just my .02 though.
>>>>> Maybe others have different ideas..
>>>>>
>>>>>>>
>>>>>>> Instead, what I think we should strive for is a common xattr mechanism
>>>>>>> that consists of the lowest common denominator between the two contexts
>>>>>>> (or IOW, core infrastructure that can be invoked from either context).
>>>>>>> For example, on a kernel without deferred xattr support, could we find a
>>>>>>> way to call the deferred variants directly and just let the
>>>>>>> context-specific caller do the transaction rolls on -EAGAIN instead of
>>>>>>> relying on the dfops infrastructure?
>>>>>> I think I did that somewhere in the older parent pointer sets.  At the time,
>>>>>> we sort of forgot that we cant completely scrap non delayed attrs (because
>>>>>> we need them for older versions).  But then protofiles needed to create
>>>>>> pptrs with out the delay mechanic, so I opened coded a sort of loop to deal
>>>>>> with the EAGAIN.  In fact, I ended up doing the same sort of loop in patch
>>>>>> 15 for xfs_attri_recover, which has the same challenge. Maybe we could make
>>>>>> a sort of general purpose wrapper?
>>>>>>
>>>>>> ISTM that should be possible, it
>>>>>>> just requires further breaking down the existing/non-deferred mechanism
>>>>>>> into smaller bits that uses the new state management logic and
>>>>>>> implements -EAGAIN handling for when the lower level code requires a
>>>>>>> transaction roll. At that point, deferred support should basically just
>>>>>>> consist of the dfops and log (i.e. intents) code to plug into the associated
>>>>>>> infrastructure. I think another side effect of that approach is that we
>>>>>>> shouldn't need these patches that add a bunch of new xattr
>>>>>>> infrastructure code, but rather we'd just continue refactoring the
>>>>>>> existing code and eventually implement a new high level function that
>>>>>>> returns -EAGAIN directly to the dfops code instead of rolling
>>>>>>> transactions explicitly. Thoughts?
>>>>>> Ok, I think I understand what you're trying to describe here.  Maybe take a
>>>>>> look at xfs_attri_recover in patch 15, and let me know if that was similar
>>>>>> to what you were thinking?
>>>>>>
>>>>>
>>>>> Yep, pretty much. Outside of the whole xfs_trans_attr() thing, I'd
>>>>> expect the direct xattr path to have to do something very similar in
>>>>> terms of invoking the xattr state machine and handling transaction rolls
>>>>> where the dfops mechanism isn't there to do it for us.
>>>>>
>>>>> Brian
>>>> Sure, that shouldn't be to hard to make a high level wrapper like that. Then
>>>> we can let go of the old code path.
>>>>
>>>
>>> I view it as more like reorganizing and reusing the old code path. ;)
>>>
>>> Brian
>>>
>>>> Thanks again for the all the reviewing!  :-)
>>>>
>>>> Allison
>>>>
>>>>>
>>>>>> Thank you for all the thorough reviewing here, I know it's a lot!
>>>>>> Allison
>>>>>>
>>>>>>>
>>>>>>> Brian
>>>>>>>
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * 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 we fit in a block, or we are in the middle of adding a leaf name.
>>>>>>>> +	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
>>>>>>>> +	 * that it is not done yet, and need to be recalled to finish up from
>>>>>>>> +	 * the last EAGAIN it returned
>>>>>>>> +	 */
>>>>>>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
>>>>>>>> +	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
>>>>>>>> +		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
>>>>>>>> +			error = xfs_attr_leaf_try_add(args, *leaf_bp);
>>>>>>>> +			args->dc.flags |= XFS_DC_FOUND_LBLK;
>>>>>>>> +
>>>>>>>> +			if (error && error != -ENOSPC)
>>>>>>>> +				return error;
>>>>>>>> +
>>>>>>>> +			return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		error = xfs_leaf_addname_later(args);
>>>>>>>> +		if (error && error != -ENOSPC)
>>>>>>>> +			return error;
>>>>>>>> +	} else {
>>>>>>>> +		error = xfs_node_addname_later(args);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	return error;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>>      * Return EEXIST if attr is found, or ENOATTR if not
>>>>>>>>      */
>>>>>>>>     int
>>>>>>>> @@ -362,6 +471,57 @@ xfs_attr_remove_args(
>>>>>>>>     	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;
>>>>>>>> +	struct xfs_buf		*bp;
>>>>>>>> +	int			forkoff, error = 0;
>>>>>>>> +
>>>>>>>> +	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_remove(args);
>>>>>>>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
>>>>>>>> +		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>>>>>>>> +		/*
>>>>>>>> +		 * If we fit in a block AND we are not in the middle of
>>>>>>>> +		 * removing node blocks, remove the leaf attribute.
>>>>>>>> +		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
>>>>>>>> +		 * signal that it is not done yet, and needs to be recalled to
>>>>>>>> +		 * to finish up from the last -EAGAIN
>>>>>>>> +		 */
>>>>>>>> +		error = xfs_leaf_has_attr(args, &bp);
>>>>>>>> +		if (error == -ENOATTR) {
>>>>>>>> +			xfs_trans_brelse(args->trans, bp);
>>>>>>>> +			return error;
>>>>>>>> +		}
>>>>>>>> +		error = 0;
>>>>>>>> +
>>>>>>>> +		xfs_attr3_leaf_remove(bp, args);
>>>>>>>> +
>>>>>>>> +		/* If the result is small enough, shrink it into the inode.*/
>>>>>>>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>>>>>>>> +		if (forkoff)
>>>>>>>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>>>>>>>> +	} else {
>>>>>>>> +		error = xfs_node_removename_later(args);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	return error;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +
>>>>>>>>     int
>>>>>>>>     xfs_attr_set(
>>>>>>>>     	struct xfs_inode	*dp,
>>>>>>>> @@ -794,6 +954,87 @@ xfs_attr_leaf_addname(struct xfs_da_args	*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).
>>>>>>>> + *
>>>>>>>> + * 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.
>>>>>>>> + */
>>>>>>>> +STATIC int
>>>>>>>> +xfs_leaf_addname_later(
>>>>>>>> +	struct xfs_da_args	*args)
>>>>>>>> +{
>>>>>>>> +	int			error, nmap;
>>>>>>>> +	struct xfs_inode	*dp = args->dp;
>>>>>>>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * If there was an out-of-line value, allocate the blocks we
>>>>>>>> +	 * identified for its storage and copy the value.  This is done
>>>>>>>> +	 * after we create the attribute so that we don't overflow the
>>>>>>>> +	 * maximum size of a transaction and/or hit a deadlock.
>>>>>>>> +	 */
>>>>>>>> +	if (args->rmtblkno > 0) {
>>>>>>>> +		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
>>>>>>>> +			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));
>>>>>>>> +
>>>>>>>> +			error = xfs_attr_rmt_find_hole(args);
>>>>>>>> +			if (error)
>>>>>>>> +				return error;
>>>>>>>> +
>>>>>>>> +			args->dc.blkcnt = args->rmtblkcnt;
>>>>>>>> +			args->dc.lblkno = args->rmtblkno;
>>>>>>>> +			args->dc.flags |= XFS_DC_ALLOC_LEAF;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * Roll through the "value", allocating blocks on disk as
>>>>>>>> +		 * required.
>>>>>>>> +		 */
>>>>>>>> +		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));
>>>>>>>> +
>>>>>>>> +			/* roll attribute extent map forwards */
>>>>>>>> +			args->dc.lblkno += map->br_blockcount;
>>>>>>>> +			args->dc.blkcnt -= map->br_blockcount;
>>>>>>>> +
>>>>>>>> +			return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		error = xfs_attr_rmtval_set_value(args);
>>>>>>>> +		if (error)
>>>>>>>> +			return error;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	if (args->rmtblkno > 0) {
>>>>>>>> +		/*
>>>>>>>> +		 * Added a "remote" value, just clear the incomplete flag.
>>>>>>>> +		 */
>>>>>>>> +		error = xfs_attr3_leaf_clearflag(args);
>>>>>>>> +	}
>>>>>>>> +	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
>>>>>>>> +	return error;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>>      * Return EEXIST if attr is found, or ENOATTR if not
>>>>>>>>      */
>>>>>>>>     STATIC int
>>>>>>>> @@ -1291,6 +1532,354 @@ xfs_attr_node_removename(
>>>>>>>>     }
>>>>>>>>     /*
>>>>>>>> + * Remove a name from a B-tree attribute list.
>>>>>>>> + *
>>>>>>>> + * 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
>>>>>>>> + * -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.
>>>>>>>> + */
>>>>>>>> +STATIC int
>>>>>>>> +xfs_node_removename_later(
>>>>>>>> +	struct xfs_da_args	*args)
>>>>>>>> +{
>>>>>>>> +	struct xfs_da_state	*state = NULL;
>>>>>>>> +	struct xfs_da_state_blk	*blk;
>>>>>>>> +	struct xfs_buf		*bp;
>>>>>>>> +	int			error, forkoff, retval = 0;
>>>>>>>> +	struct xfs_inode	*dp = args->dp;
>>>>>>>> +	int			done = 0;
>>>>>>>> +
>>>>>>>> +	trace_xfs_attr_node_removename(args);
>>>>>>>> +
>>>>>>>> +	if (args->dc.state == NULL) {
>>>>>>>> +		error = xfs_attr_node_hasname(args, &args->dc.state);
>>>>>>>> +		if (error != -EEXIST)
>>>>>>>> +			goto out;
>>>>>>>> +		else
>>>>>>>> +			error = 0;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * If there is an out-of-line value, de-allocate the blocks.
>>>>>>>> +		 * This is done before we remove the attribute so that we don't
>>>>>>>> +		 * overflow the maximum size of a transaction and/or hit a
>>>>>>>> +		 * deadlock.
>>>>>>>> +		 */
>>>>>>>> +		state = args->dc.state;
>>>>>>>> +		args->dc.blk = &state->path.blk[state->path.active - 1];
>>>>>>>> +		ASSERT(args->dc.blk->bp != NULL);
>>>>>>>> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>>>>> +	}
>>>>>>>> +	state = args->dc.state;
>>>>>>>> +	blk = args->dc.blk;
>>>>>>>> +
>>>>>>>> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>>>>>>>> +		bool isset;
>>>>>>>> +
>>>>>>>> +		error = xfs_attr3_leaf_flag_is_set(args, &isset);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +		if (!isset) {
>>>>>>>> +			/*
>>>>>>>> +			 * Fill in disk block numbers in the state structure
>>>>>>>> +			 * so that we can get the buffers back after we commit
>>>>>>>> +			 * several transactions in the following calls.
>>>>>>>> +			 */
>>>>>>>> +			error = xfs_attr_fillstate(state);
>>>>>>>> +			if (error)
>>>>>>>> +				goto out;
>>>>>>>> +
>>>>>>>> +			/*
>>>>>>>> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
>>>>>>>> +			 * remote value.
>>>>>>>> +			 */
>>>>>>>> +			error = xfs_attr3_leaf_setflag(args);
>>>>>>>> +			if (error)
>>>>>>>> +				goto out;
>>>>>>>> +
>>>>>>>> +			return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>>>>>>>> +			args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>>>>>>>> +			error = xfs_attr_rmtval_invalidate(args);
>>>>>>>> +			if (error)
>>>>>>>> +				goto out;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * 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;
>>>>>>>> +
>>>>>>>> +			if (!done)
>>>>>>>> +				return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * Refill the state structure with buffers, the prior calls
>>>>>>>> +		 * released our buffers.
>>>>>>>> +		 */
>>>>>>>> +		error = xfs_attr_refillstate(state);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Remove the name and update the hashvals in the tree.
>>>>>>>> +	 */
>>>>>>>> +	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>>>>>>>> +		blk = &state->path.blk[state->path.active - 1];
>>>>>>>> +		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>>>>> +		retval = xfs_attr3_leaf_remove(blk->bp, args);
>>>>>>>> +		xfs_da3_fixhashpath(state, &state->path);
>>>>>>>> +
>>>>>>>> +		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Check to see if the tree needs to be collapsed.
>>>>>>>> +	 */
>>>>>>>> +	if (retval && (state->path.active > 1)) {
>>>>>>>> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
>>>>>>>> +		error = xfs_da3_join(state);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +
>>>>>>>> +		return -EAGAIN;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * If the result is small enough, push it all into the inode.
>>>>>>>> +	 */
>>>>>>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>>>>>> +		/*
>>>>>>>> +		 * Have to get rid of the copy of this dabuf in the state.
>>>>>>>> +		 */
>>>>>>>> +		ASSERT(state->path.active == 1);
>>>>>>>> +		ASSERT(state->path.blk[0].bp);
>>>>>>>> +		state->path.blk[0].bp = NULL;
>>>>>>>> +
>>>>>>>> +		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +
>>>>>>>> +		forkoff = xfs_attr_shortform_allfit(bp, dp);
>>>>>>>> +		if (forkoff) {
>>>>>>>> +			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>>>>>>>> +			/* bp is gone due to xfs_da_shrink_inode */
>>>>>>>> +			if (error)
>>>>>>>> +				goto out;
>>>>>>>> +		} else
>>>>>>>> +			xfs_trans_brelse(args->trans, bp);
>>>>>>>> +	}
>>>>>>>> +out:
>>>>>>>> +	if (state != NULL)
>>>>>>>> +		xfs_da_state_free(state);
>>>>>>>> +
>>>>>>>> +	return error;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * Add a name to a Btree-format attribute list.
>>>>>>>> + *
>>>>>>>> + * This will involve walking down the Btree, and may involve splitting
>>>>>>>> + * leaf nodes and even splitting intermediate nodes up to and including
>>>>>>>> + * the root node (a special case of an intermediate node).
>>>>>>>> + *
>>>>>>>> + * "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
>>>>>>>> + * -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.
>>>>>>>> + */
>>>>>>>> +STATIC int
>>>>>>>> +xfs_node_addname_later(
>>>>>>>> +	struct xfs_da_args	*args)
>>>>>>>> +{
>>>>>>>> +	struct xfs_da_state	*state = NULL;
>>>>>>>> +	struct xfs_da_state_blk	*blk;
>>>>>>>> +	struct xfs_inode	*dp;
>>>>>>>> +	int			retval, error = 0;
>>>>>>>> +	int			nmap;
>>>>>>>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>>>>>>>> +
>>>>>>>> +	trace_xfs_attr_node_addname(args);
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Fill in bucket of arguments/results/context to carry around.
>>>>>>>> +	 */
>>>>>>>> +	dp = args->dp;
>>>>>>>> +
>>>>>>>> +	if (args->dc.flags & XFS_DC_FOUND_NBLK)
>>>>>>>> +		goto found_blk;
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Search to see if name already exists, and get back a pointer
>>>>>>>> +	 * to where it should go.
>>>>>>>> +	 */
>>>>>>>> +	retval = xfs_attr_node_hasname(args, &state);
>>>>>>>> +	blk = &state->path.blk[state->path.active-1];
>>>>>>>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>>>>> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>>>>>>> +		goto out;
>>>>>>>> +	} else if (retval == -EEXIST) {
>>>>>>>> +		if (args->name.type & ATTR_CREATE)
>>>>>>>> +			goto out;
>>>>>>>> +
>>>>>>>> +		trace_xfs_attr_node_replace(args);
>>>>>>>> +
>>>>>>>> +		/* save the attribute state for later removal*/
>>>>>>>> +		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
>>>>>>>> +		args->blkno2 = args->blkno;		/* set 2nd entry info*/
>>>>>>>> +		args->index2 = args->index;
>>>>>>>> +		args->rmtblkno2 = args->rmtblkno;
>>>>>>>> +		args->rmtblkcnt2 = args->rmtblkcnt;
>>>>>>>> +		args->rmtvaluelen2 = args->rmtvaluelen;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * clear the remote attr state now that it is saved so that the
>>>>>>>> +		 * values reflect the state of the attribute we are about to
>>>>>>>> +		 * add, not the attribute we just found and will remove later.
>>>>>>>> +		 */
>>>>>>>> +		args->rmtblkno = 0;
>>>>>>>> +		args->rmtblkcnt = 0;
>>>>>>>> +		args->rmtvaluelen = 0;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	retval = xfs_attr3_leaf_add(blk->bp, state->args);
>>>>>>>> +	if (retval == -ENOSPC) {
>>>>>>>> +		if (state->path.active == 1) {
>>>>>>>> +			/*
>>>>>>>> +			 * Its really a single leaf node, but it had
>>>>>>>> +			 * out-of-line values so it looked like it *might*
>>>>>>>> +			 * have been a b-tree.
>>>>>>>> +			 */
>>>>>>>> +			xfs_da_state_free(state);
>>>>>>>> +			state = NULL;
>>>>>>>> +			error = xfs_attr3_leaf_to_node(args);
>>>>>>>> +			if (error)
>>>>>>>> +				goto out;
>>>>>>>> +
>>>>>>>> +			return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * Split as many Btree elements as required.
>>>>>>>> +		 * This code tracks the new and old attr's location
>>>>>>>> +		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
>>>>>>>> +		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
>>>>>>>> +		 */
>>>>>>>> +		error = xfs_da3_split(state);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +	} else {
>>>>>>>> +		/*
>>>>>>>> +		 * Addition succeeded, update Btree hashvals.
>>>>>>>> +		 */
>>>>>>>> +		xfs_da3_fixhashpath(state, &state->path);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Kill the state structure, we're done with it and need to
>>>>>>>> +	 * allow the buffers to come back later.
>>>>>>>> +	 */
>>>>>>>> +	xfs_da_state_free(state);
>>>>>>>> +	state = NULL;
>>>>>>>> +
>>>>>>>> +	args->dc.flags |= XFS_DC_FOUND_NBLK;
>>>>>>>> +	return -EAGAIN;
>>>>>>>> +found_blk:
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * If there was an out-of-line value, allocate the blocks we
>>>>>>>> +	 * identified for its storage and copy the value.  This is done
>>>>>>>> +	 * after we create the attribute so that we don't overflow the
>>>>>>>> +	 * maximum size of a transaction and/or hit a deadlock.
>>>>>>>> +	 */
>>>>>>>> +	if (args->rmtblkno > 0) {
>>>>>>>> +		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
>>>>>>>> +			args->dc.flags |= XFS_DC_ALLOC_NODE;
>>>>>>>> +			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));
>>>>>>>> +
>>>>>>>> +			error = xfs_attr_rmt_find_hole(args);
>>>>>>>> +			if (error)
>>>>>>>> +				return error;
>>>>>>>> +
>>>>>>>> +			args->dc.blkcnt = args->rmtblkcnt;
>>>>>>>> +			args->dc.lblkno = args->rmtblkno;
>>>>>>>> +		}
>>>>>>>> +		/*
>>>>>>>> +		 * Roll through the "value", allocating blocks on disk as
>>>>>>>> +		 * required.
>>>>>>>> +		 */
>>>>>>>> +		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));
>>>>>>>> +
>>>>>>>> +			/* roll attribute extent map forwards */
>>>>>>>> +			args->dc.lblkno += map->br_blockcount;
>>>>>>>> +			args->dc.blkcnt -= map->br_blockcount;
>>>>>>>> +
>>>>>>>> +			return -EAGAIN;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		error = xfs_attr_rmtval_set_value(args);
>>>>>>>> +		if (error)
>>>>>>>> +			return error;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	if (args->rmtblkno > 0) {
>>>>>>>> +		/*
>>>>>>>> +		 * Added a "remote" value, just clear the incomplete flag.
>>>>>>>> +		 */
>>>>>>>> +		error = xfs_attr3_leaf_clearflag(args);
>>>>>>>> +		if (error)
>>>>>>>> +			goto out;
>>>>>>>> +	}
>>>>>>>> +	retval = error = 0;
>>>>>>>> +
>>>>>>>> +out:
>>>>>>>> +	if (state)
>>>>>>>> +		xfs_da_state_free(state);
>>>>>>>> +	if (error)
>>>>>>>> +		return error;
>>>>>>>> +
>>>>>>>> +	return retval;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>>      * Fill in the disk block numbers in the state structure for the buffers
>>>>>>>>      * that are attached to the state structure.
>>>>>>>>      * This is done so that we can quickly reattach ourselves to those buffers
>>>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>>>>>> index fb56d81..6203766 100644
>>>>>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>>>>>> @@ -149,9 +149,11 @@ 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 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 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] 64+ messages in thread

end of thread, other threads:[~2019-09-25 20:29 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-05 22:18 [PATCH v3 00/19] Delayed Attributes Allison Collins
2019-09-05 22:18 ` [PATCH v3 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
2019-09-18 16:43   ` Brian Foster
2019-09-18 18:09     ` Allison Collins
2019-09-18 18:14       ` Brian Foster
2019-09-18 18:48         ` Allison Collins
2019-09-18 19:06           ` Darrick J. Wong
2019-09-05 22:18 ` [PATCH v3 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
2019-09-18 16:44   ` Brian Foster
2019-09-18 16:47     ` Christoph Hellwig
2019-09-18 19:55     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 03/19] xfs: Add xfs_dabuf defines Allison Collins
2019-09-06  3:37   ` Darrick J. Wong
2019-09-05 22:18 ` [PATCH v3 04/19] xfs: Add xfs_has_attr and subroutines Allison Collins
2019-09-19 17:47   ` Brian Foster
2019-09-19 23:51     ` Allison Collins
2019-09-20 12:32       ` Brian Foster
2019-09-05 22:18 ` [PATCH v3 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2019-09-20 13:49   ` Brian Foster
2019-09-21  7:29     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 06/19] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
2019-09-20 13:49   ` Brian Foster
2019-09-21  7:00     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
2019-09-20 13:49   ` Brian Foster
2019-09-21  7:00     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 08/19] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
2019-09-20 13:50   ` Brian Foster
2019-09-21  1:25     ` Allison Collins
2019-09-23 12:04       ` Brian Foster
2019-09-05 22:18 ` [PATCH v3 09/19] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
2019-09-20 13:50   ` Brian Foster
2019-09-05 22:18 ` [PATCH v3 10/19] xfs: Add xfs_attr3_leaf helper functions Allison Collins
2019-09-20 13:50   ` Brian Foster
2019-09-21  1:03     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 11/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
2019-09-20 13:51   ` Brian Foster
2019-09-20 22:50     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 12/19] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
2019-09-20 13:51   ` Brian Foster
2019-09-20 22:49     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 13/19] xfs: Add delay context to xfs_da_args Allison Collins
2019-09-20 13:51   ` Brian Foster
2019-09-20 22:48     ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 14/19] xfs: Add delayed attribute routines Allison Collins
2019-09-20 15:28   ` Brian Foster
2019-09-20 19:12     ` Allison Collins
2019-09-23 12:04       ` Brian Foster
2019-09-24  5:53         ` Allison Collins
2019-09-24 10:05           ` Brian Foster
2019-09-25  4:36             ` Darrick J. Wong
2019-09-25 11:53               ` Brian Foster
2019-09-25 20:28                 ` Allison Collins
2019-09-05 22:18 ` [PATCH v3 15/19] xfs: Set up infastructure for deferred attribute operations Allison Collins
2019-09-05 22:18 ` [PATCH v3 16/19] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
2019-09-05 22:18 ` [PATCH v3 17/19] xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR Allison Collins
2019-09-05 22:18 ` [PATCH v3 18/19] xfs: Enable delayed attributes Allison Collins
2019-09-05 22:18 ` [PATCH v3 19/19] xfs_io: Add delayed attributes error tag Allison Collins
2019-09-16 12:27 ` [PATCH v3 00/19] Delayed Attributes Brian Foster
2019-09-16 18:41   ` Allison Collins
2019-09-16 19:23     ` Brian Foster
2019-09-16 20:42       ` Allison Collins
2019-09-17  4:43         ` Darrick J. Wong
2019-09-17 12:17         ` Brian Foster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).