All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/19] xfs: Delayed Ready Attrs
@ 2020-02-23  2:05 Allison Collins
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
                   ` (19 more replies)
  0 siblings, 20 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

Hi all,

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

At the moment, I would like people to focus their review efforts on just
this "delay ready" subseries, as I think that is a more conservative use
of peoples review time.  I also think the set is a bit much to manage
all at once, and we need to get the infrastructure ironed out before we
focus too much anything that depends on it. But I do have the extended
series for folks that want to see the bigger picture of where this is
going.

This series can be viewed on github here:
https://github.com/allisonhenderson/xfs_work/tree/delay_ready_attrs_v7

As well as the extended delayed attribute and parent pointer series:
https://github.com/allisonhenderson/xfs_work/tree/delay_ready_attrs_v7_extended

And the test cases:
https://github.com/allisonhenderson/xfs_work/tree/pptr_xfstests

To run the xfs attributes tests run:
check -g attr

To run as delayed attributes run:
export MKFS_OPTIONS="-n delattr"
check -g attr

To run parent pointer tests:
check -g parent

Changes since v6:
Mostly review just updates.  In the last review folks asked for a
diagram to make the code flow more visual.  They have been added in
patches 13 and 14.  At the moment, they're in the commit message.  I
figure people can decide where or if they want them somewhere in the
code later, since they are a bit lengthy.  Patch 15 is a helper function
that used to be part of 14 but I separated it to better organize things.
Patches 18 and 19 are new, and are just cleanups that I thought would
be helpful.

I've also gone through the set and rearranged the order of some of the
patches to make sort of mini sets.  I thought it would help reviewers
break down the reviewing some. For reviewing purposes, the set could be
broken up into 5 different phases:

Clean ups (patches 1-2):
These two patches were actually review suggestions made quiet some time
ago in regaurds to commit d29f781 (Remove all strlen ...), which has
since been merged.  The idea of the cleanups was to collapse down the
number of parameters getting passed around the xfs_attr_* routines.  It
has since drawn both commentary and critisim, so it's a little unclear
to me if people want it or not.  It could easily be taken as a stand
alone clean up.  But it's also not a neccassary must have in so far as
the delayed operations are concerned.  It does however pepper around a
lot of change activity up through the set.  So it would be helpfull to
get a verdict one way or another, depending on how people feel about it.
   xfs: Replace attribute parameters with struct xfs_name
   xfs: Embed struct xfs_name in xfs_da_args

Error code filtering (patches 3-4):
These two patches are all about finding and catching error codes that
need to be sent back up to user space before starting delayed
operations.  Errors that happen during a delayed operation are treated
like interal errors that cause a shutdown.  But we wouldnt want that
for example: when the user tries to rename a non existent attr.  So the
idea is that we need to find all such conditions, and take care of them
before starting a delayed operation.
   xfs: Add xfs_has_attr and subroutines
   xfs: Check for -ENOATTR or -EEXIST

Move transactions upwards (patches 5-12):
The goal of this subset is to try and move all the transaction specific
code up the call stack much as possible.  The idea being that once we
get them to the top, we can introduce the statemachine to handle the
-EAGAIN logic where ever the transactions used to be.
   xfs: Factor out new helper functions xfs_attr_rmtval_set
   xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
   xfs: Factor out xfs_attr_leaf_addname helper
   xfs: Refactor xfs_attr_try_sf_addname
   xfs: Factor out trans roll from xfs_attr3_leaf_setflag
   xfs: Factor out xfs_attr_rmtval_invalidate
   xfs: Factor out trans roll in xfs_attr3_leaf_clearflag
   xfs: Add helper function xfs_attr_rmtval_unmap

Introduce statemachine (patches 13-14):
Now that we have re-arranged the code such that we can remove the
transaction handleing, we proceed to do so.  The behavior of the attr
set/remove routines are now also compatible as a .finish_item callback
   xfs: Add delay ready attr remove routines
   xfs: Add delay ready attr set routines

Modularizing and cleanups (patches 15-19):
Now that we have pulled the transactions up to where we need them, it's
time to start breaking down the top level functions into new
subfunctions. The goal being to work towards a top level function that
deals mostly with the statemachine, and helpers for those states
   xfs: Add helper function xfs_attr_node_shrink
   xfs: Simplify xfs_attr_set_iter
   xfs: Add helper function xfs_attr_leaf_mark_incomplete
   xfs: Add remote block helper functions
   xfs: Remove xfs_attr_rmtval_remove


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

Questions, comment and feedback appreciated! 

Thanks all!
Allison

Allison Collins (18):
  xfs: Replace attribute parameters with struct xfs_name
  xfs: Embed struct xfs_name in xfs_da_args
  xfs: Check for -ENOATTR or -EEXIST
  xfs: Factor out new helper functions xfs_attr_rmtval_set
  xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
  xfs: Factor out xfs_attr_leaf_addname helper
  xfs: Refactor xfs_attr_try_sf_addname
  xfs: Factor out trans roll from xfs_attr3_leaf_setflag
  xfs: Factor out xfs_attr_rmtval_invalidate
  xfs: Factor out trans roll in xfs_attr3_leaf_clearflag
  xfs: Add helper function xfs_attr_rmtval_unmap
  xfs: Add delay ready attr remove routines
  xfs: Add delay ready attr set routines
  xfs: Add helper function xfs_attr_node_shrink
  xfs: Simplify xfs_attr_set_iter
  xfs: Add helper function xfs_attr_leaf_mark_incomplete
  xfs: Add remote block helper functions
  xfs: Remove xfs_attr_rmtval_remove

Allison Henderson (1):
  xfs: Add xfs_has_attr and subroutines

 fs/xfs/libxfs/xfs_attr.c        | 947 ++++++++++++++++++++++++++++------------
 fs/xfs/libxfs/xfs_attr.h        |  15 +-
 fs/xfs/libxfs/xfs_attr_leaf.c   | 220 +++++-----
 fs/xfs/libxfs/xfs_attr_leaf.h   |   3 +
 fs/xfs/libxfs/xfs_attr_remote.c | 260 +++++++----
 fs/xfs/libxfs/xfs_attr_remote.h |   7 +-
 fs/xfs/libxfs/xfs_da_btree.c    |   6 +-
 fs/xfs/libxfs/xfs_da_btree.h    |  47 +-
 fs/xfs/libxfs/xfs_dir2.c        |  18 +-
 fs/xfs/libxfs/xfs_dir2_block.c  |   6 +-
 fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +-
 fs/xfs/libxfs/xfs_dir2_node.c   |   8 +-
 fs/xfs/libxfs/xfs_dir2_sf.c     |  30 +-
 fs/xfs/libxfs/xfs_types.c       |  11 +
 fs/xfs/libxfs/xfs_types.h       |   1 +
 fs/xfs/scrub/attr.c             |  12 +-
 fs/xfs/scrub/common.c           |   2 +
 fs/xfs/xfs_acl.c                |  27 +-
 fs/xfs/xfs_attr_list.c          |   1 +
 fs/xfs/xfs_ioctl.c              |  25 +-
 fs/xfs/xfs_ioctl32.c            |   2 +
 fs/xfs/xfs_iops.c               |   8 +-
 fs/xfs/xfs_trace.h              |  21 +-
 fs/xfs/xfs_xattr.c              |  29 +-
 24 files changed, 1140 insertions(+), 572 deletions(-)

-- 
2.7.4


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

* [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23  9:34   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
                   ` (18 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

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

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c  | 22 +++++++++-------------
 fs/xfs/libxfs/xfs_attr.h  | 12 +++++-------
 fs/xfs/libxfs/xfs_types.c | 11 +++++++++++
 fs/xfs/libxfs/xfs_types.h |  1 +
 fs/xfs/xfs_acl.c          | 25 +++++++++++--------------
 fs/xfs/xfs_ioctl.c        | 23 +++++++++++++----------
 fs/xfs/xfs_iops.c         |  6 +++---
 fs/xfs/xfs_xattr.c        | 28 ++++++++++++++++------------
 8 files changed, 69 insertions(+), 59 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e614972..6717f47 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -61,8 +61,7 @@ STATIC int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	int			flags)
 {
 
@@ -74,8 +73,8 @@ xfs_attr_args_init(
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
 	args->flags = flags;
-	args->name = name;
-	args->namelen = namelen;
+	args->name = name->name;
+	args->namelen = name->len;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
 int
 xfs_attr_get(
 	struct xfs_inode	*ip,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		**value,
 	int			*valuelenp,
 	int			flags)
@@ -156,7 +154,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
+	error = xfs_attr_args_init(&args, ip, name, flags);
 	if (error)
 		return error;
 
@@ -339,8 +337,7 @@ xfs_attr_remove_args(
 int
 xfs_attr_set(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -356,7 +353,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name, flags);
 	if (error)
 		return error;
 
@@ -444,8 +441,7 @@ xfs_attr_set(
 int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	int			flags)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -457,7 +453,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name, flags);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 4243b22..35043db 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -147,14 +147,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
 int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
-int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 size_t namelen, unsigned char **value, int *valuelenp,
-		 int flags);
-int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 size_t namelen, unsigned char *value, int valuelen, int flags);
+int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
+		 unsigned char **value, int *valuelenp, int flags);
+int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
+		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
-		    size_t namelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c
index 4f59554..781a5a9 100644
--- a/fs/xfs/libxfs/xfs_types.c
+++ b/fs/xfs/libxfs/xfs_types.c
@@ -12,6 +12,17 @@
 #include "xfs_bit.h"
 #include "xfs_mount.h"
 
+/* Initialize a struct xfs_name with a null terminated string name */
+void
+xfs_name_init(
+	struct xfs_name *xname,
+	const char *name)
+{
+	xname->name = (unsigned char *)name;
+	xname->len = strlen(name);
+	xname->type = 0;
+}
+
 /* Find the size of the AG, in blocks. */
 xfs_agblock_t
 xfs_ag_block_count(
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 397d947..b94acb5 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -180,6 +180,7 @@ enum xfs_ag_resv_type {
  */
 struct xfs_mount;
 
+void xfs_name_init(struct xfs_name *xname, const char *name);
 xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
 bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
 		xfs_agblock_t agbno);
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index cd743fad..42ac847 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -123,7 +123,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;
 
@@ -131,10 +131,10 @@ xfs_get_acl(struct inode *inode, int type)
 
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		ea_name = SGI_ACL_FILE;
+		xfs_name_init(&name, SGI_ACL_FILE);
 		break;
 	case ACL_TYPE_DEFAULT:
-		ea_name = SGI_ACL_DEFAULT;
+		xfs_name_init(&name, SGI_ACL_DEFAULT);
 		break;
 	default:
 		BUG();
@@ -145,9 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
 	 * go out to the disk.
 	 */
 	len = XFS_ACL_MAX_SIZE(ip->i_mount);
-	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
-				(unsigned char **)&xfs_acl, &len,
-				ATTR_ALLOC | ATTR_ROOT);
+	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
+			     ATTR_ALLOC | ATTR_ROOT);
 	if (error) {
 		/*
 		 * If the attribute doesn't exist make sure we have a negative
@@ -167,17 +166,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;
+		xfs_name_init(&name, SGI_ACL_FILE);
 		break;
 	case ACL_TYPE_DEFAULT:
 		if (!S_ISDIR(inode->i_mode))
 			return acl ? -EACCES : 0;
-		ea_name = SGI_ACL_DEFAULT;
+		xfs_name_init(&name, SGI_ACL_DEFAULT);
 		break;
 	default:
 		return -EINVAL;
@@ -197,17 +196,15 @@ __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);
+		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
+				     ATTR_ROOT);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name,
-					strlen(ea_name),
-					ATTR_ROOT);
+		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index d42de92..28c07c9 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
-	size_t			namelen;
+	struct xfs_name		xname;
+
+	xfs_name_init(&xname, name);
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	namelen = strlen(name);
-	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
-			     flags);
+	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
 	if (error)
 		goto out_kfree;
 
@@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname;
+
+	xfs_name_init(&xname, name);
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -400,8 +402,7 @@ 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);
+	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname;
+
+	xfs_name_init(&xname, name);
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	namelen = strlen(name);
-	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
+
+	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 81f2f93..e85bbf5 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -48,11 +48,11 @@ xfs_initxattrs(
 	const struct xattr	*xattr;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error = 0;
+	struct xfs_name		name;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name,
-				     strlen(xattr->name),
-				     xattr->value, xattr->value_len,
+		xfs_name_init(&name, xattr->name);
+		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
 				     ATTR_SECURE);
 		if (error < 0)
 			break;
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index b0fedb5..74133a5 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -21,10 +21,12 @@ static int
 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		struct inode *inode, const char *name, void *value, size_t size)
 {
-	int xflags = handler->flags;
-	struct xfs_inode *ip = XFS_I(inode);
-	int error, asize = size;
-	size_t namelen = strlen(name);
+	int			xflags = handler->flags;
+	struct xfs_inode	*ip = XFS_I(inode);
+	int			error, asize = size;
+	struct xfs_name		xname;
+
+	xfs_name_init(&xname, name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -32,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
-			     &asize, xflags);
+	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
+			     xflags);
 	if (error)
 		return error;
 	return asize;
@@ -69,7 +71,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
-	size_t			namelen = strlen(name);
+	struct xfs_name		xname;
+
+	xfs_name_init(&xname, name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -77,11 +81,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	if (flags & XATTR_REPLACE)
 		xflags |= ATTR_REPLACE;
 
-	if (value)
-		error = xfs_attr_set(ip, name, namelen, (void *)value, size,
-				xflags);
-	else
-		error = xfs_attr_remove(ip, name, namelen, xflags);
+        if (value)
+               error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
+        else
+               error = xfs_attr_remove(ip, &xname, xflags);
+
 	if (!error)
 		xfs_forget_acl(inode, name, xflags);
 
-- 
2.7.4


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

* [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23 11:54   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
                   ` (17 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

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

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 6717f47..9acdb23 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -72,13 +72,12 @@ xfs_attr_args_init(
 	args->geo = dp->i_mount->m_attr_geo;
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
-	args->flags = flags;
-	args->name = name->name;
-	args->namelen = name->len;
-	if (args->namelen >= MAXNAMELEN)
+	memcpy(&args->name, name, sizeof(struct xfs_name));
+	args->name.type = flags;
+	if (args->name.len >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
-	args->hashval = xfs_da_hashname(args->name, args->namelen);
+	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
 	return 0;
 }
 
@@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
 	 * Commit the shortform mods, and we're done.
 	 * NOTE: this is also the error path (EEXIST, etc).
 	 */
-	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
+	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
 
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
@@ -357,6 +356,9 @@ xfs_attr_set(
 	if (error)
 		return error;
 
+	/* Use name now stored in args */
+	name = &args.name;
+
 	args.value = value;
 	args.valuelen = valuelen;
 	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
@@ -372,7 +374,7 @@ xfs_attr_set(
 	 */
 	if (XFS_IFORK_Q(dp) == 0) {
 		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
-			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
+			XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
 
 		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
 		if (error)
@@ -457,6 +459,9 @@ xfs_attr_remove(
 	if (error)
 		return error;
 
+	/* Use name now stored in args */
+	name = &args.name;
+
 	/*
 	 * we have no control over the attribute names that userspace passes us
 	 * to remove, so we have to allow the name lookup prior to attribute
@@ -532,10 +537,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 	trace_xfs_attr_sf_addname(args);
 
 	retval = xfs_attr_shortform_lookup(args);
-	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		return retval;
 	} else if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)
+		if (args->name.type & ATTR_CREATE)
 			return retval;
 		retval = xfs_attr_shortform_remove(args);
 		if (retval)
@@ -545,15 +550,15 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 		 * that the leaf format add routine won't trip over the attr
 		 * not being around.
 		 */
-		args->flags &= ~ATTR_REPLACE;
+		args->name.type &= ~ATTR_REPLACE;
 	}
 
-	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
+	if (args->name.len >= XFS_ATTR_SF_ENTSIZE_MAX ||
 	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
 		return -ENOSPC;
 
 	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
-	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
 
 	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
 	if (!forkoff)
@@ -598,11 +603,11 @@ xfs_attr_leaf_addname(
 	 * the given flags produce an error or call for an atomic rename.
 	 */
 	retval = xfs_attr3_leaf_lookup_int(bp, args);
-	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
 	} else if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE) {	/* pure create op */
+		if (args->name.type & ATTR_CREATE) {	/* pure create op */
 			xfs_trans_brelse(args->trans, bp);
 			return retval;
 		}
@@ -872,10 +877,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);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index fed537a..cb5ef66 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -464,7 +464,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;
 	}
@@ -679,27 +679,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);
@@ -749,11 +749,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;
 	}
@@ -816,11 +816,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;
 	}
@@ -847,13 +847,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;
@@ -912,13 +912,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);
@@ -1119,12 +1119,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;
@@ -1450,7 +1450,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) &&
@@ -1474,15 +1474,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;
@@ -2409,23 +2410,25 @@ xfs_attr3_leaf_lookup_int(
 		}
 		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);
@@ -2467,16 +2470,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,
@@ -2692,7 +2696,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;
@@ -2700,7 +2704,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);
 }
 
 
@@ -2754,8 +2758,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 8b7f74b..df8aca5 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -397,7 +397,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 875e04f..30f27d7 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -2125,8 +2125,10 @@ 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;
+	if (args->name.len == len && !memcmp(args->name.name, name, len))
+		return XFS_CMP_EXACT;
+
+	return XFS_CMP_DIFFERENT;
 }
 
 int
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index 0f4fbb0..14f1be3 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -54,12 +54,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 dd6fcaa..3aadddc 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;
 	}
@@ -265,8 +265,7 @@ xfs_dir_createname(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
 	args->inumber = inum;
@@ -361,8 +360,7 @@ xfs_dir_lookup(
 	 */
 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
 	args->dp = dp;
@@ -433,8 +431,7 @@ xfs_dir_removename(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
 	args->inumber = ino;
@@ -494,8 +491,7 @@ xfs_dir_replace(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
 	args->inumber = inum;
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index d6ced59..592e47c 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 = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
+	len = xfs_dir2_data_entsize(dp->i_mount, 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);
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a131b52..24a7fda 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -653,7 +653,7 @@ xfs_dir2_leaf_addname(
 	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
 	ents = leafhdr.ents;
 	bestsp = xfs_dir2_leaf_bests_p(ltp);
-	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
+	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
 
 	/*
 	 * See if there are any entries with the same hash value
@@ -856,8 +856,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);
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a0cc5e2..3c74efc 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -666,7 +666,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 = xfs_dir2_data_entsize(mp, args->namelen);
+	length = xfs_dir2_data_entsize(mp, args->name.len);
 	/*
 	 * Loop over leaf entries with the right hash value.
 	 */
@@ -1911,7 +1911,7 @@ xfs_dir2_node_addname_int(
 	int			needscan = 0;	/* need to rescan data frees */
 	__be16			*tagp;		/* data entry tag pointer */
 
-	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
+	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
 	error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &freehdr,
 					   &findex, length);
 	if (error)
@@ -1966,8 +1966,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);
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 7b7f6fb..058c526 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -387,7 +387,7 @@ xfs_dir2_sf_addname(
 	/*
 	 * Compute entry (and change in) size.
 	 */
-	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
+	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->name.len);
 	objchange = 0;
 
 	/*
@@ -470,7 +470,7 @@ xfs_dir2_sf_addname_easy(
 	/*
 	 * Grow the in-inode space.
 	 */
-	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
+	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->name.len),
 			  XFS_DATA_FORK);
 	/*
 	 * Need to set up again due to realloc of the inode data.
@@ -480,9 +480,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);
 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
 	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
 
@@ -540,7 +540,7 @@ xfs_dir2_sf_addname_hard(
 	 */
 	for (offset = args->geo->data_first_offset,
 	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
-	      add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
+	      add_datasize = xfs_dir2_data_entsize(mp, args->name.len),
 	      eof = (char *)oldsfep == &buf[old_isize];
 	     !eof;
 	     offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
@@ -570,9 +570,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);
 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
 	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
 	sfp->count++;
@@ -615,7 +615,7 @@ xfs_dir2_sf_addname_pick(
 	int			used;		/* data bytes used */
 
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-	size = xfs_dir2_data_entsize(mp, args->namelen);
+	size = xfs_dir2_data_entsize(mp, args->name.len);
 	offset = args->geo->data_first_offset;
 	sfep = xfs_dir2_sf_firstentry(sfp);
 	holefit = 0;
@@ -887,7 +887,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;
@@ -896,8 +896,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 = xfs_dir2_sf_get_parent_ino(sfp);
 		args->cmpresult = XFS_CMP_EXACT;
 		args->filetype = XFS_DIR3_FT_DIR;
@@ -984,7 +984,7 @@ xfs_dir2_sf_removename(
 	 * Calculate sizes.
 	 */
 	byteoff = (int)((char *)sfep - (char *)sfp);
-	entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
+	entsize = xfs_dir2_sf_entsize(mp, sfp, args->name.len);
 	newsize = oldsize - entsize;
 	/*
 	 * Copy the part if any after the removed entry, sliding it down.
@@ -1085,12 +1085,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 = xfs_dir2_sf_get_parent_ino(sfp);
 		ASSERT(args->inumber != ino);
 		xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index d9f0dd4..d4a9fe4 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 a86be7f..159b8af 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1633,7 +1633,7 @@ DECLARE_EVENT_CLASS(xfs_da_class,
 	TP_STRUCT__entry(
 		__field(dev_t, dev)
 		__field(xfs_ino_t, ino)
-		__dynamic_array(char, name, args->namelen)
+		__dynamic_array(char, name, args->name.len)
 		__field(int, namelen)
 		__field(xfs_dahash_t, hashval)
 		__field(xfs_ino_t, inumber)
@@ -1642,9 +1642,10 @@ DECLARE_EVENT_CLASS(xfs_da_class,
 	TP_fast_assign(
 		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
 		__entry->ino = args->dp->i_ino;
-		if (args->namelen)
-			memcpy(__get_str(name), args->name, args->namelen);
-		__entry->namelen = args->namelen;
+		if (args->name.len)
+			memcpy(__get_str(name), args->name.name,
+			       args->name.len);
+		__entry->namelen = args->name.len;
 		__entry->hashval = args->hashval;
 		__entry->inumber = args->inumber;
 		__entry->op_flags = args->op_flags;
@@ -1697,7 +1698,7 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
 	TP_STRUCT__entry(
 		__field(dev_t, dev)
 		__field(xfs_ino_t, ino)
-		__dynamic_array(char, name, args->namelen)
+		__dynamic_array(char, name, args->name.len)
 		__field(int, namelen)
 		__field(int, valuelen)
 		__field(xfs_dahash_t, hashval)
@@ -1707,12 +1708,13 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
 	TP_fast_assign(
 		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
 		__entry->ino = args->dp->i_ino;
-		if (args->namelen)
-			memcpy(__get_str(name), args->name, args->namelen);
-		__entry->namelen = args->namelen;
+		if (args->name.len)
+			memcpy(__get_str(name), args->name.name,
+			       args->name.len);
+		__entry->namelen = args->name.len;
 		__entry->valuelen = args->valuelen;
 		__entry->hashval = args->hashval;
-		__entry->flags = args->flags;
+		__entry->flags = args->name.type;
 		__entry->op_flags = args->op_flags;
 	),
 	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
-- 
2.7.4


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

* [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
  2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23 12:20   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:05 ` [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST Allison Collins
                   ` (16 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 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 appearance of duplicated code.  We will need these
routines later for delayed attributes since delayed operations cannot return error
codes.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 9acdb23..2255060 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
+				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
@@ -310,6 +313,37 @@ 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 = NULL;
+	int			error;
+
+	if (!xfs_inode_hasattr(dp))
+		return -ENOATTR;
+
+	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+		return xfs_attr_sf_findname(args, NULL, NULL);
+	}
+
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_hasname(args, &bp);
+
+		if (bp)
+			xfs_trans_brelse(args->trans, bp);
+
+		return error;
+	}
+
+	return xfs_attr_node_hasname(args, NULL);
+}
+
+/*
  * Remove the attribute specified in @args.
  */
 int
@@ -583,26 +617,20 @@ STATIC int
 xfs_attr_leaf_addname(
 	struct xfs_da_args	*args)
 {
-	struct xfs_inode	*dp;
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
+	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_leaf_addname(args);
 
 	/*
-	 * Read the (only) block in the attribute list in.
-	 */
-	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
-	if (error)
-		return error;
-
-	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
 	 * the given flags produce an error or call for an atomic rename.
 	 */
-	retval = xfs_attr3_leaf_lookup_int(bp, args);
+	retval = xfs_attr_leaf_hasname(args, &bp);
+	if (retval != -ENOATTR && retval != -EEXIST)
+		return retval;
+
 	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
@@ -754,6 +782,27 @@ xfs_attr_leaf_addname(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+STATIC int
+xfs_attr_leaf_hasname(
+	struct xfs_da_args      *args,
+	struct xfs_buf		**bp)
+{
+	int                     error = 0;
+
+	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
+	if (error)
+		return error;
+
+	error = xfs_attr3_leaf_lookup_int(*bp, args);
+	if (error != -ENOATTR && error != -EEXIST)
+		xfs_trans_brelse(args->trans, *bp);
+
+	return error;
+}
+
+/*
  * Remove a name from the leaf attribute list structure
  *
  * This leaf block cannot have a "remote" value, we only call this routine
@@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
 	 * Remove the attribute.
 	 */
 	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
-	if (error)
+
+	error = xfs_attr_leaf_hasname(args, &bp);
+	if (error != -ENOATTR && error != -EEXIST)
 		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
 	if (error == -ENOATTR) {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 
 	trace_xfs_attr_leaf_get(args);
 
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
-	if (error)
+	error = xfs_attr_leaf_hasname(args, &bp);
+	if (error != -ENOATTR && error != -EEXIST)
 		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
 	if (error != -EEXIST)  {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 	return error;
 }
 
+/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ * statep: If not null is set to point at the found state.  Caller will
+ *         be responsible for freeing the state in this case.
+ */
+STATIC int
+xfs_attr_node_hasname(
+	struct xfs_da_args	*args,
+	struct xfs_da_state	**statep)
+{
+	struct xfs_da_state	*state;
+	int			retval, error;
+
+	state = xfs_da_state_alloc();
+	state->args = args;
+	state->mp = args->dp->i_mount;
+
+	if (statep != NULL)
+		*statep = NULL;
+
+	/*
+	 * Search to see if name exists, and get back a pointer to it.
+	 */
+	error = xfs_da3_node_lookup_int(state, &retval);
+	if (error == 0) {
+		if (statep != NULL)
+			*statep = state;
+		return retval;
+	}
+
+	xfs_da_state_free(state);
+
+	return error;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
@@ -864,20 +945,17 @@ xfs_attr_node_addname(
 	dp = args->dp;
 	mp = dp->i_mount;
 restart:
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = mp;
-
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error)
+	retval = xfs_attr_node_hasname(args, &state);
+	if (retval != -ENOATTR && retval != -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)) {
+	if (retval == -ENOATTR && args->name.type & ATTR_REPLACE) {
 		goto out;
 	} else if (retval == -EEXIST) {
 		if (args->name.type & ATTR_CREATE)
@@ -1079,29 +1157,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.
@@ -1196,7 +1260,8 @@ xfs_attr_node_removename(
 	error = 0;
 
 out:
-	xfs_da_state_free(state);
+	if (state)
+		xfs_da_state_free(state);
 	return error;
 }
 
@@ -1316,31 +1381,23 @@ xfs_attr_node_get(xfs_da_args_t *args)
 {
 	xfs_da_state_t *state;
 	xfs_da_state_blk_t *blk;
-	int error, retval;
+	int error;
 	int i;
 
 	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) {
-		retval = error;
-		goto out_release;
-	}
-	if (retval != -EEXIST)
+	error = xfs_attr_node_hasname(args, &state);
+	if (error != -EEXIST)
 		goto out_release;
 
 	/*
 	 * Get the value, local or "remote"
 	 */
 	blk = &state->path.blk[state->path.active - 1];
-	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
+	error = xfs_attr3_leaf_getvalue(blk->bp, args);
 
 	/*
 	 * If not in a transaction, we have to release all the buffers.
@@ -1352,7 +1409,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
 	}
 
 	xfs_da_state_free(state);
-	return retval;
+	return error;
 }
 
 /* Returns true if the attribute entry name is valid. */
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 35043db..ce7b039 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -153,6 +153,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
+int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index cb5ef66..9d6b68c 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -654,18 +654,66 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
 }
 
 /*
+ * Return -EEXIST if attr is found, or -ENOATTR if not
+ * args:  args containing attribute name and namelen
+ * sfep:  If not null, pointer will be set to the last attr entry found on
+	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
+ *	  the last entry in the list
+ */
+int
+xfs_attr_sf_findname(
+	struct xfs_da_args	 *args,
+	struct xfs_attr_sf_entry **sfep,
+	unsigned int		 *basep)
+{
+	struct xfs_attr_shortform *sf;
+	struct xfs_attr_sf_entry *sfe;
+	unsigned int		base = sizeof(struct xfs_attr_sf_hdr);
+	int			size = 0;
+	int			end;
+	int			i;
+
+	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
+	sfe = &sf->list[0];
+	end = sf->hdr.count;
+	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
+			base += size, i++) {
+		size = XFS_ATTR_SF_ENTSIZE(sfe);
+		if (sfe->namelen != args->name.len)
+			continue;
+		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
+			continue;
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
+			continue;
+		break;
+	}
+
+	if (sfep != NULL)
+		*sfep = sfe;
+
+	if (basep != NULL)
+		*basep = base;
+
+	if (i == end)
+		return -ENOATTR;
+	return -EEXIST;
+}
+
+/*
  * Add a name/value pair to the shortform attribute list.
  * Overflow from the inode has already been checked for.
  */
 void
-xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
+xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff)
 {
-	xfs_attr_shortform_t *sf;
-	xfs_attr_sf_entry_t *sfe;
-	int i, offset, size;
-	xfs_mount_t *mp;
-	xfs_inode_t *dp;
-	struct xfs_ifork *ifp;
+	struct xfs_attr_shortform	*sf;
+	struct xfs_attr_sf_entry	*sfe;
+	int				offset, size, error;
+	struct xfs_mount		*mp;
+	struct xfs_inode		*dp;
+	struct xfs_ifork		*ifp;
 
 	trace_xfs_attr_sf_add(args);
 
@@ -676,18 +724,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 	ifp = dp->i_afp;
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
-	sfe = &sf->list[0];
-	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
-#ifdef DEBUG
-		if (sfe->namelen != args->name.len)
-			continue;
-		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
-			continue;
-		ASSERT(0);
-#endif
-	}
+	error = xfs_attr_sf_findname(args, &sfe, NULL);
+	ASSERT(error != -EEXIST);
 
 	offset = (char *)sfe - (char *)sf;
 	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
@@ -730,35 +768,26 @@ xfs_attr_fork_remove(
  * Remove an attribute from the shortform attribute list structure.
  */
 int
-xfs_attr_shortform_remove(xfs_da_args_t *args)
+xfs_attr_shortform_remove(struct xfs_da_args *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				size = 0, end, totsize;
+	unsigned int			base;
+	struct xfs_mount		*mp;
+	struct xfs_inode		*dp;
+	int				error;
 
 	trace_xfs_attr_sf_remove(args);
 
 	dp = args->dp;
 	mp = dp->i_mount;
-	base = sizeof(xfs_attr_sf_hdr_t);
 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
-	sfe = &sf->list[0];
-	end = sf->hdr.count;
-	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
-					base += size, i++) {
-		size = XFS_ATTR_SF_ENTSIZE(sfe);
-		if (sfe->namelen != args->name.len)
-			continue;
-		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
-			continue;
-		break;
-	}
-	if (i == end)
-		return -ENOATTR;
+
+	error = xfs_attr_sf_findname(args, &sfe, &base);
+	if (error != -EEXIST)
+		return error;
+	size = XFS_ATTR_SF_ENTSIZE(sfe);
 
 	/*
 	 * Fix up the attribute fork data, covering the hole
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 73615b1..0e9c87c 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -53,6 +53,9 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
 			struct xfs_buf **leaf_bp);
 int	xfs_attr_shortform_remove(struct xfs_da_args *args);
+int	xfs_attr_sf_findname(struct xfs_da_args *args,
+			     struct xfs_attr_sf_entry **sfep,
+			     unsigned 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] 135+ messages in thread

* [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (2 preceding siblings ...)
  2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23 12:25   ` Amir Goldstein
  2020-02-24 13:08   ` Brian Foster
  2020-02-23  2:05 ` [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
                   ` (15 subsequent siblings)
  19 siblings, 2 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

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

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 2255060..a2f812f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -437,6 +437,14 @@ xfs_attr_set(
 		goto out_trans_cancel;
 
 	xfs_trans_ijoin(args.trans, dp, 0);
+
+	error = xfs_has_attr(&args);
+	if (error == -EEXIST && (name->type & ATTR_CREATE))
+		goto out_trans_cancel;
+
+	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
+		goto out_trans_cancel;
+
 	error = xfs_attr_set_args(&args);
 	if (error)
 		goto out_trans_cancel;
@@ -525,6 +533,10 @@ xfs_attr_remove(
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
 
+	error = xfs_has_attr(&args);
+	if (error != -EEXIST)
+		goto out;
+
 	error = xfs_attr_remove_args(&args);
 	if (error)
 		goto out;
-- 
2.7.4


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

* [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (3 preceding siblings ...)
  2020-02-23  2:05 ` [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-25 12:53   ` Chandan Rajendra
  2020-02-23  2:05 ` [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags Allison Collins
                   ` (14 subsequent siblings)
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

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

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 149 +++++++++++++++++++++++++---------------
 1 file changed, 92 insertions(+), 57 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index df8aca5..d1eee24 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -440,32 +440,23 @@ xfs_attr_rmtval_get(
 }
 
 /*
- * Write the value associated with an attribute into the out-of-line buffer
- * that we have defined for it.
+ * Find a "hole" in the attribute address space large enough for us to drop the
+ * new attribute's value into
  */
-int
-xfs_attr_rmtval_set(
+STATIC int
+xfs_attr_rmt_find_hole(
 	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);
+	int			blkcnt;
+	xfs_fileoff_t		lfileoff = 0;
 
 	/*
-	 * 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.
+	 * 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,
@@ -473,48 +464,26 @@ xfs_attr_rmtval_set(
 	if (error)
 		return error;
 
-	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
+	args->rmtblkno = (xfs_dablk_t)lfileoff;
 	args->rmtblkcnt = blkcnt;
 
-	/*
-	 * Roll through the "value", allocating blocks on disk as required.
-	 */
-	while (blkcnt > 0) {
-		/*
-		 * Allocate a single extent, up to the size of the value.
-		 *
-		 * Note that we have to consider this a data allocation as we
-		 * write the remote attribute without logging the contents.
-		 * Hence we must ensure that we aren't using blocks that are on
-		 * the busy list so that we don't overwrite blocks which have
-		 * recently been freed but their transactions are not yet
-		 * committed to disk. If we overwrite the contents of a busy
-		 * extent and then crash then the block may not contain the
-		 * correct metadata after log recovery occurs.
-		 */
-		nmap = 1;
-		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
-				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
-				  &nmap);
-		if (error)
-			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
-
-		ASSERT(nmap == 1);
-		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
-		       (map.br_startblock != HOLESTARTBLOCK));
-		lblkno += map.br_blockcount;
-		blkcnt -= map.br_blockcount;
+	return 0;
+}
 
-		/*
-		 * Start the next trans in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			return error;
-	}
+STATIC 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
@@ -595,6 +564,72 @@ xfs_attr_rmtval_stale(
 }
 
 /*
+ * Write the value associated with an attribute into the out-of-line buffer
+ * that we have defined for it.
+ */
+int
+xfs_attr_rmtval_set(
+	struct xfs_da_args	*args)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
+	int			nmap;
+	int			error;
+
+	trace_xfs_attr_rmtval_set(args);
+
+	error = xfs_attr_rmt_find_hole(args);
+	if (error)
+		return error;
+
+	blkcnt = args->rmtblkcnt;
+	lblkno = (xfs_dablk_t)args->rmtblkno;
+	/*
+	 * Roll through the "value", allocating blocks on disk as required.
+	 */
+	while (blkcnt > 0) {
+		/*
+		 * Allocate a single extent, up to the size of the value.
+		 *
+		 * Note that we have to consider this a data allocation as we
+		 * write the remote attribute without logging the contents.
+		 * Hence we must ensure that we aren't using blocks that are on
+		 * the busy list so that we don't overwrite blocks which have
+		 * recently been freed but their transactions are not yet
+		 * committed to disk. If we overwrite the contents of a busy
+		 * extent and then crash then the block may not contain the
+		 * correct metadata after log recovery occurs.
+		 */
+		nmap = 1;
+		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
+				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
+				  &nmap);
+		if (error)
+			return error;
+		error = xfs_defer_finish(&args->trans);
+		if (error)
+			return error;
+
+		ASSERT(nmap == 1);
+		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
+		       (map.br_startblock != HOLESTARTBLOCK));
+		lblkno += map.br_blockcount;
+		blkcnt -= map.br_blockcount;
+
+		/*
+		 * Start the next trans in the chain.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, dp);
+		if (error)
+			return error;
+	}
+
+	return xfs_attr_rmtval_set_value(args);
+}
+
+/*
  * Remove the value associated with an attribute by deleting the
  * out-of-line buffer that it is stored on.
  */
-- 
2.7.4


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

* [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (4 preceding siblings ...)
  2020-02-23  2:05 ` [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23 12:30   ` Amir Goldstein
  2020-02-28  4:56   ` Chandan Rajendra
  2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
                   ` (13 subsequent siblings)
  19 siblings, 2 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 UTC (permalink / raw)
  To: linux-xfs

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

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index a2f812f..cf0cba7 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -739,6 +739,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
@@ -1081,6 +1088,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 9d6b68c..d691509 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
 			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, args->dp);
-
-	return error;
+	return 0;
 }
-- 
2.7.4


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

* [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (5 preceding siblings ...)
  2020-02-23  2:05 ` [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2020-02-23  2:05 ` Allison Collins
  2020-02-23 12:42   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
                   ` (12 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:05 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, and move the commit 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 | 88 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 31 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index cf0cba7..b2f0780 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -305,10 +305,30 @@ xfs_attr_set_args(
 		}
 	}
 
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 		error = xfs_attr_leaf_addname(args);
-	else
-		error = xfs_attr_node_addname(args);
+		if (error != -ENOSPC)
+			return error;
+
+		/*
+		 * Commit that transaction so that the node_addname()
+		 * call can manage its own transactions.
+		 */
+		error = xfs_defer_finish(&args->trans);
+		if (error)
+			return error;
+
+		/*
+		 * Commit the current trans (including the inode) and
+		 * start a new one.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, dp);
+		if (error)
+			return error;
+
+	}
+
+	error = xfs_attr_node_addname(args);
 	return error;
 }
 
@@ -620,20 +640,21 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  *========================================================================*/
 
 /*
- * Add a name to the leaf attribute list structure
+ * Tries to add an attribute to an inode in leaf form
  *
- * 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 function is meant to execute as part of a delayed operation and leaves
+ * the transaction handling to the caller.  On success the attribute is added
+ * and the inode and transaction are left dirty.  If there is not enough space,
+ * the attr data is converted to node format and -ENOSPC is returned. Caller is
+ * responsible for handling the dirty inode and transaction or adding the attr
+ * in node format.
  */
 STATIC int
-xfs_attr_leaf_addname(
-	struct xfs_da_args	*args)
+xfs_attr_leaf_try_add(
+	struct xfs_da_args	*args,
+	struct xfs_buf		*bp)
 {
-	struct xfs_buf		*bp;
-	int			retval, error, forkoff;
-	struct xfs_inode	*dp = args->dp;
-
-	trace_xfs_attr_leaf_addname(args);
+	int			retval, error;
 
 	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
@@ -679,31 +700,36 @@ xfs_attr_leaf_addname(
 	retval = xfs_attr3_leaf_add(bp, args);
 	if (retval == -ENOSPC) {
 		/*
-		 * Promote the attribute list to the Btree format, then
-		 * Commit that transaction so that the node_addname() call
-		 * can manage its own transactions.
+		 * Promote the attribute list to the Btree format.
+		 * Unless an error occurs, retain the -ENOSPC retval
 		 */
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
+	}
+	return retval;
+}
 
-		/*
-		 * Commit the current trans (including the inode) and start
-		 * a new one.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			return error;
 
-		/*
-		 * Fob the whole rest of the problem off on the Btree code.
-		 */
-		error = xfs_attr_node_addname(args);
+/*
+ * Add a name to the leaf attribute list structure
+ *
+ * This leaf block cannot have a "remote" value, we only call this routine
+ * if bmap_one_block() says there is only one block (ie: no remote blks).
+ */
+STATIC int
+xfs_attr_leaf_addname(
+	struct xfs_da_args	*args)
+{
+	int			error, forkoff;
+	struct xfs_buf		*bp = NULL;
+	struct xfs_inode	*dp = args->dp;
+
+	trace_xfs_attr_leaf_addname(args);
+
+	error = xfs_attr_leaf_try_add(args, bp);
+	if (error)
 		return error;
-	}
 
 	/*
 	 * Commit the transaction that added the attr name so that
-- 
2.7.4


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

* [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (6 preceding siblings ...)
  2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:04   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag Allison Collins
                   ` (11 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
while modularizing the adjacent code down into helpers. In this patch, hoist the
commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
attr list creation down.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index b2f0780..71298b9 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -227,8 +227,13 @@ xfs_attr_try_sf_addname(
 	struct xfs_da_args	*args)
 {
 
-	struct xfs_mount	*mp = dp->i_mount;
-	int			error, error2;
+	int			error;
+
+	/*
+	 * Build initial attribute list (if required).
+	 */
+	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+		xfs_attr_shortform_create(args);
 
 	error = xfs_attr_shortform_addname(args);
 	if (error == -ENOSPC)
@@ -241,12 +246,10 @@ xfs_attr_try_sf_addname(
 	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
 
-	if (mp->m_flags & XFS_MOUNT_WSYNC)
+	if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args->trans);
 
-	error2 = xfs_trans_commit(args->trans);
-	args->trans = NULL;
-	return error ? error : error2;
+	return error;
 }
 
 /*
@@ -258,7 +261,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,
@@ -269,17 +272,14 @@ xfs_attr_set_args(
 	     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;
+		if (error != -ENOSPC) {
+			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] 135+ messages in thread

* [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (7 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-28  7:59   ` Chandan Rajendra
  2020-02-23  2:06 ` [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

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

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 71298b9..26412da 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1244,6 +1244,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 d691509..67339f0 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2855,10 +2855,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 0;
 }
 
 /*
-- 
2.7.4


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

* [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (8 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-28 10:42   ` Chandan Rajendra
  2020-02-23  2:06 ` [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag Allison Collins
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

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

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

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index d1eee24..3de2eec 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -634,15 +634,12 @@ xfs_attr_rmtval_set(
  * out-of-line buffer that it is stored on.
  */
 int
-xfs_attr_rmtval_remove(
+xfs_attr_rmtval_invalidate(
 	struct xfs_da_args	*args)
 {
 	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.
@@ -670,13 +667,32 @@ xfs_attr_rmtval_remove(
 		lblkno += map.br_blockcount;
 		blkcnt -= map.br_blockcount;
 	}
+	return 0;
+}
 
+/*
+ * Remove the value associated with an attribute by deleting the
+ * out-of-line buffer that it is stored on.
+ */
+int
+xfs_attr_rmtval_remove(
+	struct xfs_da_args      *args)
+{
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
+	int			error = 0;
+	int			done = 0;
+
+	trace_xfs_attr_rmtval_remove(args);
+
+	error = xfs_attr_rmtval_invalidate(args);
+	if (error)
+		return error;
 	/*
 	 * Keep de-allocating extents until the remote-value region is gone.
 	 */
 	lblkno = args->rmtblkno;
 	blkcnt = args->rmtblkcnt;
-	done = 0;
 	while (!done) {
 		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
 				    XFS_BMAPI_ATTRFORK, 1, &done);
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 6fb4572..eff5f95 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -13,5 +13,5 @@ int xfs_attr_rmtval_set(struct xfs_da_args *args);
 int xfs_attr_rmtval_remove(struct xfs_da_args *args);
 int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
 		xfs_buf_flags_t incore_flags);
-
+int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4


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

* [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (9 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-28 10:56   ` Chandan Rajendra
  2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

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

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 26412da..5d73bdf 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -822,6 +822,14 @@ xfs_attr_leaf_addname(
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
+		if (error)
+			return error;
+
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	return error;
 }
@@ -1185,6 +1193,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 67339f0..1742f0a 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2804,10 +2804,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 0;
 }
 
 /*
-- 
2.7.4


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

* [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (10 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-24 13:40   ` Brian Foster
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
                   ` (7 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
new transactions. We will use this later when we introduce delayed attributes

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

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 3de2eec..da40f85 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
 	}
 	return 0;
 }
+
+/*
+ * Remove the value associated with an attribute by deleting the out-of-line
+ * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
+ * transaction and recall the function
+ */
+int
+xfs_attr_rmtval_unmap(
+	struct xfs_da_args	*args)
+{
+	int	error, done;
+
+	/*
+	 * Unmap value blocks for this attr.  This is similar to
+	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
+	 * for new transactions
+	 */
+	error = xfs_bunmapi(args->trans, args->dp,
+		    args->rmtblkno, args->rmtblkcnt,
+		    XFS_BMAPI_ATTRFORK, 1, &done);
+	if (error)
+		return error;
+
+	if (!done)
+		return -EAGAIN;
+
+	return 0;
+}
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index eff5f95..e06299a 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
 int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
 		xfs_buf_flags_t incore_flags);
 int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
+int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4


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

* [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (11 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-24 15:25   ` Brian Foster
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 14/19] xfs: Add delay ready attr set routines Allison Collins
                   ` (6 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

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

This patch also adds a new struct xfs_delattr_context, which we will use to keep
track of the current state of an attribute operation. The new xfs_delattr_state
enum is used to track various operations that are in progress so that we know not
to repeat them, and resume where we left off before EAGAIN was returned to cycle
out the transaction. Other members take the place of local variables that need
to retain their values across multiple function recalls.

Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
indicate places where the function would return -EAGAIN, and then immediately
resume from after being recalled by the calling function.  States marked as a
"subroutine state" indicate that they belong to a subroutine, and so the calling
function needs to pass them back to that subroutine to allow it to finish where
it left off. But they otherwise do not have a role in the calling function other
than just passing through.

 xfs_attr_remove_iter()
         XFS_DAS_RM_SHRINK     ─┐
         (subroutine state)     │
                                │
         XFS_DAS_RMTVAL_REMOVE ─┤
         (subroutine state)     │
                                └─>xfs_attr_node_removename()
                                                 │
                                                 v
                                         need to remove
                                   ┌─n──  rmt blocks?
                                   │             │
                                   │             y
                                   │             │
                                   │             v
                                   │  ┌─>XFS_DAS_RMTVAL_REMOVE
                                   │  │          │
                                   │  │          v
                                   │  └──y── more blks
                                   │         to remove?
                                   │             │
                                   │             n
                                   │             │
                                   │             v
                                   │         need to
                                   └─────> shrink tree? ─n─┐
                                                 │         │
                                                 y         │
                                                 │         │
                                                 v         │
                                         XFS_DAS_RM_SHRINK │
                                                 │         │
                                                 v         │
                                                done <─────┘

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
 fs/xfs/libxfs/xfs_attr.h     |   1 +
 fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
 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 +
 10 files changed, 141 insertions(+), 16 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5d73bdf..cd3a3f7 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -368,11 +368,60 @@ xfs_has_attr(
  */
 int
 xfs_attr_remove_args(
+	struct xfs_da_args	*args)
+{
+	int			error = 0;
+	int			err2 = 0;
+
+	do {
+		error = xfs_attr_remove_iter(args);
+		if (error && error != -EAGAIN)
+			goto out;
+
+		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
+			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
+
+			err2 = xfs_defer_finish(&args->trans);
+			if (err2) {
+				error = err2;
+				goto out;
+			}
+		}
+
+		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (err2) {
+			error = err2;
+			goto out;
+		}
+
+	} while (error == -EAGAIN);
+out:
+	return error;
+}
+
+/*
+ * Remove the attribute specified in @args.
+ *
+ * This function may return -EAGAIN to signal that the transaction needs to be
+ * rolled.  Callers should continue calling this function until they receive a
+ * return value other than -EAGAIN.
+ */
+int
+xfs_attr_remove_iter(
 	struct xfs_da_args      *args)
 {
 	struct xfs_inode	*dp = args->dp;
 	int			error;
 
+	/* State machine switch */
+	switch (args->dac.dela_state) {
+	case XFS_DAS_RM_SHRINK:
+	case XFS_DAS_RMTVAL_REMOVE:
+		goto node;
+	default:
+		break;
+	}
+
 	if (!xfs_inode_hasattr(dp)) {
 		error = -ENOATTR;
 	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
@@ -381,6 +430,7 @@ xfs_attr_remove_args(
 	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 		error = xfs_attr_leaf_removename(args);
 	} else {
+node:
 		error = xfs_attr_node_removename(args);
 	}
 
@@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
 		/* bp is gone due to xfs_da_shrink_inode */
 		if (error)
 			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
+
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
 	}
 	return 0;
 }
@@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
  * This will involve walking down the Btree, and may involve joining
  * leaf nodes and even joining intermediate nodes up to and including
  * the root node (a special case of an intermediate node).
+ *
+ * This routine is meant to function as either an inline or delayed operation,
+ * and may return -EAGAIN when the transaction needs to be rolled.  Calling
+ * functions will need to handle this, and recall the function until a
+ * successful error code is returned.
  */
 STATIC int
 xfs_attr_node_removename(
@@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
 	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_node_removename(args);
+	state = args->dac.da_state;
+	blk = args->dac.blk;
+
+	/* State machine switch */
+	switch (args->dac.dela_state) {
+	case XFS_DAS_RMTVAL_REMOVE:
+		goto rm_node_blks;
+	case XFS_DAS_RM_SHRINK:
+		goto rm_shrink;
+	default:
+		break;
+	}
 
 	error = xfs_attr_node_hasname(args, &state);
 	if (error != -EEXIST)
 		goto out;
+	else
+		error = 0;
 
 	/*
 	 * If there is an out-of-line value, de-allocate the blocks.
@@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->bp != NULL);
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+
+	/*
+	 * Store blk and state in the context incase we need to cycle out the
+	 * transaction
+	 */
+	args->dac.blk = blk;
+	args->dac.da_state = state;
+
 	if (args->rmtblkno > 0) {
 		/*
 		 * Fill in disk block numbers in the state structure
@@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		error = xfs_attr_rmtval_invalidate(args);
 		if (error)
 			goto out;
+	}
 
-		error = xfs_attr_rmtval_remove(args);
-		if (error)
-			goto out;
+rm_node_blks:
+
+	if (args->rmtblkno > 0) {
+		error = xfs_attr_rmtval_unmap(args);
+
+		if (error) {
+			if (error == -EAGAIN)
+				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
+			return error;
+		}
 
 		/*
 		 * Refill the state structure with buffers, the prior calls
@@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
 		error = xfs_da3_join(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
-		/*
-		 * Commit the Btree join operation and start a new trans.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			goto out;
+
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
+		args->dac.dela_state = XFS_DAS_RM_SHRINK;
+		return -EAGAIN;
 	}
 
+rm_shrink:
+	args->dac.dela_state = XFS_DAS_RM_SHRINK;
+
 	/*
 	 * If the result is small enough, push it all into the inode.
 	 */
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index ce7b039..ea873a5 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
+int xfs_attr_remove_iter(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);
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index 14f1be3..3c78498 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -50,9 +50,39 @@ enum xfs_dacmp {
 };
 
 /*
+ * Enum values for xfs_delattr_context.da_state
+ *
+ * These values are used by delayed attribute operations to keep track  of where
+ * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
+ * calling function to roll the transaction, and then recall the subroutine to
+ * finish the operation.  The enum is then used by the subroutine to jump back
+ * to where it was and resume executing where it left off.
+ */
+enum xfs_delattr_state {
+	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
+	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
+};
+
+/*
+ * Defines for xfs_delattr_context.flags
+ */
+#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
+
+/*
+ * Context used for keeping track of delayed attribute operations
+ */
+struct xfs_delattr_context {
+	struct xfs_da_state	*da_state;
+	struct xfs_da_state_blk *blk;
+	unsigned int		flags;
+	enum xfs_delattr_state	dela_state;
+};
+
+/*
  * Structure to ease passing around component names.
  */
 typedef struct xfs_da_args {
+	struct xfs_delattr_context dac; /* context used for delay attr ops */
 	struct xfs_da_geometry *geo;	/* da block geometry */
 	struct xfs_name	name;		/* name, length and argument  flags*/
 	uint8_t		filetype;	/* filetype of inode for directories */
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 42ac847..d65e6d8 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 "xfs_error.h"
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
 
-- 
2.7.4


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

* [PATCH v7 14/19] xfs: Add delay ready attr set routines
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (12 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-03-03 13:41   ` Chandan Rajendra
  2020-02-23  2:06 ` [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink Allison Collins
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

This patch modifies the attr set routines to be delay ready. This means they no
longer roll or commit transactions, but instead return -EAGAIN to have the calling
routine roll and refresh the transaction.  In this series, xfs_attr_set_args has
become xfs_attr_set_iter, which uses a state machine like switch to keep track of
where it was when EAGAIN was returned.

Part of xfs_attr_leaf_addname has been factored out into a new helper function
xfs_attr_leaf_try_add to allow transaction cycling between the two routines.

Two new helper functions have been added: xfs_attr_rmtval_set_init and
xfs_attr_rmtval_set_blk.  They provide a subset of logic similar to
xfs_attr_rmtval_set, but they store the current block in the delay attr
context to allow the caller to roll the transaction between allocations. This helps
to simplify and consolidate code used by xfs_attr_leaf_addname and
xfs_attr_node_addname. Finally, xfs_attr_set_args has become a simple loop to
refresh the transaction until the operation is completed.

Below is a state machine diagram for attr set operations. The XFS_DAS_* states
indicate places where the function would return -EAGAIN, and then immediately
resume from after being recalled by the calling function.  States marked as a
"subroutine state" indicate that they belong to a subroutine, and so the calling
function needs to pass them back to that subroutine to allow it to finish where it
left off.  But they otherwise do not have a role in the calling function other
than just passing through.

 xfs_attr_set_iter()
                 │
                 v
           need to upgrade
          from sf to leaf? ──n─┐
                 │             │
                 y             │
                 │             │
                 V             │
          XFS_DAS_ADD_LEAF     │
                 │             │
                 v             │
  ┌──────n── fork has   <──────┘
  │         only 1 blk?
  │              │
  │              y
  │              │
  │              v
  │     xfs_attr_leaf_try_add()
  │              │
  │              v
  │          had enough
  ├──────n──   space?
  │              │
  │              y
  │              │
  │              v
  │      XFS_DAS_FOUND_LBLK  ──┐
  │                            │
  │      XFS_DAS_FLIP_LFLAG  ──┤
  │      (subroutine state)    │
  │                            │
  │      XFS_DAS_ALLOC_LEAF  ──┤
  │      (subroutine state)    │
  │                            └─>xfs_attr_leaf_addname()
  │                                              │
  │                                              v
  │                                ┌─────n──  need to
  │                                │        alloc blks?
  │                                │             │
  │                                │             y
  │                                │             │
  │                                │             v
  │                                │  ┌─>XFS_DAS_ALLOC_LEAF
  │                                │  │          │
  │                                │  │          v
  │                                │  └──y── need to alloc
  │                                │         more blocks?
  │                                │             │
  │                                │             n
  │                                │             │
  │                                │             v
  │                                │          was this
  │                                └────────> a rename? ──n─┐
  │                                              │          │
  │                                              y          │
  │                                              │          │
  │                                              v          │
  │                                        flip incomplete  │
  │                                            flag         │
  │                                              │          │
  │                                              v          │
  │                                   ┌─>XFS_DAS_FLIP_LFLAG │
  │                                   │          │          │
  │                                   │          v          │
  │                                   │        remove       │
  │                                   │       old name      │
  │                                   │          │          │
  │                                   │          v          │
  │                                   └────y── more to      │
  │                                            remove       │
  │                                              │          │
  │                                              n          │
  │                                              │          │
  │                                              v          │
  │                                             done <──────┘
  └────> XFS_DAS_LEAF_TO_NODE ─┐
                               │
         XFS_DAS_FOUND_NBLK  ──┤
         (subroutine state)    │
                               │
         XFS_DAS_ALLOC_NODE  ──┤
         (subroutine state)    │
                               │
         XFS_DAS_FLIP_NFLAG  ──┤
         (subroutine state)    │
                               │
                               └─>xfs_attr_node_addname()
                                                 │
                                                 v
                                         find space to store
                                        attr. Split if needed
                                                 │
                                                 v
                                         XFS_DAS_FOUND_NBLK
                                                 │
                                                 v
                                   ┌─────n──  need to
                                   │        alloc blks?
                                   │             │
                                   │             y
                                   │             │
                                   │             v
                                   │  ┌─>XFS_DAS_ALLOC_NODE
                                   │  │          │
                                   │  │          v
                                   │  └──y── need to alloc
                                   │         more blocks?
                                   │             │
                                   │             n
                                   │             │
                                   │             v
                                   │          was this
                                   └────────> a rename? ──n─┐
                                                 │          │
                                                 y          │
                                                 │          │
                                                 v          │
                                           flip incomplete  │
                                               flag         │
                                                 │          │
                                                 v          │
                                      ┌─>XFS_DAS_FLIP_NFLAG │
                                      │          │          │
                                      │          v          │
                                      │        remove       │
                                      │       old name      │
                                      │          │          │
                                      │          v          │
                                      └────y── more to      │
                                               remove       │
                                                 │          │
                                                 n          │
                                                 │          │
                                                 v          │
                                                done <──────┘

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c        | 368 ++++++++++++++++++++++++++--------------
 fs/xfs/libxfs/xfs_attr.h        |   1 +
 fs/xfs/libxfs/xfs_attr_remote.c |  67 +++++++-
 fs/xfs/libxfs/xfs_attr_remote.h |   4 +
 fs/xfs/libxfs/xfs_da_btree.h    |  13 ++
 5 files changed, 319 insertions(+), 134 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index cd3a3f7..4b788f2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
 				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
+STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
 
 
 STATIC int
@@ -259,9 +260,86 @@ int
 xfs_attr_set_args(
 	struct xfs_da_args	*args)
 {
+	int			error = 0;
+	int			err2 = 0;
+	struct xfs_buf		*leaf_bp = NULL;
+
+	do {
+		error = xfs_attr_set_iter(args, &leaf_bp);
+		if (error && error != -EAGAIN)
+			goto out;
+
+		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
+			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
+
+			err2 = xfs_defer_finish(&args->trans);
+			if (err2) {
+				error = err2;
+				goto out;
+			}
+		}
+
+		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (err2) {
+			error = err2;
+			goto out;
+		}
+
+		if (leaf_bp) {
+			xfs_trans_bjoin(args->trans, leaf_bp);
+			xfs_trans_bhold(args->trans, leaf_bp);
+		}
+
+	} while (error == -EAGAIN);
+
+out:
+	return error;
+}
+
+/*
+ * Set the attribute specified in @args.
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+int
+xfs_attr_set_iter(
+	struct xfs_da_args	*args,
+	struct xfs_buf          **leaf_bp)
+{
 	struct xfs_inode	*dp = args->dp;
-	struct xfs_buf          *leaf_bp = NULL;
-	int			error, error2 = 0;
+	int			error = 0;
+	int			sf_size;
+
+	/* State machine switch */
+	switch (args->dac.dela_state) {
+	case XFS_DAS_ADD_LEAF:
+		goto add_leaf;
+	case XFS_DAS_ALLOC_LEAF:
+	case XFS_DAS_FLIP_LFLAG:
+	case XFS_DAS_FOUND_LBLK:
+		goto leaf;
+	case XFS_DAS_FOUND_NBLK:
+	case XFS_DAS_FLIP_NFLAG:
+	case XFS_DAS_ALLOC_NODE:
+	case XFS_DAS_LEAF_TO_NODE:
+		goto node;
+	default:
+		break;
+	}
+
+	/*
+	 * New inodes may not have an attribute fork yet. So set the attribute
+	 * fork appropriately
+	 */
+	if (XFS_IFORK_Q((args->dp)) == 0) {
+		sf_size = sizeof(struct xfs_attr_sf_hdr) +
+		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
+		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
+		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
+		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
+	}
 
 	/*
 	 * If the attribute list is non-existent or a shortform list,
@@ -275,17 +353,16 @@ 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) {
-			error2 = xfs_trans_commit(args->trans);
-			args->trans = NULL;
-			return error ? error : error2;
-		}
+
+		/* Should only be 0, -EEXIST or ENOSPC */
+		if (error != -ENOSPC)
+			return error;
 
 		/*
 		 * It won't fit in the shortform, transform to a leaf block.
 		 * GROT: another possible req'mt for a double-split btree op.
 		 */
-		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
+		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
 		if (error)
 			return error;
 
@@ -293,41 +370,48 @@ xfs_attr_set_args(
 		 * Prevent the leaf buffer from being unlocked so that a
 		 * concurrent AIL push cannot grab the half-baked leaf
 		 * buffer and run into problems with the write verifier.
-		 * Once we're done rolling the transaction we can release
-		 * the hold and add the attr to the leaf.
 		 */
-		xfs_trans_bhold(args->trans, leaf_bp);
-		error = xfs_defer_finish(&args->trans);
-		xfs_trans_bhold_release(args->trans, leaf_bp);
-		if (error) {
-			xfs_trans_brelse(args->trans, leaf_bp);
-			return error;
-		}
+		xfs_trans_bhold(args->trans, *leaf_bp);
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
+		args->dac.dela_state = XFS_DAS_ADD_LEAF;
+		return -EAGAIN;
 	}
 
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_addname(args);
-		if (error != -ENOSPC)
-			return error;
+add_leaf:
 
-		/*
-		 * Commit that transaction so that the node_addname()
-		 * call can manage its own transactions.
-		 */
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
+	/*
+	 * 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;
+	}
 
-		/*
-		 * Commit the current trans (including the inode) and
-		 * start a new one.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_try_add(args, *leaf_bp);
+		switch (error) {
+		case -ENOSPC:
+			args->dac.flags |= XFS_DAC_FINISH_TRANS;
+			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
+			return -EAGAIN;
+		case 0:
+			args->dac.dela_state = XFS_DAS_FOUND_LBLK;
+			return -EAGAIN;
+		default:
 			return error;
-
+		}
+leaf:
+		error = xfs_attr_leaf_addname(args);
+		if (error == -ENOSPC) {
+			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
+			return -EAGAIN;
+		}
+		return error;
 	}
-
+	args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
+node:
 	error = xfs_attr_node_addname(args);
 	return error;
 }
@@ -766,28 +850,29 @@ xfs_attr_leaf_try_add(
  *
  * This leaf block cannot have a "remote" value, we only call this routine
  * if bmap_one_block() says there is only one block (ie: no remote blks).
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
  */
 STATIC int
 xfs_attr_leaf_addname(
 	struct xfs_da_args	*args)
 {
-	int			error, forkoff;
 	struct xfs_buf		*bp = NULL;
+	int			error, forkoff;
 	struct xfs_inode	*dp = args->dp;
 
-	trace_xfs_attr_leaf_addname(args);
-
-	error = xfs_attr_leaf_try_add(args, bp);
-	if (error)
-		return error;
-
-	/*
-	 * Commit the transaction that added the attr name so that
-	 * later routines can manage their own transactions.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		return error;
+	/* State machine switch */
+	switch (args->dac.dela_state) {
+	case XFS_DAS_FLIP_LFLAG:
+		goto flip_flag;
+	case XFS_DAS_ALLOC_LEAF:
+		goto alloc_leaf;
+	default:
+		break;
+	}
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -796,7 +881,28 @@ xfs_attr_leaf_addname(
 	 * maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_set(args);
+
+		/* Open coded xfs_attr_rmtval_set without trans handling */
+		error = xfs_attr_rmtval_set_init(args);
+		if (error)
+			return error;
+
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+alloc_leaf:
+		while (args->dac.blkcnt > 0) {
+			error = xfs_attr_rmtval_set_blk(args);
+			if (error)
+				return error;
+
+			args->dac.flags |= XFS_DAC_FINISH_TRANS;
+			args->dac.dela_state = XFS_DAS_ALLOC_LEAF;
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
 		if (error)
 			return error;
 	}
@@ -815,13 +921,6 @@ 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
@@ -832,8 +931,17 @@ xfs_attr_leaf_addname(
 		args->rmtblkno = args->rmtblkno2;
 		args->rmtblkcnt = args->rmtblkcnt2;
 		args->rmtvaluelen = args->rmtvaluelen2;
+
+		args->dac.dela_state = XFS_DAS_FLIP_LFLAG;
+		return -EAGAIN;
+flip_flag:
 		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_remove(args);
+			error = xfs_attr_rmtval_unmap(args);
+
+			/*
+			 * if (error == -EAGAIN), we will repeat this until
+			 * args->rmtblkno is zero
+			 */
 			if (error)
 				return error;
 		}
@@ -852,34 +960,17 @@ xfs_attr_leaf_addname(
 		/*
 		 * If the result is small enough, shrink it all into the inode.
 		 */
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+		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)
-				return error;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				return error;
-		}
 
-		/*
-		 * Commit the remove and start the next trans in series.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
 
 	} else if (args->rmtblkno > 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
-		if (error)
-			return error;
-
-		/*
-		 * Commit the flag value change and start the next trans in
-		 * series.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	return error;
 }
@@ -1028,16 +1119,22 @@ xfs_attr_node_hasname(
  *
  * "Remote" attribute values confuse the issue and atomic rename operations
  * add a whole extra layer of confusion on top of that.
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ *returned.
  */
 STATIC int
 xfs_attr_node_addname(
 	struct xfs_da_args	*args)
 {
-	struct xfs_da_state	*state;
+	struct xfs_da_state	*state = NULL;
 	struct xfs_da_state_blk	*blk;
 	struct xfs_inode	*dp;
 	struct xfs_mount	*mp;
-	int			retval, error;
+	int			retval = 0;
+	int			error = 0;
 
 	trace_xfs_attr_node_addname(args);
 
@@ -1046,7 +1143,19 @@ xfs_attr_node_addname(
 	 */
 	dp = args->dp;
 	mp = dp->i_mount;
-restart:
+
+	/* State machine switch */
+	switch (args->dac.dela_state) {
+	case XFS_DAS_FLIP_NFLAG:
+		goto flip_flag;
+	case XFS_DAS_FOUND_NBLK:
+		goto found_nblk;
+	case XFS_DAS_ALLOC_NODE:
+		goto alloc_node;
+	default:
+		break;
+	}
+
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
@@ -1096,19 +1205,13 @@ xfs_attr_node_addname(
 			error = xfs_attr3_leaf_to_node(args);
 			if (error)
 				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
 
 			/*
-			 * Commit the node conversion and start the next
-			 * trans in the chain.
+			 * Restart routine from the top.  No need to set  the
+			 * state
 			 */
-			error = xfs_trans_roll_inode(&args->trans, dp);
-			if (error)
-				goto out;
-
-			goto restart;
+			args->dac.flags |= XFS_DAC_FINISH_TRANS;
+			return -EAGAIN;
 		}
 
 		/*
@@ -1120,9 +1223,7 @@ xfs_attr_node_addname(
 		error = xfs_da3_split(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
 	} else {
 		/*
 		 * Addition succeeded, update Btree hashvals.
@@ -1137,13 +1238,9 @@ xfs_attr_node_addname(
 	xfs_da_state_free(state);
 	state = NULL;
 
-	/*
-	 * Commit the leaf addition or btree split and start the next
-	 * trans in the chain.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		goto out;
+	args->dac.dela_state = XFS_DAS_FOUND_NBLK;
+	return -EAGAIN;
+found_nblk:
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -1152,7 +1249,27 @@ xfs_attr_node_addname(
 	 * maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_set(args);
+		/* Open coded xfs_attr_rmtval_set without trans handling */
+		error = xfs_attr_rmtval_set_init(args);
+		if (error)
+			return error;
+
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+alloc_node:
+		while (args->dac.blkcnt > 0) {
+			error = xfs_attr_rmtval_set_blk(args);
+			if (error)
+				return error;
+
+			args->dac.flags |= XFS_DAC_FINISH_TRANS;
+			args->dac.dela_state = XFS_DAS_ALLOC_NODE;
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
 		if (error)
 			return error;
 	}
@@ -1171,13 +1288,6 @@ 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
@@ -1188,8 +1298,21 @@ xfs_attr_node_addname(
 		args->rmtblkno = args->rmtblkno2;
 		args->rmtblkcnt = args->rmtblkcnt2;
 		args->rmtvaluelen = args->rmtvaluelen2;
+
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series
+		 */
+		args->dac.dela_state = XFS_DAS_FLIP_NFLAG;
+		return -EAGAIN;
+flip_flag:
 		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_remove(args);
+			error = xfs_attr_rmtval_unmap(args);
+
+			/*
+			 * if (error == -EAGAIN), we will repeat this until
+			 * args->rmtblkno is zero
+			 */
 			if (error)
 				return error;
 		}
@@ -1207,7 +1330,6 @@ xfs_attr_node_addname(
 		error = xfs_da3_node_lookup_int(state, &retval);
 		if (error)
 			goto out;
-
 		/*
 		 * Remove the name and update the hashvals in the tree.
 		 */
@@ -1215,7 +1337,6 @@ xfs_attr_node_addname(
 		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 		error = xfs_attr3_leaf_remove(blk->bp, args);
 		xfs_da3_fixhashpath(state, &state->path);
-
 		/*
 		 * Check to see if the tree needs to be collapsed.
 		 */
@@ -1223,18 +1344,9 @@ xfs_attr_node_addname(
 			error = xfs_da3_join(state);
 			if (error)
 				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
-		}
-
-		/*
-		 * Commit and start the next trans in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			goto out;
 
+			args->dac.flags |= XFS_DAC_FINISH_TRANS;
+		}
 	} else if (args->rmtblkno > 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
@@ -1242,14 +1354,6 @@ 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.h b/fs/xfs/libxfs/xfs_attr.h
index ea873a5..f450d8c 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -152,6 +152,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
 int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
+int xfs_attr_set_iter(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index da40f85..a0e79db 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -443,7 +443,7 @@ xfs_attr_rmtval_get(
  * Find a "hole" in the attribute address space large enough for us to drop the
  * new attribute's value into
  */
-STATIC int
+int
 xfs_attr_rmt_find_hole(
 	struct xfs_da_args	*args)
 {
@@ -470,7 +470,7 @@ xfs_attr_rmt_find_hole(
 	return 0;
 }
 
-STATIC int
+int
 xfs_attr_rmtval_set_value(
 	struct xfs_da_args	*args)
 {
@@ -630,6 +630,69 @@ xfs_attr_rmtval_set(
 }
 
 /*
+ * Find a hole for the attr and store it in the delayed attr context.  This
+ * initializes the context to roll through allocating an attr extent for a
+ * delayed attr operation
+ */
+int
+xfs_attr_rmtval_set_init(
+	struct xfs_da_args	*args)
+{
+	struct xfs_bmbt_irec	*map = &args->dac.map;
+	int error;
+
+	args->dac.lblkno = 0;
+	args->dac.lfileoff = 0;
+	args->dac.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->dac.blkcnt = args->rmtblkcnt;
+	args->dac.lblkno = args->rmtblkno;
+
+	return error;
+}
+
+/*
+ * Write one block of the value associated with an attribute into the
+ * out-of-line buffer that we have defined for it. This is similar to a subset
+ * of xfs_attr_rmtval_set, but records the current block to the delayed attr
+ * context, and leaves transaction handling to the caller.
+ */
+int
+xfs_attr_rmtval_set_blk(
+	struct xfs_da_args	*args)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_bmbt_irec	*map = &args->dac.map;
+	int nmap;
+	int error;
+
+	nmap = 1;
+	error = xfs_bmapi_write(args->trans, dp,
+		  (xfs_fileoff_t)args->dac.lblkno,
+		  args->dac.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->dac.lblkno += map->br_blockcount;
+	args->dac.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.
  */
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index e06299a..e01358e 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -15,4 +15,8 @@ int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
 		xfs_buf_flags_t incore_flags);
 int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
 int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
+int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
+int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
+int xfs_attr_rmtval_set_blk(struct xfs_da_args *args);
+int xfs_attr_rmtval_set_init(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index 3c78498..2278d15 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -61,6 +61,14 @@ enum xfs_dacmp {
 enum xfs_delattr_state {
 	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
 	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
+	XFS_DAS_ADD_LEAF,	/* We are adding a leaf attr */
+	XFS_DAS_FOUND_LBLK,	/* We found leaf blk for attr */
+	XFS_DAS_LEAF_TO_NODE,	/* Converted leaf to node */
+	XFS_DAS_FOUND_NBLK,	/* We found node blk for attr */
+	XFS_DAS_ALLOC_LEAF,	/* We are allocating leaf blocks */
+	XFS_DAS_FLIP_LFLAG,	/* Flipped leaf INCOMPLETE attr flag */
+	XFS_DAS_ALLOC_NODE,	/* We are allocating node blocks */
+	XFS_DAS_FLIP_NFLAG,	/* Flipped node INCOMPLETE attr flag */
 };
 
 /*
@@ -72,8 +80,13 @@ enum xfs_delattr_state {
  * Context used for keeping track of delayed attribute operations
  */
 struct xfs_delattr_context {
+	struct xfs_bmbt_irec	map;
+	struct xfs_buf		*leaf_bp;
+	xfs_fileoff_t		lfileoff;
 	struct xfs_da_state	*da_state;
 	struct xfs_da_state_blk *blk;
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
 	unsigned int		flags;
 	enum xfs_delattr_state	dela_state;
 };
-- 
2.7.4


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

* [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (13 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 14/19] xfs: Add delay ready attr set routines Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:22   ` Amir Goldstein
  2020-02-25  9:05   ` Dave Chinner
  2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
                   ` (4 subsequent siblings)
  19 siblings, 2 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new helper function xfs_attr_node_shrink used to shrink an
attr name into an inode if it is small enough.  This helps to modularize
the greater calling function xfs_attr_node_removename.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 4b788f2..30a16fe 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1366,6 +1366,43 @@ xfs_attr_node_addname(
 }
 
 /*
+ * Shrink an attribute from leaf to shortform
+ */
+STATIC int
+xfs_attr_node_shrink(
+	struct xfs_da_args	*args,
+	struct xfs_da_state     *state)
+{
+	struct xfs_inode	*dp = args->dp;
+	int			error, forkoff;
+	struct xfs_buf		*bp;
+
+	/*
+	 * 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, &bp);
+	if (error)
+		return error;
+
+	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)
+			return error;
+
+		args->dac.flags |= XFS_DAC_FINISH_TRANS;
+	} else
+		xfs_trans_brelse(args->trans, bp);
+
+	return 0;
+}
+
+/*
  * Remove a name from a B-tree attribute list.
  *
  * This will involve walking down the Btree, and may involve joining
@@ -1383,8 +1420,7 @@ xfs_attr_node_removename(
 {
 	struct xfs_da_state	*state;
 	struct xfs_da_state_blk	*blk;
-	struct xfs_buf		*bp;
-	int			retval, error, forkoff;
+	int			retval, error;
 	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_node_removename(args);
@@ -1493,30 +1529,8 @@ xfs_attr_node_removename(
 	/*
 	 * 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, &bp);
-		if (error)
-			goto out;
-
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
-			/* bp is gone due to xfs_da_shrink_inode */
-			if (error)
-				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
-		} else
-			xfs_trans_brelse(args->trans, bp);
-	}
-	error = 0;
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+		error = xfs_attr_node_shrink(args, state);
 
 out:
 	if (state)
-- 
2.7.4


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

* [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (14 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:26   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
                   ` (3 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

Delayed attribute mechanics make frequent use of goto statements.  We can use this
to further simplify xfs_attr_set_iter.  Because states tend to fall between if
conditions, we can invert the if logic and jump to the goto. This helps to reduce
indentation and simplify things.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 30a16fe..dd935ff 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
 }
 
 /*
+ * Check to see if the attr should be upgraded from non-existent or shortform to
+ * single-leaf-block attribute list.
+ */
+static inline bool
+xfs_attr_fmt_needs_update(
+	struct xfs_inode    *dp)
+{
+	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+	      dp->i_d.di_anextents == 0);
+}
+
+/*
  * Set the attribute specified in @args.
  */
 int
@@ -342,40 +355,40 @@ xfs_attr_set_iter(
 	}
 
 	/*
-	 * If the attribute list is non-existent or a shortform list,
-	 * upgrade it to a single-leaf-block attribute list.
+	 * If the attribute list is already in leaf format, jump straight to
+	 * leaf handling.  Otherwise, try to add the attribute to the shortform
+	 * list; if there's no room then convert the list to leaf format and try
+	 * again.
 	 */
-	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)) {
+	if (!xfs_attr_fmt_needs_update(dp))
+		goto add_leaf;
 
-		/*
-		 * Try to add the attr to the attribute list in the inode.
-		 */
-		error = xfs_attr_try_sf_addname(dp, args);
+	/*
+	 * Try to add the attr to the attribute list in the inode.
+	 */
+	error = xfs_attr_try_sf_addname(dp, args);
 
-		/* Should only be 0, -EEXIST or ENOSPC */
-		if (error != -ENOSPC)
-			return error;
+	/* Should only be 0, -EEXIST or ENOSPC */
+	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;
+	/*
+	 * 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);
-		args->dac.flags |= XFS_DAC_FINISH_TRANS;
-		args->dac.dela_state = XFS_DAS_ADD_LEAF;
-		return -EAGAIN;
-	}
+	/*
+	 * 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);
+	args->dac.flags |= XFS_DAC_FINISH_TRANS;
+	args->dac.dela_state = XFS_DAS_ADD_LEAF;
+	return -EAGAIN;
 
 add_leaf:
 
-- 
2.7.4


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

* [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (15 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:47   ` Amir Goldstein
                     ` (2 more replies)
  2020-02-23  2:06 ` [PATCH v7 18/19] xfs: Add remote block helper functions Allison Collins
                   ` (2 subsequent siblings)
  19 siblings, 3 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

This patch helps to simplify xfs_attr_node_removename by modularizing the code
around the transactions into helper functions.  This will make the function easier
to follow when we introduce delayed attributes.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index dd935ff..b9728d1 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
 }
 
 /*
+ * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
+ * for later deletion of the entry.
+ */
+STATIC int
+xfs_attr_leaf_mark_incomplete(
+	struct xfs_da_args	*args,
+	struct xfs_da_state	*state)
+{
+	int error;
+
+	/*
+	 * 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)
+		return error;
+
+	/*
+	 * Mark the attribute as INCOMPLETE
+	 */
+	error = xfs_attr3_leaf_setflag(args);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+/*
  * Remove a name from a B-tree attribute list.
  *
  * This will involve walking down the Btree, and may involve joining
@@ -1473,20 +1503,7 @@ xfs_attr_node_removename(
 	args->dac.da_state = state;
 
 	if (args->rmtblkno > 0) {
-		/*
-		 * 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);
+		error = xfs_attr_leaf_mark_incomplete(args, state);
 		if (error)
 			goto out;
 
-- 
2.7.4


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

* [PATCH v7 18/19] xfs: Add remote block helper functions
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (16 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:45   ` Amir Goldstein
  2020-03-04  4:59   ` Chandan Rajendra
  2020-02-23  2:06 ` [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove Allison Collins
  2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
  19 siblings, 2 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

This patch adds two new helper functions xfs_attr_store_rmt_blk and
xfs_attr_restore_rmt_blk. These two helpers assist to remove redunant code
associated with storing and retrieving remote blocks during the attr set operations.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index b9728d1..f88be36 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -786,6 +786,30 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  * External routines when attribute list is one block
  *========================================================================*/
 
+/* Store info about a remote block */
+STATIC void
+xfs_attr_store_rmt_blk(
+	struct xfs_da_args	*args)
+{
+	args->blkno2 = args->blkno;
+	args->index2 = args->index;
+	args->rmtblkno2 = args->rmtblkno;
+	args->rmtblkcnt2 = args->rmtblkcnt;
+	args->rmtvaluelen2 = args->rmtvaluelen;
+}
+
+/* Set stored info about a remote block */
+STATIC void
+xfs_attr_restore_rmt_blk(
+	struct xfs_da_args	*args)
+{
+	args->blkno = args->blkno2;
+	args->index = args->index2;
+	args->rmtblkno = args->rmtblkno2;
+	args->rmtblkcnt = args->rmtblkcnt2;
+	args->rmtvaluelen = args->rmtvaluelen2;
+}
+
 /*
  * Tries to add an attribute to an inode in leaf form
  *
@@ -824,11 +848,7 @@ xfs_attr_leaf_try_add(
 
 		/* save the attribute state for later removal*/
 		args->op_flags |= XFS_DA_OP_RENAME;	/* an atomic rename */
-		args->blkno2 = args->blkno;		/* set 2nd entry info*/
-		args->index2 = args->index;
-		args->rmtblkno2 = args->rmtblkno;
-		args->rmtblkcnt2 = args->rmtblkcnt;
-		args->rmtvaluelen2 = args->rmtvaluelen;
+		xfs_attr_store_rmt_blk(args);
 
 		/*
 		 * clear the remote attr state now that it is saved so that the
@@ -939,11 +959,7 @@ xfs_attr_leaf_addname(
 		 * Dismantle the "old" attribute/value pair by removing
 		 * a "remote" value (if it exists).
 		 */
-		args->index = args->index2;
-		args->blkno = args->blkno2;
-		args->rmtblkno = args->rmtblkno2;
-		args->rmtblkcnt = args->rmtblkcnt2;
-		args->rmtvaluelen = args->rmtvaluelen2;
+		xfs_attr_restore_rmt_blk(args);
 
 		args->dac.dela_state = XFS_DAS_FLIP_LFLAG;
 		return -EAGAIN;
@@ -1189,11 +1205,7 @@ xfs_attr_node_addname(
 
 		/* 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;
+		xfs_attr_store_rmt_blk(args);
 
 		/*
 		 * clear the remote attr state now that it is saved so that the
@@ -1306,11 +1318,7 @@ xfs_attr_node_addname(
 		 * Dismantle the "old" attribute/value pair by removing
 		 * a "remote" value (if it exists).
 		 */
-		args->index = args->index2;
-		args->blkno = args->blkno2;
-		args->rmtblkno = args->rmtblkno2;
-		args->rmtblkcnt = args->rmtblkcnt2;
-		args->rmtvaluelen = args->rmtvaluelen2;
+		xfs_attr_restore_rmt_blk(args);
 
 		/*
 		 * Commit the flag value change and start the next trans in
-- 
2.7.4


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

* [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (17 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 18/19] xfs: Add remote block helper functions Allison Collins
@ 2020-02-23  2:06 ` Allison Collins
  2020-02-23 13:54   ` Amir Goldstein
  2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
  19 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23  2:06 UTC (permalink / raw)
  To: linux-xfs

xfs_attr_rmtval_remove is no longer used.  Clear it out now

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 42 -----------------------------------------
 fs/xfs/xfs_trace.h              |  1 -
 2 files changed, 43 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index a0e79db..0cc0ec1 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -734,48 +734,6 @@ xfs_attr_rmtval_invalidate(
 }
 
 /*
- * Remove the value associated with an attribute by deleting the
- * out-of-line buffer that it is stored on.
- */
-int
-xfs_attr_rmtval_remove(
-	struct xfs_da_args      *args)
-{
-	xfs_dablk_t		lblkno;
-	int			blkcnt;
-	int			error = 0;
-	int			done = 0;
-
-	trace_xfs_attr_rmtval_remove(args);
-
-	error = xfs_attr_rmtval_invalidate(args);
-	if (error)
-		return error;
-	/*
-	 * Keep de-allocating extents until the remote-value region is gone.
-	 */
-	lblkno = args->rmtblkno;
-	blkcnt = args->rmtblkcnt;
-	while (!done) {
-		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
-				    XFS_BMAPI_ATTRFORK, 1, &done);
-		if (error)
-			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
-
-		/*
-		 * Close out trans and start the next one in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			return error;
-	}
-	return 0;
-}
-
-/*
  * Remove the value associated with an attribute by deleting the out-of-line
  * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
  * transaction and recall the function
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 159b8af..bf9a683 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1775,7 +1775,6 @@ DEFINE_ATTR_EVENT(xfs_attr_refillstate);
 
 DEFINE_ATTR_EVENT(xfs_attr_rmtval_get);
 DEFINE_ATTR_EVENT(xfs_attr_rmtval_set);
-DEFINE_ATTR_EVENT(xfs_attr_rmtval_remove);
 
 #define DEFINE_DA_EVENT(name) \
 DEFINE_EVENT(xfs_da_class, name, \
-- 
2.7.4


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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
                   ` (18 preceding siblings ...)
  2020-02-23  2:06 ` [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove Allison Collins
@ 2020-02-23  7:55 ` Amir Goldstein
  2020-02-23 16:02   ` Allison Collins
                     ` (2 more replies)
  19 siblings, 3 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23  7:55 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> Hi all,
>
> This set is a subset of a larger series for delayed attributes. Which is
> a subset of an even larger series, parent pointers. Delayed attributes
> allow attribute operations (set and remove) to be logged and committed
> in the same way that other delayed operations do. This allows more
> complex operations (like parent pointers) to be broken up into multiple
> smaller transactions. To do this, the existing attr operations must be
> modified to operate as either a delayed operation or a inline operation
> since older filesystems will not be able to use the new log entries.

High level question, before I dive into the series:

Which other "delayed operations" already exist?
I think delayed operations were added by Darrick to handle the growth of
translation size due to reflink. Right? So I assume the existing delayed
operations deal with block accounting.
When speaking of parent pointers, without having looked into the details yet,
it seem the delayed operations we would want to log are operations that deal
with namespace changes, i.e.: link,unlink,rename.
The information needed to be logged for these ops is minimal.
Why do we need a general infrastructure for delayed attr operations?

Thanks,
Amir.

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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2020-02-23  9:34   ` Amir Goldstein
  2020-02-23 16:03     ` Allison Collins
  2020-02-24 12:08   ` Chandan Rajendra
  2020-02-24 13:06   ` Brian Foster
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23  9:34 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> This patch replaces the attribute name and length parameters with a single struct
> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
> around and pre-simplifies the code some.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

I realize I am joining very late with lots of reviewed-by already applied,
so unless I find anything big, please regard my comments and possible
future improvements for the extended series rather than objections to this
pretty much baked patch set.

[...]

> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index d42de92..28c07c9 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
>  {
>         unsigned char           *kbuf;
>         int                     error = -EFAULT;
> -       size_t                  namelen;
> +       struct xfs_name         xname;
> +
> +       xfs_name_init(&xname, name);
>
>         if (*len > XFS_XATTR_SIZE_MAX)
>                 return -EINVAL;
> @@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
>         if (!kbuf)
>                 return -ENOMEM;
>
> -       namelen = strlen(name);
> -       error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
> -                            flags);
> +       error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>         if (error)
>                 goto out_kfree;
>
> @@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
>  {
>         unsigned char           *kbuf;
>         int                     error;
> -       size_t                  namelen;
> +       struct xfs_name         xname;
> +
> +       xfs_name_init(&xname, name);
>
>         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>                 return -EPERM;
> @@ -400,8 +402,7 @@ 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);
> +       error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>         if (!error)
>                 xfs_forget_acl(inode, name, flags);
>         kfree(kbuf);
> @@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
>         uint32_t                flags)
>  {
>         int                     error;
> -       size_t                  namelen;
> +       struct xfs_name         xname;
> +
> +       xfs_name_init(&xname, name);
>
>         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>                 return -EPERM;
> -       namelen = strlen(name);
> -       error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
> +
> +       error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>         if (!error)
>                 xfs_forget_acl(inode, name, flags);
>         return error;


A struct inititializer macro would have been nice, so code like this:

+       struct xfs_name         xname;
+
+       xfs_name_init(&xname, name);

Would become:
+       struct xfs_name         xname = XFS_NAME_STR_INIT(name);

As a matter of fact, in most of the cases a named local variable is
not needed at
all and the code could be written with an anonymous local struct variable macro:

+       error = xfs_attr_remove(XFS_I(inode), XFS_NAME_STR(name), flags);

Thanks,
Amir.

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2020-02-23 11:54   ` Amir Goldstein
  2020-02-23 16:51     ` Allison Collins
  2020-02-25  0:57   ` Dave Chinner
  2020-02-25  6:56   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 11:54 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> This patch embeds an xfs_name in xfs_da_args, replacing the name, namelen, and flags
> members.  This helps to clean up the xfs_da_args structure and make it more uniform
> with the new xfs_name parameter being passed around.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>  fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>  fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>  fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>  fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>  fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>  fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>  fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>  fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>  fs/xfs/scrub/attr.c             |  12 ++---
>  fs/xfs/xfs_trace.h              |  20 ++++----
>  12 files changed, 130 insertions(+), 123 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 6717f47..9acdb23 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>         args->geo = dp->i_mount->m_attr_geo;
>         args->whichfork = XFS_ATTR_FORK;
>         args->dp = dp;
> -       args->flags = flags;
> -       args->name = name->name;
> -       args->namelen = name->len;
> -       if (args->namelen >= MAXNAMELEN)
> +       memcpy(&args->name, name, sizeof(struct xfs_name));

Maybe xfs_name_copy and xfs_name_equal are in order?

>
> +       /* Use name now stored in args */
> +       name = &args.name;
> +

It seem that the context of these comments be clear in the future.

>         args.value = value;
>         args.valuelen = valuelen;
>         args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
> @@ -372,7 +374,7 @@ xfs_attr_set(
>          */
>         if (XFS_IFORK_Q(dp) == 0) {
>                 int sf_size = sizeof(xfs_attr_sf_hdr_t) +
> -                       XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
> +                       XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
>
>                 error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>                 if (error)
> @@ -457,6 +459,9 @@ xfs_attr_remove(
>         if (error)
>                 return error;
>
> +       /* Use name now stored in args */
> +       name = &args.name;
> +
>         /*
>          * we have no control over the attribute names that userspace passes us
>          * to remove, so we have to allow the name lookup prior to attribute
> @@ -532,10 +537,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>         trace_xfs_attr_sf_addname(args);
>
>         retval = xfs_attr_shortform_lookup(args);
> -       if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> +       if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>                 return retval;
>         } else if (retval == -EEXIST) {
> -               if (args->flags & ATTR_CREATE)
> +               if (args->name.type & ATTR_CREATE)
>                         return retval;
>                 retval = xfs_attr_shortform_remove(args);
>                 if (retval)
> @@ -545,15 +550,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;


This doesn't look good it looks like a hack.

Even if want to avoid growing struct xfs_name we can store two shorts instead
of overloading int type with flags.
type doesn't even need more than a single byte, because XFS_DIR3_FT_WHT
is not used and will never be used on-disk.

Thanks,
Amir.

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2020-02-23 12:20   ` Amir Goldstein
  2020-02-23 17:28     ` Allison Collins
  2020-02-25  6:26     ` Dave Chinner
  2020-02-24 13:08   ` Brian Foster
  2020-02-25  9:49   ` Chandan Rajendra
  2 siblings, 2 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 12:20 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
> routines later for delayed attributes since delayed operations cannot return error
> codes.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>  4 files changed, 188 insertions(+), 98 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9acdb23..2255060 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>
>  /*
>   * Internal routines when attribute list is more than one block.
> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> +                                struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>
> @@ -310,6 +313,37 @@ xfs_attr_set_args(
>  }
>
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not

This is a very silly return value for a function named has_attr in my taste.
I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
IMO this change looks like a very good opportunity to change that internal
API:

xfs_has_attr?

0: NO
1: YES (or stay with the syscall standard of -ENOATTR)
<0: error

> + */
> +int
> +xfs_has_attr(
> +       struct xfs_da_args      *args)
> +{
> +       struct xfs_inode        *dp = args->dp;
> +       struct xfs_buf          *bp = NULL;
> +       int                     error;
> +
> +       if (!xfs_inode_hasattr(dp))
> +               return -ENOATTR;
> +
> +       if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +               ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +               return xfs_attr_sf_findname(args, NULL, NULL);
> +       }
> +
> +       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +               error = xfs_attr_leaf_hasname(args, &bp);
> +
> +               if (bp)
> +                       xfs_trans_brelse(args->trans, bp);
> +
> +               return error;
> +       }
> +
> +       return xfs_attr_node_hasname(args, NULL);
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
> @@ -583,26 +617,20 @@ STATIC int
>  xfs_attr_leaf_addname(
>         struct xfs_da_args      *args)
>  {
> -       struct xfs_inode        *dp;
>         struct xfs_buf          *bp;
>         int                     retval, error, forkoff;
> +       struct xfs_inode        *dp = args->dp;
>
>         trace_xfs_attr_leaf_addname(args);
>
>         /*
> -        * Read the (only) block in the attribute list in.
> -        */
> -       dp = args->dp;
> -       args->blkno = 0;
> -       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -       if (error)
> -               return error;
> -
> -       /*
>          * Look up the given attribute in the leaf block.  Figure out if
>          * the given flags produce an error or call for an atomic rename.
>          */
> -       retval = xfs_attr3_leaf_lookup_int(bp, args);
> +       retval = xfs_attr_leaf_hasname(args, &bp);
> +       if (retval != -ENOATTR && retval != -EEXIST)
> +               return retval;
> +
>         if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {

Example of how sane code (in my taste) would look like:

       retval = xfs_attr_leaf_hasname(args, &bp);
       if (retval < 0)
               return retval;

        if ((args->name.type & ATTR_REPLACE) && !retval) {
                 xfs_trans_brelse(args->trans, bp);
                 return -ENOATTR;
        } else if (retval) {
                if (args->flags & ATTR_CREATE) {        /* pure create op */
                        xfs_trans_brelse(args->trans, bp);
                        return -EEXIST;
               }

Thanks,
Amir.

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

* Re: [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST
  2020-02-23  2:05 ` [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST Allison Collins
@ 2020-02-23 12:25   ` Amir Goldstein
  2020-02-23 17:33     ` Allison Collins
  2020-02-24 13:08   ` Brian Foster
  1 sibling, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 12:25 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> Delayed operations cannot return error codes.  So we must check for these conditions
> first before starting set or remove operations
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 2255060..a2f812f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -437,6 +437,14 @@ xfs_attr_set(
>                 goto out_trans_cancel;
>
>         xfs_trans_ijoin(args.trans, dp, 0);
> +
> +       error = xfs_has_attr(&args);
> +       if (error == -EEXIST && (name->type & ATTR_CREATE))
> +               goto out_trans_cancel;
> +
> +       if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> +               goto out_trans_cancel;
> +

And we do care about other errors?

Thanks,
Amir.

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

* Re: [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
  2020-02-23  2:05 ` [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2020-02-23 12:30   ` Amir Goldstein
  2020-02-23 17:36     ` Allison Collins
  2020-02-28  4:56   ` Chandan Rajendra
  1 sibling, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 12:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> Since delayed operations cannot roll transactions, factor up the transaction
> handling into the calling function

I am not a native English speaker, so not sure what the correct phrase is,
but I'm pretty sure its not factor up, nor factor out???

>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  7 +------
>  2 files changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index a2f812f..cf0cba7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -739,6 +739,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
> @@ -1081,6 +1088,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 9d6b68c..d691509 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
>                          XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>         }
>
> -       /*
> -        * Commit the flag value change and start the next trans in series.
> -        */
> -       error = xfs_trans_roll_inode(&args->trans, args->dp);
> -
> -       return error;
> +       return 0;
>  }
> --
> 2.7.4
>

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2020-02-23 12:42   ` Amir Goldstein
  2020-02-23 18:38     ` Allison Collins
  2020-02-25  6:42   ` Dave Chinner
  2020-02-28  6:51   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 12:42 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> Factor out new helper function xfs_attr_leaf_try_add.

Right. This should be the subject.
Not factor out xfs_attr_leaf_addname helper.

> Because new delayed attribute
> routines cannot roll transactions, we carve off the parts of xfs_attr_leaf_addname
> that we can use, and move the commit into the calling function.

And that is a different change.
It is hard enough to review a pure factor out of a helper.
Adding changed inside a pure re-factor is not good.

Belongs to another change - move transaction commit to caller.

Thanks,
Amir.

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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
@ 2020-02-23 13:04   ` Amir Goldstein
  2020-02-23 17:51     ` Allison Collins
  2020-02-24 13:08   ` Brian Foster
  2020-02-28  7:42   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:04 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,

typo: transacation


> while modularizing the adjacent code down into helpers. In this patch, hoist the
> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
> attr list creation down.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---

And I don't think the subject (Refactoring) is a reliable description
of this change,
but if nobody else cares, I don't mind what you call it.

As far as not changing logic, you may add:

Reviewed-by: Amir Goldstein <amir73il@gmail.com>


Thanks,
Amir.

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

* Re: [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink
  2020-02-23  2:06 ` [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink Allison Collins
@ 2020-02-23 13:22   ` Amir Goldstein
  2020-02-23 18:41     ` Allison Collins
  2020-02-25  9:05   ` Dave Chinner
  1 sibling, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:22 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> This patch adds a new helper function xfs_attr_node_shrink used to shrink an
> attr name into an inode if it is small enough.  This helps to modularize
> the greater calling function xfs_attr_node_removename.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 66 +++++++++++++++++++++++++++++-------------------
>  1 file changed, 40 insertions(+), 26 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 4b788f2..30a16fe 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1366,6 +1366,43 @@ xfs_attr_node_addname(
>  }
>
>  /*
> + * Shrink an attribute from leaf to shortform
> + */
> +STATIC int
> +xfs_attr_node_shrink(
> +       struct xfs_da_args      *args,
> +       struct xfs_da_state     *state)
> +{
> +       struct xfs_inode        *dp = args->dp;
> +       int                     error, forkoff;
> +       struct xfs_buf          *bp;
> +
> +       /*
> +        * 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, &bp);
> +       if (error)
> +               return error;
> +
> +       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)
> +                       return error;
> +
> +               args->dac.flags |= XFS_DAC_FINISH_TRANS;

Why did xfs_defer_finish(&args->trans); turn into the above?

Are you testing reviewers alertness? ;-)
Please keep logic preserving patches separate from logic change patches.

Thanks,
Amir.

> +       } else
> +               xfs_trans_brelse(args->trans, bp);
> +
> +       return 0;
> +}
> +
> +/*
>   * Remove a name from a B-tree attribute list.
>   *
>   * This will involve walking down the Btree, and may involve joining
> @@ -1383,8 +1420,7 @@ xfs_attr_node_removename(
>  {
>         struct xfs_da_state     *state;
>         struct xfs_da_state_blk *blk;
> -       struct xfs_buf          *bp;
> -       int                     retval, error, forkoff;
> +       int                     retval, error;
>         struct xfs_inode        *dp = args->dp;
>
>         trace_xfs_attr_node_removename(args);
> @@ -1493,30 +1529,8 @@ xfs_attr_node_removename(
>         /*
>          * 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, &bp);
> -               if (error)
> -                       goto out;
> -
> -               if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> -                       error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> -                       /* bp is gone due to xfs_da_shrink_inode */
> -                       if (error)
> -                               goto out;
> -                       error = xfs_defer_finish(&args->trans);
> -                       if (error)
> -                               goto out;
> -               } else
> -                       xfs_trans_brelse(args->trans, bp);
> -       }
> -       error = 0;
> +       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> +               error = xfs_attr_node_shrink(args, state);
>
>  out:
>         if (state)
> --
> 2.7.4
>

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
@ 2020-02-23 13:26   ` Amir Goldstein
  2020-02-23 18:42     ` Allison Collins
  2020-02-25  9:21   ` Dave Chinner
  2020-03-04  4:30   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:26 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> Delayed attribute mechanics make frequent use of goto statements.  We can use this
> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
> conditions, we can invert the if logic and jump to the goto. This helps to reduce
> indentation and simplify things.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Looks better IMO and doesn't change logic.

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

> ---
>  fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 42 insertions(+), 29 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 30a16fe..dd935ff 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>  }
>
>  /*
> + * Check to see if the attr should be upgraded from non-existent or shortform to
> + * single-leaf-block attribute list.
> + */
> +static inline bool
> +xfs_attr_fmt_needs_update(
> +       struct xfs_inode    *dp)
> +{
> +       return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> +             (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> +             dp->i_d.di_anextents == 0);
> +}
> +
> +/*
>   * Set the attribute specified in @args.
>   */
>  int
> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>         }
>
>         /*
> -        * If the attribute list is non-existent or a shortform list,
> -        * upgrade it to a single-leaf-block attribute list.
> +        * If the attribute list is already in leaf format, jump straight to
> +        * leaf handling.  Otherwise, try to add the attribute to the shortform
> +        * list; if there's no room then convert the list to leaf format and try
> +        * again.
>          */
> -       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)) {
> +       if (!xfs_attr_fmt_needs_update(dp))
> +               goto add_leaf;
>
> -               /*
> -                * Try to add the attr to the attribute list in the inode.
> -                */
> -               error = xfs_attr_try_sf_addname(dp, args);
> +       /*
> +        * Try to add the attr to the attribute list in the inode.
> +        */
> +       error = xfs_attr_try_sf_addname(dp, args);
>
> -               /* Should only be 0, -EEXIST or ENOSPC */
> -               if (error != -ENOSPC)
> -                       return error;
> +       /* Should only be 0, -EEXIST or ENOSPC */
> +       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;
> +       /*
> +        * 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);
> -               args->dac.flags |= XFS_DAC_FINISH_TRANS;
> -               args->dac.dela_state = XFS_DAS_ADD_LEAF;
> -               return -EAGAIN;
> -       }
> +       /*
> +        * 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);
> +       args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +       args->dac.dela_state = XFS_DAS_ADD_LEAF;
> +       return -EAGAIN;
>
>  add_leaf:
>
> --
> 2.7.4
>

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

* Re: [PATCH v7 18/19] xfs: Add remote block helper functions
  2020-02-23  2:06 ` [PATCH v7 18/19] xfs: Add remote block helper functions Allison Collins
@ 2020-02-23 13:45   ` Amir Goldstein
  2020-03-04  4:59   ` Chandan Rajendra
  1 sibling, 0 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:45 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> This patch adds two new helper functions xfs_attr_store_rmt_blk and
> xfs_attr_restore_rmt_blk. These two helpers assist to remove redunant code

Typo: redunant

> associated with storing and retrieving remote blocks during the attr set operations.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 48 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 28 insertions(+), 20 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index b9728d1..f88be36 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -786,6 +786,30 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>   * External routines when attribute list is one block
>   *========================================================================*/
>
> +/* Store info about a remote block */
> +STATIC void
> +xfs_attr_store_rmt_blk(
> +       struct xfs_da_args      *args)
> +{
> +       args->blkno2 = args->blkno;
> +       args->index2 = args->index;
> +       args->rmtblkno2 = args->rmtblkno;
> +       args->rmtblkcnt2 = args->rmtblkcnt;
> +       args->rmtvaluelen2 = args->rmtvaluelen;
> +}
> +
> +/* Set stored info about a remote block */
> +STATIC void
> +xfs_attr_restore_rmt_blk(
> +       struct xfs_da_args      *args)
> +{
> +       args->blkno = args->blkno2;
> +       args->index = args->index2;
> +       args->rmtblkno = args->rmtblkno2;
> +       args->rmtblkcnt = args->rmtblkcnt2;
> +       args->rmtvaluelen = args->rmtvaluelen2;
> +}
> +
>  /*
>   * Tries to add an attribute to an inode in leaf form
>   *
> @@ -824,11 +848,7 @@ xfs_attr_leaf_try_add(
>
>                 /* save the attribute state for later removal*/
>                 args->op_flags |= XFS_DA_OP_RENAME;     /* an atomic rename */
> -               args->blkno2 = args->blkno;             /* set 2nd entry info*/
> -               args->index2 = args->index;
> -               args->rmtblkno2 = args->rmtblkno;
> -               args->rmtblkcnt2 = args->rmtblkcnt;
> -               args->rmtvaluelen2 = args->rmtvaluelen;
> +               xfs_attr_store_rmt_blk(args);

I believe the common naming pattern in the kernel for the helper to match
with xx_restore of state is xxx_save (and not xxx_store).

Otherwise, cleanup looks good and doesn't change logic.

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Thanks,
Amir.

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

* Re: [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
@ 2020-02-23 13:47   ` Amir Goldstein
  2020-02-23 18:43     ` Allison Collins
  2020-02-25  9:31   ` Dave Chinner
  2020-03-04  4:37   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> This patch helps to simplify xfs_attr_node_removename by modularizing the code
> around the transactions into helper functions.  This will make the function easier
> to follow when we introduce delayed attributes.
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Found no surprises here, you may add:

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Thanks,
Amir.

> ---
>  fs/xfs/libxfs/xfs_attr.c | 45 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 31 insertions(+), 14 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index dd935ff..b9728d1 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
>  }
>
>  /*
> + * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
> + * for later deletion of the entry.
> + */
> +STATIC int
> +xfs_attr_leaf_mark_incomplete(
> +       struct xfs_da_args      *args,
> +       struct xfs_da_state     *state)
> +{
> +       int error;
> +
> +       /*
> +        * 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)
> +               return error;
> +
> +       /*
> +        * Mark the attribute as INCOMPLETE
> +        */
> +       error = xfs_attr3_leaf_setflag(args);
> +       if (error)
> +               return error;
> +
> +       return 0;
> +}
> +
> +/*
>   * Remove a name from a B-tree attribute list.
>   *
>   * This will involve walking down the Btree, and may involve joining
> @@ -1473,20 +1503,7 @@ xfs_attr_node_removename(
>         args->dac.da_state = state;
>
>         if (args->rmtblkno > 0) {
> -               /*
> -                * 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);
> +               error = xfs_attr_leaf_mark_incomplete(args, state);
>                 if (error)
>                         goto out;
>
> --
> 2.7.4
>

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

* Re: [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove
  2020-02-23  2:06 ` [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove Allison Collins
@ 2020-02-23 13:54   ` Amir Goldstein
  2020-02-23 18:50     ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-23 13:54 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> xfs_attr_rmtval_remove is no longer used.  Clear it out now
>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

Patch 12/19 add a new function similar to this one called
xfs_attr_rmtval_unmap() and now this function is removed.
I wonder if it wouldn't have been simpler to keep the original function
name and change its behavior to that of xfs_attr_rmtval_unmap().

Unless the function name change makes the logic change more clear
for the future users???

>  fs/xfs/libxfs/xfs_attr_remote.c | 42 -----------------------------------------
>  fs/xfs/xfs_trace.h              |  1 -
>  2 files changed, 43 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index a0e79db..0cc0ec1 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -734,48 +734,6 @@ xfs_attr_rmtval_invalidate(
>  }
>
>  /*
> - * Remove the value associated with an attribute by deleting the
> - * out-of-line buffer that it is stored on.
> - */
> -int
> -xfs_attr_rmtval_remove(
> -       struct xfs_da_args      *args)
> -{
> -       xfs_dablk_t             lblkno;
> -       int                     blkcnt;
> -       int                     error = 0;
> -       int                     done = 0;
> -
> -       trace_xfs_attr_rmtval_remove(args);
> -
> -       error = xfs_attr_rmtval_invalidate(args);
> -       if (error)
> -               return error;
> -       /*
> -        * Keep de-allocating extents until the remote-value region is gone.
> -        */
> -       lblkno = args->rmtblkno;
> -       blkcnt = args->rmtblkcnt;
> -       while (!done) {
> -               error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
> -                                   XFS_BMAPI_ATTRFORK, 1, &done);
> -               if (error)
> -                       return error;
> -               error = xfs_defer_finish(&args->trans);
> -               if (error)
> -                       return error;
> -
> -               /*
> -                * Close out trans and start the next one in the chain.
> -                */
> -               error = xfs_trans_roll_inode(&args->trans, args->dp);
> -               if (error)
> -                       return error;
> -       }
> -       return 0;
> -}
> -
> -/*
>   * Remove the value associated with an attribute by deleting the out-of-line
>   * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
>   * transaction and recall the function
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 159b8af..bf9a683 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -1775,7 +1775,6 @@ DEFINE_ATTR_EVENT(xfs_attr_refillstate);
>
>  DEFINE_ATTR_EVENT(xfs_attr_rmtval_get);
>  DEFINE_ATTR_EVENT(xfs_attr_rmtval_set);
> -DEFINE_ATTR_EVENT(xfs_attr_rmtval_remove);
>
>  #define DEFINE_DA_EVENT(name) \
>  DEFINE_EVENT(xfs_da_class, name, \
> --
> 2.7.4
>

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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
@ 2020-02-23 16:02   ` Allison Collins
  2020-02-24  6:30     ` Amir Goldstein
  2020-02-24  8:31   ` Chandan Rajendra
  2020-02-25  9:52   ` Dave Chinner
  2 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23 16:02 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 12:55 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> Hi all,
>>
>> This set is a subset of a larger series for delayed attributes. Which is
>> a subset of an even larger series, parent pointers. Delayed attributes
>> allow attribute operations (set and remove) to be logged and committed
>> in the same way that other delayed operations do. This allows more
>> complex operations (like parent pointers) to be broken up into multiple
>> smaller transactions. To do this, the existing attr operations must be
>> modified to operate as either a delayed operation or a inline operation
>> since older filesystems will not be able to use the new log entries.
> 
> High level question, before I dive into the series:
> 
> Which other "delayed operations" already exist?
> I think delayed operations were added by Darrick to handle the growth of
> translation size due to reflink. Right? So I assume the existing delayed
> operations deal with block accounting.
Gosh, quite a few I think, but I'm not solid on what they all do.  If we 
take a peek at XFS_LI_TYPE_DESC, theres an identifier for each type, to 
give you an idea.  A lot of them do look like they are part of reflink 
operations though.

> When speaking of parent pointers, without having looked into the details yet,
> it seem the delayed operations we would want to log are operations that deal
> with namespace changes, i.e.: link,unlink,rename.
> The information needed to be logged for these ops is minimal.
> Why do we need a general infrastructure for delayed attr operations?
> 
> Thanks,
> Amir.
> 
Great question, this one goes back a ways.  I believe the train of logic 
we had is that because parent pointers also include the filename of the 
parent, its possible we can end up with really big attributes.  Which 
may run into a lot of block map/unmap activity for name space changes. 
We didnt want to end up with overly large transactions in the log, so we 
wanted to break them up by returning -EAGAIN where ever the transactions 
used to be rolled.  I'm pretty sure that covers a quick high level 
history of where we are now?  Did that answer your question?

Allison



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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23  9:34   ` Amir Goldstein
@ 2020-02-23 16:03     ` Allison Collins
  2020-02-25  0:49       ` Dave Chinner
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23 16:03 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 2:34 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> This patch replaces the attribute name and length parameters with a single struct
>> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
>> around and pre-simplifies the code some.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> I realize I am joining very late with lots of reviewed-by already applied,
> so unless I find anything big, please regard my comments and possible
> future improvements for the extended series rather than objections to this
> pretty much baked patch set.
Sure, no worries, it has a lot of history to keep track of.

> 
> [...]
> 
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index d42de92..28c07c9 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
>>   {
>>          unsigned char           *kbuf;
>>          int                     error = -EFAULT;
>> -       size_t                  namelen;
>> +       struct xfs_name         xname;
>> +
>> +       xfs_name_init(&xname, name);
>>
>>          if (*len > XFS_XATTR_SIZE_MAX)
>>                  return -EINVAL;
>> @@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
>>          if (!kbuf)
>>                  return -ENOMEM;
>>
>> -       namelen = strlen(name);
>> -       error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
>> -                            flags);
>> +       error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>>          if (error)
>>                  goto out_kfree;
>>
>> @@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
>>   {
>>          unsigned char           *kbuf;
>>          int                     error;
>> -       size_t                  namelen;
>> +       struct xfs_name         xname;
>> +
>> +       xfs_name_init(&xname, name);
>>
>>          if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>                  return -EPERM;
>> @@ -400,8 +402,7 @@ 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);
>> +       error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>>          if (!error)
>>                  xfs_forget_acl(inode, name, flags);
>>          kfree(kbuf);
>> @@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
>>          uint32_t                flags)
>>   {
>>          int                     error;
>> -       size_t                  namelen;
>> +       struct xfs_name         xname;
>> +
>> +       xfs_name_init(&xname, name);
>>
>>          if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>                  return -EPERM;
>> -       namelen = strlen(name);
>> -       error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
>> +
>> +       error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>>          if (!error)
>>                  xfs_forget_acl(inode, name, flags);
>>          return error;
> 
> 
> A struct inititializer macro would have been nice, so code like this:
> 
> +       struct xfs_name         xname;
> +
> +       xfs_name_init(&xname, name);
> 
> Would become:
> +       struct xfs_name         xname = XFS_NAME_STR_INIT(name);
> 
> As a matter of fact, in most of the cases a named local variable is
> not needed at
> all and the code could be written with an anonymous local struct variable macro:
> 
> +       error = xfs_attr_remove(XFS_I(inode), XFS_NAME_STR(name), flags);
> 
The macro does look nice.  I would be the third iteration of 
initializers that this patch has been through though.  Can I get a 
consensus of how many people like the macro?

Allison

> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23 11:54   ` Amir Goldstein
@ 2020-02-23 16:51     ` Allison Collins
  2020-02-24  6:50       ` Amir Goldstein
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23 16:51 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 4:54 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> This patch embeds an xfs_name in xfs_da_args, replacing the name, namelen, and flags
>> members.  This helps to clean up the xfs_da_args structure and make it more uniform
>> with the new xfs_name parameter being passed around.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>   fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>   fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>   fs/xfs/scrub/attr.c             |  12 ++---
>>   fs/xfs/xfs_trace.h              |  20 ++++----
>>   12 files changed, 130 insertions(+), 123 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 6717f47..9acdb23 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>          args->geo = dp->i_mount->m_attr_geo;
>>          args->whichfork = XFS_ATTR_FORK;
>>          args->dp = dp;
>> -       args->flags = flags;
>> -       args->name = name->name;
>> -       args->namelen = name->len;
>> -       if (args->namelen >= MAXNAMELEN)
>> +       memcpy(&args->name, name, sizeof(struct xfs_name));
> 
> Maybe xfs_name_copy and xfs_name_equal are in order?
You are suggesting to add xfs_name_copy and xfs_name_equal helpers?  I'm 
not sure there's a use case yet for xfs_name_equal, at least not in this 
set.  And I think people indicated that they preferred the memcpy in 
past reviews rather than handling each member of the xfs_name struct. 
Unless I misunderstood the question, I'm not sure there is much left for 
a xfs_name_copy helper to cover that the memcpy does not?

> 
>>
>> +       /* Use name now stored in args */
>> +       name = &args.name;
>> +
> 
> It seem that the context of these comments be clear in the future.
You are asking to add more context to the comment?  How about:
	/*
	 * Use name now stored in args.  Abandon the local name 	
	 * parameter as it will not be updated in the subroutines
	 */

Does that help some?

> 
>>          args.value = value;
>>          args.valuelen = valuelen;
>>          args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
>> @@ -372,7 +374,7 @@ xfs_attr_set(
>>           */
>>          if (XFS_IFORK_Q(dp) == 0) {
>>                  int sf_size = sizeof(xfs_attr_sf_hdr_t) +
>> -                       XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
>> +                       XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
>>
>>                  error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>>                  if (error)
>> @@ -457,6 +459,9 @@ xfs_attr_remove(
>>          if (error)
>>                  return error;
>>
>> +       /* Use name now stored in args */
>> +       name = &args.name;
>> +
>>          /*
>>           * we have no control over the attribute names that userspace passes us
>>           * to remove, so we have to allow the name lookup prior to attribute
>> @@ -532,10 +537,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>>          trace_xfs_attr_sf_addname(args);
>>
>>          retval = xfs_attr_shortform_lookup(args);
>> -       if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> +       if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>                  return retval;
>>          } else if (retval == -EEXIST) {
>> -               if (args->flags & ATTR_CREATE)
>> +               if (args->name.type & ATTR_CREATE)
>>                          return retval;
>>                  retval = xfs_attr_shortform_remove(args);
>>                  if (retval)
>> @@ -545,15 +550,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;
> 
> 
> This doesn't look good it looks like a hack.
> 
> Even if want to avoid growing struct xfs_name we can store two shorts instead
> of overloading int type with flags.
> type doesn't even need more than a single byte, because XFS_DIR3_FT_WHT
> is not used and will never be used on-disk.
> 
> Thanks,
> Amir.
> 
The exact use of .type has gone around a few times since this patch 
started, which was actually all the way back in parent pointers.  :-) 
Initially the xfs_name struct replaced anything that passed all three 
parameters, and then later we decided that flags should stay separate 
for top level get/set/remove routines, but become integrated below the 
*_args routines.  I don't recall people being concerned about growing 
the struct, though a union seems reasonable to resolve the naming 
weirdness.  I would like to have a little more feedback from folks 
though just to make sure everyones in agreement since this one's gone 
through quite few reviews already. Thanks all!

Allison

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23 12:20   ` Amir Goldstein
@ 2020-02-23 17:28     ` Allison Collins
  2020-02-24  6:58       ` Amir Goldstein
  2020-02-25  6:26     ` Dave Chinner
  1 sibling, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23 17:28 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 5:20 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
>> routines later for delayed attributes since delayed operations cannot return error
>> codes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>>   4 files changed, 188 insertions(+), 98 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9acdb23..2255060 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>
>>   /*
>>    * Internal routines when attribute list is more than one block.
>> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>> +                                struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>
>> @@ -310,6 +313,37 @@ xfs_attr_set_args(
>>   }
>>
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
> 
> This is a very silly return value for a function named has_attr in my taste.
> I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
> IMO this change looks like a very good opportunity to change that internal
> API:
> 
> xfs_has_attr?
> 
> 0: NO
> 1: YES (or stay with the syscall standard of -ENOATTR)
> <0: error
Darrick had mentioned something like that in the last revision, but I 
think people wanted to keep everything a straight hoist at this phase. 
At least as much as possible.  Maybe I can add another patch that does 
this at the end when we're doing clean ups.

Allison

> 
>> + */
>> +int
>> +xfs_has_attr(
>> +       struct xfs_da_args      *args)
>> +{
>> +       struct xfs_inode        *dp = args->dp;
>> +       struct xfs_buf          *bp = NULL;
>> +       int                     error;
>> +
>> +       if (!xfs_inode_hasattr(dp))
>> +               return -ENOATTR;
>> +
>> +       if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +               ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +               return xfs_attr_sf_findname(args, NULL, NULL);
>> +       }
>> +
>> +       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +               error = xfs_attr_leaf_hasname(args, &bp);
>> +
>> +               if (bp)
>> +                       xfs_trans_brelse(args->trans, bp);
>> +
>> +               return error;
>> +       }
>> +
>> +       return xfs_attr_node_hasname(args, NULL);
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
>> @@ -583,26 +617,20 @@ STATIC int
>>   xfs_attr_leaf_addname(
>>          struct xfs_da_args      *args)
>>   {
>> -       struct xfs_inode        *dp;
>>          struct xfs_buf          *bp;
>>          int                     retval, error, forkoff;
>> +       struct xfs_inode        *dp = args->dp;
>>
>>          trace_xfs_attr_leaf_addname(args);
>>
>>          /*
>> -        * Read the (only) block in the attribute list in.
>> -        */
>> -       dp = args->dp;
>> -       args->blkno = 0;
>> -       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -       if (error)
>> -               return error;
>> -
>> -       /*
>>           * Look up the given attribute in the leaf block.  Figure out if
>>           * the given flags produce an error or call for an atomic rename.
>>           */
>> -       retval = xfs_attr3_leaf_lookup_int(bp, args);
>> +       retval = xfs_attr_leaf_hasname(args, &bp);
>> +       if (retval != -ENOATTR && retval != -EEXIST)
>> +               return retval;
>> +
>>          if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> 
> Example of how sane code (in my taste) would look like:
> 
>         retval = xfs_attr_leaf_hasname(args, &bp);
>         if (retval < 0)
>                 return retval;
> 
>          if ((args->name.type & ATTR_REPLACE) && !retval) {
>                   xfs_trans_brelse(args->trans, bp);
>                   return -ENOATTR;
>          } else if (retval) {
>                  if (args->flags & ATTR_CREATE) {        /* pure create op */
>                          xfs_trans_brelse(args->trans, bp);
>                          return -EEXIST;
>                 }
> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST
  2020-02-23 12:25   ` Amir Goldstein
@ 2020-02-23 17:33     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 17:33 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs

On 2/23/20 5:25 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> Delayed operations cannot return error codes.  So we must check for these conditions
>> first before starting set or remove operations
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 12 ++++++++++++
>>   1 file changed, 12 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 2255060..a2f812f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -437,6 +437,14 @@ xfs_attr_set(
>>                  goto out_trans_cancel;
>>
>>          xfs_trans_ijoin(args.trans, dp, 0);
>> +
>> +       error = xfs_has_attr(&args);
>> +       if (error == -EEXIST && (name->type & ATTR_CREATE))
>> +               goto out_trans_cancel;
>> +
>> +       if (error == -ENOATTR && (name->type & ATTR_REPLACE))
>> +               goto out_trans_cancel;
>> +
> 
> And we do care about other errors?

I guess they would surface during the set operation as they do now, 
though it's probably better to catch it here.  Will add!  Thanks!

Allison

> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
  2020-02-23 12:30   ` Amir Goldstein
@ 2020-02-23 17:36     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 17:36 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 5:30 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> Since delayed operations cannot roll transactions, factor up the transaction
>> handling into the calling function
> 
> I am not a native English speaker, so not sure what the correct phrase is,
> but I'm pretty sure its not factor up, nor factor out???
Sorry, I got used to this usage on another team though only recently 
have people mention they thought it odd.  I meant to clean them out and 
must of missed this one.  Will remove.

Allison

> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  7 +------
>>   2 files changed, 15 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index a2f812f..cf0cba7 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -739,6 +739,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
>> @@ -1081,6 +1088,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 9d6b68c..d691509 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
>>                           XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>>          }
>>
>> -       /*
>> -        * Commit the flag value change and start the next trans in series.
>> -        */
>> -       error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -
>> -       return error;
>> +       return 0;
>>   }
>> --
>> 2.7.4
>>

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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-23 13:04   ` Amir Goldstein
@ 2020-02-23 17:51     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 17:51 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 6:04 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
> 
> typo: transacation
Will fix :-)
> 
> 
>> while modularizing the adjacent code down into helpers. In this patch, hoist the
>> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
>> attr list creation down.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
> 
> And I don't think the subject (Refactoring) is a reliable description
> of this change,
> but if nobody else cares, I don't mind what you call it.
Yes, I struggled with that a bit since things are just generally being 
re-arranged, but if there's a more descriptive term folks prefer, please 
call it out.

> 
> As far as not changing logic, you may add:
> 
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Thanks!

Allison

> 
> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23 12:42   ` Amir Goldstein
@ 2020-02-23 18:38     ` Allison Collins
  2020-02-24  6:38       ` Amir Goldstein
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-23 18:38 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs

On 2/23/20 5:42 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> Factor out new helper function xfs_attr_leaf_try_add.
> 
> Right. This should be the subject.
> Not factor out xfs_attr_leaf_addname helper.
> 
>> Because new delayed attribute
>> routines cannot roll transactions, we carve off the parts of xfs_attr_leaf_addname
>> that we can use, and move the commit into the calling function.
> 
> And that is a different change.
> It is hard enough to review a pure factor out of a helper.
> Adding changed inside a pure re-factor is not good.
> 
> Belongs to another change - move transaction commit to caller.

Yes, this came up in the last review, but the reason I avoid it is 
because I think the transaction looks weird in either helper.  The 
reason the roll is here is because there is no room to add the attr as a 
leaf, and so we need to hand it off to the node subroutines.  But that 
seems like something that should be managed by the caller, not leaf 
helpers.  So I was concerned that separating the split and the hoist 
would generate more weird looks from people trying to understand the 
split until the see the hoist in the next patch.  If people really think 
it looks better that way, I can split them up.  But I know folks have a 
tough enough time trying to recall the discussion history, so I'm trying 
to avoid confusion of another type :-)

Thoughts?

Allison

> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink
  2020-02-23 13:22   ` Amir Goldstein
@ 2020-02-23 18:41     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 18:41 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs

On 2/23/20 6:22 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> This patch adds a new helper function xfs_attr_node_shrink used to shrink an
>> attr name into an inode if it is small enough.  This helps to modularize
>> the greater calling function xfs_attr_node_removename.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 66 +++++++++++++++++++++++++++++-------------------
>>   1 file changed, 40 insertions(+), 26 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 4b788f2..30a16fe 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1366,6 +1366,43 @@ xfs_attr_node_addname(
>>   }
>>
>>   /*
>> + * Shrink an attribute from leaf to shortform
>> + */
>> +STATIC int
>> +xfs_attr_node_shrink(
>> +       struct xfs_da_args      *args,
>> +       struct xfs_da_state     *state)
>> +{
>> +       struct xfs_inode        *dp = args->dp;
>> +       int                     error, forkoff;
>> +       struct xfs_buf          *bp;
>> +
>> +       /*
>> +        * 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, &bp);
>> +       if (error)
>> +               return error;
>> +
>> +       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)
>> +                       return error;
>> +
>> +               args->dac.flags |= XFS_DAC_FINISH_TRANS;
> 
> Why did xfs_defer_finish(&args->trans); turn into the above?
> 
> Are you testing reviewers alertness? ;-)
> Please keep logic preserving patches separate from logic change patches.
You're right, I missed this when I was separating it from the previous 
patch.  Will correct.  Thanks for the catch!

Allison

> 
> Thanks,
> Amir.
> 
>> +       } else
>> +               xfs_trans_brelse(args->trans, bp);
>> +
>> +       return 0;
>> +}
>> +
>> +/*
>>    * Remove a name from a B-tree attribute list.
>>    *
>>    * This will involve walking down the Btree, and may involve joining
>> @@ -1383,8 +1420,7 @@ xfs_attr_node_removename(
>>   {
>>          struct xfs_da_state     *state;
>>          struct xfs_da_state_blk *blk;
>> -       struct xfs_buf          *bp;
>> -       int                     retval, error, forkoff;
>> +       int                     retval, error;
>>          struct xfs_inode        *dp = args->dp;
>>
>>          trace_xfs_attr_node_removename(args);
>> @@ -1493,30 +1529,8 @@ xfs_attr_node_removename(
>>          /*
>>           * 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, &bp);
>> -               if (error)
>> -                       goto out;
>> -
>> -               if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -                       error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -                       /* bp is gone due to xfs_da_shrink_inode */
>> -                       if (error)
>> -                               goto out;
>> -                       error = xfs_defer_finish(&args->trans);
>> -                       if (error)
>> -                               goto out;
>> -               } else
>> -                       xfs_trans_brelse(args->trans, bp);
>> -       }
>> -       error = 0;
>> +       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> +               error = xfs_attr_node_shrink(args, state);
>>
>>   out:
>>          if (state)
>> --
>> 2.7.4
>>

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-23 13:26   ` Amir Goldstein
@ 2020-02-23 18:42     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 18:42 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 6:26 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> Delayed attribute mechanics make frequent use of goto statements.  We can use this
>> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
>> conditions, we can invert the if logic and jump to the goto. This helps to reduce
>> indentation and simplify things.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks better IMO and doesn't change logic.
> 
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Alrighty, thanks!

Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>>   1 file changed, 42 insertions(+), 29 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 30a16fe..dd935ff 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>>   }
>>
>>   /*
>> + * Check to see if the attr should be upgraded from non-existent or shortform to
>> + * single-leaf-block attribute list.
>> + */
>> +static inline bool
>> +xfs_attr_fmt_needs_update(
>> +       struct xfs_inode    *dp)
>> +{
>> +       return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> +             (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> +             dp->i_d.di_anextents == 0);
>> +}
>> +
>> +/*
>>    * Set the attribute specified in @args.
>>    */
>>   int
>> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>>          }
>>
>>          /*
>> -        * If the attribute list is non-existent or a shortform list,
>> -        * upgrade it to a single-leaf-block attribute list.
>> +        * If the attribute list is already in leaf format, jump straight to
>> +        * leaf handling.  Otherwise, try to add the attribute to the shortform
>> +        * list; if there's no room then convert the list to leaf format and try
>> +        * again.
>>           */
>> -       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)) {
>> +       if (!xfs_attr_fmt_needs_update(dp))
>> +               goto add_leaf;
>>
>> -               /*
>> -                * Try to add the attr to the attribute list in the inode.
>> -                */
>> -               error = xfs_attr_try_sf_addname(dp, args);
>> +       /*
>> +        * Try to add the attr to the attribute list in the inode.
>> +        */
>> +       error = xfs_attr_try_sf_addname(dp, args);
>>
>> -               /* Should only be 0, -EEXIST or ENOSPC */
>> -               if (error != -ENOSPC)
>> -                       return error;
>> +       /* Should only be 0, -EEXIST or ENOSPC */
>> +       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;
>> +       /*
>> +        * 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);
>> -               args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> -               args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> -               return -EAGAIN;
>> -       }
>> +       /*
>> +        * 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);
>> +       args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +       args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> +       return -EAGAIN;
>>
>>   add_leaf:
>>
>> --
>> 2.7.4
>>

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

* Re: [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-23 13:47   ` Amir Goldstein
@ 2020-02-23 18:43     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 18:43 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 6:47 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> This patch helps to simplify xfs_attr_node_removename by modularizing the code
>> around the transactions into helper functions.  This will make the function easier
>> to follow when we introduce delayed attributes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Found no surprises here, you may add:
> 
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> 
> Thanks,
> Amir.

Alrighty then.  Thank you!

Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 45 +++++++++++++++++++++++++++++++--------------
>>   1 file changed, 31 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index dd935ff..b9728d1 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
>>   }
>>
>>   /*
>> + * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
>> + * for later deletion of the entry.
>> + */
>> +STATIC int
>> +xfs_attr_leaf_mark_incomplete(
>> +       struct xfs_da_args      *args,
>> +       struct xfs_da_state     *state)
>> +{
>> +       int error;
>> +
>> +       /*
>> +        * 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)
>> +               return error;
>> +
>> +       /*
>> +        * Mark the attribute as INCOMPLETE
>> +        */
>> +       error = xfs_attr3_leaf_setflag(args);
>> +       if (error)
>> +               return error;
>> +
>> +       return 0;
>> +}
>> +
>> +/*
>>    * Remove a name from a B-tree attribute list.
>>    *
>>    * This will involve walking down the Btree, and may involve joining
>> @@ -1473,20 +1503,7 @@ xfs_attr_node_removename(
>>          args->dac.da_state = state;
>>
>>          if (args->rmtblkno > 0) {
>> -               /*
>> -                * 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);
>> +               error = xfs_attr_leaf_mark_incomplete(args, state);
>>                  if (error)
>>                          goto out;
>>
>> --
>> 2.7.4
>>

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

* Re: [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove
  2020-02-23 13:54   ` Amir Goldstein
@ 2020-02-23 18:50     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-23 18:50 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 6:54 AM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> xfs_attr_rmtval_remove is no longer used.  Clear it out now
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Patch 12/19 add a new function similar to this one called
> xfs_attr_rmtval_unmap() and now this function is removed.
> I wonder if it wouldn't have been simpler to keep the original function
> name and change its behavior to that of xfs_attr_rmtval_unmap().
I thought about this, but then decided against it.  Really what's 
happening is that the original function disappears across patches 13 and 
14, and I wanted to keep those patches focused on the state machine 
rather than lumping the helpers in with it.

> 
> Unless the function name change makes the logic change more clear
> for the future users???

I think they are about equivalent myself.  But the name difference helps 
the old function to stick around until it is completely phased out.  If 
folks feel strongly though, please chime in :-)

Thanks for the reviews!  I know it's a lot!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr_remote.c | 42 -----------------------------------------
>>   fs/xfs/xfs_trace.h              |  1 -
>>   2 files changed, 43 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index a0e79db..0cc0ec1 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -734,48 +734,6 @@ xfs_attr_rmtval_invalidate(
>>   }
>>
>>   /*
>> - * Remove the value associated with an attribute by deleting the
>> - * out-of-line buffer that it is stored on.
>> - */
>> -int
>> -xfs_attr_rmtval_remove(
>> -       struct xfs_da_args      *args)
>> -{
>> -       xfs_dablk_t             lblkno;
>> -       int                     blkcnt;
>> -       int                     error = 0;
>> -       int                     done = 0;
>> -
>> -       trace_xfs_attr_rmtval_remove(args);
>> -
>> -       error = xfs_attr_rmtval_invalidate(args);
>> -       if (error)
>> -               return error;
>> -       /*
>> -        * Keep de-allocating extents until the remote-value region is gone.
>> -        */
>> -       lblkno = args->rmtblkno;
>> -       blkcnt = args->rmtblkcnt;
>> -       while (!done) {
>> -               error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
>> -                                   XFS_BMAPI_ATTRFORK, 1, &done);
>> -               if (error)
>> -                       return error;
>> -               error = xfs_defer_finish(&args->trans);
>> -               if (error)
>> -                       return error;
>> -
>> -               /*
>> -                * Close out trans and start the next one in the chain.
>> -                */
>> -               error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -               if (error)
>> -                       return error;
>> -       }
>> -       return 0;
>> -}
>> -
>> -/*
>>    * Remove the value associated with an attribute by deleting the out-of-line
>>    * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
>>    * transaction and recall the function
>> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
>> index 159b8af..bf9a683 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -1775,7 +1775,6 @@ DEFINE_ATTR_EVENT(xfs_attr_refillstate);
>>
>>   DEFINE_ATTR_EVENT(xfs_attr_rmtval_get);
>>   DEFINE_ATTR_EVENT(xfs_attr_rmtval_set);
>> -DEFINE_ATTR_EVENT(xfs_attr_rmtval_remove);
>>
>>   #define DEFINE_DA_EVENT(name) \
>>   DEFINE_EVENT(xfs_da_class, name, \
>> --
>> 2.7.4
>>

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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-23 16:02   ` Allison Collins
@ 2020-02-24  6:30     ` Amir Goldstein
  2020-02-24 16:23       ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  6:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 6:02 PM Allison Collins
<allison.henderson@oracle.com> wrote:
>
>
>
> On 2/23/20 12:55 AM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
> > <allison.henderson@oracle.com> wrote:
> >>
> >> Hi all,
> >>
> >> This set is a subset of a larger series for delayed attributes. Which is
> >> a subset of an even larger series, parent pointers. Delayed attributes
> >> allow attribute operations (set and remove) to be logged and committed
> >> in the same way that other delayed operations do. This allows more
> >> complex operations (like parent pointers) to be broken up into multiple
> >> smaller transactions. To do this, the existing attr operations must be
> >> modified to operate as either a delayed operation or a inline operation
> >> since older filesystems will not be able to use the new log entries.
> >
> > High level question, before I dive into the series:
> >
> > Which other "delayed operations" already exist?
> > I think delayed operations were added by Darrick to handle the growth of
> > translation size due to reflink. Right? So I assume the existing delayed
> > operations deal with block accounting.
> Gosh, quite a few I think, but I'm not solid on what they all do.  If we
> take a peek at XFS_LI_TYPE_DESC, theres an identifier for each type, to
> give you an idea.  A lot of them do look like they are part of reflink
> operations though.
>
> > When speaking of parent pointers, without having looked into the details yet,
> > it seem the delayed operations we would want to log are operations that deal
> > with namespace changes, i.e.: link,unlink,rename.
> > The information needed to be logged for these ops is minimal.
> > Why do we need a general infrastructure for delayed attr operations?
> >
> > Thanks,
> > Amir.
> >
> Great question, this one goes back a ways.  I believe the train of logic
> we had is that because parent pointers also include the filename of the
> parent, its possible we can end up with really big attributes.  Which
> may run into a lot of block map/unmap activity for name space changes.
> We didnt want to end up with overly large transactions in the log, so we
> wanted to break them up by returning -EAGAIN where ever the transactions
> used to be rolled.  I'm pretty sure that covers a quick high level
> history of where we are now?  Did that answer your question?
>

Partly.
My question was like this:
It seems that your work is about implementing:
[intent to set xattr <new parent inode,gen,offset> <new name>]
[intent to remove xattr <old parent inode,gen,offset> <old name>]

While at a high level what the user really *intents* to do is:
[intent to link <inode> to <new parent inode>;<new name>]
[intent to unlink <inode> from <old parent inode>;<old name>]

I guess the log item sizes of the two variants is quite similar, so it
doesn't make much of a difference and deferred xattr ops are more
generic and may be used for other things in the future.

Another thing is that the transaction space required from directory
entry changes is (probably) already taken into account correctly
in the code, so there is no need to worry about deferred namespace
operations from that aspect, but from a pure design perspective,
if namespace operations become complex, *they* are the ones
that should be made into deferred operations.

Or maybe I am not reading the situations correctly at all...

Thanks,
Amir.

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23 18:38     ` Allison Collins
@ 2020-02-24  6:38       ` Amir Goldstein
  2020-02-24  7:09         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  6:38 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 8:38 PM Allison Collins
<allison.henderson@oracle.com> wrote:
>
> On 2/23/20 5:42 AM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > <allison.henderson@oracle.com> wrote:
> >>
> >> Factor out new helper function xfs_attr_leaf_try_add.
> >
> > Right. This should be the subject.
> > Not factor out xfs_attr_leaf_addname helper.
> >
> >> Because new delayed attribute
> >> routines cannot roll transactions, we carve off the parts of xfs_attr_leaf_addname
> >> that we can use, and move the commit into the calling function.
> >
> > And that is a different change.
> > It is hard enough to review a pure factor out of a helper.
> > Adding changed inside a pure re-factor is not good.
> >
> > Belongs to another change - move transaction commit to caller.
>
> Yes, this came up in the last review, but the reason I avoid it is
> because I think the transaction looks weird in either helper.  The
> reason the roll is here is because there is no room to add the attr as a
> leaf, and so we need to hand it off to the node subroutines.  But that
> seems like something that should be managed by the caller, not leaf
> helpers.  So I was concerned that separating the split and the hoist
> would generate more weird looks from people trying to understand the
> split until the see the hoist in the next patch.  If people really think
> it looks better that way, I can split them up.  But I know folks have a
> tough enough time trying to recall the discussion history, so I'm trying
> to avoid confusion of another type :-)
>
> Thoughts?
>

It's fine, so long as you document it properly in commit message.
See, we are so bad in this review process, that we rely on humans
to verify that logic preserving re-factoring patches are indeed logic
preserving. This is so lame to begin with, because there are static
checker bots out there that would gladly do that work for us :) ...
if we only annotated the logic preserving patches as such.
In the mean while, while we are substituting the review robots,
the least a developer could do is not call out a patch "re-factoring"
and sneak in a logic change without due notice to reviewers.

Thanks,
Amir.

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23 16:51     ` Allison Collins
@ 2020-02-24  6:50       ` Amir Goldstein
  2020-02-24  7:36         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  6:50 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 6:51 PM Allison Collins
<allison.henderson@oracle.com> wrote:
>
>
>
> On 2/23/20 4:54 AM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > <allison.henderson@oracle.com> wrote:
> >>
> >> This patch embeds an xfs_name in xfs_da_args, replacing the name, namelen, and flags
> >> members.  This helps to clean up the xfs_da_args structure and make it more uniform
> >> with the new xfs_name parameter being passed around.
> >>
> >> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> >> Reviewed-by: Brian Foster <bfoster@redhat.com>
> >> ---
> >>   fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
> >>   fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
> >>   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
> >>   fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
> >>   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
> >>   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
> >>   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
> >>   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
> >>   fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
> >>   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
> >>   fs/xfs/scrub/attr.c             |  12 ++---
> >>   fs/xfs/xfs_trace.h              |  20 ++++----
> >>   12 files changed, 130 insertions(+), 123 deletions(-)
> >>
> >> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >> index 6717f47..9acdb23 100644
> >> --- a/fs/xfs/libxfs/xfs_attr.c
> >> +++ b/fs/xfs/libxfs/xfs_attr.c
> >> @@ -72,13 +72,12 @@ xfs_attr_args_init(
> >>          args->geo = dp->i_mount->m_attr_geo;
> >>          args->whichfork = XFS_ATTR_FORK;
> >>          args->dp = dp;
> >> -       args->flags = flags;
> >> -       args->name = name->name;
> >> -       args->namelen = name->len;
> >> -       if (args->namelen >= MAXNAMELEN)
> >> +       memcpy(&args->name, name, sizeof(struct xfs_name));
> >
> > Maybe xfs_name_copy and xfs_name_equal are in order?
> You are suggesting to add xfs_name_copy and xfs_name_equal helpers?  I'm
> not sure there's a use case yet for xfs_name_equal, at least not in this
> set.  And I think people indicated that they preferred the memcpy in
> past reviews rather than handling each member of the xfs_name struct.
> Unless I misunderstood the question, I'm not sure there is much left for
> a xfs_name_copy helper to cover that the memcpy does not?
>

It's fine. The choice between xfs_name_copy and memcpy is
mostly personal taste. I did not read through past reviews.

> >
> >>
> >> +       /* Use name now stored in args */
> >> +       name = &args.name;
> >> +
> >
> > It seem that the context of these comments be clear in the future.
> You are asking to add more context to the comment?  How about:
>         /*
>          * Use name now stored in args.  Abandon the local name
>          * parameter as it will not be updated in the subroutines
>          */
>
> Does that help some?

Can't you just not use local name arg anymore?
Instead of re-assigning it and explaining why you do that.
Does that gain anything to code readability or anything else?

Thanks,
Amir.

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23 17:28     ` Allison Collins
@ 2020-02-24  6:58       ` Amir Goldstein
  0 siblings, 0 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  6:58 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sun, Feb 23, 2020 at 7:28 PM Allison Collins
<allison.henderson@oracle.com> wrote:
>
>
>
> On 2/23/20 5:20 AM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > <allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
> >> routines later for delayed attributes since delayed operations cannot return error
> >> codes.
> >>
> >> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> >> ---
> >>   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> >>   fs/xfs/libxfs/xfs_attr.h      |   1 +
> >>   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> >>   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> >>   4 files changed, 188 insertions(+), 98 deletions(-)
> >>
> >> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >> index 9acdb23..2255060 100644
> >> --- a/fs/xfs/libxfs/xfs_attr.c
> >> +++ b/fs/xfs/libxfs/xfs_attr.c
> >> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> >> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> >>
> >>   /*
> >>    * Internal routines when attribute list is more than one block.
> >> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> >>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> >> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> >> +                                struct xfs_da_state **state);
> >>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> >>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> >>
> >> @@ -310,6 +313,37 @@ xfs_attr_set_args(
> >>   }
> >>
> >>   /*
> >> + * Return EEXIST if attr is found, or ENOATTR if not
> >
> > This is a very silly return value for a function named has_attr in my taste.
> > I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
> > IMO this change looks like a very good opportunity to change that internal
> > API:
> >
> > xfs_has_attr?
> >
> > 0: NO
> > 1: YES (or stay with the syscall standard of -ENOATTR)
> > <0: error
> Darrick had mentioned something like that in the last revision, but I
> think people wanted to keep everything a straight hoist at this phase.
> At least as much as possible.  Maybe I can add another patch that does
> this at the end when we're doing clean ups.

In my opinion, this change is hard enough to follow as is.
Making the interface cleaner at this point is not going to make
following the change any harder if anything I thing a clean interface
that makes sense, will make things easier at this point.
But whether you do it now or later, the interface was very bad IMO before
and when attached to a helper named has_attr makes it much worse.

Thanks,
Amir.

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-24  6:38       ` Amir Goldstein
@ 2020-02-24  7:09         ` Allison Collins
  2020-02-24  7:27           ` Amir Goldstein
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-24  7:09 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 11:38 PM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 8:38 PM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>> On 2/23/20 5:42 AM, Amir Goldstein wrote:
>>> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
>>> <allison.henderson@oracle.com> wrote:
>>>>
>>>> Factor out new helper function xfs_attr_leaf_try_add.
>>>
>>> Right. This should be the subject.
>>> Not factor out xfs_attr_leaf_addname helper.
>>>
>>>> Because new delayed attribute
>>>> routines cannot roll transactions, we carve off the parts of xfs_attr_leaf_addname
>>>> that we can use, and move the commit into the calling function.
>>>
>>> And that is a different change.
>>> It is hard enough to review a pure factor out of a helper.
>>> Adding changed inside a pure re-factor is not good.
>>>
>>> Belongs to another change - move transaction commit to caller.
>>
>> Yes, this came up in the last review, but the reason I avoid it is
>> because I think the transaction looks weird in either helper.  The
>> reason the roll is here is because there is no room to add the attr as a
>> leaf, and so we need to hand it off to the node subroutines.  But that
>> seems like something that should be managed by the caller, not leaf
>> helpers.  So I was concerned that separating the split and the hoist
>> would generate more weird looks from people trying to understand the
>> split until the see the hoist in the next patch.  If people really think
>> it looks better that way, I can split them up.  But I know folks have a
>> tough enough time trying to recall the discussion history, so I'm trying
>> to avoid confusion of another type :-)
>>
>> Thoughts?
>>
> 
> It's fine, so long as you document it properly in commit message.
> See, we are so bad in this review process, that we rely on humans
> to verify that logic preserving re-factoring patches are indeed logic
> preserving. This is so lame to begin with, because there are static
> checker bots out there that would gladly do that work for us :) ...
I didnt know there were tools out there that did that.  They sound 
helpful though!

> if we only annotated the logic preserving patches as such.
> In the mean while, while we are substituting the review robots,
> the least a developer could do is not call out a patch "re-factoring"
> and sneak in a logic change without due notice to reviewers.
Ok, what if the title were to say something like:
xfs: Split out node handling from xfs_attr_leaf_addname

Or maybe just "Split apart xfs_attr_leaf_addname"?  Does that sound like 
it would be a better description here?

Thanks!
Allison

> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-24  7:09         ` Allison Collins
@ 2020-02-24  7:27           ` Amir Goldstein
  0 siblings, 0 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  7:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 9:09 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
>
>
> On 2/23/20 11:38 PM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 8:38 PM Allison Collins
> > <allison.henderson@oracle.com> wrote:
> >>
> >> On 2/23/20 5:42 AM, Amir Goldstein wrote:
> >>> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> >>> <allison.henderson@oracle.com> wrote:
> >>>>
> >>>> Factor out new helper function xfs_attr_leaf_try_add.
> >>>
> >>> Right. This should be the subject.
> >>> Not factor out xfs_attr_leaf_addname helper.
> >>>
> >>>> Because new delayed attribute
> >>>> routines cannot roll transactions, we carve off the parts of xfs_attr_leaf_addname
> >>>> that we can use, and move the commit into the calling function.
> >>>
> >>> And that is a different change.
> >>> It is hard enough to review a pure factor out of a helper.
> >>> Adding changed inside a pure re-factor is not good.
> >>>
> >>> Belongs to another change - move transaction commit to caller.
> >>
> >> Yes, this came up in the last review, but the reason I avoid it is
> >> because I think the transaction looks weird in either helper.  The
> >> reason the roll is here is because there is no room to add the attr as a
> >> leaf, and so we need to hand it off to the node subroutines.  But that
> >> seems like something that should be managed by the caller, not leaf
> >> helpers.  So I was concerned that separating the split and the hoist
> >> would generate more weird looks from people trying to understand the
> >> split until the see the hoist in the next patch.  If people really think
> >> it looks better that way, I can split them up.  But I know folks have a
> >> tough enough time trying to recall the discussion history, so I'm trying
> >> to avoid confusion of another type :-)
> >>
> >> Thoughts?
> >>
> >
> > It's fine, so long as you document it properly in commit message.
> > See, we are so bad in this review process, that we rely on humans
> > to verify that logic preserving re-factoring patches are indeed logic
> > preserving. This is so lame to begin with, because there are static
> > checker bots out there that would gladly do that work for us :) ...
> I didnt know there were tools out there that did that.  They sound
> helpful though!
>
> > if we only annotated the logic preserving patches as such.
> > In the mean while, while we are substituting the review robots,
> > the least a developer could do is not call out a patch "re-factoring"
> > and sneak in a logic change without due notice to reviewers.
> Ok, what if the title were to say something like:
> xfs: Split out node handling from xfs_attr_leaf_addname
>
> Or maybe just "Split apart xfs_attr_leaf_addname"?  Does that sound like
> it would be a better description here?
>

Sure, both are fine.
All I'm saying is that "factor out" is a well established keyword
that shouldn't be abused.

Thanks,
Amir.

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-24  6:50       ` Amir Goldstein
@ 2020-02-24  7:36         ` Allison Collins
  2020-02-24  7:43           ` Amir Goldstein
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-24  7:36 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 11:50 PM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 6:51 PM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>>
>>
>> On 2/23/20 4:54 AM, Amir Goldstein wrote:
>>> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
>>> <allison.henderson@oracle.com> wrote:
>>>>
>>>> This patch embeds an xfs_name in xfs_da_args, replacing the name, namelen, and flags
>>>> members.  This helps to clean up the xfs_da_args structure and make it more uniform
>>>> with the new xfs_name parameter being passed around.
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>>>    fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>>>    fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>>>    fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>>>    fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>>>    fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>>>    fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>>>    fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>>>    fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>>>    fs/xfs/scrub/attr.c             |  12 ++---
>>>>    fs/xfs/xfs_trace.h              |  20 ++++----
>>>>    12 files changed, 130 insertions(+), 123 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 6717f47..9acdb23 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>>>           args->geo = dp->i_mount->m_attr_geo;
>>>>           args->whichfork = XFS_ATTR_FORK;
>>>>           args->dp = dp;
>>>> -       args->flags = flags;
>>>> -       args->name = name->name;
>>>> -       args->namelen = name->len;
>>>> -       if (args->namelen >= MAXNAMELEN)
>>>> +       memcpy(&args->name, name, sizeof(struct xfs_name));
>>>
>>> Maybe xfs_name_copy and xfs_name_equal are in order?
>> You are suggesting to add xfs_name_copy and xfs_name_equal helpers?  I'm
>> not sure there's a use case yet for xfs_name_equal, at least not in this
>> set.  And I think people indicated that they preferred the memcpy in
>> past reviews rather than handling each member of the xfs_name struct.
>> Unless I misunderstood the question, I'm not sure there is much left for
>> a xfs_name_copy helper to cover that the memcpy does not?
>>
> 
> It's fine. The choice between xfs_name_copy and memcpy is
> mostly personal taste. I did not read through past reviews.
> 
>>>
>>>>
>>>> +       /* Use name now stored in args */
>>>> +       name = &args.name;
>>>> +
>>>
>>> It seem that the context of these comments be clear in the future.
>> You are asking to add more context to the comment?  How about:
>>          /*
>>           * Use name now stored in args.  Abandon the local name
>>           * parameter as it will not be updated in the subroutines
>>           */
>>
>> Does that help some?
> 
> Can't you just not use local name arg anymore?
> Instead of re-assigning it and explaining why you do that.
> Does that gain anything to code readability or anything else?
Well, with out the set, you cannot use for example name->type anymore, 
you need to use args->name->type.  In order to use the local name 
variable again, it needs to be updated.  I stumbled across this myself 
when working with it and thought it would be better to fix it right away 
rather than let others run across the same mistake.  It seems like a 
subtle and easy thing to overlook otherwise.

I do think it's a bit of a wart that people may not have thought about 
when we talked about adding this patch.  Though I don't know that it's a 
big enough deal to drop it either.  But I did feel some motivation to at 
least clean it up and make a comment about it.

Allison

> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-24  7:36         ` Allison Collins
@ 2020-02-24  7:43           ` Amir Goldstein
  0 siblings, 0 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-24  7:43 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 9:37 AM Allison Collins
<allison.henderson@oracle.com> wrote:
>
>
>
> On 2/23/20 11:50 PM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 6:51 PM Allison Collins
> > <allison.henderson@oracle.com> wrote:
> >>
> >>
> >>
> >> On 2/23/20 4:54 AM, Amir Goldstein wrote:
> >>> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> >>> <allison.henderson@oracle.com> wrote:
> >>>>
> >>>> This patch embeds an xfs_name in xfs_da_args, replacing the name, namelen, and flags
> >>>> members.  This helps to clean up the xfs_da_args structure and make it more uniform
> >>>> with the new xfs_name parameter being passed around.
> >>>>
> >>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> >>>> Reviewed-by: Brian Foster <bfoster@redhat.com>
> >>>> ---
> >>>>    fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
> >>>>    fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
> >>>>    fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
> >>>>    fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
> >>>>    fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
> >>>>    fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
> >>>>    fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
> >>>>    fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
> >>>>    fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
> >>>>    fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
> >>>>    fs/xfs/scrub/attr.c             |  12 ++---
> >>>>    fs/xfs/xfs_trace.h              |  20 ++++----
> >>>>    12 files changed, 130 insertions(+), 123 deletions(-)
> >>>>
> >>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >>>> index 6717f47..9acdb23 100644
> >>>> --- a/fs/xfs/libxfs/xfs_attr.c
> >>>> +++ b/fs/xfs/libxfs/xfs_attr.c
> >>>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
> >>>>           args->geo = dp->i_mount->m_attr_geo;
> >>>>           args->whichfork = XFS_ATTR_FORK;
> >>>>           args->dp = dp;
> >>>> -       args->flags = flags;
> >>>> -       args->name = name->name;
> >>>> -       args->namelen = name->len;
> >>>> -       if (args->namelen >= MAXNAMELEN)
> >>>> +       memcpy(&args->name, name, sizeof(struct xfs_name));
> >>>
> >>> Maybe xfs_name_copy and xfs_name_equal are in order?
> >> You are suggesting to add xfs_name_copy and xfs_name_equal helpers?  I'm
> >> not sure there's a use case yet for xfs_name_equal, at least not in this
> >> set.  And I think people indicated that they preferred the memcpy in
> >> past reviews rather than handling each member of the xfs_name struct.
> >> Unless I misunderstood the question, I'm not sure there is much left for
> >> a xfs_name_copy helper to cover that the memcpy does not?
> >>
> >
> > It's fine. The choice between xfs_name_copy and memcpy is
> > mostly personal taste. I did not read through past reviews.
> >
> >>>
> >>>>
> >>>> +       /* Use name now stored in args */
> >>>> +       name = &args.name;
> >>>> +
> >>>
> >>> It seem that the context of these comments be clear in the future.
> >> You are asking to add more context to the comment?  How about:
> >>          /*
> >>           * Use name now stored in args.  Abandon the local name
> >>           * parameter as it will not be updated in the subroutines
> >>           */
> >>
> >> Does that help some?
> >
> > Can't you just not use local name arg anymore?
> > Instead of re-assigning it and explaining why you do that.
> > Does that gain anything to code readability or anything else?
> Well, with out the set, you cannot use for example name->type anymore,
> you need to use args->name->type.  In order to use the local name
> variable again, it needs to be updated.  I stumbled across this myself
> when working with it and thought it would be better to fix it right away
> rather than let others run across the same mistake.  It seems like a
> subtle and easy thing to overlook otherwise.
>
> I do think it's a bit of a wart that people may not have thought about
> when we talked about adding this patch.  Though I don't know that it's a
> big enough deal to drop it either.  But I did feel some motivation to at
> least clean it up and make a comment about it.
>

Understood. I have no smart suggestion, so withdrawing my comment.

Thanks,
Amir.

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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
  2020-02-23 16:02   ` Allison Collins
@ 2020-02-24  8:31   ` Chandan Rajendra
  2020-02-25  9:52   ` Dave Chinner
  2 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-24  8:31 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs, Allison Collins

On Sunday, February 23, 2020 1:25 PM Amir Goldstein wrote: 
> On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
> >
> > Hi all,
> >
> > This set is a subset of a larger series for delayed attributes. Which is
> > a subset of an even larger series, parent pointers. Delayed attributes
> > allow attribute operations (set and remove) to be logged and committed
> > in the same way that other delayed operations do. This allows more
> > complex operations (like parent pointers) to be broken up into multiple
> > smaller transactions. To do this, the existing attr operations must be
> > modified to operate as either a delayed operation or a inline operation
> > since older filesystems will not be able to use the new log entries.
> 
> High level question, before I dive into the series:
>

Hi Amir,

My 2 cents on this topic (Assuming "delayed operations" refer to "deferred
ops") ... 

> Which other "delayed operations" already exist?

static const struct xfs_defer_op_type *defer_op_types[] = {
        [XFS_DEFER_OPS_TYPE_BMAP]       = &xfs_bmap_update_defer_type,
        [XFS_DEFER_OPS_TYPE_REFCOUNT]   = &xfs_refcount_update_defer_type,
        [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,
};


> I think delayed operations were added by Darrick to handle the growth of
> translation size due to reflink. Right? So I assume the existing delayed
> operations deal with block accounting.

IIRC, Deferred ops are meant to not violate the AG locking order.  If AG 'x'
metadata block[s] is locked then we can only lock metadata blocks of AGs
starting from 'x+1'. Transactions can return -EAGAIN when they detect that
they need to lock metadata blocks belonging to AG 'x-1' or less. In such a
case the transaction will be rolled during which the locks on metadata blocks
are given up.

> When speaking of parent pointers, without having looked into the details yet,
> it seem the delayed operations we would want to log are operations that deal
> with namespace changes, i.e.: link,unlink,rename.
> The information needed to be logged for these ops is minimal.
> Why do we need a general infrastructure for delayed attr operations?
> 
> Thanks,
> Amir.
> 
> 
> 
> 

-- 
chandan




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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
  2020-02-23  9:34   ` Amir Goldstein
@ 2020-02-24 12:08   ` Chandan Rajendra
  2020-02-24 16:25     ` Allison Collins
  2020-02-24 13:06   ` Brian Foster
  2 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-24 12:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM Allison Collins wrote: 
> This patch replaces the attribute name and length parameters with a single struct
> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
> around and pre-simplifies the code some.
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c  | 22 +++++++++-------------
>  fs/xfs/libxfs/xfs_attr.h  | 12 +++++-------
>  fs/xfs/libxfs/xfs_types.c | 11 +++++++++++
>  fs/xfs/libxfs/xfs_types.h |  1 +
>  fs/xfs/xfs_acl.c          | 25 +++++++++++--------------
>  fs/xfs/xfs_ioctl.c        | 23 +++++++++++++----------
>  fs/xfs/xfs_iops.c         |  6 +++---
>  fs/xfs/xfs_xattr.c        | 28 ++++++++++++++++------------
>  8 files changed, 69 insertions(+), 59 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index e614972..6717f47 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -61,8 +61,7 @@ STATIC int
>  xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  
> @@ -74,8 +73,8 @@ xfs_attr_args_init(
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
>  	args->flags = flags;
> -	args->name = name;
> -	args->namelen = namelen;
> +	args->name = name->name;
> +	args->namelen = name->len;
>  	if (args->namelen >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  
> @@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
>  int
>  xfs_attr_get(
>  	struct xfs_inode	*ip,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		**value,
>  	int			*valuelenp,
>  	int			flags)
> @@ -156,7 +154,7 @@ xfs_attr_get(
>  	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, ip, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -339,8 +337,7 @@ xfs_attr_remove_args(
>  int
>  xfs_attr_set(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		*value,
>  	int			valuelen,
>  	int			flags)
> @@ -356,7 +353,7 @@ xfs_attr_set(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -444,8 +441,7 @@ xfs_attr_set(
>  int
>  xfs_attr_remove(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> @@ -457,7 +453,7 @@ xfs_attr_remove(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 4243b22..35043db 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -147,14 +147,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
>  int xfs_attr_list_int(struct xfs_attr_list_context *);
>  int xfs_inode_hasattr(struct xfs_inode *ip);
>  int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> -		 size_t namelen, unsigned char **value, int *valuelenp,
> -		 int flags);
> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> -		 size_t namelen, unsigned char *value, int valuelen, int flags);
> +int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
> +		 unsigned char **value, int *valuelenp, int flags);
> +int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> +		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
> -		    size_t namelen, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c
> index 4f59554..781a5a9 100644
> --- a/fs/xfs/libxfs/xfs_types.c
> +++ b/fs/xfs/libxfs/xfs_types.c
> @@ -12,6 +12,17 @@
>  #include "xfs_bit.h"
>  #include "xfs_mount.h"
>  
> +/* Initialize a struct xfs_name with a null terminated string name */
> +void
> +xfs_name_init(
> +	struct xfs_name *xname,
> +	const char *name)
> +{
> +	xname->name = (unsigned char *)name;
> +	xname->len = strlen(name);
> +	xname->type = 0;
> +}
> +
>  /* Find the size of the AG, in blocks. */
>  xfs_agblock_t
>  xfs_ag_block_count(
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 397d947..b94acb5 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -180,6 +180,7 @@ enum xfs_ag_resv_type {
>   */
>  struct xfs_mount;
>  
> +void xfs_name_init(struct xfs_name *xname, const char *name);
>  xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
>  bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
>  		xfs_agblock_t agbno);
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index cd743fad..42ac847 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -123,7 +123,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;
>  
> @@ -131,10 +131,10 @@ xfs_get_acl(struct inode *inode, int type)
>  
>  	switch (type) {
>  	case ACL_TYPE_ACCESS:
> -		ea_name = SGI_ACL_FILE;
> +		xfs_name_init(&name, SGI_ACL_FILE);
>  		break;
>  	case ACL_TYPE_DEFAULT:
> -		ea_name = SGI_ACL_DEFAULT;
> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>  		break;
>  	default:
>  		BUG();
> @@ -145,9 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
>  	 * go out to the disk.
>  	 */
>  	len = XFS_ACL_MAX_SIZE(ip->i_mount);
> -	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
> -				(unsigned char **)&xfs_acl, &len,
> -				ATTR_ALLOC | ATTR_ROOT);
> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
> +			     ATTR_ALLOC | ATTR_ROOT);
>  	if (error) {
>  		/*
>  		 * If the attribute doesn't exist make sure we have a negative
> @@ -167,17 +166,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;
> +		xfs_name_init(&name, SGI_ACL_FILE);
>  		break;
>  	case ACL_TYPE_DEFAULT:
>  		if (!S_ISDIR(inode->i_mode))
>  			return acl ? -EACCES : 0;
> -		ea_name = SGI_ACL_DEFAULT;
> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>  		break;
>  	default:
>  		return -EINVAL;
> @@ -197,17 +196,15 @@ __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);
> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
> +				     ATTR_ROOT);
>  
>  		kmem_free(xfs_acl);
>  	} else {
>  		/*
>  		 * A NULL ACL argument means we want to remove the ACL.
>  		 */
> -		error = xfs_attr_remove(ip, ea_name,
> -					strlen(ea_name),
> -					ATTR_ROOT);
> +		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
>  
>  		/*
>  		 * If the attribute didn't exist to start with that's fine.
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index d42de92..28c07c9 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
>  {
>  	unsigned char		*kbuf;
>  	int			error = -EFAULT;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (*len > XFS_XATTR_SIZE_MAX)
>  		return -EINVAL;
> @@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
>  	if (!kbuf)
>  		return -ENOMEM;
>  
> -	namelen = strlen(name);
> -	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
> -			     flags);
> +	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>  	if (error)
>  		goto out_kfree;
>  
> @@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
>  {
>  	unsigned char		*kbuf;
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> @@ -400,8 +402,7 @@ 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);
> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	kfree(kbuf);
> @@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
>  	uint32_t		flags)
>  {
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> -	namelen = strlen(name);
> -	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
> +
> +	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	return error;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 81f2f93..e85bbf5 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -48,11 +48,11 @@ xfs_initxattrs(
>  	const struct xattr	*xattr;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error = 0;
> +	struct xfs_name		name;
>  
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> -		error = xfs_attr_set(ip, xattr->name,
> -				     strlen(xattr->name),
> -				     xattr->value, xattr->value_len,
> +		xfs_name_init(&name, xattr->name);
> +		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
>  				     ATTR_SECURE);
>  		if (error < 0)
>  			break;
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index b0fedb5..74133a5 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -21,10 +21,12 @@ static int
>  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, void *value, size_t size)
>  {
> -	int xflags = handler->flags;
> -	struct xfs_inode *ip = XFS_I(inode);
> -	int error, asize = size;
> -	size_t namelen = strlen(name);
> +	int			xflags = handler->flags;
> +	struct xfs_inode	*ip = XFS_I(inode);
> +	int			error, asize = size;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -32,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> -			     &asize, xflags);
> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
> +			     xflags);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -69,7 +71,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	int			xflags = handler->flags;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error;
> -	size_t			namelen = strlen(name);
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -77,11 +81,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	if (flags & XATTR_REPLACE)
>  		xflags |= ATTR_REPLACE;
>  
> -	if (value)
> -		error = xfs_attr_set(ip, name, namelen, (void *)value, size,
> -				xflags);
> -	else
> -		error = xfs_attr_remove(ip, name, namelen, xflags);
> +        if (value)
> +               error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
> +        else
> +               error = xfs_attr_remove(ip, &xname, xflags);
> +
>  	if (!error)
>  		xfs_forget_acl(inode, name, xflags);
>  
> 


-- 
chandan




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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
  2020-02-23  9:34   ` Amir Goldstein
  2020-02-24 12:08   ` Chandan Rajendra
@ 2020-02-24 13:06   ` Brian Foster
  2020-02-24 16:25     ` Allison Collins
  2 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-24 13:06 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:05:53PM -0700, Allison Collins wrote:
> This patch replaces the attribute name and length parameters with a single struct
> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
> around and pre-simplifies the code some.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

Looks fine to me:

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

>  fs/xfs/libxfs/xfs_attr.c  | 22 +++++++++-------------
>  fs/xfs/libxfs/xfs_attr.h  | 12 +++++-------
>  fs/xfs/libxfs/xfs_types.c | 11 +++++++++++
>  fs/xfs/libxfs/xfs_types.h |  1 +
>  fs/xfs/xfs_acl.c          | 25 +++++++++++--------------
>  fs/xfs/xfs_ioctl.c        | 23 +++++++++++++----------
>  fs/xfs/xfs_iops.c         |  6 +++---
>  fs/xfs/xfs_xattr.c        | 28 ++++++++++++++++------------
>  8 files changed, 69 insertions(+), 59 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index e614972..6717f47 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -61,8 +61,7 @@ STATIC int
>  xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  
> @@ -74,8 +73,8 @@ xfs_attr_args_init(
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
>  	args->flags = flags;
> -	args->name = name;
> -	args->namelen = namelen;
> +	args->name = name->name;
> +	args->namelen = name->len;
>  	if (args->namelen >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  
> @@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
>  int
>  xfs_attr_get(
>  	struct xfs_inode	*ip,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		**value,
>  	int			*valuelenp,
>  	int			flags)
> @@ -156,7 +154,7 @@ xfs_attr_get(
>  	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, ip, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -339,8 +337,7 @@ xfs_attr_remove_args(
>  int
>  xfs_attr_set(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		*value,
>  	int			valuelen,
>  	int			flags)
> @@ -356,7 +353,7 @@ xfs_attr_set(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -444,8 +441,7 @@ xfs_attr_set(
>  int
>  xfs_attr_remove(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> @@ -457,7 +453,7 @@ xfs_attr_remove(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 4243b22..35043db 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -147,14 +147,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
>  int xfs_attr_list_int(struct xfs_attr_list_context *);
>  int xfs_inode_hasattr(struct xfs_inode *ip);
>  int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> -		 size_t namelen, unsigned char **value, int *valuelenp,
> -		 int flags);
> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> -		 size_t namelen, unsigned char *value, int valuelen, int flags);
> +int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
> +		 unsigned char **value, int *valuelenp, int flags);
> +int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> +		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
> -		    size_t namelen, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c
> index 4f59554..781a5a9 100644
> --- a/fs/xfs/libxfs/xfs_types.c
> +++ b/fs/xfs/libxfs/xfs_types.c
> @@ -12,6 +12,17 @@
>  #include "xfs_bit.h"
>  #include "xfs_mount.h"
>  
> +/* Initialize a struct xfs_name with a null terminated string name */
> +void
> +xfs_name_init(
> +	struct xfs_name *xname,
> +	const char *name)
> +{
> +	xname->name = (unsigned char *)name;
> +	xname->len = strlen(name);
> +	xname->type = 0;
> +}
> +
>  /* Find the size of the AG, in blocks. */
>  xfs_agblock_t
>  xfs_ag_block_count(
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 397d947..b94acb5 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -180,6 +180,7 @@ enum xfs_ag_resv_type {
>   */
>  struct xfs_mount;
>  
> +void xfs_name_init(struct xfs_name *xname, const char *name);
>  xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
>  bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
>  		xfs_agblock_t agbno);
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index cd743fad..42ac847 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -123,7 +123,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;
>  
> @@ -131,10 +131,10 @@ xfs_get_acl(struct inode *inode, int type)
>  
>  	switch (type) {
>  	case ACL_TYPE_ACCESS:
> -		ea_name = SGI_ACL_FILE;
> +		xfs_name_init(&name, SGI_ACL_FILE);
>  		break;
>  	case ACL_TYPE_DEFAULT:
> -		ea_name = SGI_ACL_DEFAULT;
> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>  		break;
>  	default:
>  		BUG();
> @@ -145,9 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
>  	 * go out to the disk.
>  	 */
>  	len = XFS_ACL_MAX_SIZE(ip->i_mount);
> -	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
> -				(unsigned char **)&xfs_acl, &len,
> -				ATTR_ALLOC | ATTR_ROOT);
> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
> +			     ATTR_ALLOC | ATTR_ROOT);
>  	if (error) {
>  		/*
>  		 * If the attribute doesn't exist make sure we have a negative
> @@ -167,17 +166,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;
> +		xfs_name_init(&name, SGI_ACL_FILE);
>  		break;
>  	case ACL_TYPE_DEFAULT:
>  		if (!S_ISDIR(inode->i_mode))
>  			return acl ? -EACCES : 0;
> -		ea_name = SGI_ACL_DEFAULT;
> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>  		break;
>  	default:
>  		return -EINVAL;
> @@ -197,17 +196,15 @@ __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);
> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
> +				     ATTR_ROOT);
>  
>  		kmem_free(xfs_acl);
>  	} else {
>  		/*
>  		 * A NULL ACL argument means we want to remove the ACL.
>  		 */
> -		error = xfs_attr_remove(ip, ea_name,
> -					strlen(ea_name),
> -					ATTR_ROOT);
> +		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
>  
>  		/*
>  		 * If the attribute didn't exist to start with that's fine.
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index d42de92..28c07c9 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
>  {
>  	unsigned char		*kbuf;
>  	int			error = -EFAULT;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (*len > XFS_XATTR_SIZE_MAX)
>  		return -EINVAL;
> @@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
>  	if (!kbuf)
>  		return -ENOMEM;
>  
> -	namelen = strlen(name);
> -	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
> -			     flags);
> +	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>  	if (error)
>  		goto out_kfree;
>  
> @@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
>  {
>  	unsigned char		*kbuf;
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> @@ -400,8 +402,7 @@ 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);
> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	kfree(kbuf);
> @@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
>  	uint32_t		flags)
>  {
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> -	namelen = strlen(name);
> -	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
> +
> +	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	return error;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 81f2f93..e85bbf5 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -48,11 +48,11 @@ xfs_initxattrs(
>  	const struct xattr	*xattr;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error = 0;
> +	struct xfs_name		name;
>  
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> -		error = xfs_attr_set(ip, xattr->name,
> -				     strlen(xattr->name),
> -				     xattr->value, xattr->value_len,
> +		xfs_name_init(&name, xattr->name);
> +		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
>  				     ATTR_SECURE);
>  		if (error < 0)
>  			break;
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index b0fedb5..74133a5 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -21,10 +21,12 @@ static int
>  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, void *value, size_t size)
>  {
> -	int xflags = handler->flags;
> -	struct xfs_inode *ip = XFS_I(inode);
> -	int error, asize = size;
> -	size_t namelen = strlen(name);
> +	int			xflags = handler->flags;
> +	struct xfs_inode	*ip = XFS_I(inode);
> +	int			error, asize = size;
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -32,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> -			     &asize, xflags);
> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
> +			     xflags);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -69,7 +71,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	int			xflags = handler->flags;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error;
> -	size_t			namelen = strlen(name);
> +	struct xfs_name		xname;
> +
> +	xfs_name_init(&xname, name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -77,11 +81,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	if (flags & XATTR_REPLACE)
>  		xflags |= ATTR_REPLACE;
>  
> -	if (value)
> -		error = xfs_attr_set(ip, name, namelen, (void *)value, size,
> -				xflags);
> -	else
> -		error = xfs_attr_remove(ip, name, namelen, xflags);
> +        if (value)
> +               error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
> +        else
> +               error = xfs_attr_remove(ip, &xname, xflags);
> +
>  	if (!error)
>  		xfs_forget_acl(inode, name, xflags);
>  
> -- 
> 2.7.4
> 


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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
  2020-02-23 12:20   ` Amir Goldstein
@ 2020-02-24 13:08   ` Brian Foster
  2020-02-24 21:18     ` Allison Collins
  2020-02-25  9:49   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-24 13:08 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:05:55PM -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 appearance of duplicated code.  We will need these
> routines later for delayed attributes since delayed operations cannot return error
> codes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>  4 files changed, 188 insertions(+), 98 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9acdb23..2255060 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -310,6 +313,37 @@ 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 = NULL;
> +	int			error;
> +
> +	if (!xfs_inode_hasattr(dp))
> +		return -ENOATTR;
> +
> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		return xfs_attr_sf_findname(args, NULL, NULL);

Nit: any reason we use "findname" here and "hasname" for the other two
variants?

Just a few other nit level things..

> +	}
> +
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_hasname(args, &bp);
> +
> +		if (bp)
> +			xfs_trans_brelse(args->trans, bp);
> +
> +		return error;
> +	}
> +
> +	return xfs_attr_node_hasname(args, NULL);
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
...
> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>  	 * Remove the attribute.
>  	 */
>  	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -	if (error)
> +
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error == -ENOATTR) {

It looks like some of these error checks could be cleaned up where the
helper function is used. I.e., something like the following here:

	if (error == -ENOATTR) {
		xfs_trans_brelse(...);
		return error;
	} else if (error != -EEXIST)
		return error;

>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_leaf_get(args);
>  
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -	if (error)
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error != -EEXIST)  {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;

Similar thing here, just reordering the checks simplifies the logic.

> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  	return error;
>  }
>  
> +/*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * statep: If not null is set to point at the found state.  Caller will
> + *         be responsible for freeing the state in this case.
> + */
> +STATIC int
> +xfs_attr_node_hasname(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**statep)
> +{
> +	struct xfs_da_state	*state;
> +	int			retval, error;
> +
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = args->dp->i_mount;
> +
> +	if (statep != NULL)
> +		*statep = NULL;
> +
> +	/*
> +	 * Search to see if name exists, and get back a pointer to it.
> +	 */
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error == 0) {
> +		if (statep != NULL)
> +			*statep = state;
> +		return retval;
> +	}
> +
> +	xfs_da_state_free(state);
> +
> +	return error;
> +}
> +
>  /*========================================================================
>   * External routines when attribute list size > geo->blksize
>   *========================================================================*/
...
> @@ -1316,31 +1381,23 @@ xfs_attr_node_get(xfs_da_args_t *args)
>  {
>  	xfs_da_state_t *state;
>  	xfs_da_state_blk_t *blk;
> -	int error, retval;
> +	int error;
>  	int i;
>  
>  	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) {
> -		retval = error;
> -		goto out_release;
> -	}
> -	if (retval != -EEXIST)
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST)
>  		goto out_release;
>  
>  	/*
>  	 * Get the value, local or "remote"
>  	 */
>  	blk = &state->path.blk[state->path.active - 1];
> -	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
> +	error = xfs_attr3_leaf_getvalue(blk->bp, args);
>  
>  	/*
>  	 * If not in a transaction, we have to release all the buffers.
> @@ -1352,7 +1409,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
>  	}
>  
>  	xfs_da_state_free(state);

Do we need an 'if (state)' check here like the other node funcs?

> -	return retval;
> +	return error;
>  }
>  
>  /* Returns true if the attribute entry name is valid. */
...
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index cb5ef66..9d6b68c 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -654,18 +654,66 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>  }
>  
>  /*
> + * Return -EEXIST if attr is found, or -ENOATTR if not
> + * args:  args containing attribute name and namelen
> + * sfep:  If not null, pointer will be set to the last attr entry found on
> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
> + * basep: If not null, pointer is set to the byte offset of the entry in the
> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
> + *	  the last entry in the list
> + */
> +int
> +xfs_attr_sf_findname(
> +	struct xfs_da_args	 *args,
> +	struct xfs_attr_sf_entry **sfep,
> +	unsigned int		 *basep)
> +{
> +	struct xfs_attr_shortform *sf;
> +	struct xfs_attr_sf_entry *sfe;
> +	unsigned int		base = sizeof(struct xfs_attr_sf_hdr);
> +	int			size = 0;
> +	int			end;
> +	int			i;
> +
> +	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++) {

Slightly more readable to align indendation with the sfe assignment
above.

Brian

> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> +		if (sfe->namelen != args->name.len)
> +			continue;
> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> +			continue;
> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> +			continue;
> +		break;
> +	}
> +
> +	if (sfep != NULL)
> +		*sfep = sfe;
> +
> +	if (basep != NULL)
> +		*basep = base;
> +
> +	if (i == end)
> +		return -ENOATTR;
> +	return -EEXIST;
> +}
> +
> +/*
>   * Add a name/value pair to the shortform attribute list.
>   * Overflow from the inode has already been checked for.
>   */
>  void
> -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> +xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff)
>  {
> -	xfs_attr_shortform_t *sf;
> -	xfs_attr_sf_entry_t *sfe;
> -	int i, offset, size;
> -	xfs_mount_t *mp;
> -	xfs_inode_t *dp;
> -	struct xfs_ifork *ifp;
> +	struct xfs_attr_shortform	*sf;
> +	struct xfs_attr_sf_entry	*sfe;
> +	int				offset, size, error;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	struct xfs_ifork		*ifp;
>  
>  	trace_xfs_attr_sf_add(args);
>  
> @@ -676,18 +724,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  	ifp = dp->i_afp;
>  	ASSERT(ifp->if_flags & XFS_IFINLINE);
>  	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> -#ifdef DEBUG
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		ASSERT(0);
> -#endif
> -	}
> +	error = xfs_attr_sf_findname(args, &sfe, NULL);
> +	ASSERT(error != -EEXIST);
>  
>  	offset = (char *)sfe - (char *)sf;
>  	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> @@ -730,35 +768,26 @@ xfs_attr_fork_remove(
>   * Remove an attribute from the shortform attribute list structure.
>   */
>  int
> -xfs_attr_shortform_remove(xfs_da_args_t *args)
> +xfs_attr_shortform_remove(struct xfs_da_args *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				size = 0, end, totsize;
> +	unsigned int			base;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	int				error;
>  
>  	trace_xfs_attr_sf_remove(args);
>  
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -	base = sizeof(xfs_attr_sf_hdr_t);
>  	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	end = sf->hdr.count;
> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> -					base += size, i++) {
> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		break;
> -	}
> -	if (i == end)
> -		return -ENOATTR;
> +
> +	error = xfs_attr_sf_findname(args, &sfe, &base);
> +	if (error != -EEXIST)
> +		return error;
> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>  
>  	/*
>  	 * Fix up the attribute fork data, covering the hole
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 73615b1..0e9c87c 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -53,6 +53,9 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>  int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>  			struct xfs_buf **leaf_bp);
>  int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> +int	xfs_attr_sf_findname(struct xfs_da_args *args,
> +			     struct xfs_attr_sf_entry **sfep,
> +			     unsigned 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] 135+ messages in thread

* Re: [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST
  2020-02-23  2:05 ` [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST Allison Collins
  2020-02-23 12:25   ` Amir Goldstein
@ 2020-02-24 13:08   ` Brian Foster
  2020-02-24 21:18     ` Allison Collins
  1 sibling, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-24 13:08 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:05:56PM -0700, Allison Collins wrote:
> Delayed operations cannot return error codes.  So we must check for these conditions
> first before starting set or remove operations
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 2255060..a2f812f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -437,6 +437,14 @@ xfs_attr_set(
>  		goto out_trans_cancel;
>  
>  	xfs_trans_ijoin(args.trans, dp, 0);
> +
> +	error = xfs_has_attr(&args);
> +	if (error == -EEXIST && (name->type & ATTR_CREATE))
> +		goto out_trans_cancel;
> +
> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> +		goto out_trans_cancel;
> +

So xfs_has_attr() calls the format-specific variant for the attr fork.
If it's node format, xfs_attr_node_hasname() allocs a state and only
frees it if the lookup happens to fail. That looks like a potential
memory leak... Perhaps that helper should free the state in any case the
caller doesn't ask for a pointer?

Brian

>  	error = xfs_attr_set_args(&args);
>  	if (error)
>  		goto out_trans_cancel;
> @@ -525,6 +533,10 @@ xfs_attr_remove(
>  	 */
>  	xfs_trans_ijoin(args.trans, dp, 0);
>  
> +	error = xfs_has_attr(&args);
> +	if (error != -EEXIST)
> +		goto out;
> +
>  	error = xfs_attr_remove_args(&args);
>  	if (error)
>  		goto out;
> -- 
> 2.7.4
> 


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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
  2020-02-23 13:04   ` Amir Goldstein
@ 2020-02-24 13:08   ` Brian Foster
  2020-02-24 21:19     ` Allison Collins
  2020-02-28  7:42   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-24 13:08 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:00PM -0700, Allison Collins wrote:
> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
> while modularizing the adjacent code down into helpers. In this patch, hoist the
> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
> attr list creation down.
> 
> 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 | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index b2f0780..71298b9 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -227,8 +227,13 @@ xfs_attr_try_sf_addname(
>  	struct xfs_da_args	*args)
>  {
>  
> -	struct xfs_mount	*mp = dp->i_mount;
> -	int			error, error2;
> +	int			error;
> +
> +	/*
> +	 * Build initial attribute list (if required).
> +	 */
> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> +		xfs_attr_shortform_create(args);
>  
>  	error = xfs_attr_shortform_addname(args);
>  	if (error == -ENOSPC)
> @@ -241,12 +246,10 @@ xfs_attr_try_sf_addname(
>  	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>  
> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
> +	if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args->trans);
>  
> -	error2 = xfs_trans_commit(args->trans);
> -	args->trans = NULL;
> -	return error ? error : error2;
> +	return error;
>  }
>  
>  /*
> @@ -258,7 +261,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,
> @@ -269,17 +272,14 @@ xfs_attr_set_args(
>  	     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;
> +		if (error != -ENOSPC) {
> +			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	[flat|nested] 135+ messages in thread

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
@ 2020-02-24 13:40   ` Brian Foster
  2020-02-24 21:44     ` Allison Collins
  2020-02-25  7:21   ` Dave Chinner
  2020-02-28 14:22   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-24 13:40 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
> new transactions. We will use this later when we introduce delayed attributes
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 29 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 3de2eec..da40f85 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>  	}
>  	return 0;
>  }
> +
> +/*
> + * Remove the value associated with an attribute by deleting the out-of-line
> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
> + * transaction and recall the function
> + */
> +int
> +xfs_attr_rmtval_unmap(
> +	struct xfs_da_args	*args)
> +{
> +	int	error, done;
> +
> +	/*
> +	 * Unmap value blocks for this attr.  This is similar to
> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> +	 * for new transactions
> +	 */
> +	error = xfs_bunmapi(args->trans, args->dp,
> +		    args->rmtblkno, args->rmtblkcnt,
> +		    XFS_BMAPI_ATTRFORK, 1, &done);
> +	if (error)
> +		return error;
> +
> +	if (!done)
> +		return -EAGAIN;
> +
> +	return 0;
> +}

Hmm.. any reason this isn't a refactor of the existing remove function?
Just skipping to the end of the series, I see we leave the reference to
xfs_attr_rmtval_remove() (which no longer exists and so is not very
useful) in this comment as well as a stale function declaration in
xfs_attr_remote.h.

I haven't grokked how this is used yet, but it seems like it would be
more appropriate to lift out the transaction handling from the original
function as we have throughout the rest of the code. That could also
mean creating a temporary wrapper (i.e., rmtval_remove() calls
rmtval_unmap()) for the loop/transaction code that could be removed
later if it ends up unused. Either way is much easier to follow than
creating a (currently unused) replacement..

Brian

> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index eff5f95..e06299a 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>  int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
>  		xfs_buf_flags_t incore_flags);
>  int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
> +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 


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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
@ 2020-02-24 15:25   ` Brian Foster
  2020-02-24 17:03     ` Brian Foster
  2020-02-24 23:14     ` Allison Collins
  2020-02-25  8:57   ` Dave Chinner
  2020-03-03  5:03   ` Chandan Rajendra
  2 siblings, 2 replies; 135+ messages in thread
From: Brian Foster @ 2020-02-24 15:25 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> This patch modifies the attr remove routines to be delay ready. This means they no
> longer roll or commit transactions, but instead return -EAGAIN to have the calling
> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> been modified to use the switch, and a  new version of xfs_attr_remove_args
> consists of a simple loop to refresh the transaction until the operation is
> completed.
> 
> This patch also adds a new struct xfs_delattr_context, which we will use to keep
> track of the current state of an attribute operation. The new xfs_delattr_state
> enum is used to track various operations that are in progress so that we know not
> to repeat them, and resume where we left off before EAGAIN was returned to cycle
> out the transaction. Other members take the place of local variables that need
> to retain their values across multiple function recalls.
> 
> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> indicate places where the function would return -EAGAIN, and then immediately
> resume from after being recalled by the calling function.  States marked as a
> "subroutine state" indicate that they belong to a subroutine, and so the calling
> function needs to pass them back to that subroutine to allow it to finish where
> it left off. But they otherwise do not have a role in the calling function other
> than just passing through.
> 
>  xfs_attr_remove_iter()
>          XFS_DAS_RM_SHRINK     ─┐
>          (subroutine state)     │
>                                 │
>          XFS_DAS_RMTVAL_REMOVE ─┤
>          (subroutine state)     │
>                                 └─>xfs_attr_node_removename()
>                                                  │
>                                                  v
>                                          need to remove
>                                    ┌─n──  rmt blocks?
>                                    │             │
>                                    │             y
>                                    │             │
>                                    │             v
>                                    │  ┌─>XFS_DAS_RMTVAL_REMOVE
>                                    │  │          │
>                                    │  │          v
>                                    │  └──y── more blks
>                                    │         to remove?
>                                    │             │
>                                    │             n
>                                    │             │
>                                    │             v
>                                    │         need to
>                                    └─────> shrink tree? ─n─┐
>                                                  │         │
>                                                  y         │
>                                                  │         │
>                                                  v         │
>                                          XFS_DAS_RM_SHRINK │
>                                                  │         │
>                                                  v         │
>                                                 done <─────┘
> 

Wow. :P I guess I have nothing against verbose commit logs, but I wonder
how useful this level of documentation is for a patch that shouldn't
really change the existing flow of the operation.

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>  fs/xfs/libxfs/xfs_attr.h     |   1 +
>  fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>  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 +
>  10 files changed, 141 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5d73bdf..cd3a3f7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -368,11 +368,60 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	int			err2 = 0;
> +
> +	do {
> +		error = xfs_attr_remove_iter(args);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +

I'm a little confused on the logic of this loop given that the only
caller commits the transaction (which also finishes dfops). IOW, it
seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
that is the case, this can be simplified to something like:

int
xfs_attr_remove_args(
        struct xfs_da_args      *args)
{
        int                     error;

        do {
                error = xfs_attr_remove_iter(args);
                if (error != -EAGAIN)
                        break;

                if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
                        args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
                        error = xfs_defer_finish(&args->trans);
                        if (error)
                                break;
                }

                error = xfs_trans_roll_inode(&args->trans, args->dp);
                if (error)
                        break;
        } while (true);

        return error;
}

That has the added benefit of eliminating the whole err2 pattern, which
always strikes me as a landmine.

> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {

BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?

> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> +
> +			err2 = xfs_defer_finish(&args->trans);
> +			if (err2) {
> +				error = err2;
> +				goto out;
> +			}
> +		}
> +
> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +	} while (error == -EAGAIN);
> +out:
> +	return error;
> +}
> +
> +/*
> + * Remove the attribute specified in @args.
> + *
> + * This function may return -EAGAIN to signal that the transaction needs to be
> + * rolled.  Callers should continue calling this function until they receive a
> + * return value other than -EAGAIN.
> + */
> +int
> +xfs_attr_remove_iter(
>  	struct xfs_da_args      *args)
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	int			error;
>  
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_RM_SHRINK:
> +	case XFS_DAS_RMTVAL_REMOVE:
> +		goto node;
> +	default:
> +		break;
> +	}
> +
>  	if (!xfs_inode_hasattr(dp)) {
>  		error = -ENOATTR;
>  	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_removename(args);
>  	} else {
> +node:
>  		error = xfs_attr_node_removename(args);
>  	}
>  
> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>  		/* bp is gone due to xfs_da_shrink_inode */
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +
> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>  	}
>  	return 0;
>  }
> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>   * This will involve walking down the Btree, and may involve joining
>   * leaf nodes and even joining intermediate nodes up to and including
>   * the root node (a special case of an intermediate node).
> + *
> + * This routine is meant to function as either an inline or delayed operation,
> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> + * functions will need to handle this, and recall the function until a
> + * successful error code is returned.
>   */
>  STATIC int
>  xfs_attr_node_removename(
> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>  	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = args->dac.da_state;
> +	blk = args->dac.blk;
> +
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_RMTVAL_REMOVE:
> +		goto rm_node_blks;
> +	case XFS_DAS_RM_SHRINK:
> +		goto rm_shrink;
> +	default:
> +		break;
> +	}
>  
>  	error = xfs_attr_node_hasname(args, &state);
>  	if (error != -EEXIST)
>  		goto out;
> +	else
> +		error = 0;

This doesn't look necessary.

>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->bp != NULL);
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +
> +	/*
> +	 * Store blk and state in the context incase we need to cycle out the
> +	 * transaction
> +	 */
> +	args->dac.blk = blk;
> +	args->dac.da_state = state;
> +
>  	if (args->rmtblkno > 0) {
>  		/*
>  		 * Fill in disk block numbers in the state structure
> @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		error = xfs_attr_rmtval_invalidate(args);

Remind me why we lose the above trans roll? I vaguely recall that this
was intentional, but I could be mistaken...

>  		if (error)
>  			goto out;
> +	}
>  
> -		error = xfs_attr_rmtval_remove(args);
> -		if (error)
> -			goto out;
> +rm_node_blks:
> +
> +	if (args->rmtblkno > 0) {
> +		error = xfs_attr_rmtval_unmap(args);
> +
> +		if (error) {
> +			if (error == -EAGAIN)
> +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;

Might be helpful for the code labels to match the state names. I.e., use
das_rmtval_remove: for the label above.

> +			return error;
> +		}
>  
>  		/*
>  		 * Refill the state structure with buffers, the prior calls
> @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
>  		error = xfs_da3_join(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> -		/*
> -		 * Commit the Btree join operation and start a new trans.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			goto out;
> +
> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
> +		return -EAGAIN;
>  	}
>  
> +rm_shrink:
> +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
> +

There's an xfs_defer_finish() call further down this function. Should
that be replaced with the flag?

Finally, I mentioned in a previous review that this function should
probably be further broken down before fitting in the state management
stuff. It doesn't look like that happened so I've attached a diff that
is just intended to give an idea of what I mean by sectioning off the
hunks that might be able to break down into helpers. The helpers
wouldn't contain any state management, so we create a clear separation
between the state code and functional components. I think this initial
refactoring would make the introduction of state much more simple (and
perhaps alleviate the need for the huge diagram). It might also be
interesting to see how much of the result could be folded up further
into _removename_iter()...

Brian

>  	/*
>  	 * If the result is small enough, push it all into the inode.
>  	 */
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index ce7b039..ea873a5 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> +int xfs_attr_remove_iter(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);
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index 14f1be3..3c78498 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>  };
>  
>  /*
> + * Enum values for xfs_delattr_context.da_state
> + *
> + * These values are used by delayed attribute operations to keep track  of where
> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> + * calling function to roll the transaction, and then recall the subroutine to
> + * finish the operation.  The enum is then used by the subroutine to jump back
> + * to where it was and resume executing where it left off.
> + */
> +enum xfs_delattr_state {
> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> +};
> +
> +/*
> + * Defines for xfs_delattr_context.flags
> + */
> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delattr_context {
> +	struct xfs_da_state	*da_state;
> +	struct xfs_da_state_blk *blk;
> +	unsigned int		flags;
> +	enum xfs_delattr_state	dela_state;
> +};
> +
> +/*
>   * Structure to ease passing around component names.
>   */
>  typedef struct xfs_da_args {
> +	struct xfs_delattr_context dac; /* context used for delay attr ops */
>  	struct xfs_da_geometry *geo;	/* da block geometry */
>  	struct xfs_name	name;		/* name, length and argument  flags*/
>  	uint8_t		filetype;	/* filetype of inode for directories */
> 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 42ac847..d65e6d8 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 "xfs_error.h"
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
>  
> -- 
> 2.7.4
> 


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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-24  6:30     ` Amir Goldstein
@ 2020-02-24 16:23       ` Allison Collins
  2020-02-25  5:53         ` Amir Goldstein
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-24 16:23 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: linux-xfs



On 2/23/20 11:30 PM, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 6:02 PM Allison Collins
> <allison.henderson@oracle.com> wrote:
>>
>>
>>
>> On 2/23/20 12:55 AM, Amir Goldstein wrote:
>>> On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
>>> <allison.henderson@oracle.com> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> This set is a subset of a larger series for delayed attributes. Which is
>>>> a subset of an even larger series, parent pointers. Delayed attributes
>>>> allow attribute operations (set and remove) to be logged and committed
>>>> in the same way that other delayed operations do. This allows more
>>>> complex operations (like parent pointers) to be broken up into multiple
>>>> smaller transactions. To do this, the existing attr operations must be
>>>> modified to operate as either a delayed operation or a inline operation
>>>> since older filesystems will not be able to use the new log entries.
>>>
>>> High level question, before I dive into the series:
>>>
>>> Which other "delayed operations" already exist?
>>> I think delayed operations were added by Darrick to handle the growth of
>>> translation size due to reflink. Right? So I assume the existing delayed
>>> operations deal with block accounting.
>> Gosh, quite a few I think, but I'm not solid on what they all do.  If we
>> take a peek at XFS_LI_TYPE_DESC, theres an identifier for each type, to
>> give you an idea.  A lot of them do look like they are part of reflink
>> operations though.
>>
>>> When speaking of parent pointers, without having looked into the details yet,
>>> it seem the delayed operations we would want to log are operations that deal
>>> with namespace changes, i.e.: link,unlink,rename.
>>> The information needed to be logged for these ops is minimal.
>>> Why do we need a general infrastructure for delayed attr operations?
>>>
>>> Thanks,
>>> Amir.
>>>
>> Great question, this one goes back a ways.  I believe the train of logic
>> we had is that because parent pointers also include the filename of the
>> parent, its possible we can end up with really big attributes.  Which
>> may run into a lot of block map/unmap activity for name space changes.
>> We didnt want to end up with overly large transactions in the log, so we
>> wanted to break them up by returning -EAGAIN where ever the transactions
>> used to be rolled.  I'm pretty sure that covers a quick high level
>> history of where we are now?  Did that answer your question?
>>
> 
> Partly.
> My question was like this:
> It seems that your work is about implementing:
> [intent to set xattr <new parent inode,gen,offset> <new name>]
> [intent to remove xattr <old parent inode,gen,offset> <old name>]
> 
> While at a high level what the user really *intents* to do is:
> [intent to link <inode> to <new parent inode>;<new name>]
> [intent to unlink <inode> from <old parent inode>;<old name>]
> 
> I guess the log item sizes of the two variants is quite similar, so it
> doesn't make much of a difference and deferred xattr ops are more
> generic and may be used for other things in the future.
> 
> Another thing is that the transaction space required from directory
> entry changes is (probably) already taken into account correctly
> in the code, so there is no need to worry about deferred namespace
> operations from that aspect, but from a pure design perspective,
> if namespace operations become complex, *they* are the ones
> that should be made into deferred operations.
> 
> Or maybe I am not reading the situations correctly at all...
Ok, I think I understand what you're trying to say.  Would it help to 
explain then that setting or removing an attr becomes part of the 
namespace operations later?  When we get up into the parent pointer set, 
a lot of those patches add an attribute set or remove every time we 
link, unlink, rename etc.  Did that help answer your question?

Allison

> 
> Thanks,
> Amir.
> 

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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-24 12:08   ` Chandan Rajendra
@ 2020-02-24 16:25     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-24 16:25 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/24/20 5:08 AM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:35 AM Allison Collins wrote:
>> This patch replaces the attribute name and length parameters with a single struct
>> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
>> around and pre-simplifies the code some.
>>
> 
> I don't see any logical errors.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Alrighty, thank you!

Allison

> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c  | 22 +++++++++-------------
>>   fs/xfs/libxfs/xfs_attr.h  | 12 +++++-------
>>   fs/xfs/libxfs/xfs_types.c | 11 +++++++++++
>>   fs/xfs/libxfs/xfs_types.h |  1 +
>>   fs/xfs/xfs_acl.c          | 25 +++++++++++--------------
>>   fs/xfs/xfs_ioctl.c        | 23 +++++++++++++----------
>>   fs/xfs/xfs_iops.c         |  6 +++---
>>   fs/xfs/xfs_xattr.c        | 28 ++++++++++++++++------------
>>   8 files changed, 69 insertions(+), 59 deletions(-)
>>

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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-24 13:06   ` Brian Foster
@ 2020-02-24 16:25     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-24 16:25 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/24/20 6:06 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:05:53PM -0700, Allison Collins wrote:
>> This patch replaces the attribute name and length parameters with a single struct
>> xfs_name parameter.  This helps to clean up the numbers of parameters being passed
>> around and pre-simplifies the code some.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Looks fine to me:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Great!  Thanks for the reviews!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c  | 22 +++++++++-------------
>>   fs/xfs/libxfs/xfs_attr.h  | 12 +++++-------
>>   fs/xfs/libxfs/xfs_types.c | 11 +++++++++++
>>   fs/xfs/libxfs/xfs_types.h |  1 +
>>   fs/xfs/xfs_acl.c          | 25 +++++++++++--------------
>>   fs/xfs/xfs_ioctl.c        | 23 +++++++++++++----------
>>   fs/xfs/xfs_iops.c         |  6 +++---
>>   fs/xfs/xfs_xattr.c        | 28 ++++++++++++++++------------
>>   8 files changed, 69 insertions(+), 59 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index e614972..6717f47 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -61,8 +61,7 @@ STATIC int
>>   xfs_attr_args_init(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	int			flags)
>>   {
>>   
>> @@ -74,8 +73,8 @@ xfs_attr_args_init(
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>>   	args->flags = flags;
>> -	args->name = name;
>> -	args->namelen = namelen;
>> +	args->name = name->name;
>> +	args->namelen = name->len;
>>   	if (args->namelen >= MAXNAMELEN)
>>   		return -EFAULT;		/* match IRIX behaviour */
>>   
>> @@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
>>   int
>>   xfs_attr_get(
>>   	struct xfs_inode	*ip,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	unsigned char		**value,
>>   	int			*valuelenp,
>>   	int			flags)
>> @@ -156,7 +154,7 @@ xfs_attr_get(
>>   	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, ip, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> @@ -339,8 +337,7 @@ xfs_attr_remove_args(
>>   int
>>   xfs_attr_set(
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	unsigned char		*value,
>>   	int			valuelen,
>>   	int			flags)
>> @@ -356,7 +353,7 @@ xfs_attr_set(
>>   	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, dp, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> @@ -444,8 +441,7 @@ xfs_attr_set(
>>   int
>>   xfs_attr_remove(
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	int			flags)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>> @@ -457,7 +453,7 @@ xfs_attr_remove(
>>   	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, dp, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 4243b22..35043db 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -147,14 +147,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
>>   int xfs_attr_list_int(struct xfs_attr_list_context *);
>>   int xfs_inode_hasattr(struct xfs_inode *ip);
>>   int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
>> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>> -		 size_t namelen, unsigned char **value, int *valuelenp,
>> -		 int flags);
>> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>> -		 size_t namelen, unsigned char *value, int valuelen, int flags);
>> +int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>> +		 unsigned char **value, int *valuelenp, int flags);
>> +int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>> +		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>> -		    size_t namelen, int flags);
>> +int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>> diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c
>> index 4f59554..781a5a9 100644
>> --- a/fs/xfs/libxfs/xfs_types.c
>> +++ b/fs/xfs/libxfs/xfs_types.c
>> @@ -12,6 +12,17 @@
>>   #include "xfs_bit.h"
>>   #include "xfs_mount.h"
>>   
>> +/* Initialize a struct xfs_name with a null terminated string name */
>> +void
>> +xfs_name_init(
>> +	struct xfs_name *xname,
>> +	const char *name)
>> +{
>> +	xname->name = (unsigned char *)name;
>> +	xname->len = strlen(name);
>> +	xname->type = 0;
>> +}
>> +
>>   /* Find the size of the AG, in blocks. */
>>   xfs_agblock_t
>>   xfs_ag_block_count(
>> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
>> index 397d947..b94acb5 100644
>> --- a/fs/xfs/libxfs/xfs_types.h
>> +++ b/fs/xfs/libxfs/xfs_types.h
>> @@ -180,6 +180,7 @@ enum xfs_ag_resv_type {
>>    */
>>   struct xfs_mount;
>>   
>> +void xfs_name_init(struct xfs_name *xname, const char *name);
>>   xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
>>   bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
>>   		xfs_agblock_t agbno);
>> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index cd743fad..42ac847 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -123,7 +123,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;
>>   
>> @@ -131,10 +131,10 @@ xfs_get_acl(struct inode *inode, int type)
>>   
>>   	switch (type) {
>>   	case ACL_TYPE_ACCESS:
>> -		ea_name = SGI_ACL_FILE;
>> +		xfs_name_init(&name, SGI_ACL_FILE);
>>   		break;
>>   	case ACL_TYPE_DEFAULT:
>> -		ea_name = SGI_ACL_DEFAULT;
>> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>>   		break;
>>   	default:
>>   		BUG();
>> @@ -145,9 +145,8 @@ xfs_get_acl(struct inode *inode, int type)
>>   	 * go out to the disk.
>>   	 */
>>   	len = XFS_ACL_MAX_SIZE(ip->i_mount);
>> -	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
>> -				(unsigned char **)&xfs_acl, &len,
>> -				ATTR_ALLOC | ATTR_ROOT);
>> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
>> +			     ATTR_ALLOC | ATTR_ROOT);
>>   	if (error) {
>>   		/*
>>   		 * If the attribute doesn't exist make sure we have a negative
>> @@ -167,17 +166,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;
>> +		xfs_name_init(&name, SGI_ACL_FILE);
>>   		break;
>>   	case ACL_TYPE_DEFAULT:
>>   		if (!S_ISDIR(inode->i_mode))
>>   			return acl ? -EACCES : 0;
>> -		ea_name = SGI_ACL_DEFAULT;
>> +		xfs_name_init(&name, SGI_ACL_DEFAULT);
>>   		break;
>>   	default:
>>   		return -EINVAL;
>> @@ -197,17 +196,15 @@ __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);
>> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
>> +				     ATTR_ROOT);
>>   
>>   		kmem_free(xfs_acl);
>>   	} else {
>>   		/*
>>   		 * A NULL ACL argument means we want to remove the ACL.
>>   		 */
>> -		error = xfs_attr_remove(ip, ea_name,
>> -					strlen(ea_name),
>> -					ATTR_ROOT);
>> +		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
>>   
>>   		/*
>>   		 * If the attribute didn't exist to start with that's fine.
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index d42de92..28c07c9 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -357,7 +357,9 @@ xfs_attrmulti_attr_get(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error = -EFAULT;
>> -	size_t			namelen;
>> +	struct xfs_name		xname;
>> +
>> +	xfs_name_init(&xname, name);
>>   
>>   	if (*len > XFS_XATTR_SIZE_MAX)
>>   		return -EINVAL;
>> @@ -365,9 +367,7 @@ xfs_attrmulti_attr_get(
>>   	if (!kbuf)
>>   		return -ENOMEM;
>>   
>> -	namelen = strlen(name);
>> -	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
>> -			     flags);
>> +	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>>   	if (error)
>>   		goto out_kfree;
>>   
>> @@ -389,7 +389,9 @@ xfs_attrmulti_attr_set(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error;
>> -	size_t			namelen;
>> +	struct xfs_name		xname;
>> +
>> +	xfs_name_init(&xname, name);
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> @@ -400,8 +402,7 @@ 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);
>> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	kfree(kbuf);
>> @@ -415,12 +416,14 @@ xfs_attrmulti_attr_remove(
>>   	uint32_t		flags)
>>   {
>>   	int			error;
>> -	size_t			namelen;
>> +	struct xfs_name		xname;
>> +
>> +	xfs_name_init(&xname, name);
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> -	namelen = strlen(name);
>> -	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
>> +
>> +	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	return error;
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index 81f2f93..e85bbf5 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -48,11 +48,11 @@ xfs_initxattrs(
>>   	const struct xattr	*xattr;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>>   	int			error = 0;
>> +	struct xfs_name		name;
>>   
>>   	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
>> -		error = xfs_attr_set(ip, xattr->name,
>> -				     strlen(xattr->name),
>> -				     xattr->value, xattr->value_len,
>> +		xfs_name_init(&name, xattr->name);
>> +		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
>>   				     ATTR_SECURE);
>>   		if (error < 0)
>>   			break;
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index b0fedb5..74133a5 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -21,10 +21,12 @@ static int
>>   xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		struct inode *inode, const char *name, void *value, size_t size)
>>   {
>> -	int xflags = handler->flags;
>> -	struct xfs_inode *ip = XFS_I(inode);
>> -	int error, asize = size;
>> -	size_t namelen = strlen(name);
>> +	int			xflags = handler->flags;
>> +	struct xfs_inode	*ip = XFS_I(inode);
>> +	int			error, asize = size;
>> +	struct xfs_name		xname;
>> +
>> +	xfs_name_init(&xname, name);
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (!size) {
>> @@ -32,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		value = NULL;
>>   	}
>>   
>> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
>> -			     &asize, xflags);
>> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
>> +			     xflags);
>>   	if (error)
>>   		return error;
>>   	return asize;
>> @@ -69,7 +71,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   	int			xflags = handler->flags;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>>   	int			error;
>> -	size_t			namelen = strlen(name);
>> +	struct xfs_name		xname;
>> +
>> +	xfs_name_init(&xname, name);
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (flags & XATTR_CREATE)
>> @@ -77,11 +81,11 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   	if (flags & XATTR_REPLACE)
>>   		xflags |= ATTR_REPLACE;
>>   
>> -	if (value)
>> -		error = xfs_attr_set(ip, name, namelen, (void *)value, size,
>> -				xflags);
>> -	else
>> -		error = xfs_attr_remove(ip, name, namelen, xflags);
>> +        if (value)
>> +               error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
>> +        else
>> +               error = xfs_attr_remove(ip, &xname, xflags);
>> +
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, xflags);
>>   
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-24 15:25   ` Brian Foster
@ 2020-02-24 17:03     ` Brian Foster
  2020-02-24 23:14     ` Allison Collins
  1 sibling, 0 replies; 135+ messages in thread
From: Brian Foster @ 2020-02-24 17:03 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

[-- Attachment #1: Type: text/plain, Size: 18088 bytes --]

On Mon, Feb 24, 2020 at 10:25:55AM -0500, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> > This patch modifies the attr remove routines to be delay ready. This means they no
> > longer roll or commit transactions, but instead return -EAGAIN to have the calling
> > routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> > become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> > track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> > been modified to use the switch, and a  new version of xfs_attr_remove_args
> > consists of a simple loop to refresh the transaction until the operation is
> > completed.
> > 
> > This patch also adds a new struct xfs_delattr_context, which we will use to keep
> > track of the current state of an attribute operation. The new xfs_delattr_state
> > enum is used to track various operations that are in progress so that we know not
> > to repeat them, and resume where we left off before EAGAIN was returned to cycle
> > out the transaction. Other members take the place of local variables that need
> > to retain their values across multiple function recalls.
> > 
> > Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> > indicate places where the function would return -EAGAIN, and then immediately
> > resume from after being recalled by the calling function.  States marked as a
> > "subroutine state" indicate that they belong to a subroutine, and so the calling
> > function needs to pass them back to that subroutine to allow it to finish where
> > it left off. But they otherwise do not have a role in the calling function other
> > than just passing through.
> > 
> >  xfs_attr_remove_iter()
> >          XFS_DAS_RM_SHRINK     ─┐
> >          (subroutine state)     │
> >                                 │
> >          XFS_DAS_RMTVAL_REMOVE ─┤
> >          (subroutine state)     │
> >                                 └─>xfs_attr_node_removename()
> >                                                  │
> >                                                  v
> >                                          need to remove
> >                                    ┌─n──  rmt blocks?
> >                                    │             │
> >                                    │             y
> >                                    │             │
> >                                    │             v
> >                                    │  ┌─>XFS_DAS_RMTVAL_REMOVE
> >                                    │  │          │
> >                                    │  │          v
> >                                    │  └──y── more blks
> >                                    │         to remove?
> >                                    │             │
> >                                    │             n
> >                                    │             │
> >                                    │             v
> >                                    │         need to
> >                                    └─────> shrink tree? ─n─┐
> >                                                  │         │
> >                                                  y         │
> >                                                  │         │
> >                                                  v         │
> >                                          XFS_DAS_RM_SHRINK │
> >                                                  │         │
> >                                                  v         │
> >                                                 done <─────┘
> > 
> 
> Wow. :P I guess I have nothing against verbose commit logs, but I wonder
> how useful this level of documentation is for a patch that shouldn't
> really change the existing flow of the operation.
> 
> > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
> >  fs/xfs/libxfs/xfs_attr.h     |   1 +
> >  fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
> >  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 +
> >  10 files changed, 141 insertions(+), 16 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 5d73bdf..cd3a3f7 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -368,11 +368,60 @@ xfs_has_attr(
> >   */
> >  int
> >  xfs_attr_remove_args(
> > +	struct xfs_da_args	*args)
> > +{
> > +	int			error = 0;
> > +	int			err2 = 0;
> > +
> > +	do {
> > +		error = xfs_attr_remove_iter(args);
> > +		if (error && error != -EAGAIN)
> > +			goto out;
> > +
> 
> I'm a little confused on the logic of this loop given that the only
> caller commits the transaction (which also finishes dfops). IOW, it
> seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
> that is the case, this can be simplified to something like:
> 
> int
> xfs_attr_remove_args(
>         struct xfs_da_args      *args)
> {
>         int                     error;
> 
>         do {
>                 error = xfs_attr_remove_iter(args);
>                 if (error != -EAGAIN)
>                         break;
> 
>                 if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>                         args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>                         error = xfs_defer_finish(&args->trans);
>                         if (error)
>                                 break;
>                 }
> 
>                 error = xfs_trans_roll_inode(&args->trans, args->dp);
>                 if (error)
>                         break;
>         } while (true);
> 
>         return error;
> }
> 
> That has the added benefit of eliminating the whole err2 pattern, which
> always strikes me as a landmine.
> 
> > +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> 
> BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
> operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
> 
> > +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> > +
> > +			err2 = xfs_defer_finish(&args->trans);
> > +			if (err2) {
> > +				error = err2;
> > +				goto out;
> > +			}
> > +		}
> > +
> > +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> > +		if (err2) {
> > +			error = err2;
> > +			goto out;
> > +		}
> > +
> > +	} while (error == -EAGAIN);
> > +out:
> > +	return error;
> > +}
> > +
> > +/*
> > + * Remove the attribute specified in @args.
> > + *
> > + * This function may return -EAGAIN to signal that the transaction needs to be
> > + * rolled.  Callers should continue calling this function until they receive a
> > + * return value other than -EAGAIN.
> > + */
> > +int
> > +xfs_attr_remove_iter(
> >  	struct xfs_da_args      *args)
> >  {
> >  	struct xfs_inode	*dp = args->dp;
> >  	int			error;
> >  
> > +	/* State machine switch */
> > +	switch (args->dac.dela_state) {
> > +	case XFS_DAS_RM_SHRINK:
> > +	case XFS_DAS_RMTVAL_REMOVE:
> > +		goto node;
> > +	default:
> > +		break;
> > +	}
> > +
> >  	if (!xfs_inode_hasattr(dp)) {
> >  		error = -ENOATTR;
> >  	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > @@ -381,6 +430,7 @@ xfs_attr_remove_args(
> >  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> >  		error = xfs_attr_leaf_removename(args);
> >  	} else {
> > +node:
> >  		error = xfs_attr_node_removename(args);
> >  	}
> >  
> > @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
> >  		/* bp is gone due to xfs_da_shrink_inode */
> >  		if (error)
> >  			return error;
> > -		error = xfs_defer_finish(&args->trans);
> > -		if (error)
> > -			return error;
> > +
> > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> >  	}
> >  	return 0;
> >  }
> > @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
> >   * This will involve walking down the Btree, and may involve joining
> >   * leaf nodes and even joining intermediate nodes up to and including
> >   * the root node (a special case of an intermediate node).
> > + *
> > + * This routine is meant to function as either an inline or delayed operation,
> > + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> > + * functions will need to handle this, and recall the function until a
> > + * successful error code is returned.
> >   */
> >  STATIC int
> >  xfs_attr_node_removename(
> > @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
> >  	struct xfs_inode	*dp = args->dp;
> >  
> >  	trace_xfs_attr_node_removename(args);
> > +	state = args->dac.da_state;
> > +	blk = args->dac.blk;
> > +
> > +	/* State machine switch */
> > +	switch (args->dac.dela_state) {
> > +	case XFS_DAS_RMTVAL_REMOVE:
> > +		goto rm_node_blks;
> > +	case XFS_DAS_RM_SHRINK:
> > +		goto rm_shrink;
> > +	default:
> > +		break;
> > +	}
> >  
> >  	error = xfs_attr_node_hasname(args, &state);
> >  	if (error != -EEXIST)
> >  		goto out;
> > +	else
> > +		error = 0;
> 
> This doesn't look necessary.
> 
> >  
> >  	/*
> >  	 * If there is an out-of-line value, de-allocate the blocks.
> > @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
> >  	blk = &state->path.blk[ state->path.active-1 ];
> >  	ASSERT(blk->bp != NULL);
> >  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > +
> > +	/*
> > +	 * Store blk and state in the context incase we need to cycle out the
> > +	 * transaction
> > +	 */
> > +	args->dac.blk = blk;
> > +	args->dac.da_state = state;
> > +
> >  	if (args->rmtblkno > 0) {
> >  		/*
> >  		 * Fill in disk block numbers in the state structure
> > @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
> >  		if (error)
> >  			goto out;
> >  
> > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > +		error = xfs_attr_rmtval_invalidate(args);
> 
> Remind me why we lose the above trans roll? I vaguely recall that this
> was intentional, but I could be mistaken...
> 
> >  		if (error)
> >  			goto out;
> > +	}
> >  
> > -		error = xfs_attr_rmtval_remove(args);
> > -		if (error)
> > -			goto out;
> > +rm_node_blks:
> > +
> > +	if (args->rmtblkno > 0) {
> > +		error = xfs_attr_rmtval_unmap(args);
> > +
> > +		if (error) {
> > +			if (error == -EAGAIN)
> > +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
> 
> Might be helpful for the code labels to match the state names. I.e., use
> das_rmtval_remove: for the label above.
> 
> > +			return error;
> > +		}
> >  
> >  		/*
> >  		 * Refill the state structure with buffers, the prior calls
> > @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
> >  		error = xfs_da3_join(state);
> >  		if (error)
> >  			goto out;
> > -		error = xfs_defer_finish(&args->trans);
> > -		if (error)
> > -			goto out;
> > -		/*
> > -		 * Commit the Btree join operation and start a new trans.
> > -		 */
> > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > -		if (error)
> > -			goto out;
> > +
> > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > +		return -EAGAIN;
> >  	}
> >  
> > +rm_shrink:
> > +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > +
> 
> There's an xfs_defer_finish() call further down this function. Should
> that be replaced with the flag?
> 
> Finally, I mentioned in a previous review that this function should
> probably be further broken down before fitting in the state management
> stuff. It doesn't look like that happened so I've attached a diff that
> is just intended to give an idea of what I mean by sectioning off the
> hunks that might be able to break down into helpers. The helpers
> wouldn't contain any state management, so we create a clear separation
> between the state code and functional components. I think this initial
> refactoring would make the introduction of state much more simple (and
> perhaps alleviate the need for the huge diagram). It might also be
> interesting to see how much of the result could be folded up further
> into _removename_iter()...
> 

Gah.. attached for real this time.

Brian

> Brian
> 
> >  	/*
> >  	 * If the result is small enough, push it all into the inode.
> >  	 */
> > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > index ce7b039..ea873a5 100644
> > --- a/fs/xfs/libxfs/xfs_attr.h
> > +++ b/fs/xfs/libxfs/xfs_attr.h
> > @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> >  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> >  int xfs_has_attr(struct xfs_da_args *args);
> >  int xfs_attr_remove_args(struct xfs_da_args *args);
> > +int xfs_attr_remove_iter(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);
> > diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> > index 14f1be3..3c78498 100644
> > --- a/fs/xfs/libxfs/xfs_da_btree.h
> > +++ b/fs/xfs/libxfs/xfs_da_btree.h
> > @@ -50,9 +50,39 @@ enum xfs_dacmp {
> >  };
> >  
> >  /*
> > + * Enum values for xfs_delattr_context.da_state
> > + *
> > + * These values are used by delayed attribute operations to keep track  of where
> > + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> > + * calling function to roll the transaction, and then recall the subroutine to
> > + * finish the operation.  The enum is then used by the subroutine to jump back
> > + * to where it was and resume executing where it left off.
> > + */
> > +enum xfs_delattr_state {
> > +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> > +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> > +};
> > +
> > +/*
> > + * Defines for xfs_delattr_context.flags
> > + */
> > +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> > +
> > +/*
> > + * Context used for keeping track of delayed attribute operations
> > + */
> > +struct xfs_delattr_context {
> > +	struct xfs_da_state	*da_state;
> > +	struct xfs_da_state_blk *blk;
> > +	unsigned int		flags;
> > +	enum xfs_delattr_state	dela_state;
> > +};
> > +
> > +/*
> >   * Structure to ease passing around component names.
> >   */
> >  typedef struct xfs_da_args {
> > +	struct xfs_delattr_context dac; /* context used for delay attr ops */
> >  	struct xfs_da_geometry *geo;	/* da block geometry */
> >  	struct xfs_name	name;		/* name, length and argument  flags*/
> >  	uint8_t		filetype;	/* filetype of inode for directories */
> > 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 42ac847..d65e6d8 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 "xfs_error.h"
> > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> > index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
> >  
> > -- 
> > 2.7.4
> > 
> 

[-- Attachment #2: xfs_attr_node_removename.diff --]
[-- Type: text/plain, Size: 1297 bytes --]

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index cd3a3f75c429..e0eaa274b70b 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1297,6 +1297,7 @@ xfs_attr_node_removename(
 		break;
 	}
 
+#if 0
 	error = xfs_attr_node_hasname(args, &state);
 	if (error != -EEXIST)
 		goto out;
@@ -1341,9 +1342,13 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 	}
+#else
+	error = xfs_attr_node_removename_setup();
+#endif
 
 rm_node_blks:
 
+#if 0
 	if (args->rmtblkno > 0) {
 		error = xfs_attr_rmtval_unmap(args);
 
@@ -1361,6 +1366,11 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 	}
+#else
+	args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
+	error = xfs_attr_node_removename_rmt();
+	/* -EAGAIN */
+#endif
 
 	/*
 	 * Remove the name and update the hashvals in the tree.
@@ -1370,6 +1380,7 @@ xfs_attr_node_removename(
 	retval = xfs_attr3_leaf_remove(blk->bp, args);
 	xfs_da3_fixhashpath(state, &state->path);
 
+#if 0
 	/*
 	 * Check to see if the tree needs to be collapsed.
 	 */
@@ -1413,6 +1424,12 @@ xfs_attr_node_removename(
 			xfs_trans_brelse(args->trans, bp);
 	}
 	error = 0;
+#else
+rm_shrink:
+	args->dac.dela_state = XFS_DAS_RM_SHRINK;
+	error = xfs_attr_node_removename_shrink();
+	/* -EAGAIN */
+#endif
 
 out:
 	if (state)

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-24 13:08   ` Brian Foster
@ 2020-02-24 21:18     ` Allison Collins
  2020-02-25 13:25       ` Brian Foster
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-24 21:18 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/24/20 6:08 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:05:55PM -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 appearance of duplicated code.  We will need these
>> routines later for delayed attributes since delayed operations cannot return error
>> codes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>>   4 files changed, 188 insertions(+), 98 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9acdb23..2255060 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
> ...
>> @@ -310,6 +313,37 @@ 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 = NULL;
>> +	int			error;
>> +
>> +	if (!xfs_inode_hasattr(dp))
>> +		return -ENOATTR;
>> +
>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		return xfs_attr_sf_findname(args, NULL, NULL);
> 
> Nit: any reason we use "findname" here and "hasname" for the other two
> variants?
It was asked for in the v4 review.  Reason being we also return the 
location of the sf entry and byte offset.

> 
> Just a few other nit level things..
> 
>> +	}
>> +
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_hasname(args, &bp);
>> +
>> +		if (bp)
>> +			xfs_trans_brelse(args->trans, bp);
>> +
>> +		return error;
>> +	}
>> +
>> +	return xfs_attr_node_hasname(args, NULL);
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
> ...
>> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>>   	 * Remove the attribute.
>>   	 */
>>   	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -	if (error)
>> +
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error == -ENOATTR) {
> 
> It looks like some of these error checks could be cleaned up where the
> helper function is used. I.e., something like the following here:
> 
> 	if (error == -ENOATTR) {
> 		xfs_trans_brelse(...);
> 		return error;
> 	} else if (error != -EEXIST)
> 		return error;
Sure, I'm starting to get more pressure in other reviews to change this 
api to a boolean return type though (1: y, 0: no, <0: error).  I think 
we talked about this in v3, but decided to stick with this original api 
for now.  I'm thinking maybe adding a patch at the end to shift the api 
might be a good compromise?  Thoughts?

> 
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_leaf_get(args);
>>   
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -	if (error)
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error != -EEXIST)  {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
> 
> Similar thing here, just reordering the checks simplifies the logic.
Sure, will do.

> 
>> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   	return error;
>>   }
>>   
>> +/*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * statep: If not null is set to point at the found state.  Caller will
>> + *         be responsible for freeing the state in this case.
>> + */
>> +STATIC int
>> +xfs_attr_node_hasname(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**statep)
>> +{
>> +	struct xfs_da_state	*state;
>> +	int			retval, error;
>> +
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = args->dp->i_mount;
>> +
>> +	if (statep != NULL)
>> +		*statep = NULL;
>> +
>> +	/*
>> +	 * Search to see if name exists, and get back a pointer to it.
>> +	 */
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error == 0) {
>> +		if (statep != NULL)
>> +			*statep = state;
>> +		return retval;
>> +	}
>> +
>> +	xfs_da_state_free(state);
>> +
>> +	return error;
>> +}
>> +
>>   /*========================================================================
>>    * External routines when attribute list size > geo->blksize
>>    *========================================================================*/
> ...
>> @@ -1316,31 +1381,23 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>   {
>>   	xfs_da_state_t *state;
>>   	xfs_da_state_blk_t *blk;
>> -	int error, retval;
>> +	int error;
>>   	int i;
>>   
>>   	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) {
>> -		retval = error;
>> -		goto out_release;
>> -	}
>> -	if (retval != -EEXIST)
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST)
>>   		goto out_release;
>>   
>>   	/*
>>   	 * Get the value, local or "remote"
>>   	 */
>>   	blk = &state->path.blk[state->path.active - 1];
>> -	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
>> +	error = xfs_attr3_leaf_getvalue(blk->bp, args);
>>   
>>   	/*
>>   	 * If not in a transaction, we have to release all the buffers.
>> @@ -1352,7 +1409,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>   	}
>>   
>>   	xfs_da_state_free(state);
> 
> Do we need an 'if (state)' check here like the other node funcs?
I think so, because if xfs_attr_node_hasname errors out it releases the 
state.  Will add.

> 
>> -	return retval;
>> +	return error;
>>   }
>>   
>>   /* Returns true if the attribute entry name is valid. */
> ...
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index cb5ef66..9d6b68c 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -654,18 +654,66 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>   }
>>   
>>   /*
>> + * Return -EEXIST if attr is found, or -ENOATTR if not
>> + * args:  args containing attribute name and namelen
>> + * sfep:  If not null, pointer will be set to the last attr entry found on
>> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
>> + *	  the last entry in the list
>> + */
>> +int
>> +xfs_attr_sf_findname(
>> +	struct xfs_da_args	 *args,
>> +	struct xfs_attr_sf_entry **sfep,
>> +	unsigned int		 *basep)
>> +{
>> +	struct xfs_attr_shortform *sf;
>> +	struct xfs_attr_sf_entry *sfe;
>> +	unsigned int		base = sizeof(struct xfs_attr_sf_hdr);
>> +	int			size = 0;
>> +	int			end;
>> +	int			i;
>> +
>> +	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++) {
> 
> Slightly more readable to align indendation with the sfe assignment
> above.
Sure, will fix.  Thanks!

Allison

> 
> Brian
> 
>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> +		if (sfe->namelen != args->name.len)
>> +			continue;
>> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> +			continue;
>> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> +			continue;
>> +		break;
>> +	}
>> +
>> +	if (sfep != NULL)
>> +		*sfep = sfe;
>> +
>> +	if (basep != NULL)
>> +		*basep = base;
>> +
>> +	if (i == end)
>> +		return -ENOATTR;
>> +	return -EEXIST;
>> +}
>> +
>> +/*
>>    * Add a name/value pair to the shortform attribute list.
>>    * Overflow from the inode has already been checked for.
>>    */
>>   void
>> -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>> +xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff)
>>   {
>> -	xfs_attr_shortform_t *sf;
>> -	xfs_attr_sf_entry_t *sfe;
>> -	int i, offset, size;
>> -	xfs_mount_t *mp;
>> -	xfs_inode_t *dp;
>> -	struct xfs_ifork *ifp;
>> +	struct xfs_attr_shortform	*sf;
>> +	struct xfs_attr_sf_entry	*sfe;
>> +	int				offset, size, error;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	struct xfs_ifork		*ifp;
>>   
>>   	trace_xfs_attr_sf_add(args);
>>   
>> @@ -676,18 +724,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   	ifp = dp->i_afp;
>>   	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>> -#ifdef DEBUG
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		ASSERT(0);
>> -#endif
>> -	}
>> +	error = xfs_attr_sf_findname(args, &sfe, NULL);
>> +	ASSERT(error != -EEXIST);
>>   
>>   	offset = (char *)sfe - (char *)sf;
>>   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> @@ -730,35 +768,26 @@ xfs_attr_fork_remove(
>>    * Remove an attribute from the shortform attribute list structure.
>>    */
>>   int
>> -xfs_attr_shortform_remove(xfs_da_args_t *args)
>> +xfs_attr_shortform_remove(struct xfs_da_args *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				size = 0, end, totsize;
>> +	unsigned int			base;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	int				error;
>>   
>>   	trace_xfs_attr_sf_remove(args);
>>   
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	end = sf->hdr.count;
>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> -					base += size, i++) {
>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		break;
>> -	}
>> -	if (i == end)
>> -		return -ENOATTR;
>> +
>> +	error = xfs_attr_sf_findname(args, &sfe, &base);
>> +	if (error != -EEXIST)
>> +		return error;
>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>   
>>   	/*
>>   	 * Fix up the attribute fork data, covering the hole
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 73615b1..0e9c87c 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -53,6 +53,9 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>   			struct xfs_buf **leaf_bp);
>>   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>> +int	xfs_attr_sf_findname(struct xfs_da_args *args,
>> +			     struct xfs_attr_sf_entry **sfep,
>> +			     unsigned 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] 135+ messages in thread

* Re: [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST
  2020-02-24 13:08   ` Brian Foster
@ 2020-02-24 21:18     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-24 21:18 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/24/20 6:08 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:05:56PM -0700, Allison Collins wrote:
>> Delayed operations cannot return error codes.  So we must check for these conditions
>> first before starting set or remove operations
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 12 ++++++++++++
>>   1 file changed, 12 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 2255060..a2f812f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -437,6 +437,14 @@ xfs_attr_set(
>>   		goto out_trans_cancel;
>>   
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>> +
>> +	error = xfs_has_attr(&args);
>> +	if (error == -EEXIST && (name->type & ATTR_CREATE))
>> +		goto out_trans_cancel;
>> +
>> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
>> +		goto out_trans_cancel;
>> +
> 
> So xfs_has_attr() calls the format-specific variant for the attr fork.
> If it's node format, xfs_attr_node_hasname() allocs a state and only
> frees it if the lookup happens to fail. That looks like a potential
> memory leak... Perhaps that helper should free the state in any case the
> caller doesn't ask for a pointer?
> 
> Brian
Ok, I see it.  Will fix.  Thanks!

Allison


> 
>>   	error = xfs_attr_set_args(&args);
>>   	if (error)
>>   		goto out_trans_cancel;
>> @@ -525,6 +533,10 @@ xfs_attr_remove(
>>   	 */
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>>   
>> +	error = xfs_has_attr(&args);
>> +	if (error != -EEXIST)
>> +		goto out;
>> +
>>   	error = xfs_attr_remove_args(&args);
>>   	if (error)
>>   		goto out;
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-24 13:08   ` Brian Foster
@ 2020-02-24 21:19     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-24 21:19 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/24/20 6:08 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:06:00PM -0700, Allison Collins wrote:
>> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
>> while modularizing the adjacent code down into helpers. In this patch, hoist the
>> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
>> attr list creation down.
>>
>> 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>
Alrighty, thank you!

Allison
> 
>>   fs/xfs/libxfs/xfs_attr.c | 30 +++++++++++++++---------------
>>   1 file changed, 15 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index b2f0780..71298b9 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -227,8 +227,13 @@ xfs_attr_try_sf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>>   
>> -	struct xfs_mount	*mp = dp->i_mount;
>> -	int			error, error2;
>> +	int			error;
>> +
>> +	/*
>> +	 * Build initial attribute list (if required).
>> +	 */
>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> +		xfs_attr_shortform_create(args);
>>   
>>   	error = xfs_attr_shortform_addname(args);
>>   	if (error == -ENOSPC)
>> @@ -241,12 +246,10 @@ xfs_attr_try_sf_addname(
>>   	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>   
>> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
>> +	if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args->trans);
>>   
>> -	error2 = xfs_trans_commit(args->trans);
>> -	args->trans = NULL;
>> -	return error ? error : error2;
>> +	return error;
>>   }
>>   
>>   /*
>> @@ -258,7 +261,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,
>> @@ -269,17 +272,14 @@ xfs_attr_set_args(
>>   	     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;
>> +		if (error != -ENOSPC) {
>> +			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	[flat|nested] 135+ messages in thread

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-24 13:40   ` Brian Foster
@ 2020-02-24 21:44     ` Allison Collins
  2020-02-25 13:27       ` Brian Foster
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-24 21:44 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/24/20 6:40 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
>> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
>> new transactions. We will use this later when we introduce delayed attributes
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 29 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 3de2eec..da40f85 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>>   	}
>>   	return 0;
>>   }
>> +
>> +/*
>> + * Remove the value associated with an attribute by deleting the out-of-line
>> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
>> + * transaction and recall the function
>> + */
>> +int
>> +xfs_attr_rmtval_unmap(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int	error, done;
>> +
>> +	/*
>> +	 * Unmap value blocks for this attr.  This is similar to
>> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>> +	 * for new transactions
>> +	 */
>> +	error = xfs_bunmapi(args->trans, args->dp,
>> +		    args->rmtblkno, args->rmtblkcnt,
>> +		    XFS_BMAPI_ATTRFORK, 1, &done);
>> +	if (error)
>> +		return error;
>> +
>> +	if (!done)
>> +		return -EAGAIN;
>> +
>> +	return 0;
>> +}
> 
> Hmm.. any reason this isn't a refactor of the existing remove function?
> Just skipping to the end of the series, I see we leave the reference to
> xfs_attr_rmtval_remove() (which no longer exists and so is not very
> useful) in this comment as well as a stale function declaration in
> xfs_attr_remote.h.
> 
> I haven't grokked how this is used yet, but it seems like it would be
> more appropriate to lift out the transaction handling from the original
> function as we have throughout the rest of the code. That could also
> mean creating a temporary wrapper (i.e., rmtval_remove() calls
> rmtval_unmap()) for the loop/transaction code that could be removed
> later if it ends up unused. Either way is much easier to follow than
> creating a (currently unused) replacement..
Yes, this came up in one of the other reviews.  I thought about it, but 
then decided against it.  xfs_attr_rmtval_remove disappears across 
patches 13 and 14.  The use of xfs_attr_rmtval_remove is replaced with 
xfs_attr_rmtval_unmap when we finally yank out all the transaction code. 
  The reason I dont want to do it all at once is because that would mean 
patches 12, 13, 14 and 19 would lump together to make the swap 
instantaneous in once patch.

I've been getting feedback that the set is really complicated, so I've 
been trying to find a way to organize it to help make it easier to 
review.  So I thought isolating 13 and 14 to just the state machine 
would help.  Thus I decided to keep patch 12 separate to take as much 
craziness out of 13 and 14 as possible.  Patches 12 and 19 seem like 
otherwise easy things for people to look at.  Let me know your thoughts 
on this. :-)

You are right about the stale comment though, I missed it while going 
back over the commentary at the top.  Will fix.

Allison

> 
> Brian
> 
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index eff5f95..e06299a 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
>>   		xfs_buf_flags_t incore_flags);
>>   int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
>> +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-24 15:25   ` Brian Foster
  2020-02-24 17:03     ` Brian Foster
@ 2020-02-24 23:14     ` Allison Collins
  2020-02-24 23:56       ` Darrick J. Wong
  2020-02-25 13:34       ` Brian Foster
  1 sibling, 2 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-24 23:14 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 2/24/20 8:25 AM, Brian Foster wrote:
> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
>> This patch modifies the attr remove routines to be delay ready. This means they no
>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
>> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
>> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
>> been modified to use the switch, and a  new version of xfs_attr_remove_args
>> consists of a simple loop to refresh the transaction until the operation is
>> completed.
>>
>> This patch also adds a new struct xfs_delattr_context, which we will use to keep
>> track of the current state of an attribute operation. The new xfs_delattr_state
>> enum is used to track various operations that are in progress so that we know not
>> to repeat them, and resume where we left off before EAGAIN was returned to cycle
>> out the transaction. Other members take the place of local variables that need
>> to retain their values across multiple function recalls.
>>
>> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
>> indicate places where the function would return -EAGAIN, and then immediately
>> resume from after being recalled by the calling function.  States marked as a
>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>> function needs to pass them back to that subroutine to allow it to finish where
>> it left off. But they otherwise do not have a role in the calling function other
>> than just passing through.
>>
>>   xfs_attr_remove_iter()
>>           XFS_DAS_RM_SHRINK     ─┐
>>           (subroutine state)     │
>>                                  │
>>           XFS_DAS_RMTVAL_REMOVE ─┤
>>           (subroutine state)     │
>>                                  └─>xfs_attr_node_removename()
>>                                                   │
>>                                                   v
>>                                           need to remove
>>                                     ┌─n──  rmt blocks?
>>                                     │             │
>>                                     │             y
>>                                     │             │
>>                                     │             v
>>                                     │  ┌─>XFS_DAS_RMTVAL_REMOVE
>>                                     │  │          │
>>                                     │  │          v
>>                                     │  └──y── more blks
>>                                     │         to remove?
>>                                     │             │
>>                                     │             n
>>                                     │             │
>>                                     │             v
>>                                     │         need to
>>                                     └─────> shrink tree? ─n─┐
>>                                                   │         │
>>                                                   y         │
>>                                                   │         │
>>                                                   v         │
>>                                           XFS_DAS_RM_SHRINK │
>>                                                   │         │
>>                                                   v         │
>>                                                  done <─────┘
>>
> 
> Wow. :P I guess I have nothing against verbose commit logs, but I wonder
> how useful this level of documentation is for a patch that shouldn't
> really change the existing flow of the operation.

Yes Darrick had requested a diagram in the last review, so I had put 
this together.  I wasnt sure where the best place to put it even was, so 
I put it here at least for now.  I have no idea if there is a limit on 
commit message length, but if there is, I'm pretty sure I blew right 
past it in this patch and the next.  Maybe if anything it can just be 
here for now while we work through things?

> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>>   fs/xfs/libxfs/xfs_attr.h     |   1 +
>>   fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>>   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 +
>>   10 files changed, 141 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5d73bdf..cd3a3f7 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -368,11 +368,60 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +
>> +	do {
>> +		error = xfs_attr_remove_iter(args);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
> 
> I'm a little confused on the logic of this loop given that the only
> caller commits the transaction (which also finishes dfops). IOW, it
> seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
> that is the case, this can be simplified to something like:
Well, we need to do it when error == -EAGAIN or 0, right? Which I think 
better imitates the defer_finish routines.  That's why a lot of the 
existing code that just finishes off with a transaction just sort of 
gets sawed off at the end. Otherwise they would need one more state just 
to return -EAGAIN as the last thing they have to do. Did that make sense?

> 
> int
> xfs_attr_remove_args(
>          struct xfs_da_args      *args)
> {
>          int                     error;
> 
>          do {
>                  error = xfs_attr_remove_iter(args);
>                  if (error != -EAGAIN)
>                          break;
> 
>                  if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>                          args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>                          error = xfs_defer_finish(&args->trans);
>                          if (error)
>                                  break;
>                  }
> 
>                  error = xfs_trans_roll_inode(&args->trans, args->dp);
>                  if (error)
>                          break;
>          } while (true);
> 
>          return error;
> }
> 
> That has the added benefit of eliminating the whole err2 pattern, which
> always strikes me as a landmine.
> 
>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> 
> BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
> operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
Sure, will update

> 
>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>> +
>> +			err2 = xfs_defer_finish(&args->trans);
>> +			if (err2) {
>> +				error = err2;
>> +				goto out;
>> +			}
>> +		}
>> +
>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + *
>> + * This function may return -EAGAIN to signal that the transaction needs to be
>> + * rolled.  Callers should continue calling this function until they receive a
>> + * return value other than -EAGAIN.
>> + */
>> +int
>> +xfs_attr_remove_iter(
>>   	struct xfs_da_args      *args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	int			error;
>>   
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_RM_SHRINK:
>> +	case XFS_DAS_RMTVAL_REMOVE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	if (!xfs_inode_hasattr(dp)) {
>>   		error = -ENOATTR;
>>   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>>   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_removename(args);
>>   	} else {
>> +node:
>>   		error = xfs_attr_node_removename(args);
>>   	}
>>   
>> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>>   		/* bp is gone due to xfs_da_shrink_inode */
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +
>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>   	}
>>   	return 0;
>>   }
>> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>>    * This will involve walking down the Btree, and may involve joining
>>    * leaf nodes and even joining intermediate nodes up to and including
>>    * the root node (a special case of an intermediate node).
>> + *
>> + * This routine is meant to function as either an inline or delayed operation,
>> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
>> + * functions will need to handle this, and recall the function until a
>> + * successful error code is returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_removename(
>> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>>   	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_node_removename(args);
>> +	state = args->dac.da_state;
>> +	blk = args->dac.blk;
>> +
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_RMTVAL_REMOVE:
>> +		goto rm_node_blks;
>> +	case XFS_DAS_RM_SHRINK:
>> +		goto rm_shrink;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	error = xfs_attr_node_hasname(args, &state);
>>   	if (error != -EEXIST)
>>   		goto out;
>> +	else
>> +		error = 0;
> 
> This doesn't look necessary.
Well, at this point error has to be -EEXIST.  Which is great because we 
need the attr to exist, but we dont want to return that as error for 
this function.  Which can happen if error is not otherwise set.

> 
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
>>   	blk = &state->path.blk[ state->path.active-1 ];
>>   	ASSERT(blk->bp != NULL);
>>   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +
>> +	/*
>> +	 * Store blk and state in the context incase we need to cycle out the
>> +	 * transaction
>> +	 */
>> +	args->dac.blk = blk;
>> +	args->dac.da_state = state;
>> +
>>   	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Fill in disk block numbers in the state structure
>> @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr_rmtval_invalidate(args);
> 
> Remind me why we lose the above trans roll? I vaguely recall that this
> was intentional, but I could be mistaken...
I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE 
state, but then we reasoned that because these are just in-core changes, 
we didnt need it, so we eliminated this state entirely.

Maybe i just add a comment here?  Just as a reminder

> 
>>   		if (error)
>>   			goto out;
>> +	}
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>> -		if (error)
>> -			goto out;
>> +rm_node_blks:
>> +
>> +	if (args->rmtblkno > 0) {
>> +		error = xfs_attr_rmtval_unmap(args);
>> +
>> +		if (error) {
>> +			if (error == -EAGAIN)
>> +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
> 
> Might be helpful for the code labels to match the state names. I.e., use
> das_rmtval_remove: for the label above.
Sure, I can update add the das prefix.

> 
>> +			return error;
>> +		}
>>   
>>   		/*
>>   		 * Refill the state structure with buffers, the prior calls
>> @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
>>   		error = xfs_da3_join(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the Btree join operation and start a new trans.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			goto out;
>> +
>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
>> +		return -EAGAIN;
>>   	}
>>   
>> +rm_shrink:
>> +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
>> +
> 
> There's an xfs_defer_finish() call further down this function. Should
> that be replaced with the flag?
> 
> Finally, I mentioned in a previous review that this function should
> probably be further broken down before fitting in the state management
> stuff. It doesn't look like that happened so I've attached a diff that
> is just intended to give an idea of what I mean by sectioning off the
> hunks that might be able to break down into helpers. The helpers
> wouldn't contain any state management, so we create a clear separation
> between the state code and functional components. 
Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch 
to try and keep the activity in this one to a minimum.  Apologies if it 
surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS 
flag with it.  I meant to keep all the state machine stuff here.  Will fix!

I think this initial
> refactoring would make the introduction of state much more simple 

I guess I didn't think people would be partial to introducing helpers 
before or after the state logic.  I put them after in this set because 
the states are visible now, so I though it would make the goal of 
modularizing code between the states more clear to folks.  Do you think 
I should move it back behind the state machine patches?

(and
> perhaps alleviate the need for the huge diagram). 
Well, I get the impression that people find the series sort of scary and 
maybe the diagrams help them a bit.  Maybe we can take them out later 
after people feel like they are comfortable with things?

It might also be
> interesting to see how much of the result could be folded up further
> into _removename_iter()...

Yes, I think that is the goal we're reaching for.  I will add the other 
helpers I see in your diff too.

Thanks for the reviews!
Allison

> 
> Brian
> 
>>   	/*
>>   	 * If the result is small enough, push it all into the inode.
>>   	 */
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index ce7b039..ea873a5 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> +int xfs_attr_remove_iter(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);
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index 14f1be3..3c78498 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>>   };
>>   
>>   /*
>> + * Enum values for xfs_delattr_context.da_state
>> + *
>> + * These values are used by delayed attribute operations to keep track  of where
>> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
>> + * calling function to roll the transaction, and then recall the subroutine to
>> + * finish the operation.  The enum is then used by the subroutine to jump back
>> + * to where it was and resume executing where it left off.
>> + */
>> +enum xfs_delattr_state {
>> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
>> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
>> +};
>> +
>> +/*
>> + * Defines for xfs_delattr_context.flags
>> + */
>> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delattr_context {
>> +	struct xfs_da_state	*da_state;
>> +	struct xfs_da_state_blk *blk;
>> +	unsigned int		flags;
>> +	enum xfs_delattr_state	dela_state;
>> +};
>> +
>> +/*
>>    * Structure to ease passing around component names.
>>    */
>>   typedef struct xfs_da_args {
>> +	struct xfs_delattr_context dac; /* context used for delay attr ops */
>>   	struct xfs_da_geometry *geo;	/* da block geometry */
>>   	struct xfs_name	name;		/* name, length and argument  flags*/
>>   	uint8_t		filetype;	/* filetype of inode for directories */
>> 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 42ac847..d65e6d8 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 "xfs_error.h"
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
>>   
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-24 23:14     ` Allison Collins
@ 2020-02-24 23:56       ` Darrick J. Wong
  2020-02-25 13:34       ` Brian Foster
  1 sibling, 0 replies; 135+ messages in thread
From: Darrick J. Wong @ 2020-02-24 23:56 UTC (permalink / raw)
  To: Allison Collins; +Cc: Brian Foster, linux-xfs

On Mon, Feb 24, 2020 at 04:14:48PM -0700, Allison Collins wrote:
> On 2/24/20 8:25 AM, Brian Foster wrote:
> > On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> > > This patch modifies the attr remove routines to be delay ready. This means they no
> > > longer roll or commit transactions, but instead return -EAGAIN to have the calling
> > > routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> > > become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> > > track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> > > been modified to use the switch, and a  new version of xfs_attr_remove_args
> > > consists of a simple loop to refresh the transaction until the operation is
> > > completed.
> > > 
> > > This patch also adds a new struct xfs_delattr_context, which we will use to keep
> > > track of the current state of an attribute operation. The new xfs_delattr_state
> > > enum is used to track various operations that are in progress so that we know not
> > > to repeat them, and resume where we left off before EAGAIN was returned to cycle
> > > out the transaction. Other members take the place of local variables that need
> > > to retain their values across multiple function recalls.
> > > 
> > > Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> > > indicate places where the function would return -EAGAIN, and then immediately
> > > resume from after being recalled by the calling function.  States marked as a
> > > "subroutine state" indicate that they belong to a subroutine, and so the calling
> > > function needs to pass them back to that subroutine to allow it to finish where
> > > it left off. But they otherwise do not have a role in the calling function other
> > > than just passing through.
> > > 
> > >   xfs_attr_remove_iter()
> > >           XFS_DAS_RM_SHRINK     ─┐
> > >           (subroutine state)     │
> > >                                  │
> > >           XFS_DAS_RMTVAL_REMOVE ─┤
> > >           (subroutine state)     │
> > >                                  └─>xfs_attr_node_removename()
> > >                                                   │
> > >                                                   v
> > >                                           need to remove
> > >                                     ┌─n──  rmt blocks?
> > >                                     │             │
> > >                                     │             y
> > >                                     │             │
> > >                                     │             v
> > >                                     │  ┌─>XFS_DAS_RMTVAL_REMOVE
> > >                                     │  │          │
> > >                                     │  │          v
> > >                                     │  └──y── more blks
> > >                                     │         to remove?
> > >                                     │             │
> > >                                     │             n
> > >                                     │             │
> > >                                     │             v
> > >                                     │         need to
> > >                                     └─────> shrink tree? ─n─┐
> > >                                                   │         │
> > >                                                   y         │
> > >                                                   │         │
> > >                                                   v         │
> > >                                           XFS_DAS_RM_SHRINK │
> > >                                                   │         │
> > >                                                   v         │
> > >                                                  done <─────┘
> > > 
> > 
> > Wow. :P I guess I have nothing against verbose commit logs, but I wonder
> > how useful this level of documentation is for a patch that shouldn't
> > really change the existing flow of the operation.
> 
> Yes Darrick had requested a diagram in the last review, so I had put this
> together.  I wasnt sure where the best place to put it even was, so I put it
> here at least for now.  I have no idea if there is a limit on commit message
> length, but if there is, I'm pretty sure I blew right past it in this patch
> and the next.  Maybe if anything it can just be here for now while we work
> through things?

There is no limit, as far as I'm concerned, and it's worthwhile if it
will make it easy to trace through the old attr code, the new
restartable attr code, and (eventually) the attr intent item code to
make sure that nothing fell out by accident.

--D

> > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
> > >   fs/xfs/libxfs/xfs_attr.h     |   1 +
> > >   fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
> > >   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 +
> > >   10 files changed, 141 insertions(+), 16 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 5d73bdf..cd3a3f7 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -368,11 +368,60 @@ xfs_has_attr(
> > >    */
> > >   int
> > >   xfs_attr_remove_args(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error = 0;
> > > +	int			err2 = 0;
> > > +
> > > +	do {
> > > +		error = xfs_attr_remove_iter(args);
> > > +		if (error && error != -EAGAIN)
> > > +			goto out;
> > > +
> > 
> > I'm a little confused on the logic of this loop given that the only
> > caller commits the transaction (which also finishes dfops). IOW, it
> > seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
> > that is the case, this can be simplified to something like:
> Well, we need to do it when error == -EAGAIN or 0, right? Which I think
> better imitates the defer_finish routines.  That's why a lot of the existing
> code that just finishes off with a transaction just sort of gets sawed off
> at the end. Otherwise they would need one more state just to return -EAGAIN
> as the last thing they have to do. Did that make sense?
> 
> > 
> > int
> > xfs_attr_remove_args(
> >          struct xfs_da_args      *args)
> > {
> >          int                     error;
> > 
> >          do {
> >                  error = xfs_attr_remove_iter(args);
> >                  if (error != -EAGAIN)
> >                          break;
> > 
> >                  if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> >                          args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> >                          error = xfs_defer_finish(&args->trans);
> >                          if (error)
> >                                  break;
> >                  }
> > 
> >                  error = xfs_trans_roll_inode(&args->trans, args->dp);
> >                  if (error)
> >                          break;
> >          } while (true);
> > 
> >          return error;
> > }
> > 
> > That has the added benefit of eliminating the whole err2 pattern, which
> > always strikes me as a landmine.
> > 
> > > +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> > 
> > BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
> > operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
> Sure, will update
> 
> > 
> > > +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> > > +
> > > +			err2 = xfs_defer_finish(&args->trans);
> > > +			if (err2) {
> > > +				error = err2;
> > > +				goto out;
> > > +			}
> > > +		}
> > > +
> > > +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		if (err2) {
> > > +			error = err2;
> > > +			goto out;
> > > +		}
> > > +
> > > +	} while (error == -EAGAIN);
> > > +out:
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > > + * Remove the attribute specified in @args.
> > > + *
> > > + * This function may return -EAGAIN to signal that the transaction needs to be
> > > + * rolled.  Callers should continue calling this function until they receive a
> > > + * return value other than -EAGAIN.
> > > + */
> > > +int
> > > +xfs_attr_remove_iter(
> > >   	struct xfs_da_args      *args)
> > >   {
> > >   	struct xfs_inode	*dp = args->dp;
> > >   	int			error;
> > > +	/* State machine switch */
> > > +	switch (args->dac.dela_state) {
> > > +	case XFS_DAS_RM_SHRINK:
> > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > +		goto node;
> > > +	default:
> > > +		break;
> > > +	}
> > > +
> > >   	if (!xfs_inode_hasattr(dp)) {
> > >   		error = -ENOATTR;
> > >   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > > @@ -381,6 +430,7 @@ xfs_attr_remove_args(
> > >   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > >   		error = xfs_attr_leaf_removename(args);
> > >   	} else {
> > > +node:
> > >   		error = xfs_attr_node_removename(args);
> > >   	}
> > > @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
> > >   		/* bp is gone due to xfs_da_shrink_inode */
> > >   		if (error)
> > >   			return error;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			return error;
> > > +
> > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > >   	}
> > >   	return 0;
> > >   }
> > > @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
> > >    * This will involve walking down the Btree, and may involve joining
> > >    * leaf nodes and even joining intermediate nodes up to and including
> > >    * the root node (a special case of an intermediate node).
> > > + *
> > > + * This routine is meant to function as either an inline or delayed operation,
> > > + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> > > + * functions will need to handle this, and recall the function until a
> > > + * successful error code is returned.
> > >    */
> > >   STATIC int
> > >   xfs_attr_node_removename(
> > > @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
> > >   	struct xfs_inode	*dp = args->dp;
> > >   	trace_xfs_attr_node_removename(args);
> > > +	state = args->dac.da_state;
> > > +	blk = args->dac.blk;
> > > +
> > > +	/* State machine switch */
> > > +	switch (args->dac.dela_state) {
> > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > +		goto rm_node_blks;
> > > +	case XFS_DAS_RM_SHRINK:
> > > +		goto rm_shrink;
> > > +	default:
> > > +		break;
> > > +	}
> > >   	error = xfs_attr_node_hasname(args, &state);
> > >   	if (error != -EEXIST)
> > >   		goto out;
> > > +	else
> > > +		error = 0;
> > 
> > This doesn't look necessary.
> Well, at this point error has to be -EEXIST.  Which is great because we need
> the attr to exist, but we dont want to return that as error for this
> function.  Which can happen if error is not otherwise set.
> 
> > 
> > >   	/*
> > >   	 * If there is an out-of-line value, de-allocate the blocks.
> > > @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
> > >   	blk = &state->path.blk[ state->path.active-1 ];
> > >   	ASSERT(blk->bp != NULL);
> > >   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +
> > > +	/*
> > > +	 * Store blk and state in the context incase we need to cycle out the
> > > +	 * transaction
> > > +	 */
> > > +	args->dac.blk = blk;
> > > +	args->dac.da_state = state;
> > > +
> > >   	if (args->rmtblkno > 0) {
> > >   		/*
> > >   		 * Fill in disk block numbers in the state structure
> > > @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		error = xfs_attr_rmtval_invalidate(args);
> > 
> > Remind me why we lose the above trans roll? I vaguely recall that this
> > was intentional, but I could be mistaken...
> I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE
> state, but then we reasoned that because these are just in-core changes, we
> didnt need it, so we eliminated this state entirely.
> 
> Maybe i just add a comment here?  Just as a reminder
> 
> > 
> > >   		if (error)
> > >   			goto out;
> > > +	}
> > > -		error = xfs_attr_rmtval_remove(args);
> > > -		if (error)
> > > -			goto out;
> > > +rm_node_blks:
> > > +
> > > +	if (args->rmtblkno > 0) {
> > > +		error = xfs_attr_rmtval_unmap(args);
> > > +
> > > +		if (error) {
> > > +			if (error == -EAGAIN)
> > > +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
> > 
> > Might be helpful for the code labels to match the state names. I.e., use
> > das_rmtval_remove: for the label above.
> Sure, I can update add the das prefix.
> 
> > 
> > > +			return error;
> > > +		}
> > >   		/*
> > >   		 * Refill the state structure with buffers, the prior calls
> > > @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
> > >   		error = xfs_da3_join(state);
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			goto out;
> > > -		/*
> > > -		 * Commit the Btree join operation and start a new trans.
> > > -		 */
> > > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > > -		if (error)
> > > -			goto out;
> > > +
> > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > > +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > +		return -EAGAIN;
> > >   	}
> > > +rm_shrink:
> > > +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > +
> > 
> > There's an xfs_defer_finish() call further down this function. Should
> > that be replaced with the flag?
> > 
> > Finally, I mentioned in a previous review that this function should
> > probably be further broken down before fitting in the state management
> > stuff. It doesn't look like that happened so I've attached a diff that
> > is just intended to give an idea of what I mean by sectioning off the
> > hunks that might be able to break down into helpers. The helpers
> > wouldn't contain any state management, so we create a clear separation
> > between the state code and functional components.
> Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch to
> try and keep the activity in this one to a minimum.  Apologies if it
> surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS
> flag with it.  I meant to keep all the state machine stuff here.  Will fix!
> 
> I think this initial
> > refactoring would make the introduction of state much more simple
> 
> I guess I didn't think people would be partial to introducing helpers before
> or after the state logic.  I put them after in this set because the states
> are visible now, so I though it would make the goal of modularizing code
> between the states more clear to folks.  Do you think I should move it back
> behind the state machine patches?
> 
> (and
> > perhaps alleviate the need for the huge diagram).
> Well, I get the impression that people find the series sort of scary and
> maybe the diagrams help them a bit.  Maybe we can take them out later after
> people feel like they are comfortable with things?
> 
> It might also be
> > interesting to see how much of the result could be folded up further
> > into _removename_iter()...
> 
> Yes, I think that is the goal we're reaching for.  I will add the other
> helpers I see in your diff too.
> 
> Thanks for the reviews!
> Allison
> 
> > 
> > Brian
> > 
> > >   	/*
> > >   	 * If the result is small enough, push it all into the inode.
> > >   	 */
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index ce7b039..ea873a5 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> > >   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> > >   int xfs_has_attr(struct xfs_da_args *args);
> > >   int xfs_attr_remove_args(struct xfs_da_args *args);
> > > +int xfs_attr_remove_iter(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);
> > > diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> > > index 14f1be3..3c78498 100644
> > > --- a/fs/xfs/libxfs/xfs_da_btree.h
> > > +++ b/fs/xfs/libxfs/xfs_da_btree.h
> > > @@ -50,9 +50,39 @@ enum xfs_dacmp {
> > >   };
> > >   /*
> > > + * Enum values for xfs_delattr_context.da_state
> > > + *
> > > + * These values are used by delayed attribute operations to keep track  of where
> > > + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> > > + * calling function to roll the transaction, and then recall the subroutine to
> > > + * finish the operation.  The enum is then used by the subroutine to jump back
> > > + * to where it was and resume executing where it left off.
> > > + */
> > > +enum xfs_delattr_state {
> > > +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> > > +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> > > +};
> > > +
> > > +/*
> > > + * Defines for xfs_delattr_context.flags
> > > + */
> > > +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> > > +
> > > +/*
> > > + * Context used for keeping track of delayed attribute operations
> > > + */
> > > +struct xfs_delattr_context {
> > > +	struct xfs_da_state	*da_state;
> > > +	struct xfs_da_state_blk *blk;
> > > +	unsigned int		flags;
> > > +	enum xfs_delattr_state	dela_state;
> > > +};
> > > +
> > > +/*
> > >    * Structure to ease passing around component names.
> > >    */
> > >   typedef struct xfs_da_args {
> > > +	struct xfs_delattr_context dac; /* context used for delay attr ops */
> > >   	struct xfs_da_geometry *geo;	/* da block geometry */
> > >   	struct xfs_name	name;		/* name, length and argument  flags*/
> > >   	uint8_t		filetype;	/* filetype of inode for directories */
> > > 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 42ac847..d65e6d8 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 "xfs_error.h"
> > > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> > > index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
> > > -- 
> > > 2.7.4
> > > 
> > 

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

* Re: [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name
  2020-02-23 16:03     ` Allison Collins
@ 2020-02-25  0:49       ` Dave Chinner
  0 siblings, 0 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  0:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: Amir Goldstein, linux-xfs

On Sun, Feb 23, 2020 at 09:03:05AM -0700, Allison Collins wrote:
> On 2/23/20 2:34 AM, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > A struct inititializer macro would have been nice, so code like this:
> > 
> > +       struct xfs_name         xname;
> > +
> > +       xfs_name_init(&xname, name);
> > 
> > Would become:
> > +       struct xfs_name         xname = XFS_NAME_STR_INIT(name);
> > 
> > As a matter of fact, in most of the cases a named local variable is
> > not needed at
> > all and the code could be written with an anonymous local struct variable macro:
> > 
> > +       error = xfs_attr_remove(XFS_I(inode), XFS_NAME_STR(name), flags);
> > 
> The macro does look nice.  I would be the third iteration of initializers
> that this patch has been through though.  Can I get a consensus of how many
> people like the macro?

Not me. All it means is that every time I look at this code I have
to go look at what that shouty macro does, then have to understand
it's being "smart and clever" to save a couple of lines of clear,
obviously correct code.

That's not an improvement.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
  2020-02-23 11:54   ` Amir Goldstein
@ 2020-02-25  0:57   ` Dave Chinner
  2020-02-25  2:00     ` Allison Collins
  2020-02-25  6:56   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  0:57 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:05:54PM -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.

Commit message should wrap at 68-72 columns.

> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>  fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>  fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>  fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>  fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>  fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>  fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>  fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>  fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>  fs/xfs/scrub/attr.c             |  12 ++---
>  fs/xfs/xfs_trace.h              |  20 ++++----
>  12 files changed, 130 insertions(+), 123 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 6717f47..9acdb23 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>  	args->geo = dp->i_mount->m_attr_geo;
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
> -	args->flags = flags;
> -	args->name = name->name;
> -	args->namelen = name->len;
> -	if (args->namelen >= MAXNAMELEN)
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
> +	args->name.type = flags;

This doesn't play well with Christoph's cleanup series which fixes
up all the confusion with internal versus API flags. I guess the
namespace is part of the attribute name, but I think this would be a
much clearer conversion when placed on top of the way Christoph
cleaned all this up...

Have you looked at rebasing this on top of that cleanup series?

Cheers,

-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  0:57   ` Dave Chinner
@ 2020-02-25  2:00     ` Allison Collins
  2020-02-25  4:06       ` Dave Chinner
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-25  2:00 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/24/20 5:57 PM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:05:54PM -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.
> 
> Commit message should wrap at 68-72 columns.
> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>   fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>   fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>   fs/xfs/scrub/attr.c             |  12 ++---
>>   fs/xfs/xfs_trace.h              |  20 ++++----
>>   12 files changed, 130 insertions(+), 123 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 6717f47..9acdb23 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>   	args->geo = dp->i_mount->m_attr_geo;
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>> -	args->flags = flags;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> -	if (args->namelen >= MAXNAMELEN)
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>> +	args->name.type = flags;
> 
> This doesn't play well with Christoph's cleanup series which fixes
> up all the confusion with internal versus API flags. I guess the
> namespace is part of the attribute name, but I think this would be a
> much clearer conversion when placed on top of the way Christoph
> cleaned all this up...
> 
> Have you looked at rebasing this on top of that cleanup series?
> 
> Cheers,
> 
Yes, there is some conflict between the sets here and there, but I think 
folks wanted to keep them separate for now.  Are you referring to 
"[780d29057781] xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag"?  I'm 
pretty sure this set is already seated on top of that one.  This one is 
based on the latest for-next.

Allison

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  2:00     ` Allison Collins
@ 2020-02-25  4:06       ` Dave Chinner
  2020-02-25  4:19         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  4:06 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 07:00:35PM -0700, Allison Collins wrote:
> 
> 
> On 2/24/20 5:57 PM, Dave Chinner wrote:
> > On Sat, Feb 22, 2020 at 07:05:54PM -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.
> > 
> > Commit message should wrap at 68-72 columns.
> > 
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > Reviewed-by: Brian Foster <bfoster@redhat.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
> > >   fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
> > >   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
> > >   fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
> > >   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
> > >   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
> > >   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
> > >   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
> > >   fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
> > >   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
> > >   fs/xfs/scrub/attr.c             |  12 ++---
> > >   fs/xfs/xfs_trace.h              |  20 ++++----
> > >   12 files changed, 130 insertions(+), 123 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 6717f47..9acdb23 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -72,13 +72,12 @@ xfs_attr_args_init(
> > >   	args->geo = dp->i_mount->m_attr_geo;
> > >   	args->whichfork = XFS_ATTR_FORK;
> > >   	args->dp = dp;
> > > -	args->flags = flags;
> > > -	args->name = name->name;
> > > -	args->namelen = name->len;
> > > -	if (args->namelen >= MAXNAMELEN)
> > > +	memcpy(&args->name, name, sizeof(struct xfs_name));
> > > +	args->name.type = flags;
> > 
> > This doesn't play well with Christoph's cleanup series which fixes
> > up all the confusion with internal versus API flags. I guess the
> > namespace is part of the attribute name, but I think this would be a
> > much clearer conversion when placed on top of the way Christoph
> > cleaned all this up...
> > 
> > Have you looked at rebasing this on top of that cleanup series?
> > 
> > Cheers,
> > 
> Yes, there is some conflict between the sets here and there, but I think
> folks wanted to keep them separate for now.

That makes it really hard to form a clear view of what the code
looks like after both patchsets have been applied. :(

> Are you referring to
> "[780d29057781] xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag"?  I'm
> pretty sure this set is already seated on top of that one.  This one is
> based on the latest for-next.

No, I'm talking about the series that ends up undoing that commit
(i.e. the DA_OP_INCOMPLETE flag goes away again) and turns
args->flags into args->attr_filter as the namespace filter for
lookups. THis also turn adds XFS_ATTR_INCOMPLETE into a lookup
filter.

With this separation of ops vs lookup filters, moving the lookup
filter into the xfs_name makes a bit more sense (i.e. the namespace
filter is passed with the attribute name), but as a standalone
movement it creates a bit of an impedence mismatch between the xname
and the use of these flags.

I think the end result will be fine, but it's making it hard for me
to reconcile the changes in the two patchsets...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  4:06       ` Dave Chinner
@ 2020-02-25  4:19         ` Allison Collins
  2020-02-25  4:27           ` Darrick J. Wong
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-25  4:19 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/24/20 9:06 PM, Dave Chinner wrote:
> On Mon, Feb 24, 2020 at 07:00:35PM -0700, Allison Collins wrote:
>>
>>
>> On 2/24/20 5:57 PM, Dave Chinner wrote:
>>> On Sat, Feb 22, 2020 at 07:05:54PM -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.
>>>
>>> Commit message should wrap at 68-72 columns.
>>>
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>>>    fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>>>    fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>>>    fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>>>    fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>>>    fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>>>    fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>>>    fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>>>    fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>>>    fs/xfs/scrub/attr.c             |  12 ++---
>>>>    fs/xfs/xfs_trace.h              |  20 ++++----
>>>>    12 files changed, 130 insertions(+), 123 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 6717f47..9acdb23 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>>>    	args->geo = dp->i_mount->m_attr_geo;
>>>>    	args->whichfork = XFS_ATTR_FORK;
>>>>    	args->dp = dp;
>>>> -	args->flags = flags;
>>>> -	args->name = name->name;
>>>> -	args->namelen = name->len;
>>>> -	if (args->namelen >= MAXNAMELEN)
>>>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>>> +	args->name.type = flags;
>>>
>>> This doesn't play well with Christoph's cleanup series which fixes
>>> up all the confusion with internal versus API flags. I guess the
>>> namespace is part of the attribute name, but I think this would be a
>>> much clearer conversion when placed on top of the way Christoph
>>> cleaned all this up...
>>>
>>> Have you looked at rebasing this on top of that cleanup series?
>>>
>>> Cheers,
>>>
>> Yes, there is some conflict between the sets here and there, but I think
>> folks wanted to keep them separate for now.
> 
> That makes it really hard to form a clear view of what the code
> looks like after both patchsets have been applied. :(
> 
>> Are you referring to
>> "[780d29057781] xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag"?  I'm
>> pretty sure this set is already seated on top of that one.  This one is
>> based on the latest for-next.
> 
> No, I'm talking about the series that ends up undoing that commit
> (i.e. the DA_OP_INCOMPLETE flag goes away again) and turns
> args->flags into args->attr_filter as the namespace filter for
> lookups. THis also turn adds XFS_ATTR_INCOMPLETE into a lookup
> filter.
> 
> With this separation of ops vs lookup filters, moving the lookup
> filter into the xfs_name makes a bit more sense (i.e. the namespace
> filter is passed with the attribute name), but as a standalone
> movement it creates a bit of an impedence mismatch between the xname
> and the use of these flags.
> 
> I think the end result will be fine, but it's making it hard for me
> to reconcile the changes in the two patchsets...
> 
> Cheers,

I'd be happy to go through the sets and find the intersections. Or make 
a big super set if you like.  I got the impression though that Christoph 
didnt particularly like the delayed attr series or the idea of blending 
them.  But I do think it would be a good idea to take into consideration 
what the combination of them is going to look like.

Allison

> 
> Dave.
> 



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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  4:19         ` Allison Collins
@ 2020-02-25  4:27           ` Darrick J. Wong
  2020-02-25  6:07             ` Allison Collins
  2020-02-25 17:21             ` Christoph Hellwig
  0 siblings, 2 replies; 135+ messages in thread
From: Darrick J. Wong @ 2020-02-25  4:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: Dave Chinner, linux-xfs

On Mon, Feb 24, 2020 at 09:19:58PM -0700, Allison Collins wrote:
> 
> 
> On 2/24/20 9:06 PM, Dave Chinner wrote:
> > On Mon, Feb 24, 2020 at 07:00:35PM -0700, Allison Collins wrote:
> > > 
> > > 
> > > On 2/24/20 5:57 PM, Dave Chinner wrote:
> > > > On Sat, Feb 22, 2020 at 07:05:54PM -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.
> > > > 
> > > > Commit message should wrap at 68-72 columns.
> > > > 
> > > > > 
> > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > Reviewed-by: Brian Foster <bfoster@redhat.com>
> > > > > ---
> > > > >    fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
> > > > >    fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
> > > > >    fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
> > > > >    fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
> > > > >    fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
> > > > >    fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
> > > > >    fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
> > > > >    fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
> > > > >    fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
> > > > >    fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
> > > > >    fs/xfs/scrub/attr.c             |  12 ++---
> > > > >    fs/xfs/xfs_trace.h              |  20 ++++----
> > > > >    12 files changed, 130 insertions(+), 123 deletions(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > index 6717f47..9acdb23 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > > @@ -72,13 +72,12 @@ xfs_attr_args_init(
> > > > >    	args->geo = dp->i_mount->m_attr_geo;
> > > > >    	args->whichfork = XFS_ATTR_FORK;
> > > > >    	args->dp = dp;
> > > > > -	args->flags = flags;
> > > > > -	args->name = name->name;
> > > > > -	args->namelen = name->len;
> > > > > -	if (args->namelen >= MAXNAMELEN)
> > > > > +	memcpy(&args->name, name, sizeof(struct xfs_name));
> > > > > +	args->name.type = flags;
> > > > 
> > > > This doesn't play well with Christoph's cleanup series which fixes
> > > > up all the confusion with internal versus API flags. I guess the
> > > > namespace is part of the attribute name, but I think this would be a
> > > > much clearer conversion when placed on top of the way Christoph
> > > > cleaned all this up...
> > > > 
> > > > Have you looked at rebasing this on top of that cleanup series?
> > > > 
> > > > Cheers,
> > > > 
> > > Yes, there is some conflict between the sets here and there, but I think
> > > folks wanted to keep them separate for now.
> > 
> > That makes it really hard to form a clear view of what the code
> > looks like after both patchsets have been applied. :(
> > 
> > > Are you referring to
> > > "[780d29057781] xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag"?  I'm
> > > pretty sure this set is already seated on top of that one.  This one is
> > > based on the latest for-next.
> > 
> > No, I'm talking about the series that ends up undoing that commit
> > (i.e. the DA_OP_INCOMPLETE flag goes away again) and turns
> > args->flags into args->attr_filter as the namespace filter for
> > lookups. THis also turn adds XFS_ATTR_INCOMPLETE into a lookup
> > filter.
> > 
> > With this separation of ops vs lookup filters, moving the lookup
> > filter into the xfs_name makes a bit more sense (i.e. the namespace
> > filter is passed with the attribute name), but as a standalone
> > movement it creates a bit of an impedence mismatch between the xname
> > and the use of these flags.
> > 
> > I think the end result will be fine, but it's making it hard for me
> > to reconcile the changes in the two patchsets...
> > 
> > Cheers,
> 
> I'd be happy to go through the sets and find the intersections. Or make a
> big super set if you like.  I got the impression though that Christoph didnt
> particularly like the delayed attr series or the idea of blending them.  But
> I do think it would be a good idea to take into consideration what the
> combination of them is going to look like.

At this point you might as well wait for me to actually put hch's attr
interface refactoring series into for-next (unless this series is
already based off of that??) though Christoph might be a bit time
constrained this week...

--D

> Allison
> 
> > 
> > Dave.
> > 
> 
> 

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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-24 16:23       ` Allison Collins
@ 2020-02-25  5:53         ` Amir Goldstein
  0 siblings, 0 replies; 135+ messages in thread
From: Amir Goldstein @ 2020-02-25  5:53 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

> Ok, I think I understand what you're trying to say.  Would it help to
> explain then that setting or removing an attr becomes part of the
> namespace operations later?  When we get up into the parent pointer set,
> a lot of those patches add an attribute set or remove every time we
> link, unlink, rename etc.  Did that help answer your question?
>

I will wait for the parent pointers series,

Thanks,
Amir.

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  4:27           ` Darrick J. Wong
@ 2020-02-25  6:07             ` Allison Collins
  2020-02-25  6:30               ` Dave Chinner
  2020-02-25 17:21             ` Christoph Hellwig
  1 sibling, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-25  6:07 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Dave Chinner, linux-xfs



On 2/24/20 9:27 PM, Darrick J. Wong wrote:
> On Mon, Feb 24, 2020 at 09:19:58PM -0700, Allison Collins wrote:
>>
>>
>> On 2/24/20 9:06 PM, Dave Chinner wrote:
>>> On Mon, Feb 24, 2020 at 07:00:35PM -0700, Allison Collins wrote:
>>>>
>>>>
>>>> On 2/24/20 5:57 PM, Dave Chinner wrote:
>>>>> On Sat, Feb 22, 2020 at 07:05:54PM -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.
>>>>>
>>>>> Commit message should wrap at 68-72 columns.
>>>>>
>>>>>>
>>>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>>>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>>>>>> ---
>>>>>>     fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>>>>>     fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>>>>>     fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>>>>>     fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>>>>>     fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>>>>>     fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>>>>>     fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>>>>>     fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>>>>>     fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>>>>>     fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>>>>>     fs/xfs/scrub/attr.c             |  12 ++---
>>>>>>     fs/xfs/xfs_trace.h              |  20 ++++----
>>>>>>     12 files changed, 130 insertions(+), 123 deletions(-)
>>>>>>
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>>>> index 6717f47..9acdb23 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>>>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>>>>>     	args->geo = dp->i_mount->m_attr_geo;
>>>>>>     	args->whichfork = XFS_ATTR_FORK;
>>>>>>     	args->dp = dp;
>>>>>> -	args->flags = flags;
>>>>>> -	args->name = name->name;
>>>>>> -	args->namelen = name->len;
>>>>>> -	if (args->namelen >= MAXNAMELEN)
>>>>>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>>>>> +	args->name.type = flags;
>>>>>
>>>>> This doesn't play well with Christoph's cleanup series which fixes
>>>>> up all the confusion with internal versus API flags. I guess the
>>>>> namespace is part of the attribute name, but I think this would be a
>>>>> much clearer conversion when placed on top of the way Christoph
>>>>> cleaned all this up...
>>>>>
>>>>> Have you looked at rebasing this on top of that cleanup series?
>>>>>
>>>>> Cheers,
>>>>>
>>>> Yes, there is some conflict between the sets here and there, but I think
>>>> folks wanted to keep them separate for now.
>>>
>>> That makes it really hard to form a clear view of what the code
>>> looks like after both patchsets have been applied. :(
>>>
>>>> Are you referring to
>>>> "[780d29057781] xfs: fix misuse of the XFS_ATTR_INCOMPLETE flag"?  I'm
>>>> pretty sure this set is already seated on top of that one.  This one is
>>>> based on the latest for-next.
>>>
>>> No, I'm talking about the series that ends up undoing that commit
>>> (i.e. the DA_OP_INCOMPLETE flag goes away again) and turns
>>> args->flags into args->attr_filter as the namespace filter for
>>> lookups. THis also turn adds XFS_ATTR_INCOMPLETE into a lookup
>>> filter.
>>>
>>> With this separation of ops vs lookup filters, moving the lookup
>>> filter into the xfs_name makes a bit more sense (i.e. the namespace
>>> filter is passed with the attribute name), but as a standalone
>>> movement it creates a bit of an impedence mismatch between the xname
>>> and the use of these flags.
>>>
>>> I think the end result will be fine, but it's making it hard for me
>>> to reconcile the changes in the two patchsets...
>>>
>>> Cheers,
>>
>> I'd be happy to go through the sets and find the intersections. Or make a
>> big super set if you like.  I got the impression though that Christoph didnt
>> particularly like the delayed attr series or the idea of blending them.  But
>> I do think it would be a good idea to take into consideration what the
>> combination of them is going to look like.
> 
> At this point you might as well wait for me to actually put hch's attr
> interface refactoring series into for-next (unless this series is
> already based off of that??) though Christoph might be a bit time
> constrained this week...

It's based on for-next at this point.  Both these sets are pretty big, 
so it's a lot to chase if he's not interested in slowing down to work 
with the combination of them.  If folks would like to see the 
combination set before moving forward, I'd be happy to try and put that 
together.  Otherwise, it can wait too.  Let me know.  Thanks!

Allison

> 
> --D
> 
>> Allison
>>
>>>
>>> Dave.
>>>
>>
>>

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23 12:20   ` Amir Goldstein
  2020-02-23 17:28     ` Allison Collins
@ 2020-02-25  6:26     ` Dave Chinner
  2020-02-25  6:43       ` Amir Goldstein
  1 sibling, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  6:26 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Allison Collins, linux-xfs

On Sun, Feb 23, 2020 at 02:20:32PM +0200, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> <allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
> > routines later for delayed attributes since delayed operations cannot return error
> > codes.
> >
> > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> >  fs/xfs/libxfs/xfs_attr.h      |   1 +
> >  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> >  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> >  4 files changed, 188 insertions(+), 98 deletions(-)
> >
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 9acdb23..2255060 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> >
> >  /*
> >   * Internal routines when attribute list is more than one block.
> > @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> > +                                struct xfs_da_state **state);
> >  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> >  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> >
> > @@ -310,6 +313,37 @@ xfs_attr_set_args(
> >  }
> >
> >  /*
> > + * Return EEXIST if attr is found, or ENOATTR if not
> 
> This is a very silly return value for a function named has_attr in my taste.
> I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
> IMO this change looks like a very good opportunity to change that internal
> API:

tl;dr Cleaning up this API is work for another patchset.

> 
> xfs_has_attr?
> 
> 0: NO
> 1: YES (or stay with the syscall standard of -ENOATTR)
> <0: error

While I agree with your sentiment, Amir, the API you suggest is an
anti-pattern. We've been removing ternary return value APIs like
this from XFS and replacing them with an explicit error return value
and an operational return parameter like so:

	error = xfs_has_attr(&exists)
	if (error)
		return error;

	if (!exists && REPLACE) {
		error = -ENOATTR;
		goto out_error_release;
	}
	if (exists && CREATE) {
		error = -EEXIST;
		goto out_error_release;
	}

	.....

out_error_release:
	xfs_trans_brelse(args->trans, bp);
	return error;

This allows us to separate out fatal metadata fetch and parsing
errors from the operational logic that is run on the status returned
from a successful function call.

IMO, this sort of API change needs to be driven right down into
the internal functions that generate ENOATTR/EEXIST in the first
place. Otherwise all we are doing here is forcing the new code to
translate ENOATTR/EEXIST to some intermediate error code that the
higher layer code then has to convert back to ENOATTR/EEXIST so that
it's callers function properly.

Hence I don't think chagning this API just for this new function
makes the code simpler or easier to maintain. And I don't really
think changing the entire API is in the scope of this work. Hence,
even though I don't like the API, I think it is fine to be retained
for this patchset.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  6:07             ` Allison Collins
@ 2020-02-25  6:30               ` Dave Chinner
  0 siblings, 0 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  6:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: Darrick J. Wong, linux-xfs

On Mon, Feb 24, 2020 at 11:07:37PM -0700, Allison Collins wrote:
> It's based on for-next at this point.  Both these sets are pretty big, so
> it's a lot to chase if he's not interested in slowing down to work with the
> combination of them.  If folks would like to see the combination set before
> moving forward, I'd be happy to try and put that together.  Otherwise, it
> can wait too.  Let me know.  Thanks!

I'd simply rebase it on top of christoph's patchset based on the
fact it's likely to be merged before this one. Christoph posted a
git tree link, just pull that down and use that as the topic branch
you rebase onto....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
  2020-02-23 12:42   ` Amir Goldstein
@ 2020-02-25  6:42   ` Dave Chinner
  2020-02-25 13:26     ` Brian Foster
  2020-02-25 23:26     ` Allison Collins
  2020-02-28  6:51   ` Chandan Rajendra
  2 siblings, 2 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  6:42 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:05:59PM -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, and move the commit into the calling function.

68-72 columns :P

> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 88 +++++++++++++++++++++++++++++++-----------------
>  1 file changed, 57 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index cf0cba7..b2f0780 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -305,10 +305,30 @@ xfs_attr_set_args(
>  		}
>  	}
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_addname(args);
> -	else
> -		error = xfs_attr_node_addname(args);
> +		if (error != -ENOSPC)
> +			return error;
> +
> +		/*
> +		 * Commit that transaction so that the node_addname()
> +		 * call can manage its own transactions.
> +		 */
> +		error = xfs_defer_finish(&args->trans);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Commit the current trans (including the inode) and
> +		 * start a new one.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, dp);
> +		if (error)
> +			return error;
> +
> +	}
> +
> +	error = xfs_attr_node_addname(args);
>  	return error;

	return xfs_attr_node_addname(args);

better yet:

	if (!xfs_bmap_one_block(dp, XFS_ATTR_FORK))
		return xfs_attr_node_addname(args);

	error = xfs_attr_leaf_addname(args);
	if (error != -ENOSPC)
		return error;
	.....

BTW, I think I see the pattern now - isolate all the metadata
changes from the mechanism of rolling the transactions, which means
it can be converted to a set of operations connected by a generic
transaction rolling mechanism. It's all starting to make more sense
now :P

> @@ -679,31 +700,36 @@ xfs_attr_leaf_addname(
>  	retval = xfs_attr3_leaf_add(bp, args);
>  	if (retval == -ENOSPC) {
>  		/*
> -		 * Promote the attribute list to the Btree format, then
> -		 * Commit that transaction so that the node_addname() call
> -		 * can manage its own transactions.
> +		 * Promote the attribute list to the Btree format.
> +		 * Unless an error occurs, retain the -ENOSPC retval
>  		 */

Comments should use all 80 columns...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25  6:26     ` Dave Chinner
@ 2020-02-25  6:43       ` Amir Goldstein
  2020-02-25 22:27         ` Dave Chinner
  0 siblings, 1 reply; 135+ messages in thread
From: Amir Goldstein @ 2020-02-25  6:43 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Allison Collins, linux-xfs

On Tue, Feb 25, 2020 at 8:26 AM Dave Chinner <david@fromorbit.com> wrote:
>
> On Sun, Feb 23, 2020 at 02:20:32PM +0200, Amir Goldstein wrote:
> > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > <allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
> > > routines later for delayed attributes since delayed operations cannot return error
> > > codes.
> > >
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> > >  fs/xfs/libxfs/xfs_attr.h      |   1 +
> > >  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> > >  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> > >  4 files changed, 188 insertions(+), 98 deletions(-)
> > >
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 9acdb23..2255060 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > > +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> > >
> > >  /*
> > >   * Internal routines when attribute list is more than one block.
> > > @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> > >  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> > > +                                struct xfs_da_state **state);
> > >  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> > >  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> > >
> > > @@ -310,6 +313,37 @@ xfs_attr_set_args(
> > >  }
> > >
> > >  /*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> >
> > This is a very silly return value for a function named has_attr in my taste.
> > I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
> > IMO this change looks like a very good opportunity to change that internal
> > API:
>
> tl;dr Cleaning up this API is work for another patchset.
>
> >
> > xfs_has_attr?
> >
> > 0: NO
> > 1: YES (or stay with the syscall standard of -ENOATTR)
> > <0: error
>
> While I agree with your sentiment, Amir, the API you suggest is an
> anti-pattern. We've been removing ternary return value APIs like
> this from XFS and replacing them with an explicit error return value
> and an operational return parameter like so:
>
>         error = xfs_has_attr(&exists)
>         if (error)
>                 return error;
>

That would be neat and tidy.

One of the outcomes of new reviewers is comments on code unrelated
to the changes... I have no problem of keeping API as is for Allison's
change, but I did want to point out that the API became worse to read
due to the helper name change from _lookup_attr to _has_attr, which
really asks for a yes or no answer.

Thanks,
Amir.

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
  2020-02-23 11:54   ` Amir Goldstein
  2020-02-25  0:57   ` Dave Chinner
@ 2020-02-25  6:56   ` Chandan Rajendra
  2020-02-25 23:26     ` Allison Collins
  2 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-25  6:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM 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.
>

The statement "name = &args.name;" in xfs_attr_set() and xfs_attr_remove() was
not apparent to me on first read. However your explaination to Amir's question
about name.type being set in xfs_attr_args_init() made it clear.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>  fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>  fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>  fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>  fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>  fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>  fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>  fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>  fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>  fs/xfs/scrub/attr.c             |  12 ++---
>  fs/xfs/xfs_trace.h              |  20 ++++----
>  12 files changed, 130 insertions(+), 123 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 6717f47..9acdb23 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>  	args->geo = dp->i_mount->m_attr_geo;
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
> -	args->flags = flags;
> -	args->name = name->name;
> -	args->namelen = name->len;
> -	if (args->namelen >= MAXNAMELEN)
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
> +	args->name.type = flags;
> +	if (args->name.len >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  
> -	args->hashval = xfs_da_hashname(args->name, args->namelen);
> +	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
>  	return 0;
>  }
>  
> @@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
>  	 * Commit the shortform mods, and we're done.
>  	 * NOTE: this is also the error path (EEXIST, etc).
>  	 */
> -	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
> +	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>  
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
> @@ -357,6 +356,9 @@ xfs_attr_set(
>  	if (error)
>  		return error;
>  
> +	/* Use name now stored in args */
> +	name = &args.name;
> +
>  	args.value = value;
>  	args.valuelen = valuelen;
>  	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
> @@ -372,7 +374,7 @@ xfs_attr_set(
>  	 */
>  	if (XFS_IFORK_Q(dp) == 0) {
>  		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
> -			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
> +			XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
>  
>  		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>  		if (error)
> @@ -457,6 +459,9 @@ xfs_attr_remove(
>  	if (error)
>  		return error;
>  
> +	/* Use name now stored in args */
> +	name = &args.name;
> +
>  	/*
>  	 * we have no control over the attribute names that userspace passes us
>  	 * to remove, so we have to allow the name lookup prior to attribute
> @@ -532,10 +537,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>  	trace_xfs_attr_sf_addname(args);
>  
>  	retval = xfs_attr_shortform_lookup(args);
> -	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		return retval;
>  	} else if (retval == -EEXIST) {
> -		if (args->flags & ATTR_CREATE)
> +		if (args->name.type & ATTR_CREATE)
>  			return retval;
>  		retval = xfs_attr_shortform_remove(args);
>  		if (retval)
> @@ -545,15 +550,15 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>  		 * that the leaf format add routine won't trip over the attr
>  		 * not being around.
>  		 */
> -		args->flags &= ~ATTR_REPLACE;
> +		args->name.type &= ~ATTR_REPLACE;
>  	}
>  
> -	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
> +	if (args->name.len >= XFS_ATTR_SF_ENTSIZE_MAX ||
>  	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
>  		return -ENOSPC;
>  
>  	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
> -	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
> +	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>  
>  	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
>  	if (!forkoff)
> @@ -598,11 +603,11 @@ xfs_attr_leaf_addname(
>  	 * the given flags produce an error or call for an atomic rename.
>  	 */
>  	retval = xfs_attr3_leaf_lookup_int(bp, args);
> -	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return retval;
>  	} else if (retval == -EEXIST) {
> -		if (args->flags & ATTR_CREATE) {	/* pure create op */
> +		if (args->name.type & ATTR_CREATE) {	/* pure create op */
>  			xfs_trans_brelse(args->trans, bp);
>  			return retval;
>  		}
> @@ -872,10 +877,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);
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index fed537a..cb5ef66 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -464,7 +464,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;
>  	}
> @@ -679,27 +679,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);
> @@ -749,11 +749,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;
>  	}
> @@ -816,11 +816,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;
>  	}
> @@ -847,13 +847,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;
> @@ -912,13 +912,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);
> @@ -1119,12 +1119,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;
> @@ -1450,7 +1450,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) &&
> @@ -1474,15 +1474,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;
> @@ -2409,23 +2410,25 @@ xfs_attr3_leaf_lookup_int(
>  		}
>  		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);
> @@ -2467,16 +2470,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,
> @@ -2692,7 +2696,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;
> @@ -2700,7 +2704,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);
>  }
>  
>  
> @@ -2754,8 +2758,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 8b7f74b..df8aca5 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -397,7 +397,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 875e04f..30f27d7 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.c
> +++ b/fs/xfs/libxfs/xfs_da_btree.c
> @@ -2125,8 +2125,10 @@ 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;
> +	if (args->name.len == len && !memcmp(args->name.name, name, len))
> +		return XFS_CMP_EXACT;
> +
> +	return XFS_CMP_DIFFERENT;
>  }
>  
>  int
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index 0f4fbb0..14f1be3 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -54,12 +54,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 dd6fcaa..3aadddc 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;
>  	}
> @@ -265,8 +265,7 @@ xfs_dir_createname(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>  	args->filetype = name->type;
>  	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>  	args->inumber = inum;
> @@ -361,8 +360,7 @@ xfs_dir_lookup(
>  	 */
>  	args = kmem_zalloc(sizeof(*args), KM_NOFS);
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>  	args->filetype = name->type;
>  	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>  	args->dp = dp;
> @@ -433,8 +431,7 @@ xfs_dir_removename(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>  	args->filetype = name->type;
>  	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>  	args->inumber = ino;
> @@ -494,8 +491,7 @@ xfs_dir_replace(
>  		return -ENOMEM;
>  
>  	args->geo = dp->i_mount->m_dir_geo;
> -	args->name = name->name;
> -	args->namelen = name->len;
> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>  	args->filetype = name->type;
>  	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>  	args->inumber = inum;
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index d6ced59..592e47c 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 = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
> +	len = xfs_dir2_data_entsize(dp->i_mount, 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);
>  	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>  	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a131b52..24a7fda 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -653,7 +653,7 @@ xfs_dir2_leaf_addname(
>  	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
>  	ents = leafhdr.ents;
>  	bestsp = xfs_dir2_leaf_bests_p(ltp);
> -	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
> +	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
>  
>  	/*
>  	 * See if there are any entries with the same hash value
> @@ -856,8 +856,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);
>  	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>  	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a0cc5e2..3c74efc 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -666,7 +666,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 = xfs_dir2_data_entsize(mp, args->namelen);
> +	length = xfs_dir2_data_entsize(mp, args->name.len);
>  	/*
>  	 * Loop over leaf entries with the right hash value.
>  	 */
> @@ -1911,7 +1911,7 @@ xfs_dir2_node_addname_int(
>  	int			needscan = 0;	/* need to rescan data frees */
>  	__be16			*tagp;		/* data entry tag pointer */
>  
> -	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
> +	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
>  	error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &freehdr,
>  					   &findex, length);
>  	if (error)
> @@ -1966,8 +1966,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);
>  	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>  	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 7b7f6fb..058c526 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -387,7 +387,7 @@ xfs_dir2_sf_addname(
>  	/*
>  	 * Compute entry (and change in) size.
>  	 */
> -	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
> +	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->name.len);
>  	objchange = 0;
>  
>  	/*
> @@ -470,7 +470,7 @@ xfs_dir2_sf_addname_easy(
>  	/*
>  	 * Grow the in-inode space.
>  	 */
> -	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
> +	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->name.len),
>  			  XFS_DATA_FORK);
>  	/*
>  	 * Need to set up again due to realloc of the inode data.
> @@ -480,9 +480,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);
>  	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
>  	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
>  
> @@ -540,7 +540,7 @@ xfs_dir2_sf_addname_hard(
>  	 */
>  	for (offset = args->geo->data_first_offset,
>  	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
> -	      add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
> +	      add_datasize = xfs_dir2_data_entsize(mp, args->name.len),
>  	      eof = (char *)oldsfep == &buf[old_isize];
>  	     !eof;
>  	     offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
> @@ -570,9 +570,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);
>  	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
>  	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
>  	sfp->count++;
> @@ -615,7 +615,7 @@ xfs_dir2_sf_addname_pick(
>  	int			used;		/* data bytes used */
>  
>  	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
> -	size = xfs_dir2_data_entsize(mp, args->namelen);
> +	size = xfs_dir2_data_entsize(mp, args->name.len);
>  	offset = args->geo->data_first_offset;
>  	sfep = xfs_dir2_sf_firstentry(sfp);
>  	holefit = 0;
> @@ -887,7 +887,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;
> @@ -896,8 +896,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 = xfs_dir2_sf_get_parent_ino(sfp);
>  		args->cmpresult = XFS_CMP_EXACT;
>  		args->filetype = XFS_DIR3_FT_DIR;
> @@ -984,7 +984,7 @@ xfs_dir2_sf_removename(
>  	 * Calculate sizes.
>  	 */
>  	byteoff = (int)((char *)sfep - (char *)sfp);
> -	entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
> +	entsize = xfs_dir2_sf_entsize(mp, sfp, args->name.len);
>  	newsize = oldsize - entsize;
>  	/*
>  	 * Copy the part if any after the removed entry, sliding it down.
> @@ -1085,12 +1085,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 = xfs_dir2_sf_get_parent_ino(sfp);
>  		ASSERT(args->inumber != ino);
>  		xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
> diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
> index d9f0dd4..d4a9fe4 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 a86be7f..159b8af 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -1633,7 +1633,7 @@ DECLARE_EVENT_CLASS(xfs_da_class,
>  	TP_STRUCT__entry(
>  		__field(dev_t, dev)
>  		__field(xfs_ino_t, ino)
> -		__dynamic_array(char, name, args->namelen)
> +		__dynamic_array(char, name, args->name.len)
>  		__field(int, namelen)
>  		__field(xfs_dahash_t, hashval)
>  		__field(xfs_ino_t, inumber)
> @@ -1642,9 +1642,10 @@ DECLARE_EVENT_CLASS(xfs_da_class,
>  	TP_fast_assign(
>  		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
>  		__entry->ino = args->dp->i_ino;
> -		if (args->namelen)
> -			memcpy(__get_str(name), args->name, args->namelen);
> -		__entry->namelen = args->namelen;
> +		if (args->name.len)
> +			memcpy(__get_str(name), args->name.name,
> +			       args->name.len);
> +		__entry->namelen = args->name.len;
>  		__entry->hashval = args->hashval;
>  		__entry->inumber = args->inumber;
>  		__entry->op_flags = args->op_flags;
> @@ -1697,7 +1698,7 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>  	TP_STRUCT__entry(
>  		__field(dev_t, dev)
>  		__field(xfs_ino_t, ino)
> -		__dynamic_array(char, name, args->namelen)
> +		__dynamic_array(char, name, args->name.len)
>  		__field(int, namelen)
>  		__field(int, valuelen)
>  		__field(xfs_dahash_t, hashval)
> @@ -1707,12 +1708,13 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>  	TP_fast_assign(
>  		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
>  		__entry->ino = args->dp->i_ino;
> -		if (args->namelen)
> -			memcpy(__get_str(name), args->name, args->namelen);
> -		__entry->namelen = args->namelen;
> +		if (args->name.len)
> +			memcpy(__get_str(name), args->name.name,
> +			       args->name.len);
> +		__entry->namelen = args->name.len;
>  		__entry->valuelen = args->valuelen;
>  		__entry->hashval = args->hashval;
> -		__entry->flags = args->flags;
> +		__entry->flags = args->name.type;
>  		__entry->op_flags = args->op_flags;
>  	),
>  	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
> 


-- 
chandan




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

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
  2020-02-24 13:40   ` Brian Foster
@ 2020-02-25  7:21   ` Dave Chinner
  2020-02-25 23:27     ` Allison Collins
  2020-02-28 14:22   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  7:21 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
> new transactions. We will use this later when we introduce delayed attributes

68-72 columns...

> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 29 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 3de2eec..da40f85 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>  	}
>  	return 0;
>  }
> +
> +/*
> + * Remove the value associated with an attribute by deleting the out-of-line
> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
> + * transaction and recall the function
> + */
> +int
> +xfs_attr_rmtval_unmap(
> +	struct xfs_da_args	*args)
> +{
> +	int	error, done;

Best to initialise done to zero here.

> +
> +	/*
> +	 * Unmap value blocks for this attr.  This is similar to
> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> +	 * for new transactions
> +	 */
> +	error = xfs_bunmapi(args->trans, args->dp,
> +		    args->rmtblkno, args->rmtblkcnt,
> +		    XFS_BMAPI_ATTRFORK, 1, &done);

Got 80 columns for code, please use them all :)

> +	if (error)
> +		return error;
> +
> +	if (!done)
> +		return -EAGAIN;

Hmmm, I guess I'm missing the context at this point: why not just pass the done
variable all the way back to the caller that will be looping on this function
call?

That turns this function into:

int
xfs_attr_rmtval_unmap(
	struct xfs_da_args      *args,
	bool			*done)
{
	return xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
				args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, done);
}

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
  2020-02-24 15:25   ` Brian Foster
@ 2020-02-25  8:57   ` Dave Chinner
  2020-02-26  0:57     ` Allison Collins
  2020-03-03  5:03   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  8:57 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> This patch modifies the attr remove routines to be delay ready. This means they no
> longer roll or commit transactions, but instead return -EAGAIN to have the calling
> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> been modified to use the switch, and a  new version of xfs_attr_remove_args
> consists of a simple loop to refresh the transaction until the operation is
> completed.
> 
> This patch also adds a new struct xfs_delattr_context, which we will use to keep
> track of the current state of an attribute operation. The new xfs_delattr_state
> enum is used to track various operations that are in progress so that we know not
> to repeat them, and resume where we left off before EAGAIN was returned to cycle
> out the transaction. Other members take the place of local variables that need
> to retain their values across multiple function recalls.
> 
> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states

Ok, so I find all the DA/da prefixes in this code confusing,
especially as they have very similar actual names. e.g. da_state
vs delattr_state, DAS vs DA_STATE, etc.

Basically, I can't tell from reading the code what "DA" the actual
variable belongs to, and in a few months time I'll most definitely
have forgotten and have to relearn it from scratch.

So while "Delayed Attributes" is a great name for the feature, I
don't think it makes a great acronym for shortening variable names
because of the conflict with the existing DA namespace prefix.

Also, "dac" as shorthand for delattr context is also overloaded.
"DAC" is "discretionary access control" and is quite widely used
in the kernel (e.g. CAP_DAC_READ_SEARCH, CAP_DAC_OVERRIDE) so again
I read thsi code and it doesn't make much sense.

I haven't come up with a better name - "attribute iterator" is the
best I've managed (marketing++ - XFS has AI now!) and shortening it
down to ator would go a long way to alleviating my namespace
confusion....

> indicate places where the function would return -EAGAIN, and then immediately
> resume from after being recalled by the calling function.  States marked as a
> "subroutine state" indicate that they belong to a subroutine, and so the calling
> function needs to pass them back to that subroutine to allow it to finish where
> it left off. But they otherwise do not have a role in the calling function other
> than just passing through.
> 
>  xfs_attr_remove_iter()
>          XFS_DAS_RM_SHRINK     ─┐
>          (subroutine state)     │
>                                 │
>          XFS_DAS_RMTVAL_REMOVE ─┤
>          (subroutine state)     │
>                                 └─>xfs_attr_node_removename()
>                                                  │
>                                                  v
>                                          need to remove
>                                    ┌─n──  rmt blocks?
>                                    │             │
>                                    │             y
>                                    │             │
>                                    │             v
>                                    │  ┌─>XFS_DAS_RMTVAL_REMOVE
>                                    │  │          │
>                                    │  │          v
>                                    │  └──y── more blks
>                                    │         to remove?
>                                    │             │
>                                    │             n
>                                    │             │
>                                    │             v
>                                    │         need to
>                                    └─────> shrink tree? ─n─┐
>                                                  │         │
>                                                  y         │
>                                                  │         │
>                                                  v         │
>                                          XFS_DAS_RM_SHRINK │
>                                                  │         │
>                                                  v         │
>                                                 done <─────┘

Nice.

> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>  fs/xfs/libxfs/xfs_attr.h     |   1 +
>  fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>  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 +
>  10 files changed, 141 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5d73bdf..cd3a3f7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -368,11 +368,60 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	int			err2 = 0;
> +
> +	do {
> +		error = xfs_attr_remove_iter(args);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> +
> +			err2 = xfs_defer_finish(&args->trans);
> +			if (err2) {
> +				error = err2;
> +				goto out;
> +			}
> +		}
> +
> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +	} while (error == -EAGAIN);
> +out:
> +	return error;
> +}

Brian commented on the structure of this loop better than I could.

> +
> +/*
> + * Remove the attribute specified in @args.
> + *
> + * This function may return -EAGAIN to signal that the transaction needs to be
> + * rolled.  Callers should continue calling this function until they receive a
> + * return value other than -EAGAIN.
> + */
> +int
> +xfs_attr_remove_iter(
>  	struct xfs_da_args      *args)
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	int			error;
>  
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_RM_SHRINK:
> +	case XFS_DAS_RMTVAL_REMOVE:
> +		goto node;
> +	default:
> +		break;
> +	}

Why separate out the state machine? Doesn't this shortcut the
xfs_inode_hasattr() check? Shouldn't that come first?

As it is:

	case XFS_DAS_RM_SHRINK:
	case XFS_DAS_RMTVAL_REMOVE:
		return xfs_attr_node_removename(args);
	default:
		break;

would be nicer, and if this is the only way we can get to
xfs_attr_node_removename(), getting rid of it from the code
below could be done, too.


> +
>  	if (!xfs_inode_hasattr(dp)) {
>  		error = -ENOATTR;
>  	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_removename(args);
>  	} else {
> +node:
>  		error = xfs_attr_node_removename(args);
>  	}
>  
> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>  		/* bp is gone due to xfs_da_shrink_inode */
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +
> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>  	}
>  	return 0;
>  }
> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>   * This will involve walking down the Btree, and may involve joining
>   * leaf nodes and even joining intermediate nodes up to and including
>   * the root node (a special case of an intermediate node).
> + *
> + * This routine is meant to function as either an inline or delayed operation,
> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> + * functions will need to handle this, and recall the function until a
> + * successful error code is returned.
>   */
>  STATIC int
>  xfs_attr_node_removename(
> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>  	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = args->dac.da_state;
> +	blk = args->dac.blk;
> +
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_RMTVAL_REMOVE:
> +		goto rm_node_blks;
> +	case XFS_DAS_RM_SHRINK:
> +		goto rm_shrink;
> +	default:
> +		break;
> +	}

This really is calling out for this function to be broken into three
smaller functions. That would greatly simplify the code flow and
logic here.

> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index ce7b039..ea873a5 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> +int xfs_attr_remove_iter(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);
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index 14f1be3..3c78498 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>  };
>  
>  /*
> + * Enum values for xfs_delattr_context.da_state
> + *
> + * These values are used by delayed attribute operations to keep track  of where
> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> + * calling function to roll the transaction, and then recall the subroutine to
> + * finish the operation.  The enum is then used by the subroutine to jump back
> + * to where it was and resume executing where it left off.
> + */
> +enum xfs_delattr_state {
> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> +};
> +
> +/*
> + * Defines for xfs_delattr_context.flags
> + */
> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delattr_context {
> +	struct xfs_da_state	*da_state;
> +	struct xfs_da_state_blk *blk;
> +	unsigned int		flags;
> +	enum xfs_delattr_state	dela_state;
> +};
> +
> +/*
>   * Structure to ease passing around component names.
>   */
>  typedef struct xfs_da_args {
> +	struct xfs_delattr_context dac; /* context used for delay attr ops */

Probably should put this at the end of the structure rather than the
front.

I'm also wondering if it should be kept separate to the da_args and
contain a pointer to the da_args instead of being wrapped inside
them.

i.e. we put the iterating state structure on the stack, then

	struct attr_iter	ater = {
		.da_args = args,
	};

	do {
		error = xfs_attr_remove_iter(&ater);
		.....
	
And that largely separates the delayed attribute iteration state
from the da_args that holds the internal attribute manipulation
information.

>  	struct xfs_da_geometry *geo;	/* da block geometry */
>  	struct xfs_name	name;		/* name, length and argument  flags*/
>  	uint8_t		filetype;	/* filetype of inode for directories */
> 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"

Hmmm - why are these new includes necessary? You didn't add anything
new to these files or common header files to make the includes
needed....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink
  2020-02-23  2:06 ` [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink Allison Collins
  2020-02-23 13:22   ` Amir Goldstein
@ 2020-02-25  9:05   ` Dave Chinner
  2020-02-26  1:48     ` Allison Collins
  1 sibling, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  9:05 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:07PM -0700, Allison Collins wrote:
> This patch adds a new helper function xfs_attr_node_shrink used to shrink an
> attr name into an inode if it is small enough.  This helps to modularize
> the greater calling function xfs_attr_node_removename.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Can you move this helper function up to early in the patch set?
That way the code gets simpler and less tangled before adding
all the new state machine gubbins?

I suspect that you should do this for all the functions the state
machine breaks up into gotos, too. THat way adding the state machine
is really just changing how the functions that do the work are
called, rather than jumping into the middle of long functions....

I know, it turns it into a longer series, but it also means that all
the refactoring work (which needs to be done anyway) can be
separated and merged while we are still reviewing and working on the
state machine based operations, thereby reducing the size of the
patchset you have to manage and keep up to date over time....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
  2020-02-23 13:26   ` Amir Goldstein
@ 2020-02-25  9:21   ` Dave Chinner
  2020-02-26  2:13     ` Allison Collins
  2020-03-04  4:30   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  9:21 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:08PM -0700, Allison Collins wrote:
> Delayed attribute mechanics make frequent use of goto statements.  We can use this
> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
> conditions, we can invert the if logic and jump to the goto. This helps to reduce
> indentation and simplify things.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 42 insertions(+), 29 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 30a16fe..dd935ff 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>  }
>  
>  /*
> + * Check to see if the attr should be upgraded from non-existent or shortform to
> + * single-leaf-block attribute list.
> + */
> +static inline bool
> +xfs_attr_fmt_needs_update(
> +	struct xfs_inode    *dp)

Can we use *ip for the inode in newly factored code helpers like
this?

> +{
> +	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> +	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> +	      dp->i_d.di_anextents == 0);
> +}
> +
> +/*
>   * Set the attribute specified in @args.
>   */
>  int
> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>  	}
>  
>  	/*
> -	 * If the attribute list is non-existent or a shortform list,
> -	 * upgrade it to a single-leaf-block attribute list.
> +	 * If the attribute list is already in leaf format, jump straight to
> +	 * leaf handling.  Otherwise, try to add the attribute to the shortform
> +	 * list; if there's no room then convert the list to leaf format and try
> +	 * again.
>  	 */
> -	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)) {
> +	if (!xfs_attr_fmt_needs_update(dp))
> +		goto add_leaf;

The logic seems inverted to me here, but that really indicates a
sub-optimal function name. It's really checking if the attribute
fork is empty or in shortform format. Hence:

	if (!xfs_attr_is_shortform(dp))
		goto add_leaf;

> -		/*
> -		 * Try to add the attr to the attribute list in the inode.
> -		 */
> -		error = xfs_attr_try_sf_addname(dp, args);
> +	/*
> +	 * Try to add the attr to the attribute list in the inode.
> +	 */
> +	error = xfs_attr_try_sf_addname(dp, args);
>  
> -		/* Should only be 0, -EEXIST or ENOSPC */
> -		if (error != -ENOSPC)
> -			return error;
> +	/* Should only be 0, -EEXIST or ENOSPC */
> +	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;
> +	/*
> +	 * 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);
> -		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> -		args->dac.dela_state = XFS_DAS_ADD_LEAF;
> -		return -EAGAIN;
> -	}
> +	/*
> +	 * 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);
> +	args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +	args->dac.dela_state = XFS_DAS_ADD_LEAF;
> +	return -EAGAIN;

Heh. This is an example of exactly why I think this should be
factored into functions first. Move all the code you just
re-indented into xfs_attr_set_shortform(), and the goto disappears
because this code becomes:

	if (xfs_attr_is_shortform(dp))
		return xfs_attr_set_shortform(dp, args);

add_leaf:

That massively improves the readability of the code - it separates
the operation implementation from the decision logic nice and
cleanly, and lends itself to being implemented in the delayed attr
state machine without needing gotos at all.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
  2020-02-23 13:47   ` Amir Goldstein
@ 2020-02-25  9:31   ` Dave Chinner
  2020-02-26  2:17     ` Allison Collins
  2020-03-04  4:37   ` Chandan Rajendra
  2 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  9:31 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Feb 22, 2020 at 07:06:09PM -0700, Allison Collins wrote:
> This patch helps to simplify xfs_attr_node_removename by modularizing the code
> around the transactions into helper functions.  This will make the function easier
> to follow when we introduce delayed attributes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Another candidate for being at the start of this patchset.

> ---
>  fs/xfs/libxfs/xfs_attr.c | 45 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 31 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index dd935ff..b9728d1 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
>  }
>  
>  /*
> + * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
> + * for later deletion of the entry.
> + */
> +STATIC int
> +xfs_attr_leaf_mark_incomplete(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	*state)
> +{
> +	int error;
> +
> +	/*
> +	 * 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.
> +	 */

Reformat to use all 80 columns.

[ Handy vim hints, add this to your .vimrc:

" set the textwidth to 80 characters for C code
 au BufNewFile,BufRead *.c,*.h set tw=80

" set the textwidth to 68 characters for guilt commit messages
 au BufNewFile,BufRead guilt.msg.*,.gitsendemail.*,git.*,*/.git/* set tw=68

" Formatting the current paragraph according to
" the current 'textwidth' with ^J (control-j):
  imap <C-J> <c-o>gqap
   map <C-J> gqap

" highlight textwidth
set cc=+1

]

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
  2020-02-23 12:20   ` Amir Goldstein
  2020-02-24 13:08   ` Brian Foster
@ 2020-02-25  9:49   ` Chandan Rajendra
  2020-02-25 10:15     ` Chandan Rajendra
  2020-02-26  2:18     ` Allison Collins
  2 siblings, 2 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-25  9:49 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM 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 appearance of duplicated code.  We will need these
> routines later for delayed attributes since delayed operations cannot return error
> codes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>  4 files changed, 188 insertions(+), 98 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9acdb23..2255060 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>  
>  /*
>   * Internal routines when attribute list is more than one block.
> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> +				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>  
> @@ -310,6 +313,37 @@ 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 = NULL;
> +	int			error;
> +
> +	if (!xfs_inode_hasattr(dp))
> +		return -ENOATTR;
> +
> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		return xfs_attr_sf_findname(args, NULL, NULL);
> +	}
> +
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_hasname(args, &bp);
> +
> +		if (bp)
> +			xfs_trans_brelse(args->trans, bp);
> +
> +		return error;
> +	}
> +
> +	return xfs_attr_node_hasname(args, NULL);
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
> @@ -583,26 +617,20 @@ STATIC int
>  xfs_attr_leaf_addname(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_inode	*dp;
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
> +	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_leaf_addname(args);
>  
>  	/*
> -	 * Read the (only) block in the attribute list in.
> -	 */
> -	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -	if (error)
> -		return error;
> -
> -	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
>  	 * the given flags produce an error or call for an atomic rename.
>  	 */
> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
> +	retval = xfs_attr_leaf_hasname(args, &bp);
> +	if (retval != -ENOATTR && retval != -EEXIST)
> +		return retval;
> +
>  	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return retval;
> @@ -754,6 +782,27 @@ xfs_attr_leaf_addname(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +STATIC int
> +xfs_attr_leaf_hasname(
> +	struct xfs_da_args      *args,
> +	struct xfs_buf		**bp)
> +{
> +	int                     error = 0;
> +
> +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
> +	if (error)
> +		return error;
> +
> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
> +	if (error != -ENOATTR && error != -EEXIST)
> +		xfs_trans_brelse(args->trans, *bp);
> +
> +	return error;
> +}
> +
> +/*
>   * Remove a name from the leaf attribute list structure
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>  	 * Remove the attribute.
>  	 */
>  	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -	if (error)
> +
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error == -ENOATTR) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_leaf_get(args);
>  
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> -	if (error)
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error != -EEXIST)  {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  	return error;
>  }
>  
> +/*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * statep: If not null is set to point at the found state.  Caller will
> + *         be responsible for freeing the state in this case.
> + */
> +STATIC int
> +xfs_attr_node_hasname(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**statep)
> +{
> +	struct xfs_da_state	*state;
> +	int			retval, error;
> +
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = args->dp->i_mount;
> +
> +	if (statep != NULL)
> +		*statep = NULL;
> +
> +	/*
> +	 * Search to see if name exists, and get back a pointer to it.
> +	 */
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error == 0) {
> +		if (statep != NULL)
> +			*statep = state;
> +		return retval;
> +	}

If 'statep' were NULL, then this would leak the memory pointed to by 'state'
right? 

-- 
chandan




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

* Re: [PATCH v7 00/19] xfs: Delayed Ready Attrs
  2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
  2020-02-23 16:02   ` Allison Collins
  2020-02-24  8:31   ` Chandan Rajendra
@ 2020-02-25  9:52   ` Dave Chinner
  2 siblings, 0 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-25  9:52 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Allison Collins, linux-xfs

On Sun, Feb 23, 2020 at 09:55:48AM +0200, Amir Goldstein wrote:
> On Sun, Feb 23, 2020 at 4:06 AM Allison Collins
> <allison.henderson@oracle.com> wrote:
> >
> > Hi all,
> >
> > This set is a subset of a larger series for delayed attributes. Which is
> > a subset of an even larger series, parent pointers. Delayed attributes
> > allow attribute operations (set and remove) to be logged and committed
> > in the same way that other delayed operations do. This allows more
> > complex operations (like parent pointers) to be broken up into multiple
> > smaller transactions. To do this, the existing attr operations must be
> > modified to operate as either a delayed operation or a inline operation
> > since older filesystems will not be able to use the new log entries.
> 
> High level question, before I dive into the series:
> 
> Which other "delayed operations" already exist?

See Chandan's answer :P

> I think delayed operations were added by Darrick to handle the growth of
> translation size due to reflink. Right? So I assume the existing delayed
> operations deal with block accounting.

No, they are intended to allow atomic, recoverable multi-transaction
operations. They grew out of this:

https://xfs.org/index.php/Improving_Metadata_Performance_By_Reducing_Journal_Overhead#Atomic_Multi-Transaction_Operations

which was essentially an generalisation of the EFI/EFD intent
logging that has existed in XFS for 20 years.

Essentially, it is a mechanism of chaining intent operations to
ensure that recover will restart the operation at the point the
system failed so that once the operation is started (i.e. first
intent is logged to the journal) the entire operation is always
completed regardless of whether the system crashes or not.

> When speaking of parent pointers, without having looked into the details yet,
> it seem the delayed operations we would want to log are operations that deal
> with namespace changes, i.e.: link,unlink,rename.
> The information needed to be logged for these ops is minimal.

Not really. the parent pointers are held in attributes, so parent
pointers are effectively adding an attribute creation to every inode
allocation and an attribute modification to every directory
modification. And, well, when an inode has 100 million hard links,
it's going to have 100 million parent pointer attributes. Modifying
a link is then a major operation, and Chandan has done a great job
in analysing the attr btree to see if there are scalability issues
that will be exposed by this sort of attribute usage....

> Why do we need a general infrastructure for delayed attr operations?

These have to be done atomically with the create/unlink/rename/etc
and to include attribute modification in those transaction
reservations blows the size of them out massively (especially
rename!). By converting these operations to use defered operations
to add the parent pointer to the inode, we no longer need to
increase the log reservation for the operations (because the attr
reservation is usually smaller than the directory reservation), and
it is guaranteed to be atomic with the directory modification. i.e.
parent pointers never get out of sync, even when the system crashes.

Hence having attributes modified as a series of individual
operations chained together into an atomic whole via intents is a
pre-requisite for updating attributes atomically within directory
modification operations.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25  9:49   ` Chandan Rajendra
@ 2020-02-25 10:15     ` Chandan Rajendra
  2020-02-26  2:19       ` Allison Collins
  2020-02-26  2:18     ` Allison Collins
  1 sibling, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-25 10:15 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Tuesday, February 25, 2020 3:19 PM Chandan Rajendra wrote: 
> On Sunday, February 23, 2020 7:35 AM 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 appearance of duplicated code.  We will need these
> > routines later for delayed attributes since delayed operations cannot return error
> > codes.
> > 
> > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> >  fs/xfs/libxfs/xfs_attr.h      |   1 +
> >  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> >  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> >  4 files changed, 188 insertions(+), 98 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 9acdb23..2255060 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> >  
> >  /*
> >   * Internal routines when attribute list is more than one block.
> > @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> >  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> > +				 struct xfs_da_state **state);
> >  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> >  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> >  
> > @@ -310,6 +313,37 @@ 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 = NULL;
> > +	int			error;
> > +
> > +	if (!xfs_inode_hasattr(dp))
> > +		return -ENOATTR;
> > +
> > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> > +		return xfs_attr_sf_findname(args, NULL, NULL);
> > +	}
> > +
> > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > +		error = xfs_attr_leaf_hasname(args, &bp);
> > +
> > +		if (bp)
> > +			xfs_trans_brelse(args->trans, bp);
> > +
> > +		return error;
> > +	}
> > +
> > +	return xfs_attr_node_hasname(args, NULL);
> > +}
> > +
> > +/*
> >   * Remove the attribute specified in @args.
> >   */
> >  int
> > @@ -583,26 +617,20 @@ STATIC int
> >  xfs_attr_leaf_addname(
> >  	struct xfs_da_args	*args)
> >  {
> > -	struct xfs_inode	*dp;
> >  	struct xfs_buf		*bp;
> >  	int			retval, error, forkoff;
> > +	struct xfs_inode	*dp = args->dp;
> >  
> >  	trace_xfs_attr_leaf_addname(args);
> >  
> >  	/*
> > -	 * Read the (only) block in the attribute list in.
> > -	 */
> > -	dp = args->dp;
> > -	args->blkno = 0;
> > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> > -	if (error)
> > -		return error;
> > -
> > -	/*
> >  	 * Look up the given attribute in the leaf block.  Figure out if
> >  	 * the given flags produce an error or call for an atomic rename.
> >  	 */
> > -	retval = xfs_attr3_leaf_lookup_int(bp, args);
> > +	retval = xfs_attr_leaf_hasname(args, &bp);
> > +	if (retval != -ENOATTR && retval != -EEXIST)
> > +		return retval;
> > +
> >  	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> >  		xfs_trans_brelse(args->trans, bp);
> >  		return retval;
> > @@ -754,6 +782,27 @@ xfs_attr_leaf_addname(
> >  }
> >  
> >  /*
> > + * Return EEXIST if attr is found, or ENOATTR if not
> > + */
> > +STATIC int
> > +xfs_attr_leaf_hasname(
> > +	struct xfs_da_args      *args,
> > +	struct xfs_buf		**bp)
> > +{
> > +	int                     error = 0;
> > +
> > +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
> > +	if (error)
> > +		return error;
> > +
> > +	error = xfs_attr3_leaf_lookup_int(*bp, args);
> > +	if (error != -ENOATTR && error != -EEXIST)
> > +		xfs_trans_brelse(args->trans, *bp);
> > +
> > +	return error;
> > +}
> > +
> > +/*
> >   * Remove a name from the leaf attribute list structure
> >   *
> >   * This leaf block cannot have a "remote" value, we only call this routine
> > @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
> >  	 * Remove the attribute.
> >  	 */
> >  	dp = args->dp;
> > -	args->blkno = 0;
> > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> > -	if (error)
> > +
> > +	error = xfs_attr_leaf_hasname(args, &bp);
> > +	if (error != -ENOATTR && error != -EEXIST)
> >  		return error;
> >  
> > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> >  	if (error == -ENOATTR) {
> >  		xfs_trans_brelse(args->trans, bp);
> >  		return error;
> > @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> >  
> >  	trace_xfs_attr_leaf_get(args);
> >  
> > -	args->blkno = 0;
> > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> > -	if (error)
> > +	error = xfs_attr_leaf_hasname(args, &bp);
> > +	if (error != -ENOATTR && error != -EEXIST)
> >  		return error;
> >  
> > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> >  	if (error != -EEXIST)  {
> >  		xfs_trans_brelse(args->trans, bp);
> >  		return error;
> > @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> >  	return error;
> >  }
> >  
> > +/*
> > + * Return EEXIST if attr is found, or ENOATTR if not
> > + * statep: If not null is set to point at the found state.  Caller will
> > + *         be responsible for freeing the state in this case.
> > + */
> > +STATIC int
> > +xfs_attr_node_hasname(
> > +	struct xfs_da_args	*args,
> > +	struct xfs_da_state	**statep)
> > +{
> > +	struct xfs_da_state	*state;
> > +	int			retval, error;
> > +
> > +	state = xfs_da_state_alloc();
> > +	state->args = args;
> > +	state->mp = args->dp->i_mount;
> > +
> > +	if (statep != NULL)
> > +		*statep = NULL;
> > +
> > +	/*
> > +	 * Search to see if name exists, and get back a pointer to it.
> > +	 */
> > +	error = xfs_da3_node_lookup_int(state, &retval);
> > +	if (error == 0) {
> > +		if (statep != NULL)
> > +			*statep = state;
> > +		return retval;
> > +	}
> 
> If 'statep' were NULL, then this would leak the memory pointed to by 'state'
> right? 
> 
Apart from the above, the remaining changes look good to me.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

-- 
chandan




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

* Re: [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2020-02-23  2:05 ` [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2020-02-25 12:53   ` Chandan Rajendra
  2020-02-26  2:20     ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-25 12:53 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM 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.

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 149 +++++++++++++++++++++++++---------------
>  1 file changed, 92 insertions(+), 57 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index df8aca5..d1eee24 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -440,32 +440,23 @@ xfs_attr_rmtval_get(
>  }
>  
>  /*
> - * Write the value associated with an attribute into the out-of-line buffer
> - * that we have defined for it.
> + * Find a "hole" in the attribute address space large enough for us to drop the
> + * new attribute's value into
>   */
> -int
> -xfs_attr_rmtval_set(
> +STATIC int
> +xfs_attr_rmt_find_hole(
>  	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);
> +	int			blkcnt;
> +	xfs_fileoff_t		lfileoff = 0;
>  
>  	/*
> -	 * 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.
> +	 * 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,
> @@ -473,48 +464,26 @@ xfs_attr_rmtval_set(
>  	if (error)
>  		return error;
>  
> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
> +	args->rmtblkno = (xfs_dablk_t)lfileoff;
>  	args->rmtblkcnt = blkcnt;
>  
> -	/*
> -	 * Roll through the "value", allocating blocks on disk as required.
> -	 */
> -	while (blkcnt > 0) {
> -		/*
> -		 * Allocate a single extent, up to the size of the value.
> -		 *
> -		 * Note that we have to consider this a data allocation as we
> -		 * write the remote attribute without logging the contents.
> -		 * Hence we must ensure that we aren't using blocks that are on
> -		 * the busy list so that we don't overwrite blocks which have
> -		 * recently been freed but their transactions are not yet
> -		 * committed to disk. If we overwrite the contents of a busy
> -		 * extent and then crash then the block may not contain the
> -		 * correct metadata after log recovery occurs.
> -		 */
> -		nmap = 1;
> -		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
> -				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
> -				  &nmap);
> -		if (error)
> -			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> -
> -		ASSERT(nmap == 1);
> -		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
> -		       (map.br_startblock != HOLESTARTBLOCK));
> -		lblkno += map.br_blockcount;
> -		blkcnt -= map.br_blockcount;
> +	return 0;
> +}
>  
> -		/*
> -		 * Start the next trans in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			return error;
> -	}
> +STATIC 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
> @@ -595,6 +564,72 @@ xfs_attr_rmtval_stale(
>  }
>  
>  /*
> + * Write the value associated with an attribute into the out-of-line buffer
> + * that we have defined for it.
> + */
> +int
> +xfs_attr_rmtval_set(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +	int			nmap;
> +	int			error;
> +
> +	trace_xfs_attr_rmtval_set(args);
> +
> +	error = xfs_attr_rmt_find_hole(args);
> +	if (error)
> +		return error;
> +
> +	blkcnt = args->rmtblkcnt;
> +	lblkno = (xfs_dablk_t)args->rmtblkno;
> +	/*
> +	 * Roll through the "value", allocating blocks on disk as required.
> +	 */
> +	while (blkcnt > 0) {
> +		/*
> +		 * Allocate a single extent, up to the size of the value.
> +		 *
> +		 * Note that we have to consider this a data allocation as we
> +		 * write the remote attribute without logging the contents.
> +		 * Hence we must ensure that we aren't using blocks that are on
> +		 * the busy list so that we don't overwrite blocks which have
> +		 * recently been freed but their transactions are not yet
> +		 * committed to disk. If we overwrite the contents of a busy
> +		 * extent and then crash then the block may not contain the
> +		 * correct metadata after log recovery occurs.
> +		 */
> +		nmap = 1;
> +		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
> +				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
> +				  &nmap);
> +		if (error)
> +			return error;
> +		error = xfs_defer_finish(&args->trans);
> +		if (error)
> +			return error;
> +
> +		ASSERT(nmap == 1);
> +		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
> +		       (map.br_startblock != HOLESTARTBLOCK));
> +		lblkno += map.br_blockcount;
> +		blkcnt -= map.br_blockcount;
> +
> +		/*
> +		 * Start the next trans in the chain.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, dp);
> +		if (error)
> +			return error;
> +	}
> +
> +	return xfs_attr_rmtval_set_value(args);
> +}
> +
> +/*
>   * Remove the value associated with an attribute by deleting the
>   * out-of-line buffer that it is stored on.
>   */
> 


-- 
chandan




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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-24 21:18     ` Allison Collins
@ 2020-02-25 13:25       ` Brian Foster
  2020-02-26  2:31         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-25 13:25 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 02:18:35PM -0700, Allison Collins wrote:
> 
> 
> On 2/24/20 6:08 AM, Brian Foster wrote:
> > On Sat, Feb 22, 2020 at 07:05:55PM -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 appearance of duplicated code.  We will need these
> > > routines later for delayed attributes since delayed operations cannot return error
> > > codes.
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> > >   fs/xfs/libxfs/xfs_attr.h      |   1 +
> > >   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> > >   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> > >   4 files changed, 188 insertions(+), 98 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 9acdb23..2255060 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > ...
> > > @@ -310,6 +313,37 @@ 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 = NULL;
> > > +	int			error;
> > > +
> > > +	if (!xfs_inode_hasattr(dp))
> > > +		return -ENOATTR;
> > > +
> > > +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > > +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> > > +		return xfs_attr_sf_findname(args, NULL, NULL);
> > 
> > Nit: any reason we use "findname" here and "hasname" for the other two
> > variants?
> It was asked for in the v4 review.  Reason being we also return the location
> of the sf entry and byte offset.
> 

Ok.

> > 
> > Just a few other nit level things..
> > 
> > > +	}
> > > +
> > > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > +		error = xfs_attr_leaf_hasname(args, &bp);
> > > +
> > > +		if (bp)
> > > +			xfs_trans_brelse(args->trans, bp);
> > > +
> > > +		return error;
> > > +	}
> > > +
> > > +	return xfs_attr_node_hasname(args, NULL);
> > > +}
> > > +
> > > +/*
> > >    * Remove the attribute specified in @args.
> > >    */
> > >   int
> > ...
> > > @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
> > >   	 * Remove the attribute.
> > >   	 */
> > >   	dp = args->dp;
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> > > -	if (error)
> > > +
> > > +	error = xfs_attr_leaf_hasname(args, &bp);
> > > +	if (error != -ENOATTR && error != -EEXIST)
> > >   		return error;
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > >   	if (error == -ENOATTR) {
> > 
> > It looks like some of these error checks could be cleaned up where the
> > helper function is used. I.e., something like the following here:
> > 
> > 	if (error == -ENOATTR) {
> > 		xfs_trans_brelse(...);
> > 		return error;
> > 	} else if (error != -EEXIST)
> > 		return error;
> Sure, I'm starting to get more pressure in other reviews to change this api
> to a boolean return type though (1: y, 0: no, <0: error).  I think we talked
> about this in v3, but decided to stick with this original api for now.  I'm
> thinking maybe adding a patch at the end to shift the api might be a good
> compromise?  Thoughts?
> 

I think Dave commented on this earlier with regard to some of these API
cleanups being orthogonal to this work. The big challenge with this
series is really taking apart this big tangle of xattr code such that it
has smaller components and is thus mostly reusable between dfops context
for parent pointers etc. and the traditional codepath. I can see the
appeal of such API cleanups (so it's good feedback overall), but I agree
that it's probably wiser to allow this series to work with the interface
style we have in the existing code and consider that type of thing as a
follow on cleanup when the subsystem itself is more stabilized.

Brian

> > 
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > > @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> > >   	trace_xfs_attr_leaf_get(args);
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
> > > -	if (error)
> > > +	error = xfs_attr_leaf_hasname(args, &bp);
> > > +	if (error != -ENOATTR && error != -EEXIST)
> > >   		return error;
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > >   	if (error != -EEXIST)  {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > 
> > Similar thing here, just reordering the checks simplifies the logic.
> Sure, will do.
> 
> > 
> > > @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> > >   	return error;
> > >   }
> > > +/*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + * statep: If not null is set to point at the found state.  Caller will
> > > + *         be responsible for freeing the state in this case.
> > > + */
> > > +STATIC int
> > > +xfs_attr_node_hasname(
> > > +	struct xfs_da_args	*args,
> > > +	struct xfs_da_state	**statep)
> > > +{
> > > +	struct xfs_da_state	*state;
> > > +	int			retval, error;
> > > +
> > > +	state = xfs_da_state_alloc();
> > > +	state->args = args;
> > > +	state->mp = args->dp->i_mount;
> > > +
> > > +	if (statep != NULL)
> > > +		*statep = NULL;
> > > +
> > > +	/*
> > > +	 * Search to see if name exists, and get back a pointer to it.
> > > +	 */
> > > +	error = xfs_da3_node_lookup_int(state, &retval);
> > > +	if (error == 0) {
> > > +		if (statep != NULL)
> > > +			*statep = state;
> > > +		return retval;
> > > +	}
> > > +
> > > +	xfs_da_state_free(state);
> > > +
> > > +	return error;
> > > +}
> > > +
> > >   /*========================================================================
> > >    * External routines when attribute list size > geo->blksize
> > >    *========================================================================*/
> > ...
> > > @@ -1316,31 +1381,23 @@ xfs_attr_node_get(xfs_da_args_t *args)
> > >   {
> > >   	xfs_da_state_t *state;
> > >   	xfs_da_state_blk_t *blk;
> > > -	int error, retval;
> > > +	int error;
> > >   	int i;
> > >   	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) {
> > > -		retval = error;
> > > -		goto out_release;
> > > -	}
> > > -	if (retval != -EEXIST)
> > > +	error = xfs_attr_node_hasname(args, &state);
> > > +	if (error != -EEXIST)
> > >   		goto out_release;
> > >   	/*
> > >   	 * Get the value, local or "remote"
> > >   	 */
> > >   	blk = &state->path.blk[state->path.active - 1];
> > > -	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
> > > +	error = xfs_attr3_leaf_getvalue(blk->bp, args);
> > >   	/*
> > >   	 * If not in a transaction, we have to release all the buffers.
> > > @@ -1352,7 +1409,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
> > >   	}
> > >   	xfs_da_state_free(state);
> > 
> > Do we need an 'if (state)' check here like the other node funcs?
> I think so, because if xfs_attr_node_hasname errors out it releases the
> state.  Will add.
> 
> > 
> > > -	return retval;
> > > +	return error;
> > >   }
> > >   /* Returns true if the attribute entry name is valid. */
> > ...
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > index cb5ef66..9d6b68c 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > @@ -654,18 +654,66 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
> > >   }
> > >   /*
> > > + * Return -EEXIST if attr is found, or -ENOATTR if not
> > > + * args:  args containing attribute name and namelen
> > > + * sfep:  If not null, pointer will be set to the last attr entry found on
> > > +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
> > > + * basep: If not null, pointer is set to the byte offset of the entry in the
> > > + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
> > > + *	  the last entry in the list
> > > + */
> > > +int
> > > +xfs_attr_sf_findname(
> > > +	struct xfs_da_args	 *args,
> > > +	struct xfs_attr_sf_entry **sfep,
> > > +	unsigned int		 *basep)
> > > +{
> > > +	struct xfs_attr_shortform *sf;
> > > +	struct xfs_attr_sf_entry *sfe;
> > > +	unsigned int		base = sizeof(struct xfs_attr_sf_hdr);
> > > +	int			size = 0;
> > > +	int			end;
> > > +	int			i;
> > > +
> > > +	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++) {
> > 
> > Slightly more readable to align indendation with the sfe assignment
> > above.
> Sure, will fix.  Thanks!
> 
> Allison
> 
> > 
> > Brian
> > 
> > > +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> > > +		if (sfe->namelen != args->name.len)
> > > +			continue;
> > > +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> > > +			continue;
> > > +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> > > +			continue;
> > > +		break;
> > > +	}
> > > +
> > > +	if (sfep != NULL)
> > > +		*sfep = sfe;
> > > +
> > > +	if (basep != NULL)
> > > +		*basep = base;
> > > +
> > > +	if (i == end)
> > > +		return -ENOATTR;
> > > +	return -EEXIST;
> > > +}
> > > +
> > > +/*
> > >    * Add a name/value pair to the shortform attribute list.
> > >    * Overflow from the inode has already been checked for.
> > >    */
> > >   void
> > > -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> > > +xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff)
> > >   {
> > > -	xfs_attr_shortform_t *sf;
> > > -	xfs_attr_sf_entry_t *sfe;
> > > -	int i, offset, size;
> > > -	xfs_mount_t *mp;
> > > -	xfs_inode_t *dp;
> > > -	struct xfs_ifork *ifp;
> > > +	struct xfs_attr_shortform	*sf;
> > > +	struct xfs_attr_sf_entry	*sfe;
> > > +	int				offset, size, error;
> > > +	struct xfs_mount		*mp;
> > > +	struct xfs_inode		*dp;
> > > +	struct xfs_ifork		*ifp;
> > >   	trace_xfs_attr_sf_add(args);
> > > @@ -676,18 +724,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> > >   	ifp = dp->i_afp;
> > >   	ASSERT(ifp->if_flags & XFS_IFINLINE);
> > >   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> > > -	sfe = &sf->list[0];
> > > -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> > > -#ifdef DEBUG
> > > -		if (sfe->namelen != args->name.len)
> > > -			continue;
> > > -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
> > > -			continue;
> > > -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> > > -			continue;
> > > -		ASSERT(0);
> > > -#endif
> > > -	}
> > > +	error = xfs_attr_sf_findname(args, &sfe, NULL);
> > > +	ASSERT(error != -EEXIST);
> > >   	offset = (char *)sfe - (char *)sf;
> > >   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> > > @@ -730,35 +768,26 @@ xfs_attr_fork_remove(
> > >    * Remove an attribute from the shortform attribute list structure.
> > >    */
> > >   int
> > > -xfs_attr_shortform_remove(xfs_da_args_t *args)
> > > +xfs_attr_shortform_remove(struct xfs_da_args *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				size = 0, end, totsize;
> > > +	unsigned int			base;
> > > +	struct xfs_mount		*mp;
> > > +	struct xfs_inode		*dp;
> > > +	int				error;
> > >   	trace_xfs_attr_sf_remove(args);
> > >   	dp = args->dp;
> > >   	mp = dp->i_mount;
> > > -	base = sizeof(xfs_attr_sf_hdr_t);
> > >   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> > > -	sfe = &sf->list[0];
> > > -	end = sf->hdr.count;
> > > -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> > > -					base += size, i++) {
> > > -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> > > -		if (sfe->namelen != args->name.len)
> > > -			continue;
> > > -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> > > -			continue;
> > > -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> > > -			continue;
> > > -		break;
> > > -	}
> > > -	if (i == end)
> > > -		return -ENOATTR;
> > > +
> > > +	error = xfs_attr_sf_findname(args, &sfe, &base);
> > > +	if (error != -EEXIST)
> > > +		return error;
> > > +	size = XFS_ATTR_SF_ENTSIZE(sfe);
> > >   	/*
> > >   	 * Fix up the attribute fork data, covering the hole
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > index 73615b1..0e9c87c 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > @@ -53,6 +53,9 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
> > >   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
> > >   			struct xfs_buf **leaf_bp);
> > >   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> > > +int	xfs_attr_sf_findname(struct xfs_da_args *args,
> > > +			     struct xfs_attr_sf_entry **sfep,
> > > +			     unsigned 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] 135+ messages in thread

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-25  6:42   ` Dave Chinner
@ 2020-02-25 13:26     ` Brian Foster
  2020-02-25 23:26     ` Allison Collins
  1 sibling, 0 replies; 135+ messages in thread
From: Brian Foster @ 2020-02-25 13:26 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Allison Collins, linux-xfs

On Tue, Feb 25, 2020 at 05:42:07PM +1100, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:05:59PM -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, and move the commit into the calling function.
> 
> 68-72 columns :P
> 
> > 
> > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > Reviewed-by: Brian Foster <bfoster@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c | 88 +++++++++++++++++++++++++++++++-----------------
> >  1 file changed, 57 insertions(+), 31 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index cf0cba7..b2f0780 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -305,10 +305,30 @@ xfs_attr_set_args(
> >  		}
> >  	}
> >  
> > -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> > +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> >  		error = xfs_attr_leaf_addname(args);
> > -	else
> > -		error = xfs_attr_node_addname(args);
> > +		if (error != -ENOSPC)
> > +			return error;
> > +
> > +		/*
> > +		 * Commit that transaction so that the node_addname()
> > +		 * call can manage its own transactions.
> > +		 */
> > +		error = xfs_defer_finish(&args->trans);
> > +		if (error)
> > +			return error;
> > +
> > +		/*
> > +		 * Commit the current trans (including the inode) and
> > +		 * start a new one.
> > +		 */
> > +		error = xfs_trans_roll_inode(&args->trans, dp);
> > +		if (error)
> > +			return error;
> > +
> > +	}
> > +
> > +	error = xfs_attr_node_addname(args);
> >  	return error;
> 
> 	return xfs_attr_node_addname(args);
> 
> better yet:
> 
> 	if (!xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> 		return xfs_attr_node_addname(args);
> 
> 	error = xfs_attr_leaf_addname(args);
> 	if (error != -ENOSPC)
> 		return error;
> 	.....
> 
> BTW, I think I see the pattern now - isolate all the metadata
> changes from the mechanism of rolling the transactions, which means
> it can be converted to a set of operations connected by a generic
> transaction rolling mechanism. It's all starting to make more sense
> now :P
> 

Yeah.. IIRC the initial attempt at this was going down the path of
creating an entire separate xattr codepath for xattr intents. The
existing codepath has the issue of rolling transactions all over the
place, which makes it difficult to execute from dfops context. The goal
is then to try and take this thing apart such that it works in dfops
context for intents and at the same time can be driven by a high level
transaction rolling loop to support the traditional xattr codepath for
backwards compatibility.

The whole state/context thing fell out of that. I think most agree that
it's ugly, but it's a useful intermediate step for breaking down this
hunk of code into components that can be further evaluated for
simplification and reduction (while making functional progress as well).
E.g., perhaps the top-level states can be eliminated in favor of simply
looking at current xattr fork format. This gets hairier deeper down in
the set path, but I think we may eventually see some similar patterns
emerge when you consider that leaf and node adds follow a very similar
flow and make many of the same function calls with regard to handling
remote values, renames, etc. etc. All in all, I think it will be
interesting if we could come up with some abstractions that ultimately
facilitate removal of the state stuff. That's certainly not clear
enough to me at least right now, but something to keep in mind when
working through this code..

Brian

> > @@ -679,31 +700,36 @@ xfs_attr_leaf_addname(
> >  	retval = xfs_attr3_leaf_add(bp, args);
> >  	if (retval == -ENOSPC) {
> >  		/*
> > -		 * Promote the attribute list to the Btree format, then
> > -		 * Commit that transaction so that the node_addname() call
> > -		 * can manage its own transactions.
> > +		 * Promote the attribute list to the Btree format.
> > +		 * Unless an error occurs, retain the -ENOSPC retval
> >  		 */
> 
> Comments should use all 80 columns...
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
> 


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

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-24 21:44     ` Allison Collins
@ 2020-02-25 13:27       ` Brian Foster
  2020-02-26  3:29         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-25 13:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 02:44:14PM -0700, Allison Collins wrote:
> 
> 
> On 2/24/20 6:40 AM, Brian Foster wrote:
> > On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
> > > This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
> > > new transactions. We will use this later when we introduce delayed attributes
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
> > >   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
> > >   2 files changed, 29 insertions(+)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> > > index 3de2eec..da40f85 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> > > @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
> > >   	}
> > >   	return 0;
> > >   }
> > > +
> > > +/*
> > > + * Remove the value associated with an attribute by deleting the out-of-line
> > > + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
> > > + * transaction and recall the function
> > > + */
> > > +int
> > > +xfs_attr_rmtval_unmap(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int	error, done;
> > > +
> > > +	/*
> > > +	 * Unmap value blocks for this attr.  This is similar to
> > > +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> > > +	 * for new transactions
> > > +	 */
> > > +	error = xfs_bunmapi(args->trans, args->dp,
> > > +		    args->rmtblkno, args->rmtblkcnt,
> > > +		    XFS_BMAPI_ATTRFORK, 1, &done);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	if (!done)
> > > +		return -EAGAIN;
> > > +
> > > +	return 0;
> > > +}
> > 
> > Hmm.. any reason this isn't a refactor of the existing remove function?
> > Just skipping to the end of the series, I see we leave the reference to
> > xfs_attr_rmtval_remove() (which no longer exists and so is not very
> > useful) in this comment as well as a stale function declaration in
> > xfs_attr_remote.h.
> > 
> > I haven't grokked how this is used yet, but it seems like it would be
> > more appropriate to lift out the transaction handling from the original
> > function as we have throughout the rest of the code. That could also
> > mean creating a temporary wrapper (i.e., rmtval_remove() calls
> > rmtval_unmap()) for the loop/transaction code that could be removed
> > later if it ends up unused. Either way is much easier to follow than
> > creating a (currently unused) replacement..
> Yes, this came up in one of the other reviews.  I thought about it, but then
> decided against it.  xfs_attr_rmtval_remove disappears across patches 13 and
> 14.  The use of xfs_attr_rmtval_remove is replaced with
> xfs_attr_rmtval_unmap when we finally yank out all the transaction code.
> The reason I dont want to do it all at once is because that would mean
> patches 12, 13, 14 and 19 would lump together to make the swap instantaneous
> in once patch.
> 

Hmm.. I don't think we're talking about the same thing. If
xfs_attr_rmtval_remove() was broken down into two functions such that
one of the two looks exactly like the _unmap() variant, can't we just
remove the other half when it becomes unused and allow the _remove()
variant to exist with the implementation of _unmap() proposed here? This
seems fairly mechanical to me..

> I've been getting feedback that the set is really complicated, so I've been
> trying to find a way to organize it to help make it easier to review.  So I
> thought isolating 13 and 14 to just the state machine would help.  Thus I
> decided to keep patch 12 separate to take as much craziness out of 13 and 14
> as possible.  Patches 12 and 19 seem like otherwise easy things for people
> to look at.  Let me know your thoughts on this. :-)
> 

I think doing as much refactoring of existing code as early as possible
will go a long way towards simplifying the complexity around the
introduction of the state bits.

Brian

> You are right about the stale comment though, I missed it while going back
> over the commentary at the top.  Will fix.
> 
> Allison
> 
> > 
> > Brian
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> > > index eff5f95..e06299a 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.h
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> > > @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> > >   int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
> > >   		xfs_buf_flags_t incore_flags);
> > >   int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
> > > +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
> > >   #endif /* __XFS_ATTR_REMOTE_H__ */
> > > -- 
> > > 2.7.4
> > > 
> > 
> 


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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-24 23:14     ` Allison Collins
  2020-02-24 23:56       ` Darrick J. Wong
@ 2020-02-25 13:34       ` Brian Foster
  2020-02-26  5:36         ` Allison Collins
  1 sibling, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-25 13:34 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Feb 24, 2020 at 04:14:48PM -0700, Allison Collins wrote:
> On 2/24/20 8:25 AM, Brian Foster wrote:
> > On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> > > This patch modifies the attr remove routines to be delay ready. This means they no
> > > longer roll or commit transactions, but instead return -EAGAIN to have the calling
> > > routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> > > become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> > > track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> > > been modified to use the switch, and a  new version of xfs_attr_remove_args
> > > consists of a simple loop to refresh the transaction until the operation is
> > > completed.
> > > 
> > > This patch also adds a new struct xfs_delattr_context, which we will use to keep
> > > track of the current state of an attribute operation. The new xfs_delattr_state
> > > enum is used to track various operations that are in progress so that we know not
> > > to repeat them, and resume where we left off before EAGAIN was returned to cycle
> > > out the transaction. Other members take the place of local variables that need
> > > to retain their values across multiple function recalls.
> > > 
> > > Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> > > indicate places where the function would return -EAGAIN, and then immediately
> > > resume from after being recalled by the calling function.  States marked as a
> > > "subroutine state" indicate that they belong to a subroutine, and so the calling
> > > function needs to pass them back to that subroutine to allow it to finish where
> > > it left off. But they otherwise do not have a role in the calling function other
> > > than just passing through.
> > > 
> > >   xfs_attr_remove_iter()
> > >           XFS_DAS_RM_SHRINK     ─┐
> > >           (subroutine state)     │
> > >                                  │
> > >           XFS_DAS_RMTVAL_REMOVE ─┤
> > >           (subroutine state)     │
> > >                                  └─>xfs_attr_node_removename()
> > >                                                   │
> > >                                                   v
> > >                                           need to remove
> > >                                     ┌─n──  rmt blocks?
> > >                                     │             │
> > >                                     │             y
> > >                                     │             │
> > >                                     │             v
> > >                                     │  ┌─>XFS_DAS_RMTVAL_REMOVE
> > >                                     │  │          │
> > >                                     │  │          v
> > >                                     │  └──y── more blks
> > >                                     │         to remove?
> > >                                     │             │
> > >                                     │             n
> > >                                     │             │
> > >                                     │             v
> > >                                     │         need to
> > >                                     └─────> shrink tree? ─n─┐
> > >                                                   │         │
> > >                                                   y         │
> > >                                                   │         │
> > >                                                   v         │
> > >                                           XFS_DAS_RM_SHRINK │
> > >                                                   │         │
> > >                                                   v         │
> > >                                                  done <─────┘
> > > 
> > 
> > Wow. :P I guess I have nothing against verbose commit logs, but I wonder
> > how useful this level of documentation is for a patch that shouldn't
> > really change the existing flow of the operation.
> 
> Yes Darrick had requested a diagram in the last review, so I had put this
> together.  I wasnt sure where the best place to put it even was, so I put it
> here at least for now.  I have no idea if there is a limit on commit message
> length, but if there is, I'm pretty sure I blew right past it in this patch
> and the next.  Maybe if anything it can just be here for now while we work
> through things?
> 

No problem.. if it's useful it's good to have a record of out around
somewhere until the end result is more stabilized and we can determine
whether this warrants a permanent home somewhere in the code.

> > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
> > >   fs/xfs/libxfs/xfs_attr.h     |   1 +
> > >   fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
> > >   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 +
> > >   10 files changed, 141 insertions(+), 16 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 5d73bdf..cd3a3f7 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -368,11 +368,60 @@ xfs_has_attr(
> > >    */
> > >   int
> > >   xfs_attr_remove_args(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error = 0;
> > > +	int			err2 = 0;
> > > +
> > > +	do {
> > > +		error = xfs_attr_remove_iter(args);
> > > +		if (error && error != -EAGAIN)
> > > +			goto out;
> > > +
> > 
> > I'm a little confused on the logic of this loop given that the only
> > caller commits the transaction (which also finishes dfops). IOW, it
> > seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
> > that is the case, this can be simplified to something like:
> Well, we need to do it when error == -EAGAIN or 0, right? Which I think
> better imitates the defer_finish routines.  That's why a lot of the existing
> code that just finishes off with a transaction just sort of gets sawed off
> at the end. Otherwise they would need one more state just to return -EAGAIN
> as the last thing they have to do. Did that make sense?
> 

Hmm.. I could just be missing something or not far along enough in the
series. Can you point me at an example of where we need to finish/roll
before the caller of xfs_attr_remove_args() commits the transaction?

> > 
> > int
> > xfs_attr_remove_args(
> >          struct xfs_da_args      *args)
> > {
> >          int                     error;
> > 
> >          do {
> >                  error = xfs_attr_remove_iter(args);
> >                  if (error != -EAGAIN)
> >                          break;
> > 
> >                  if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> >                          args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> >                          error = xfs_defer_finish(&args->trans);
> >                          if (error)
> >                                  break;
> >                  }
> > 
> >                  error = xfs_trans_roll_inode(&args->trans, args->dp);
> >                  if (error)
> >                          break;
> >          } while (true);
> > 
> >          return error;
> > }
> > 
> > That has the added benefit of eliminating the whole err2 pattern, which
> > always strikes me as a landmine.
> > 
> > > +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> > 
> > BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
> > operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
> Sure, will update
> 
> > 
> > > +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> > > +
> > > +			err2 = xfs_defer_finish(&args->trans);
> > > +			if (err2) {
> > > +				error = err2;
> > > +				goto out;
> > > +			}
> > > +		}
> > > +
> > > +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		if (err2) {
> > > +			error = err2;
> > > +			goto out;
> > > +		}
> > > +
> > > +	} while (error == -EAGAIN);
> > > +out:
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > > + * Remove the attribute specified in @args.
> > > + *
> > > + * This function may return -EAGAIN to signal that the transaction needs to be
> > > + * rolled.  Callers should continue calling this function until they receive a
> > > + * return value other than -EAGAIN.
> > > + */
> > > +int
> > > +xfs_attr_remove_iter(
> > >   	struct xfs_da_args      *args)
> > >   {
> > >   	struct xfs_inode	*dp = args->dp;
> > >   	int			error;
> > > +	/* State machine switch */
> > > +	switch (args->dac.dela_state) {
> > > +	case XFS_DAS_RM_SHRINK:
> > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > +		goto node;
> > > +	default:
> > > +		break;
> > > +	}
> > > +
> > >   	if (!xfs_inode_hasattr(dp)) {
> > >   		error = -ENOATTR;
> > >   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > > @@ -381,6 +430,7 @@ xfs_attr_remove_args(
> > >   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > >   		error = xfs_attr_leaf_removename(args);
> > >   	} else {
> > > +node:
> > >   		error = xfs_attr_node_removename(args);
> > >   	}
> > > @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
> > >   		/* bp is gone due to xfs_da_shrink_inode */
> > >   		if (error)
> > >   			return error;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			return error;
> > > +
> > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > >   	}
> > >   	return 0;
> > >   }
> > > @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
> > >    * This will involve walking down the Btree, and may involve joining
> > >    * leaf nodes and even joining intermediate nodes up to and including
> > >    * the root node (a special case of an intermediate node).
> > > + *
> > > + * This routine is meant to function as either an inline or delayed operation,
> > > + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> > > + * functions will need to handle this, and recall the function until a
> > > + * successful error code is returned.
> > >    */
> > >   STATIC int
> > >   xfs_attr_node_removename(
> > > @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
> > >   	struct xfs_inode	*dp = args->dp;
> > >   	trace_xfs_attr_node_removename(args);
> > > +	state = args->dac.da_state;
> > > +	blk = args->dac.blk;
> > > +
> > > +	/* State machine switch */
> > > +	switch (args->dac.dela_state) {
> > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > +		goto rm_node_blks;
> > > +	case XFS_DAS_RM_SHRINK:
> > > +		goto rm_shrink;
> > > +	default:
> > > +		break;
> > > +	}
> > >   	error = xfs_attr_node_hasname(args, &state);
> > >   	if (error != -EEXIST)
> > >   		goto out;
> > > +	else
> > > +		error = 0;
> > 
> > This doesn't look necessary.
> Well, at this point error has to be -EEXIST.  Which is great because we need
> the attr to exist, but we dont want to return that as error for this
> function.  Which can happen if error is not otherwise set.
> 

AFAICT every codepath after this assigns error one way or another before
it's returned. There's another error = 0 assignment just before the out:
label.

> > 
> > >   	/*
> > >   	 * If there is an out-of-line value, de-allocate the blocks.
> > > @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
> > >   	blk = &state->path.blk[ state->path.active-1 ];
> > >   	ASSERT(blk->bp != NULL);
> > >   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +
> > > +	/*
> > > +	 * Store blk and state in the context incase we need to cycle out the
> > > +	 * transaction
> > > +	 */
> > > +	args->dac.blk = blk;
> > > +	args->dac.da_state = state;
> > > +
> > >   	if (args->rmtblkno > 0) {
> > >   		/*
> > >   		 * Fill in disk block numbers in the state structure
> > > @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		error = xfs_attr_rmtval_invalidate(args);
> > 
> > Remind me why we lose the above trans roll? I vaguely recall that this
> > was intentional, but I could be mistaken...
> I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE
> state, but then we reasoned that because these are just in-core changes, we
> didnt need it, so we eliminated this state entirely.
> 
> Maybe i just add a comment here?  Just as a reminder
> 

Ah, Ok. Normally I'd say document things like this in the commit log so
we don't lose track, though I don't know how much space we have there.
;)

> > 
> > >   		if (error)
> > >   			goto out;
> > > +	}
> > > -		error = xfs_attr_rmtval_remove(args);
> > > -		if (error)
> > > -			goto out;
> > > +rm_node_blks:
> > > +
> > > +	if (args->rmtblkno > 0) {
> > > +		error = xfs_attr_rmtval_unmap(args);
> > > +
> > > +		if (error) {
> > > +			if (error == -EAGAIN)
> > > +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
> > 
> > Might be helpful for the code labels to match the state names. I.e., use
> > das_rmtval_remove: for the label above.
> Sure, I can update add the das prefix.
> 
> > 
> > > +			return error;
> > > +		}
> > >   		/*
> > >   		 * Refill the state structure with buffers, the prior calls
> > > @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
> > >   		error = xfs_da3_join(state);
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			goto out;
> > > -		/*
> > > -		 * Commit the Btree join operation and start a new trans.
> > > -		 */
> > > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > > -		if (error)
> > > -			goto out;
> > > +
> > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > > +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > +		return -EAGAIN;
> > >   	}
> > > +rm_shrink:
> > > +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > +
> > 
> > There's an xfs_defer_finish() call further down this function. Should
> > that be replaced with the flag?
> > 
> > Finally, I mentioned in a previous review that this function should
> > probably be further broken down before fitting in the state management
> > stuff. It doesn't look like that happened so I've attached a diff that
> > is just intended to give an idea of what I mean by sectioning off the
> > hunks that might be able to break down into helpers. The helpers
> > wouldn't contain any state management, so we create a clear separation
> > between the state code and functional components.
> Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch to
> try and keep the activity in this one to a minimum.  Apologies if it
> surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS
> flag with it.  I meant to keep all the state machine stuff here.  Will fix!
> 

Ok, I might have just not got there yet.

> I think this initial
> > refactoring would make the introduction of state much more simple
> 
> I guess I didn't think people would be partial to introducing helpers before
> or after the state logic.  I put them after in this set because the states
> are visible now, so I though it would make the goal of modularizing code
> between the states more clear to folks.  Do you think I should move it back
> behind the state machine patches?
> 

I do think the refactoring should be done first. This does make it more
challenging for the developer (IMO) because I know I'd probably have to
hack around with the state bits to have a better idea of how to refactor
things in some cases, and then go back and retrofit the refactoring.

The advantage is that the heavy lifting in this series becomes agnostic
to the state bits. Refactoring patches are easier to review and we can
make progress because there's less of a need to carry those out of tree
through however many versions of the state code we'll need before
getting it merged. Once the code is sufficiently factored, the state
code should be much simpler to introduce and review since we hopefully
won't be jumping around into the middle of functions, multiple branches
of logic deep, etc.

(I see Dave commented similarly on a couple of the subsequent patches. I
100% agree with the approach he describes there and that is similar to
what I was trying to describe with the diff I attached in my earlier
mail...)

Brian

> (and
> > perhaps alleviate the need for the huge diagram).
> Well, I get the impression that people find the series sort of scary and
> maybe the diagrams help them a bit.  Maybe we can take them out later after
> people feel like they are comfortable with things?
> 
> It might also be
> > interesting to see how much of the result could be folded up further
> > into _removename_iter()...
> 
> Yes, I think that is the goal we're reaching for.  I will add the other
> helpers I see in your diff too.
> 
> Thanks for the reviews!
> Allison
> 
> > 
> > Brian
> > 
> > >   	/*
> > >   	 * If the result is small enough, push it all into the inode.
> > >   	 */
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index ce7b039..ea873a5 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> > >   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> > >   int xfs_has_attr(struct xfs_da_args *args);
> > >   int xfs_attr_remove_args(struct xfs_da_args *args);
> > > +int xfs_attr_remove_iter(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);
> > > diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> > > index 14f1be3..3c78498 100644
> > > --- a/fs/xfs/libxfs/xfs_da_btree.h
> > > +++ b/fs/xfs/libxfs/xfs_da_btree.h
> > > @@ -50,9 +50,39 @@ enum xfs_dacmp {
> > >   };
> > >   /*
> > > + * Enum values for xfs_delattr_context.da_state
> > > + *
> > > + * These values are used by delayed attribute operations to keep track  of where
> > > + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> > > + * calling function to roll the transaction, and then recall the subroutine to
> > > + * finish the operation.  The enum is then used by the subroutine to jump back
> > > + * to where it was and resume executing where it left off.
> > > + */
> > > +enum xfs_delattr_state {
> > > +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> > > +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> > > +};
> > > +
> > > +/*
> > > + * Defines for xfs_delattr_context.flags
> > > + */
> > > +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> > > +
> > > +/*
> > > + * Context used for keeping track of delayed attribute operations
> > > + */
> > > +struct xfs_delattr_context {
> > > +	struct xfs_da_state	*da_state;
> > > +	struct xfs_da_state_blk *blk;
> > > +	unsigned int		flags;
> > > +	enum xfs_delattr_state	dela_state;
> > > +};
> > > +
> > > +/*
> > >    * Structure to ease passing around component names.
> > >    */
> > >   typedef struct xfs_da_args {
> > > +	struct xfs_delattr_context dac; /* context used for delay attr ops */
> > >   	struct xfs_da_geometry *geo;	/* da block geometry */
> > >   	struct xfs_name	name;		/* name, length and argument  flags*/
> > >   	uint8_t		filetype;	/* filetype of inode for directories */
> > > 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 42ac847..d65e6d8 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 "xfs_error.h"
> > > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> > > index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
> > > -- 
> > > 2.7.4
> > > 
> > 
> 


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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  4:27           ` Darrick J. Wong
  2020-02-25  6:07             ` Allison Collins
@ 2020-02-25 17:21             ` Christoph Hellwig
  1 sibling, 0 replies; 135+ messages in thread
From: Christoph Hellwig @ 2020-02-25 17:21 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Collins, Dave Chinner, linux-xfs

On Mon, Feb 24, 2020 at 08:27:07PM -0800, Darrick J. Wong wrote:
> At this point you might as well wait for me to actually put hch's attr
> interface refactoring series into for-next (unless this series is
> already based off of that??) though Christoph might be a bit time
> constrained this week...

I can resend it.  The only change from the last version is to drop
the da_args move, I've just been waiting for more comments to not
spam the list too much..

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25  6:43       ` Amir Goldstein
@ 2020-02-25 22:27         ` Dave Chinner
  0 siblings, 0 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-25 22:27 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Allison Collins, linux-xfs

On Tue, Feb 25, 2020 at 08:43:53AM +0200, Amir Goldstein wrote:
> On Tue, Feb 25, 2020 at 8:26 AM Dave Chinner <david@fromorbit.com> wrote:
> >
> > On Sun, Feb 23, 2020 at 02:20:32PM +0200, Amir Goldstein wrote:
> > > On Sun, Feb 23, 2020 at 4:07 AM Allison Collins
> > > <allison.henderson@oracle.com> 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 appearance of duplicated code.  We will need these
> > > > routines later for delayed attributes since delayed operations cannot return error
> > > > codes.
> > > >
> > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > ---
> > > >  fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
> > > >  fs/xfs/libxfs/xfs_attr.h      |   1 +
> > > >  fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
> > > >  fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
> > > >  4 files changed, 188 insertions(+), 98 deletions(-)
> > > >
> > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > index 9acdb23..2255060 100644
> > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > > > +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> > > >
> > > >  /*
> > > >   * Internal routines when attribute list is more than one block.
> > > > @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> > > >  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > > > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> > > > +                                struct xfs_da_state **state);
> > > >  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> > > >  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> > > >
> > > > @@ -310,6 +313,37 @@ xfs_attr_set_args(
> > > >  }
> > > >
> > > >  /*
> > > > + * Return EEXIST if attr is found, or ENOATTR if not
> > >
> > > This is a very silly return value for a function named has_attr in my taste.
> > > I realize you inherited this interface from xfs_attr3_leaf_lookup_int(), but
> > > IMO this change looks like a very good opportunity to change that internal
> > > API:
> >
> > tl;dr Cleaning up this API is work for another patchset.
> >
> > >
> > > xfs_has_attr?
> > >
> > > 0: NO
> > > 1: YES (or stay with the syscall standard of -ENOATTR)
> > > <0: error
> >
> > While I agree with your sentiment, Amir, the API you suggest is an
> > anti-pattern. We've been removing ternary return value APIs like
> > this from XFS and replacing them with an explicit error return value
> > and an operational return parameter like so:
> >
> >         error = xfs_has_attr(&exists)
> >         if (error)
> >                 return error;
> >
> 
> That would be neat and tidy.
> 
> One of the outcomes of new reviewers is comments on code unrelated
> to the changes... I have no problem of keeping API as is for Allison's
> change, but I did want to point out that the API became worse to read
> due to the helper name change from _lookup_attr to _has_attr, which
> really asks for a yes or no answer.

No argument from me on that. :P

But we really need to make progress on the new attribute features
rather than get bogged down in completely rewriting the attribute
code because it's a bit gross and smelly. The smell can be removed
later...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-25  6:42   ` Dave Chinner
  2020-02-25 13:26     ` Brian Foster
@ 2020-02-25 23:26     ` Allison Collins
  1 sibling, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-25 23:26 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/24/20 11:42 PM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:05:59PM -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, and move the commit into the calling function.
> 
> 68-72 columns :P
Yes, I had adjusted the configs on the editor and thought I had it 
fixed.  Will fix
> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 88 +++++++++++++++++++++++++++++++-----------------
>>   1 file changed, 57 insertions(+), 31 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index cf0cba7..b2f0780 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -305,10 +305,30 @@ xfs_attr_set_args(
>>   		}
>>   	}
>>   
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_addname(args);
>> -	else
>> -		error = xfs_attr_node_addname(args);
>> +		if (error != -ENOSPC)
>> +			return error;
>> +
>> +		/*
>> +		 * Commit that transaction so that the node_addname()
>> +		 * call can manage its own transactions.
>> +		 */
>> +		error = xfs_defer_finish(&args->trans);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Commit the current trans (including the inode) and
>> +		 * start a new one.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, dp);
>> +		if (error)
>> +			return error;
>> +
>> +	}
>> +
>> +	error = xfs_attr_node_addname(args);
>>   	return error;
> 
> 	return xfs_attr_node_addname(args);
> 
> better yet:
> 
> 	if (!xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> 		return xfs_attr_node_addname(args);
> 
> 	error = xfs_attr_leaf_addname(args);
> 	if (error != -ENOSPC)
> 		return error;
> 	.....
Sure, let me dig around first though, because that's going to move 
around where the states appear in patch 14.  The set is admittedly a bit 
of a balancing act :-)

> 
> BTW, I think I see the pattern now - isolate all the metadata
> changes from the mechanism of rolling the transactions, which means
> it can be converted to a set of operations connected by a generic
> transaction rolling mechanism. It's all starting to make more sense
> now :P
Alrighty, I'm glad it's coming together. :-)

> 
>> @@ -679,31 +700,36 @@ xfs_attr_leaf_addname(
>>   	retval = xfs_attr3_leaf_add(bp, args);
>>   	if (retval == -ENOSPC) {
>>   		/*
>> -		 * Promote the attribute list to the Btree format, then
>> -		 * Commit that transaction so that the node_addname() call
>> -		 * can manage its own transactions.
>> +		 * Promote the attribute list to the Btree format.
>> +		 * Unless an error occurs, retain the -ENOSPC retval
>>   		 */
> 
> Comments should use all 80 columns...
Will fix

Thanks for the reviews!
Allison
> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args
  2020-02-25  6:56   ` Chandan Rajendra
@ 2020-02-25 23:26     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-25 23:26 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/24/20 11:56 PM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:35 AM 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.
>>
> 
> The statement "name = &args.name;" in xfs_attr_set() and xfs_attr_remove() was
> not apparent to me on first read. However your explaination to Amir's question
> about name.type being set in xfs_attr_args_init() made it clear.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Alrighty, thanks for the review!

Allison
> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        |  37 +++++++-------
>>   fs/xfs/libxfs/xfs_attr_leaf.c   | 104 +++++++++++++++++++++-------------------
>>   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>   fs/xfs/libxfs/xfs_da_btree.c    |   6 ++-
>>   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_node.c   |   8 ++--
>>   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>   fs/xfs/scrub/attr.c             |  12 ++---
>>   fs/xfs/xfs_trace.h              |  20 ++++----
>>   12 files changed, 130 insertions(+), 123 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 6717f47..9acdb23 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>   	args->geo = dp->i_mount->m_attr_geo;
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>> -	args->flags = flags;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> -	if (args->namelen >= MAXNAMELEN)
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>> +	args->name.type = flags;
>> +	if (args->name.len >= MAXNAMELEN)
>>   		return -EFAULT;		/* match IRIX behaviour */
>>   
>> -	args->hashval = xfs_da_hashname(args->name, args->namelen);
>> +	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
>>   	return 0;
>>   }
>>   
>> @@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
>>   	 * Commit the shortform mods, and we're done.
>>   	 * NOTE: this is also the error path (EEXIST, etc).
>>   	 */
>> -	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
>> +	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>   
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>> @@ -357,6 +356,9 @@ xfs_attr_set(
>>   	if (error)
>>   		return error;
>>   
>> +	/* Use name now stored in args */
>> +	name = &args.name;
>> +
>>   	args.value = value;
>>   	args.valuelen = valuelen;
>>   	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
>> @@ -372,7 +374,7 @@ xfs_attr_set(
>>   	 */
>>   	if (XFS_IFORK_Q(dp) == 0) {
>>   		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
>> -			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
>> +			XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
>>   
>>   		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>>   		if (error)
>> @@ -457,6 +459,9 @@ xfs_attr_remove(
>>   	if (error)
>>   		return error;
>>   
>> +	/* Use name now stored in args */
>> +	name = &args.name;
>> +
>>   	/*
>>   	 * we have no control over the attribute names that userspace passes us
>>   	 * to remove, so we have to allow the name lookup prior to attribute
>> @@ -532,10 +537,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>>   	trace_xfs_attr_sf_addname(args);
>>   
>>   	retval = xfs_attr_shortform_lookup(args);
>> -	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		return retval;
>>   	} else if (retval == -EEXIST) {
>> -		if (args->flags & ATTR_CREATE)
>> +		if (args->name.type & ATTR_CREATE)
>>   			return retval;
>>   		retval = xfs_attr_shortform_remove(args);
>>   		if (retval)
>> @@ -545,15 +550,15 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>>   		 * that the leaf format add routine won't trip over the attr
>>   		 * not being around.
>>   		 */
>> -		args->flags &= ~ATTR_REPLACE;
>> +		args->name.type &= ~ATTR_REPLACE;
>>   	}
>>   
>> -	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
>> +	if (args->name.len >= XFS_ATTR_SF_ENTSIZE_MAX ||
>>   	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
>>   		return -ENOSPC;
>>   
>>   	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
>> -	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>> +	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>>   
>>   	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
>>   	if (!forkoff)
>> @@ -598,11 +603,11 @@ xfs_attr_leaf_addname(
>>   	 * the given flags produce an error or call for an atomic rename.
>>   	 */
>>   	retval = xfs_attr3_leaf_lookup_int(bp, args);
>> -	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> +	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return retval;
>>   	} else if (retval == -EEXIST) {
>> -		if (args->flags & ATTR_CREATE) {	/* pure create op */
>> +		if (args->name.type & ATTR_CREATE) {	/* pure create op */
>>   			xfs_trans_brelse(args->trans, bp);
>>   			return retval;
>>   		}
>> @@ -872,10 +877,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);
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index fed537a..cb5ef66 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -464,7 +464,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;
>>   	}
>> @@ -679,27 +679,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);
>> @@ -749,11 +749,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;
>>   	}
>> @@ -816,11 +816,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;
>>   	}
>> @@ -847,13 +847,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;
>> @@ -912,13 +912,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);
>> @@ -1119,12 +1119,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;
>> @@ -1450,7 +1450,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) &&
>> @@ -1474,15 +1474,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;
>> @@ -2409,23 +2410,25 @@ xfs_attr3_leaf_lookup_int(
>>   		}
>>   		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);
>> @@ -2467,16 +2470,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,
>> @@ -2692,7 +2696,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;
>> @@ -2700,7 +2704,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);
>>   }
>>   
>>   
>> @@ -2754,8 +2758,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 8b7f74b..df8aca5 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -397,7 +397,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 875e04f..30f27d7 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.c
>> +++ b/fs/xfs/libxfs/xfs_da_btree.c
>> @@ -2125,8 +2125,10 @@ 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;
>> +	if (args->name.len == len && !memcmp(args->name.name, name, len))
>> +		return XFS_CMP_EXACT;
>> +
>> +	return XFS_CMP_DIFFERENT;
>>   }
>>   
>>   int
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index 0f4fbb0..14f1be3 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -54,12 +54,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 dd6fcaa..3aadddc 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;
>>   	}
>> @@ -265,8 +265,7 @@ xfs_dir_createname(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>   	args->filetype = name->type;
>>   	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>>   	args->inumber = inum;
>> @@ -361,8 +360,7 @@ xfs_dir_lookup(
>>   	 */
>>   	args = kmem_zalloc(sizeof(*args), KM_NOFS);
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>   	args->filetype = name->type;
>>   	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>>   	args->dp = dp;
>> @@ -433,8 +431,7 @@ xfs_dir_removename(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>   	args->filetype = name->type;
>>   	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>>   	args->inumber = ino;
>> @@ -494,8 +491,7 @@ xfs_dir_replace(
>>   		return -ENOMEM;
>>   
>>   	args->geo = dp->i_mount->m_dir_geo;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>>   	args->filetype = name->type;
>>   	args->hashval = xfs_dir2_hashname(dp->i_mount, name);
>>   	args->inumber = inum;
>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index d6ced59..592e47c 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 = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
>> +	len = xfs_dir2_data_entsize(dp->i_mount, 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);
>>   	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>>   	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a131b52..24a7fda 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -653,7 +653,7 @@ xfs_dir2_leaf_addname(
>>   	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
>>   	ents = leafhdr.ents;
>>   	bestsp = xfs_dir2_leaf_bests_p(ltp);
>> -	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
>> +	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
>>   
>>   	/*
>>   	 * See if there are any entries with the same hash value
>> @@ -856,8 +856,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);
>>   	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>>   	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 a0cc5e2..3c74efc 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -666,7 +666,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 = xfs_dir2_data_entsize(mp, args->namelen);
>> +	length = xfs_dir2_data_entsize(mp, args->name.len);
>>   	/*
>>   	 * Loop over leaf entries with the right hash value.
>>   	 */
>> @@ -1911,7 +1911,7 @@ xfs_dir2_node_addname_int(
>>   	int			needscan = 0;	/* need to rescan data frees */
>>   	__be16			*tagp;		/* data entry tag pointer */
>>   
>> -	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
>> +	length = xfs_dir2_data_entsize(dp->i_mount, args->name.len);
>>   	error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &freehdr,
>>   					   &findex, length);
>>   	if (error)
>> @@ -1966,8 +1966,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);
>>   	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
>>   	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 7b7f6fb..058c526 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -387,7 +387,7 @@ xfs_dir2_sf_addname(
>>   	/*
>>   	 * Compute entry (and change in) size.
>>   	 */
>> -	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
>> +	incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->name.len);
>>   	objchange = 0;
>>   
>>   	/*
>> @@ -470,7 +470,7 @@ xfs_dir2_sf_addname_easy(
>>   	/*
>>   	 * Grow the in-inode space.
>>   	 */
>> -	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
>> +	xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->name.len),
>>   			  XFS_DATA_FORK);
>>   	/*
>>   	 * Need to set up again due to realloc of the inode data.
>> @@ -480,9 +480,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);
>>   	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
>>   	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
>>   
>> @@ -540,7 +540,7 @@ xfs_dir2_sf_addname_hard(
>>   	 */
>>   	for (offset = args->geo->data_first_offset,
>>   	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
>> -	      add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
>> +	      add_datasize = xfs_dir2_data_entsize(mp, args->name.len),
>>   	      eof = (char *)oldsfep == &buf[old_isize];
>>   	     !eof;
>>   	     offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
>> @@ -570,9 +570,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);
>>   	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
>>   	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
>>   	sfp->count++;
>> @@ -615,7 +615,7 @@ xfs_dir2_sf_addname_pick(
>>   	int			used;		/* data bytes used */
>>   
>>   	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
>> -	size = xfs_dir2_data_entsize(mp, args->namelen);
>> +	size = xfs_dir2_data_entsize(mp, args->name.len);
>>   	offset = args->geo->data_first_offset;
>>   	sfep = xfs_dir2_sf_firstentry(sfp);
>>   	holefit = 0;
>> @@ -887,7 +887,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;
>> @@ -896,8 +896,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 = xfs_dir2_sf_get_parent_ino(sfp);
>>   		args->cmpresult = XFS_CMP_EXACT;
>>   		args->filetype = XFS_DIR3_FT_DIR;
>> @@ -984,7 +984,7 @@ xfs_dir2_sf_removename(
>>   	 * Calculate sizes.
>>   	 */
>>   	byteoff = (int)((char *)sfep - (char *)sfp);
>> -	entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
>> +	entsize = xfs_dir2_sf_entsize(mp, sfp, args->name.len);
>>   	newsize = oldsize - entsize;
>>   	/*
>>   	 * Copy the part if any after the removed entry, sliding it down.
>> @@ -1085,12 +1085,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 = xfs_dir2_sf_get_parent_ino(sfp);
>>   		ASSERT(args->inumber != ino);
>>   		xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
>> diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
>> index d9f0dd4..d4a9fe4 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 a86be7f..159b8af 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -1633,7 +1633,7 @@ DECLARE_EVENT_CLASS(xfs_da_class,
>>   	TP_STRUCT__entry(
>>   		__field(dev_t, dev)
>>   		__field(xfs_ino_t, ino)
>> -		__dynamic_array(char, name, args->namelen)
>> +		__dynamic_array(char, name, args->name.len)
>>   		__field(int, namelen)
>>   		__field(xfs_dahash_t, hashval)
>>   		__field(xfs_ino_t, inumber)
>> @@ -1642,9 +1642,10 @@ DECLARE_EVENT_CLASS(xfs_da_class,
>>   	TP_fast_assign(
>>   		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
>>   		__entry->ino = args->dp->i_ino;
>> -		if (args->namelen)
>> -			memcpy(__get_str(name), args->name, args->namelen);
>> -		__entry->namelen = args->namelen;
>> +		if (args->name.len)
>> +			memcpy(__get_str(name), args->name.name,
>> +			       args->name.len);
>> +		__entry->namelen = args->name.len;
>>   		__entry->hashval = args->hashval;
>>   		__entry->inumber = args->inumber;
>>   		__entry->op_flags = args->op_flags;
>> @@ -1697,7 +1698,7 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>>   	TP_STRUCT__entry(
>>   		__field(dev_t, dev)
>>   		__field(xfs_ino_t, ino)
>> -		__dynamic_array(char, name, args->namelen)
>> +		__dynamic_array(char, name, args->name.len)
>>   		__field(int, namelen)
>>   		__field(int, valuelen)
>>   		__field(xfs_dahash_t, hashval)
>> @@ -1707,12 +1708,13 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>>   	TP_fast_assign(
>>   		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
>>   		__entry->ino = args->dp->i_ino;
>> -		if (args->namelen)
>> -			memcpy(__get_str(name), args->name, args->namelen);
>> -		__entry->namelen = args->namelen;
>> +		if (args->name.len)
>> +			memcpy(__get_str(name), args->name.name,
>> +			       args->name.len);
>> +		__entry->namelen = args->name.len;
>>   		__entry->valuelen = args->valuelen;
>>   		__entry->hashval = args->hashval;
>> -		__entry->flags = args->flags;
>> +		__entry->flags = args->name.type;
>>   		__entry->op_flags = args->op_flags;
>>   	),
>>   	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
>>
> 
> 

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

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-25  7:21   ` Dave Chinner
@ 2020-02-25 23:27     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-25 23:27 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/25/20 12:21 AM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
>> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
>> new transactions. We will use this later when we introduce delayed attributes
> 
> 68-72 columns...
> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 29 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 3de2eec..da40f85 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>>   	}
>>   	return 0;
>>   }
>> +
>> +/*
>> + * Remove the value associated with an attribute by deleting the out-of-line
>> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
>> + * transaction and recall the function
>> + */
>> +int
>> +xfs_attr_rmtval_unmap(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int	error, done;
> 
> Best to initialise done to zero here.
> 
>> +
>> +	/*
>> +	 * Unmap value blocks for this attr.  This is similar to
>> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>> +	 * for new transactions
>> +	 */
>> +	error = xfs_bunmapi(args->trans, args->dp,
>> +		    args->rmtblkno, args->rmtblkcnt,
>> +		    XFS_BMAPI_ATTRFORK, 1, &done);
> 
> Got 80 columns for code, please use them all :)
> 
>> +	if (error)
>> +		return error;
>> +
>> +	if (!done)
>> +		return -EAGAIN;
> 
> Hmmm, I guess I'm missing the context at this point: why not just pass the done
> variable all the way back to the caller that will be looping on this function
> call?
> 
> That turns this function into:
> 
> int
> xfs_attr_rmtval_unmap(
> 	struct xfs_da_args      *args,
> 	bool			*donec
> {
> 	return xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
> 				args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, done);
> }
Well, this is a helper we talked about adding in the v5 review ([PATCH 
v5 13/14] xfs: Add delay ready attr remove routines)  In v5, I did not 
have this helper function, and just open coded xfs_attr_rmtval_remove in 
the middle of the calling function (xfs_attr_remove_iter), except with 
out the transaction.  Then later we identified it as an area we could 
modularize.  It's kind of hard to see the bigger picture with out the 
states being here yet.  But really what we're trying to do is modularize 
everything that shows up between the states later in the set.

Hope that helps a bit!
Allison

> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-25  8:57   ` Dave Chinner
@ 2020-02-26  0:57     ` Allison Collins
  2020-02-26 22:34       ` Dave Chinner
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-26  0:57 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/25/20 1:57 AM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
>> This patch modifies the attr remove routines to be delay ready. This means they no
>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
>> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
>> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
>> been modified to use the switch, and a  new version of xfs_attr_remove_args
>> consists of a simple loop to refresh the transaction until the operation is
>> completed.
>>
>> This patch also adds a new struct xfs_delattr_context, which we will use to keep
>> track of the current state of an attribute operation. The new xfs_delattr_state
>> enum is used to track various operations that are in progress so that we know not
>> to repeat them, and resume where we left off before EAGAIN was returned to cycle
>> out the transaction. Other members take the place of local variables that need
>> to retain their values across multiple function recalls.
>>
>> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> 
> Ok, so I find all the DA/da prefixes in this code confusing,
> especially as they have very similar actual names. e.g. da_state
> vs delattr_state, DAS vs DA_STATE, etc.
> 
> Basically, I can't tell from reading the code what "DA" the actual
> variable belongs to, and in a few months time I'll most definitely
> have forgotten and have to relearn it from scratch.
> 
> So while "Delayed Attributes" is a great name for the feature, I
> don't think it makes a great acronym for shortening variable names
> because of the conflict with the existing DA namespace prefix.
> 
> Also, "dac" as shorthand for delattr context is also overloaded.
> "DAC" is "discretionary access control" and is quite widely used
> in the kernel (e.g. CAP_DAC_READ_SEARCH, CAP_DAC_OVERRIDE) so again
> I read thsi code and it doesn't make much sense.
> 
> I haven't come up with a better name - "attribute iterator" is the
> best I've managed (marketing++ - XFS has AI now!) and shortening it
> down to ator would go a long way to alleviating my namespace
> confusion....

Sure, no worries, there's still time to give it some thought
> 
>> indicate places where the function would return -EAGAIN, and then immediately
>> resume from after being recalled by the calling function.  States marked as a
>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>> function needs to pass them back to that subroutine to allow it to finish where
>> it left off. But they otherwise do not have a role in the calling function other
>> than just passing through.
>>
>>   xfs_attr_remove_iter()
>>           XFS_DAS_RM_SHRINK     ─┐
>>           (subroutine state)     │
>>                                  │
>>           XFS_DAS_RMTVAL_REMOVE ─┤
>>           (subroutine state)     │
>>                                  └─>xfs_attr_node_removename()
>>                                                   │
>>                                                   v
>>                                           need to remove
>>                                     ┌─n──  rmt blocks?
>>                                     │             │
>>                                     │             y
>>                                     │             │
>>                                     │             v
>>                                     │  ┌─>XFS_DAS_RMTVAL_REMOVE
>>                                     │  │          │
>>                                     │  │          v
>>                                     │  └──y── more blks
>>                                     │         to remove?
>>                                     │             │
>>                                     │             n
>>                                     │             │
>>                                     │             v
>>                                     │         need to
>>                                     └─────> shrink tree? ─n─┐
>>                                                   │         │
>>                                                   y         │
>>                                                   │         │
>>                                                   v         │
>>                                           XFS_DAS_RM_SHRINK │
>>                                                   │         │
>>                                                   v         │
>>                                                  done <─────┘
> 
> Nice.
I'm glad people like those, I wasnt sure what people expected or what to 
expect as a response, but I think it helps facilitate the design at 
least for the time being :-)

> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>>   fs/xfs/libxfs/xfs_attr.h     |   1 +
>>   fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>>   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 +
>>   10 files changed, 141 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5d73bdf..cd3a3f7 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -368,11 +368,60 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> +	struct xfs_da_args	*argsc
>> +{
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +
>> +	do {
>> +		error = xfs_attr_remove_iter(args);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>> +
>> +			err2 = xfs_defer_finish(&args->trans);
>> +			if (err2) {
>> +				error = err2;
>> +				goto out;
>> +			}
>> +		}
>> +
>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +out:
>> +	return error;
>> +}
> 
> Brian commented on the structure of this loop better than I could.
> 
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + *
>> + * This function may return -EAGAIN to signal that the transaction needs to be
>> + * rolled.  Callers should continue calling this function until they receive a
>> + * return value other than -EAGAIN.
>> + */
>> +int
>> +xfs_attr_remove_iter(
>>   	struct xfs_da_args      *args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	int			error;
>>   
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_RM_SHRINK:
>> +	case XFS_DAS_RMTVAL_REMOVE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
> 
> Why separate out the state machine? Doesn't this shortcut the
> xfs_inode_hasattr() check? Shouldn't that come first?
Well, the idea is that when we first start the routine, we come in with 
neither state set, and we fall through to the break.  So we execute the 
check the first time through.

Though now that you point it out, I should probably go back and put the 
explicit numbering back in the enum (starting with 1) or they will 
default to zero, which would be incorrect.  I had pulled it out in one 
of the last reviews thinking it would be ok, but it should go back in.

> 
> As it is:
> 
> 	case XFS_DAS_RM_SHRINK:
> 	case XFS_DAS_RMTVAL_REMOVE:
> 		return xfs_attr_node_removename(args);
> 	default:
> 		break;
> 
> would be nicer, and if this is the only way we can get to
> xfs_attr_node_removename(c, getting rid of it from the code
> below could be done, too.
Well, the remove path is a lot simpler than the set path, so that trick 
does work here :-)

The idea though was to establish "jump points" with the "XFS_DAS_*" 
states.  Based on the state, we jump back to where we were.  We could 
break this pattern for the remove path, but I dont think we'd want to do 
the same for the others.  The set routine is a really big function that 
would end up being inside a really big switch!

> 
> 
>> +
>>   	if (!xfs_inode_hasattr(dp)) {
>>   		error = -ENOATTR;
>>   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>>   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_removename(args);
>>   	} else {
>> +node:
>>   		error = xfs_attr_node_removename(args);
>>   	}
>>   
>> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>>   		/* bp is gone due to xfs_da_shrink_inode */
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +
>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>   	}
>>   	return 0;
>>   }
>> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>>    * This will involve walking down the Btree, and may involve joining
>>    * leaf nodes and even joining intermediate nodes up to and including
>>    * the root node (a special case of an intermediate node).
>> + *
>> + * This routine is meant to function as either an inline or delayed operation,
>> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
>> + * functions will need to handle this, and recall the function until a
>> + * successful error code is returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_removename(
>> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>>   	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_node_removename(args);
>> +	state = args->dac.da_state;
>> +	blk = args->dac.blk;
>> +
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_RMTVAL_REMOVE:
>> +		goto rm_node_blks;
>> +	case XFS_DAS_RM_SHRINK:
>> +		goto rm_shrink;
>> +	default:
>> +		break;
>> +	}
> 
> This really is calling out for this function to be broken into three
> smaller functions. That would greatly simplify the code flow and
> logic here.
Yes, that is the goal we are working towards.

> 
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index ce7b039..ea873a5 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> +int xfs_attr_remove_iter(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);
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index 14f1be3..3c78498 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>>   };
>>   
>>   /*
>> + * Enum values for xfs_delattr_context.da_state
>> + *
>> + * These values are used by delayed attribute operations to keep track  of where
>> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
>> + * calling function to roll the transaction, and then recall the subroutine to
>> + * finish the operation.  The enum is then used by the subroutine to jump back
>> + * to where it was and resume executing where it left off.
>> + */
>> +enum xfs_delattr_state {
>> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */Note to self: need put the ordering back to starting at 1, not zero

>> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
>> +};
>> +
>> +/*
>> + * Defines for xfs_delattr_context.flags
>> + */
>> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delattr_context {
>> +	struct xfs_da_state	*da_state;
>> +	struct xfs_da_state_blk *blk;
>> +	unsigned int		flags;
>> +	enum xfs_delattr_state	dela_state;
>> +};
>> +
>> +/*
>>    * Structure to ease passing around component names.
>>    */
>>   typedef struct xfs_da_args {
>> +	struct xfs_delattr_context dac; /* context used for delay attr ops */
> 
> Probably should put this at the end of the structure rather than the
> front.
Sure, will do

> 
> I'm also wondering if it should be kept separate to the da_args and
> contain a pointer to the da_args instead of being wrapped inside
> them.
> 
> i.e. we put the iterating state structure on the stack, then
> 
> 	struct attr_iter	ater = {
> 		.da_args = args,
> 	};
> 
> 	do {
> 		error = xfs_attr_remove_iter(&ater);
> 		.....
> 	
> And that largely separates the delayed attribute iteration state
> from the da_args that holds the internal attribute manipulation
> information.
Oh i see.  Sure, let me see if that will work, it seems like it should

> 
>>   	struct xfs_da_geometry *geo;	/* da block geometry */
>>   	struct xfs_name	name;		/* name, length and argument  flags*/
>>   	uint8_t		filetype;	/* filetype of inode for directories */
>> 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"
> 
> Hmmm - why are these new includes necessary? You didn't add anything
> new to these files or common header files to make the includes
> needed....

Because the delayed attr context uses things from those headers.  And we 
put the context in xfs_da_args.  Now everything that uses xfs_da_args 
needs those includes.  But maybe if we do what you suggest above, we 
wont need to. :-)

Thanks for the reviews!  I know its a lot!
Allison

> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink
  2020-02-25  9:05   ` Dave Chinner
@ 2020-02-26  1:48     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  1:48 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/25/20 2:05 AM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:06:07PM -0700, Allison Collins wrote:
>> This patch adds a new helper function xfs_attr_node_shrink used to shrink an
>> attr name into an inode if it is small enough.  This helps to modularize
>> the greater calling function xfs_attr_node_removename.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Can you move this helper function up to early in the patch set?
> That way the code gets simpler and less tangled before adding
> all the new state machine gubbins?
> 
> I suspect that you should do this for all the functions the state
> machine breaks up into gotos, too. THat way adding the state machine
> is really just changing how the functions that do the work are
> called, rather than jumping into the middle of long functions....
> 
> I know, it turns it into a longer series, but it also means that all
> the refactoring work (which needs to be done anyway) can be
> separated and merged while we are still reviewing and working on the
> state machine based operations, thereby reducing the size of the
> patchset you have to manage and keep up to date over time....
> 
> Cheers,
> 
> Dave.
> 
Sure, looking ahead it sounds like that works better for others too, so 
I'll move them back down.  Thanks!

Allison

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-25  9:21   ` Dave Chinner
@ 2020-02-26  2:13     ` Allison Collins
  2020-02-26 22:39       ` Dave Chinner
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:13 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/25/20 2:21 AM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:06:08PM -0700, Allison Collins wrote:
>> Delayed attribute mechanics make frequent use of goto statements.  We can use this
>> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
>> conditions, we can invert the if logic and jump to the goto. This helps to reduce
>> indentation and simplify things.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>>   1 file changed, 42 insertions(+), 29 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 30a16fe..dd935ff 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>>   }
>>   
>>   /*
>> + * Check to see if the attr should be upgraded from non-existent or shortform to
>> + * single-leaf-block attribute list.
>> + */
>> +static inline bool
>> +xfs_attr_fmt_needs_update(
>> +	struct xfs_inode    *dp)
> 
> Can we use *ip for the inode in newly factored code helpers like
> this?

Sure, will fix

> 
>> +{
>> +	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> +	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> +	      dp->i_d.di_anextents == 0);
>> +}
>> +
>> +/*
>>    * Set the attribute specified in @args.
>>    */
>>   int
>> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>>   	}
>>   
>>   	/*
>> -	 * If the attribute list is non-existent or a shortform list,
>> -	 * upgrade it to a single-leaf-block attribute list.
>> +	 * If the attribute list is already in leaf format, jump straight to
>> +	 * leaf handling.  Otherwise, try to add the attribute to the shortform
>> +	 * list; if there's no room then convert the list to leaf format and try
>> +	 * again.
>>   	 */
>> -	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)) {
>> +	if (!xfs_attr_fmt_needs_update(dp))
>> +		goto add_leaf;
> 
> The logic seems inverted to me here, but that really indicates a
> sub-optimal function name. It's really checking if the attribute
> fork is empty or in shortform format. Hence:
> 
> 	if (!xfs_attr_is_shortform(dp))
> 		goto add_leaf;
> 
Ok, this had come up in the last review too, we had tried to simplify it 
to an "is_leaf" helper, though it turned out the logic didnt quite work 
the same functionally, so I put it back and renamed it "needs_update". 
I think "is_shortform" is a closer description though.  Will update.

>> -		/*
>> -		 * Try to add the attr to the attribute list in the inode.
>> -		 */
>> -		error = xfs_attr_try_sf_addname(dp, args);
>> +	/*
>> +	 * Try to add the attr to the attribute list in the inode.
>> +	 */
>> +	error = xfs_attr_try_sf_addname(dp, args);
>>   
>> -		/* Should only be 0, -EEXIST or ENOSPC */
>> -		if (error != -ENOSPC)
>> -			return error;
>> +	/* Should only be 0, -EEXIST or ENOSPC */
>> +	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;
>> +	/*
>> +	 * 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);
>> -		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> -		args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> -		return -EAGAIN;
>> -	}
>> +	/*
>> +	 * 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);
>> +	args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +	args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> +	return -EAGAIN;
> 
> Heh. This is an example of exactly why I think this should be
> factored into functions first. Move all the code you just
> re-indented into xfs_attr_set_shortform(), and the goto disappears
> because this code becomes:
> 
> 	if (xfs_attr_is_shortform(dp))
> 		return xfs_attr_set_shortform(dp, args);
> 
> add_leaf:
> 
> That massively improves the readability of the code - it separates
> the operation implementation from the decision logic nice and
> cleanly, and lends itself to being implemented in the delayed attr
> state machine without needing gotos at all.
Sure, I actually had it more like that in the last version.  I flipped 
it around because I thought it would help people understand what the 
refactoring was for if they could see it in context with the states. 
But if the other way is more helpful, its easy to put back.  Will move :-)

Allison
> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-25  9:31   ` Dave Chinner
@ 2020-02-26  2:17     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:17 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/25/20 2:31 AM, Dave Chinner wrote:
> On Sat, Feb 22, 2020 at 07:06:09PM -0700, Allison Collins wrote:
>> This patch helps to simplify xfs_attr_node_removename by modularizing the code
>> around the transactions into helper functions.  This will make the function easier
>> to follow when we introduce delayed attributes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Another candidate for being at the start of this patchset.
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 45 +++++++++++++++++++++++++++++++--------------
>>   1 file changed, 31 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index dd935ff..b9728d1 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
>>   }
>>   
>>   /*
>> + * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
>> + * for later deletion of the entry.
>> + */
>> +STATIC int
>> +xfs_attr_leaf_mark_incomplete(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	*state)
>> +{
>> +	int error;
>> +
>> +	/*
>> +	 * 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.
>> +	 */
> 
> Reformat to use all 80 columns.
> 
> [ Handy vim hints, add this to your .vimrc:
> 
> " set the textwidth to 80 characters for C code
>   au BufNewFile,BufRead *.c,*.h set tw=80
> 
> " set the textwidth to 68 characters for guilt commit messages
>   au BufNewFile,BufRead guilt.msg.*,.gitsendemail.*,git.*,*/.git/* set tw=68
> 
> " Formatting the current paragraph according to
> " the current 'textwidth' with ^J (control-j):
>    imap <C-J> <c-o>gqap
>     map <C-J> gqap
> 
> " highlight textwidth
> set cc=+1
> 
> ]

Ah, alrighty, I will try these out and update the comment.

Thanks!
Allison
> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25  9:49   ` Chandan Rajendra
  2020-02-25 10:15     ` Chandan Rajendra
@ 2020-02-26  2:18     ` Allison Collins
  1 sibling, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:18 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/25/20 2:49 AM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:35 AM 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 appearance of duplicated code.  We will need these
>> routines later for delayed attributes since delayed operations cannot return error
>> codes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>>   4 files changed, 188 insertions(+), 98 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9acdb23..2255060 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>   
>>   /*
>>    * Internal routines when attribute list is more than one block.
>> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>> +				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>   
>> @@ -310,6 +313,37 @@ 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 = NULL;
>> +	int			error;
>> +
>> +	if (!xfs_inode_hasattr(dp))
>> +		return -ENOATTR;
>> +
>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		return xfs_attr_sf_findname(args, NULL, NULL);
>> +	}
>> +
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_hasname(args, &bp);
>> +
>> +		if (bp)
>> +			xfs_trans_brelse(args->trans, bp);
>> +
>> +		return error;
>> +	}
>> +
>> +	return xfs_attr_node_hasname(args, NULL);
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
>> @@ -583,26 +617,20 @@ STATIC int
>>   xfs_attr_leaf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_inode	*dp;
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>> +	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_leaf_addname(args);
>>   
>>   	/*
>> -	 * Read the (only) block in the attribute list in.
>> -	 */
>> -	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>>   	 * the given flags produce an error or call for an atomic rename.
>>   	 */
>> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
>> +	retval = xfs_attr_leaf_hasname(args, &bp);
>> +	if (retval != -ENOATTR && retval != -EEXIST)
>> +		return retval;
>> +
>>   	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return retval;
>> @@ -754,6 +782,27 @@ xfs_attr_leaf_addname(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +STATIC int
>> +xfs_attr_leaf_hasname(
>> +	struct xfs_da_args      *args,
>> +	struct xfs_buf		**bp)
>> +{
>> +	int                     error = 0;
>> +
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
>> +	if (error)
>> +		return error;
>> +
>> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
>> +	if (error != -ENOATTR && error != -EEXIST)
>> +		xfs_trans_brelse(args->trans, *bp);
>> +
>> +	return error;
>> +}
>> +
>> +/*
>>    * Remove a name from the leaf attribute list structure
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>>   	 * Remove the attribute.
>>   	 */
>>   	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -	if (error)
>> +
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error == -ENOATTR) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_leaf_get(args);
>>   
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>> -	if (error)
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error != -EEXIST)  {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   	return error;
>>   }
>>   
>> +/*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * statep: If not null is set to point at the found state.  Caller will
>> + *         be responsible for freeing the state in this case.
>> + */
>> +STATIC int
>> +xfs_attr_node_hasname(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**statep)
>> +{
>> +	struct xfs_da_state	*state;
>> +	int			retval, error;
>> +
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = args->dp->i_mount;
>> +
>> +	if (statep != NULL)
>> +		*statep = NULL;
>> +
>> +	/*
>> +	 * Search to see if name exists, and get back a pointer to it.
>> +	 */
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error == 0) {
>> +		if (statep != NULL)
>> +			*statep = state;
>> +		return retval;
>> +	}
> 
> If 'statep' were NULL, then this would leak the memory pointed to by 'state'
> right?
> 
Another reviewer caught this too.  Will update!  :-)

Thanks!
Allison

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25 10:15     ` Chandan Rajendra
@ 2020-02-26  2:19       ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:19 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/25/20 3:15 AM, Chandan Rajendra wrote:
> On Tuesday, February 25, 2020 3:19 PM Chandan Rajendra wrote:
>> On Sunday, February 23, 2020 7:35 AM 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 appearance of duplicated code.  We will need these
>>> routines later for delayed attributes since delayed operations cannot return error
>>> codes.
>>>
>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>> ---
>>>   fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>>   fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>>>   fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>>>   4 files changed, 188 insertions(+), 98 deletions(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 9acdb23..2255060 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>>   
>>>   /*
>>>    * Internal routines when attribute list is more than one block.
>>> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>> +				 struct xfs_da_state **state);
>>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>>   
>>> @@ -310,6 +313,37 @@ 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 = NULL;
>>> +	int			error;
>>> +
>>> +	if (!xfs_inode_hasattr(dp))
>>> +		return -ENOATTR;
>>> +
>>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>> +		return xfs_attr_sf_findname(args, NULL, NULL);
>>> +	}
>>> +
>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>> +		error = xfs_attr_leaf_hasname(args, &bp);
>>> +
>>> +		if (bp)
>>> +			xfs_trans_brelse(args->trans, bp);
>>> +
>>> +		return error;
>>> +	}
>>> +
>>> +	return xfs_attr_node_hasname(args, NULL);
>>> +}
>>> +
>>> +/*
>>>    * Remove the attribute specified in @args.
>>>    */
>>>   int
>>> @@ -583,26 +617,20 @@ STATIC int
>>>   xfs_attr_leaf_addname(
>>>   	struct xfs_da_args	*args)
>>>   {
>>> -	struct xfs_inode	*dp;
>>>   	struct xfs_buf		*bp;
>>>   	int			retval, error, forkoff;
>>> +	struct xfs_inode	*dp = args->dp;
>>>   
>>>   	trace_xfs_attr_leaf_addname(args);
>>>   
>>>   	/*
>>> -	 * Read the (only) block in the attribute list in.
>>> -	 */
>>> -	dp = args->dp;
>>> -	args->blkno = 0;
>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>>> -	if (error)
>>> -		return error;
>>> -
>>> -	/*
>>>   	 * Look up the given attribute in the leaf block.  Figure out if
>>>   	 * the given flags produce an error or call for an atomic rename.
>>>   	 */
>>> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
>>> +	retval = xfs_attr_leaf_hasname(args, &bp);
>>> +	if (retval != -ENOATTR && retval != -EEXIST)
>>> +		return retval;
>>> +
>>>   	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>>   		xfs_trans_brelse(args->trans, bp);
>>>   		return retval;
>>> @@ -754,6 +782,27 @@ xfs_attr_leaf_addname(
>>>   }
>>>   
>>>   /*
>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>> + */
>>> +STATIC int
>>> +xfs_attr_leaf_hasname(
>>> +	struct xfs_da_args      *args,
>>> +	struct xfs_buf		**bp)
>>> +{
>>> +	int                     error = 0;
>>> +
>>> +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
>>> +	if (error)
>>> +		return error;
>>> +
>>> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
>>> +	if (error != -ENOATTR && error != -EEXIST)
>>> +		xfs_trans_brelse(args->trans, *bp);
>>> +
>>> +	return error;
>>> +}
>>> +
>>> +/*
>>>    * Remove a name from the leaf attribute list structure
>>>    *
>>>    * This leaf block cannot have a "remote" value, we only call this routine
>>> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>>>   	 * Remove the attribute.
>>>   	 */
>>>   	dp = args->dp;
>>> -	args->blkno = 0;
>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>>> -	if (error)
>>> +
>>> +	error = xfs_attr_leaf_hasname(args, &bp);
>>> +	if (error != -ENOATTR && error != -EEXIST)
>>>   		return error;
>>>   
>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>   	if (error == -ENOATTR) {
>>>   		xfs_trans_brelse(args->trans, bp);
>>>   		return error;
>>> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>   
>>>   	trace_xfs_attr_leaf_get(args);
>>>   
>>> -	args->blkno = 0;
>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>>> -	if (error)
>>> +	error = xfs_attr_leaf_hasname(args, &bp);
>>> +	if (error != -ENOATTR && error != -EEXIST)
>>>   		return error;
>>>   
>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>   	if (error != -EEXIST)  {
>>>   		xfs_trans_brelse(args->trans, bp);
>>>   		return error;
>>> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>   	return error;
>>>   }
>>>   
>>> +/*
>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>> + * statep: If not null is set to point at the found state.  Caller will
>>> + *         be responsible for freeing the state in this case.
>>> + */
>>> +STATIC int
>>> +xfs_attr_node_hasname(
>>> +	struct xfs_da_args	*args,
>>> +	struct xfs_da_state	**statep)
>>> +{
>>> +	struct xfs_da_state	*state;
>>> +	int			retval, error;
>>> +
>>> +	state = xfs_da_state_alloc();
>>> +	state->args = args;
>>> +	state->mp = args->dp->i_mount;
>>> +
>>> +	if (statep != NULL)
>>> +		*statep = NULL;
>>> +
>>> +	/*
>>> +	 * Search to see if name exists, and get back a pointer to it.
>>> +	 */
>>> +	error = xfs_da3_node_lookup_int(state, &retval);
>>> +	if (error == 0) {
>>> +		if (statep != NULL)
>>> +			*statep = state;
>>> +		return retval;
>>> +	}
>>
>> If 'statep' were NULL, then this would leak the memory pointed to by 'state'
>> right?
>>
> Apart from the above, the remaining changes look good to me.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> 
Alrighty, will fix.  Thanks!

Allison

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

* Re: [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2020-02-25 12:53   ` Chandan Rajendra
@ 2020-02-26  2:20     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:20 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/25/20 5:53 AM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:35 AM 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.
> 
> I don't see any logical errors.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Great!  Thank you!

Allison
> 
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 149 +++++++++++++++++++++++++---------------
>>   1 file changed, 92 insertions(+), 57 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index df8aca5..d1eee24 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -440,32 +440,23 @@ xfs_attr_rmtval_get(
>>   }
>>   
>>   /*
>> - * Write the value associated with an attribute into the out-of-line buffer
>> - * that we have defined for it.
>> + * Find a "hole" in the attribute address space large enough for us to drop the
>> + * new attribute's value into
>>    */
>> -int
>> -xfs_attr_rmtval_set(
>> +STATIC int
>> +xfs_attr_rmt_find_hole(
>>   	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);
>> +	int			blkcnt;
>> +	xfs_fileoff_t		lfileoff = 0;
>>   
>>   	/*
>> -	 * 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.
>> +	 * 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,
>> @@ -473,48 +464,26 @@ xfs_attr_rmtval_set(
>>   	if (error)
>>   		return error;
>>   
>> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
>> +	args->rmtblkno = (xfs_dablk_t)lfileoff;
>>   	args->rmtblkcnt = blkcnt;
>>   
>> -	/*
>> -	 * Roll through the "value", allocating blocks on disk as required.
>> -	 */
>> -	while (blkcnt > 0) {
>> -		/*
>> -		 * Allocate a single extent, up to the size of the value.
>> -		 *
>> -		 * Note that we have to consider this a data allocation as we
>> -		 * write the remote attribute without logging the contents.
>> -		 * Hence we must ensure that we aren't using blocks that are on
>> -		 * the busy list so that we don't overwrite blocks which have
>> -		 * recently been freed but their transactions are not yet
>> -		 * committed to disk. If we overwrite the contents of a busy
>> -		 * extent and then crash then the block may not contain the
>> -		 * correct metadata after log recovery occurs.
>> -		 */
>> -		nmap = 1;
>> -		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
>> -				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
>> -				  &nmap);
>> -		if (error)
>> -			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> -
>> -		ASSERT(nmap == 1);
>> -		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
>> -		       (map.br_startblock != HOLESTARTBLOCK));
>> -		lblkno += map.br_blockcount;
>> -		blkcnt -= map.br_blockcount;
>> +	return 0;
>> +}
>>   
>> -		/*
>> -		 * Start the next trans in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			return error;
>> -	}
>> +STATIC 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
>> @@ -595,6 +564,72 @@ xfs_attr_rmtval_stale(
>>   }
>>   
>>   /*
>> + * Write the value associated with an attribute into the out-of-line buffer
>> + * that we have defined for it.
>> + */
>> +int
>> +xfs_attr_rmtval_set(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	int			blkcnt;
>> +	int			nmap;
>> +	int			error;
>> +
>> +	trace_xfs_attr_rmtval_set(args);
>> +
>> +	error = xfs_attr_rmt_find_hole(args);
>> +	if (error)
>> +		return error;
>> +
>> +	blkcnt = args->rmtblkcnt;
>> +	lblkno = (xfs_dablk_t)args->rmtblkno;
>> +	/*
>> +	 * Roll through the "value", allocating blocks on disk as required.
>> +	 */
>> +	while (blkcnt > 0) {
>> +		/*
>> +		 * Allocate a single extent, up to the size of the value.
>> +		 *
>> +		 * Note that we have to consider this a data allocation as we
>> +		 * write the remote attribute without logging the contents.
>> +		 * Hence we must ensure that we aren't using blocks that are on
>> +		 * the busy list so that we don't overwrite blocks which have
>> +		 * recently been freed but their transactions are not yet
>> +		 * committed to disk. If we overwrite the contents of a busy
>> +		 * extent and then crash then the block may not contain the
>> +		 * correct metadata after log recovery occurs.
>> +		 */
>> +		nmap = 1;
>> +		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
>> +				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
>> +				  &nmap);
>> +		if (error)
>> +			return error;
>> +		error = xfs_defer_finish(&args->trans);
>> +		if (error)
>> +			return error;
>> +
>> +		ASSERT(nmap == 1);
>> +		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
>> +		       (map.br_startblock != HOLESTARTBLOCK));
>> +		lblkno += map.br_blockcount;
>> +		blkcnt -= map.br_blockcount;
>> +
>> +		/*
>> +		 * Start the next trans in the chain.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, dp);
>> +		if (error)
>> +			return error;
>> +	}
>> +
>> +	return xfs_attr_rmtval_set_value(args);
>> +}
>> +
>> +/*
>>    * Remove the value associated with an attribute by deleting the
>>    * out-of-line buffer that it is stored on.
>>    */
>>
> 
> 

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

* Re: [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines
  2020-02-25 13:25       ` Brian Foster
@ 2020-02-26  2:31         ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26  2:31 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On 2/25/20 6:25 AM, Brian Foster wrote:
> On Mon, Feb 24, 2020 at 02:18:35PM -0700, Allison Collins wrote:
>>
>>
>> On 2/24/20 6:08 AM, Brian Foster wrote:
>>> On Sat, Feb 22, 2020 at 07:05:55PM -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 appearance of duplicated code.  We will need these
>>>> routines later for delayed attributes since delayed operations cannot return error
>>>> codes.
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c      | 171 ++++++++++++++++++++++++++++--------------
>>>>    fs/xfs/libxfs/xfs_attr.h      |   1 +
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c | 111 +++++++++++++++++----------
>>>>    fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
>>>>    4 files changed, 188 insertions(+), 98 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 9acdb23..2255060 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> ...
>>>> @@ -310,6 +313,37 @@ 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 = NULL;
>>>> +	int			error;
>>>> +
>>>> +	if (!xfs_inode_hasattr(dp))
>>>> +		return -ENOATTR;
>>>> +
>>>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>>> +		return xfs_attr_sf_findname(args, NULL, NULL);
>>>
>>> Nit: any reason we use "findname" here and "hasname" for the other two
>>> variants?
>> It was asked for in the v4 review.  Reason being we also return the location
>> of the sf entry and byte offset.
>>
> 
> Ok.
> 
>>>
>>> Just a few other nit level things..
>>>
>>>> +	}
>>>> +
>>>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>> +		error = xfs_attr_leaf_hasname(args, &bp);
>>>> +
>>>> +		if (bp)
>>>> +			xfs_trans_brelse(args->trans, bp);
>>>> +
>>>> +		return error;
>>>> +	}
>>>> +
>>>> +	return xfs_attr_node_hasname(args, NULL);
>>>> +}
>>>> +
>>>> +/*
>>>>     * Remove the attribute specified in @args.
>>>>     */
>>>>    int
>>> ...
>>>> @@ -773,12 +822,11 @@ xfs_attr_leaf_removename(
>>>>    	 * Remove the attribute.
>>>>    	 */
>>>>    	dp = args->dp;
>>>> -	args->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>>>> -	if (error)
>>>> +
>>>> +	error = xfs_attr_leaf_hasname(args, &bp);
>>>> +	if (error != -ENOATTR && error != -EEXIST)
>>>>    		return error;
>>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>>    	if (error == -ENOATTR) {
>>>
>>> It looks like some of these error checks could be cleaned up where the
>>> helper function is used. I.e., something like the following here:
>>>
>>> 	if (error == -ENOATTR) {
>>> 		xfs_trans_brelse(...);
>>> 		return error;
>>> 	} else if (error != -EEXIST)
>>> 		return error;
>> Sure, I'm starting to get more pressure in other reviews to change this api
>> to a boolean return type though (1: y, 0: no, <0: error).  I think we talked
>> about this in v3, but decided to stick with this original api for now.  I'm
>> thinking maybe adding a patch at the end to shift the api might be a good
>> compromise?  Thoughts?
>>
> 
> I think Dave commented on this earlier with regard to some of these API
> cleanups being orthogonal to this work. The big challenge with this
> series is really taking apart this big tangle of xattr code such that it
> has smaller components and is thus mostly reusable between dfops context
> for parent pointers etc. and the traditional codepath. I can see the
> appeal of such API cleanups (so it's good feedback overall), but I agree
> that it's probably wiser to allow this series to work with the interface
> style we have in the existing code and consider that type of thing as a
> follow on cleanup when the subsystem itself is more stabilized.
> 
> Brian
Alrighty, sounds good for now. We'll come back and touch on it at a 
later time once we get through all the bigger stuff

Allison

> 
>>>
>>>>    		xfs_trans_brelse(args->trans, bp);
>>>>    		return error;
>>>> @@ -817,12 +865,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>>    	trace_xfs_attr_leaf_get(args);
>>>> -	args->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
>>>> -	if (error)
>>>> +	error = xfs_attr_leaf_hasname(args, &bp);
>>>> +	if (error != -ENOATTR && error != -EEXIST)
>>>>    		return error;
>>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>>    	if (error != -EEXIST)  {
>>>>    		xfs_trans_brelse(args->trans, bp);
>>>>    		return error;
>>>
>>> Similar thing here, just reordering the checks simplifies the logic.
>> Sure, will do.
>>
>>>
>>>> @@ -832,6 +878,41 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>>    	return error;
>>>>    }
>>>> +/*
>>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>>> + * statep: If not null is set to point at the found state.  Caller will
>>>> + *         be responsible for freeing the state in this case.
>>>> + */
>>>> +STATIC int
>>>> +xfs_attr_node_hasname(
>>>> +	struct xfs_da_args	*args,
>>>> +	struct xfs_da_state	**statep)
>>>> +{
>>>> +	struct xfs_da_state	*state;
>>>> +	int			retval, error;
>>>> +
>>>> +	state = xfs_da_state_alloc();
>>>> +	state->args = args;
>>>> +	state->mp = args->dp->i_mount;
>>>> +
>>>> +	if (statep != NULL)
>>>> +		*statep = NULL;
>>>> +
>>>> +	/*
>>>> +	 * Search to see if name exists, and get back a pointer to it.
>>>> +	 */
>>>> +	error = xfs_da3_node_lookup_int(state, &retval);
>>>> +	if (error == 0) {
>>>> +		if (statep != NULL)
>>>> +			*statep = state;
>>>> +		return retval;
>>>> +	}
>>>> +
>>>> +	xfs_da_state_free(state);
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>>    /*========================================================================
>>>>     * External routines when attribute list size > geo->blksize
>>>>     *========================================================================*/
>>> ...
>>>> @@ -1316,31 +1381,23 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>>>    {
>>>>    	xfs_da_state_t *state;
>>>>    	xfs_da_state_blk_t *blk;
>>>> -	int error, retval;
>>>> +	int error;
>>>>    	int i;
>>>>    	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) {
>>>> -		retval = error;
>>>> -		goto out_release;
>>>> -	}
>>>> -	if (retval != -EEXIST)
>>>> +	error = xfs_attr_node_hasname(args, &state);
>>>> +	if (error != -EEXIST)
>>>>    		goto out_release;
>>>>    	/*
>>>>    	 * Get the value, local or "remote"
>>>>    	 */
>>>>    	blk = &state->path.blk[state->path.active - 1];
>>>> -	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
>>>> +	error = xfs_attr3_leaf_getvalue(blk->bp, args);
>>>>    	/*
>>>>    	 * If not in a transaction, we have to release all the buffers.
>>>> @@ -1352,7 +1409,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>>>    	}
>>>>    	xfs_da_state_free(state);
>>>
>>> Do we need an 'if (state)' check here like the other node funcs?
>> I think so, because if xfs_attr_node_hasname errors out it releases the
>> state.  Will add.
>>
>>>
>>>> -	return retval;
>>>> +	return error;
>>>>    }
>>>>    /* Returns true if the attribute entry name is valid. */
>>> ...
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> index cb5ef66..9d6b68c 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> @@ -654,18 +654,66 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>>>    }
>>>>    /*
>>>> + * Return -EEXIST if attr is found, or -ENOATTR if not
>>>> + * args:  args containing attribute name and namelen
>>>> + * sfep:  If not null, pointer will be set to the last attr entry found on
>>>> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
>>>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>>>> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
>>>> + *	  the last entry in the list
>>>> + */
>>>> +int
>>>> +xfs_attr_sf_findname(
>>>> +	struct xfs_da_args	 *args,
>>>> +	struct xfs_attr_sf_entry **sfep,
>>>> +	unsigned int		 *basep)
>>>> +{
>>>> +	struct xfs_attr_shortform *sf;
>>>> +	struct xfs_attr_sf_entry *sfe;
>>>> +	unsigned int		base = sizeof(struct xfs_attr_sf_hdr);
>>>> +	int			size = 0;
>>>> +	int			end;
>>>> +	int			i;
>>>> +
>>>> +	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++) {
>>>
>>> Slightly more readable to align indendation with the sfe assignment
>>> above.
>> Sure, will fix.  Thanks!
>>
>> Allison
>>
>>>
>>> Brian
>>>
>>>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>> +		if (sfe->namelen != args->name.len)
>>>> +			continue;
>>>> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>>>> +			continue;
>>>> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>>>> +			continue;
>>>> +		break;
>>>> +	}
>>>> +
>>>> +	if (sfep != NULL)
>>>> +		*sfep = sfe;
>>>> +
>>>> +	if (basep != NULL)
>>>> +		*basep = base;
>>>> +
>>>> +	if (i == end)
>>>> +		return -ENOATTR;
>>>> +	return -EEXIST;
>>>> +}
>>>> +
>>>> +/*
>>>>     * Add a name/value pair to the shortform attribute list.
>>>>     * Overflow from the inode has already been checked for.
>>>>     */
>>>>    void
>>>> -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>>> +xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff)
>>>>    {
>>>> -	xfs_attr_shortform_t *sf;
>>>> -	xfs_attr_sf_entry_t *sfe;
>>>> -	int i, offset, size;
>>>> -	xfs_mount_t *mp;
>>>> -	xfs_inode_t *dp;
>>>> -	struct xfs_ifork *ifp;
>>>> +	struct xfs_attr_shortform	*sf;
>>>> +	struct xfs_attr_sf_entry	*sfe;
>>>> +	int				offset, size, error;
>>>> +	struct xfs_mount		*mp;
>>>> +	struct xfs_inode		*dp;
>>>> +	struct xfs_ifork		*ifp;
>>>>    	trace_xfs_attr_sf_add(args);
>>>> @@ -676,18 +724,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>>>    	ifp = dp->i_afp;
>>>>    	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>>>    	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>>>> -	sfe = &sf->list[0];
>>>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>>>> -#ifdef DEBUG
>>>> -		if (sfe->namelen != args->name.len)
>>>> -			continue;
>>>> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
>>>> -			continue;
>>>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>>>> -			continue;
>>>> -		ASSERT(0);
>>>> -#endif
>>>> -	}
>>>> +	error = xfs_attr_sf_findname(args, &sfe, NULL);
>>>> +	ASSERT(error != -EEXIST);
>>>>    	offset = (char *)sfe - (char *)sf;
>>>>    	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>>>> @@ -730,35 +768,26 @@ xfs_attr_fork_remove(
>>>>     * Remove an attribute from the shortform attribute list structure.
>>>>     */
>>>>    int
>>>> -xfs_attr_shortform_remove(xfs_da_args_t *args)
>>>> +xfs_attr_shortform_remove(struct xfs_da_args *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				size = 0, end, totsize;
>>>> +	unsigned int			base;
>>>> +	struct xfs_mount		*mp;
>>>> +	struct xfs_inode		*dp;
>>>> +	int				error;
>>>>    	trace_xfs_attr_sf_remove(args);
>>>>    	dp = args->dp;
>>>>    	mp = dp->i_mount;
>>>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>>>    	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>>>> -	sfe = &sf->list[0];
>>>> -	end = sf->hdr.count;
>>>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>>>> -					base += size, i++) {
>>>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>> -		if (sfe->namelen != args->name.len)
>>>> -			continue;
>>>> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>>>> -			continue;
>>>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>>>> -			continue;
>>>> -		break;
>>>> -	}
>>>> -	if (i == end)
>>>> -		return -ENOATTR;
>>>> +
>>>> +	error = xfs_attr_sf_findname(args, &sfe, &base);
>>>> +	if (error != -EEXIST)
>>>> +		return error;
>>>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>>    	/*
>>>>    	 * Fix up the attribute fork data, covering the hole
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> index 73615b1..0e9c87c 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> @@ -53,6 +53,9 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>>>    int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>>>    			struct xfs_buf **leaf_bp);
>>>>    int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>>>> +int	xfs_attr_sf_findname(struct xfs_da_args *args,
>>>> +			     struct xfs_attr_sf_entry **sfep,
>>>> +			     unsigned 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] 135+ messages in thread

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-25 13:27       ` Brian Foster
@ 2020-02-26  3:29         ` Allison Collins
  2020-02-26 13:47           ` Brian Foster
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-26  3:29 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/25/20 6:27 AM, Brian Foster wrote:
> On Mon, Feb 24, 2020 at 02:44:14PM -0700, Allison Collins wrote:
>>
>>
>> On 2/24/20 6:40 AM, Brian Foster wrote:
>>> On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
>>>> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
>>>> new transactions. We will use this later when we introduce delayed attributes
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>>>>    fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>>>    2 files changed, 29 insertions(+)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> index 3de2eec..da40f85 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>>>>    	}
>>>>    	return 0;
>>>>    }
>>>> +
>>>> +/*
>>>> + * Remove the value associated with an attribute by deleting the out-of-line
>>>> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
>>>> + * transaction and recall the function
>>>> + */
>>>> +int
>>>> +xfs_attr_rmtval_unmap(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int	error, done;
>>>> +
>>>> +	/*
>>>> +	 * Unmap value blocks for this attr.  This is similar to
>>>> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>>>> +	 * for new transactions
>>>> +	 */
>>>> +	error = xfs_bunmapi(args->trans, args->dp,
>>>> +		    args->rmtblkno, args->rmtblkcnt,
>>>> +		    XFS_BMAPI_ATTRFORK, 1, &done);
>>>> +	if (error)
>>>> +		return error;
>>>> +
>>>> +	if (!done)
>>>> +		return -EAGAIN;
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> Hmm.. any reason this isn't a refactor of the existing remove function?
>>> Just skipping to the end of the series, I see we leave the reference to
>>> xfs_attr_rmtval_remove() (which no longer exists and so is not very
>>> useful) in this comment as well as a stale function declaration in
>>> xfs_attr_remote.h.
>>>
>>> I haven't grokked how this is used yet, but it seems like it would be
>>> more appropriate to lift out the transaction handling from the original
>>> function as we have throughout the rest of the code. That could also
>>> mean creating a temporary wrapper (i.e., rmtval_remove() calls
>>> rmtval_unmap()) for the loop/transaction code that could be removed
>>> later if it ends up unused. Either way is much easier to follow than
>>> creating a (currently unused) replacement..
>> Yes, this came up in one of the other reviews.  I thought about it, but then
>> decided against it.  xfs_attr_rmtval_remove disappears across patches 13 and
>> 14.  The use of xfs_attr_rmtval_remove is replaced with
>> xfs_attr_rmtval_unmap when we finally yank out all the transaction code.
>> The reason I dont want to do it all at once is because that would mean
>> patches 12, 13, 14 and 19 would lump together to make the swap instantaneous
>> in once patch.
>>
> 
> Hmm.. I don't think we're talking about the same thing. If
> xfs_attr_rmtval_remove() was broken down into two functions such that
> one of the two looks exactly like the _unmap() variant, can't we just
> remove the other half when it becomes unused and allow the _remove()
> variant to exist with the implementation of _unmap() proposed here? This
> seems fairly mechanical to me..
Oh, I see what you mean.  No, I had done a review of the uses of 
xfs_attr_rmtval_remove and realized that it appears in both the set and 
remove paths. We use it in the set path when we're doing a rename, and 
need to remove the old attr.

So in patch 13, we replace xfs_attr_rmtval_remove with 
xfs_attr_rmtval_unmap for the remove routines.  But it's still in the 
set routines.  So we cant take it away yet.  Once we get through patch 
14, it is no longer used and we can remove it.  Did that make sense?

> 
>> I've been getting feedback that the set is really complicated, so I've been
>> trying to find a way to organize it to help make it easier to review.  So I
>> thought isolating 13 and 14 to just the state machine would help.  Thus I
>> decided to keep patch 12 separate to take as much craziness out of 13 and 14
>> as possible.  Patches 12 and 19 seem like otherwise easy things for people
>> to look at.  Let me know your thoughts on this. :-)
>>
> 
> I think doing as much refactoring of existing code as early as possible
> will go a long way towards simplifying the complexity around the
> introduction of the state bits.

Alrighty, I was thinking that if I reordered things such that 
modularizing appeared at the end of the set, that it would help people 
to see it in context with the states.  But it sounds like people like it 
the other way around, it's easy enough to put back.  Though I think we 
may still be stuck with 12 and 19 being apart unless 13 and 14 come 
together.  :-(

Allison

> 
> Brian
> 
>> You are right about the stale comment though, I missed it while going back
>> over the commentary at the top.  Will fix.
>>
>> Allison
>>
>>>
>>> Brian
>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>>>> index eff5f95..e06299a 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>>>> @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>>>>    int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
>>>>    		xfs_buf_flags_t incore_flags);
>>>>    int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
>>>> +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
>>>>    #endif /* __XFS_ATTR_REMOTE_H__ */
>>>> -- 
>>>> 2.7.4
>>>>
>>>
>>
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-25 13:34       ` Brian Foster
@ 2020-02-26  5:36         ` Allison Collins
  2020-02-26 13:48           ` Brian Foster
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-02-26  5:36 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/25/20 6:34 AM, Brian Foster wrote:
> On Mon, Feb 24, 2020 at 04:14:48PM -0700, Allison Collins wrote:
>> On 2/24/20 8:25 AM, Brian Foster wrote:
>>> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
>>>> This patch modifies the attr remove routines to be delay ready. This means they no
>>>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>>>> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
>>>> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
>>>> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
>>>> been modified to use the switch, and a  new version of xfs_attr_remove_args
>>>> consists of a simple loop to refresh the transaction until the operation is
>>>> completed.
>>>>
>>>> This patch also adds a new struct xfs_delattr_context, which we will use to keep
>>>> track of the current state of an attribute operation. The new xfs_delattr_state
>>>> enum is used to track various operations that are in progress so that we know not
>>>> to repeat them, and resume where we left off before EAGAIN was returned to cycle
>>>> out the transaction. Other members take the place of local variables that need
>>>> to retain their values across multiple function recalls.
>>>>
>>>> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
>>>> indicate places where the function would return -EAGAIN, and then immediately
>>>> resume from after being recalled by the calling function.  States marked as a
>>>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>>>> function needs to pass them back to that subroutine to allow it to finish where
>>>> it left off. But they otherwise do not have a role in the calling function other
>>>> than just passing through.
>>>>
>>>>    xfs_attr_remove_iter()
>>>>            XFS_DAS_RM_SHRINK     ─┐
>>>>            (subroutine state)     │
>>>>                                   │
>>>>            XFS_DAS_RMTVAL_REMOVE ─┤
>>>>            (subroutine state)     │
>>>>                                   └─>xfs_attr_node_removename()
>>>>                                                    │
>>>>                                                    v
>>>>                                            need to remove
>>>>                                      ┌─n──  rmt blocks?
>>>>                                      │             │
>>>>                                      │             y
>>>>                                      │             │
>>>>                                      │             v
>>>>                                      │  ┌─>XFS_DAS_RMTVAL_REMOVE
>>>>                                      │  │          │
>>>>                                      │  │          v
>>>>                                      │  └──y── more blks
>>>>                                      │         to remove?
>>>>                                      │             │
>>>>                                      │             n
>>>>                                      │             │
>>>>                                      │             v
>>>>                                      │         need to
>>>>                                      └─────> shrink tree? ─n─┐
>>>>                                                    │         │
>>>>                                                    y         │
>>>>                                                    │         │
>>>>                                                    v         │
>>>>                                            XFS_DAS_RM_SHRINK │
>>>>                                                    │         │
>>>>                                                    v         │
>>>>                                                   done <─────┘
>>>>
>>>
>>> Wow. :P I guess I have nothing against verbose commit logs, but I wonder
>>> how useful this level of documentation is for a patch that shouldn't
>>> really change the existing flow of the operation.
>>
>> Yes Darrick had requested a diagram in the last review, so I had put this
>> together.  I wasnt sure where the best place to put it even was, so I put it
>> here at least for now.  I have no idea if there is a limit on commit message
>> length, but if there is, I'm pretty sure I blew right past it in this patch
>> and the next.  Maybe if anything it can just be here for now while we work
>> through things?
>>
> 
> No problem.. if it's useful it's good to have a record of out around
> somewhere until the end result is more stabilized and we can determine
> whether this warrants a permanent home somewhere in the code.
> 
>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>>>>    fs/xfs/libxfs/xfs_attr.h     |   1 +
>>>>    fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>>>>    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 +
>>>>    10 files changed, 141 insertions(+), 16 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 5d73bdf..cd3a3f7 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -368,11 +368,60 @@ xfs_has_attr(
>>>>     */
>>>>    int
>>>>    xfs_attr_remove_args(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int			error = 0;
>>>> +	int			err2 = 0;
>>>> +
>>>> +	do {
>>>> +		error = xfs_attr_remove_iter(args);
>>>> +		if (error && error != -EAGAIN)
>>>> +			goto out;
>>>> +
>>>
>>> I'm a little confused on the logic of this loop given that the only
>>> caller commits the transaction (which also finishes dfops). IOW, it
>>> seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
>>> that is the case, this can be simplified to something like:
>> Well, we need to do it when error == -EAGAIN or 0, right? Which I think
>> better imitates the defer_finish routines.  That's why a lot of the existing
>> code that just finishes off with a transaction just sort of gets sawed off
>> at the end. Otherwise they would need one more state just to return -EAGAIN
>> as the last thing they have to do. Did that make sense?
>>
> 
> Hmm.. I could just be missing something or not far along enough in the
> series. Can you point me at an example of where we need to finish/roll
> before the caller of xfs_attr_remove_args() commits the transaction?
> 
Ok, in looking for an example, realized all such examples appear in the 
next patch ;-)  So maybe we can get away with simplifying it in this patch.

For the next patch though, it's any place the roll/finish disappears, 
and an "return -EAGAIN" does not.  For example, at the end of 
xfs_attr_leaf_addname.

>>>
>>> int
>>> xfs_attr_remove_args(
>>>           struct xfs_da_args      *args)
>>> {
>>>           int                     error;
>>>
>>>           do {
>>>                   error = xfs_attr_remove_iter(args);
>>>                   if (error != -EAGAIN)
>>>                           break;
>>>
>>>                   if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>>>                           args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>>>                           error = xfs_defer_finish(&args->trans);
>>>                           if (error)
>>>                                   break;
>>>                   }
>>>
>>>                   error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>                   if (error)
>>>                           break;
>>>           } while (true);
>>>
>>>           return error;
>>> }
>>>
>>> That has the added benefit of eliminating the whole err2 pattern, which
>>> always strikes me as a landmine.
>>>
>>>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>>>
>>> BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
>>> operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
>> Sure, will update
>>
>>>
>>>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>>>> +
>>>> +			err2 = xfs_defer_finish(&args->trans);
>>>> +			if (err2) {
>>>> +				error = err2;
>>>> +				goto out;
>>>> +			}
>>>> +		}
>>>> +
>>>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>>>> +		if (err2) {
>>>> +			error = err2;
>>>> +			goto out;
>>>> +		}
>>>> +
>>>> +	} while (error == -EAGAIN);
>>>> +out:
>>>> +	return error;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Remove the attribute specified in @args.
>>>> + *
>>>> + * This function may return -EAGAIN to signal that the transaction needs to be
>>>> + * rolled.  Callers should continue calling this function until they receive a
>>>> + * return value other than -EAGAIN.
>>>> + */
>>>> +int
>>>> +xfs_attr_remove_iter(
>>>>    	struct xfs_da_args      *args)
>>>>    {
>>>>    	struct xfs_inode	*dp = args->dp;
>>>>    	int			error;
>>>> +	/* State machine switch */
>>>> +	switch (args->dac.dela_state) {
>>>> +	case XFS_DAS_RM_SHRINK:
>>>> +	case XFS_DAS_RMTVAL_REMOVE:
>>>> +		goto node;
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>> +
>>>>    	if (!xfs_inode_hasattr(dp)) {
>>>>    		error = -ENOATTR;
>>>>    	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>>>>    	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>>    		error = xfs_attr_leaf_removename(args);
>>>>    	} else {
>>>> +node:
>>>>    		error = xfs_attr_node_removename(args);
>>>>    	}
>>>> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>>>>    		/* bp is gone due to xfs_da_shrink_inode */
>>>>    		if (error)
>>>>    			return error;
>>>> -		error = xfs_defer_finish(&args->trans);
>>>> -		if (error)
>>>> -			return error;
>>>> +
>>>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>>>    	}
>>>>    	return 0;
>>>>    }
>>>> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>>>>     * This will involve walking down the Btree, and may involve joining
>>>>     * leaf nodes and even joining intermediate nodes up to and including
>>>>     * the root node (a special case of an intermediate node).
>>>> + *
>>>> + * This routine is meant to function as either an inline or delayed operation,
>>>> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
>>>> + * functions will need to handle this, and recall the function until a
>>>> + * successful error code is returned.
>>>>     */
>>>>    STATIC int
>>>>    xfs_attr_node_removename(
>>>> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>>>>    	struct xfs_inode	*dp = args->dp;
>>>>    	trace_xfs_attr_node_removename(args);
>>>> +	state = args->dac.da_state;
>>>> +	blk = args->dac.blk;
>>>> +
>>>> +	/* State machine switch */
>>>> +	switch (args->dac.dela_state) {
>>>> +	case XFS_DAS_RMTVAL_REMOVE:
>>>> +		goto rm_node_blks;
>>>> +	case XFS_DAS_RM_SHRINK:
>>>> +		goto rm_shrink;
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>>    	error = xfs_attr_node_hasname(args, &state);
>>>>    	if (error != -EEXIST)
>>>>    		goto out;
>>>> +	else
>>>> +		error = 0;
>>>
>>> This doesn't look necessary.
>> Well, at this point error has to be -EEXIST.  Which is great because we need
>> the attr to exist, but we dont want to return that as error for this
>> function.  Which can happen if error is not otherwise set.
>>
> 
> AFAICT every codepath after this assigns error one way or another before
> it's returned. There's another error = 0 assignment just before the out:
> label.
Ok, I see it.  Will remove.

> 
>>>
>>>>    	/*
>>>>    	 * If there is an out-of-line value, de-allocate the blocks.
>>>> @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
>>>>    	blk = &state->path.blk[ state->path.active-1 ];
>>>>    	ASSERT(blk->bp != NULL);
>>>>    	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> +
>>>> +	/*
>>>> +	 * Store blk and state in the context incase we need to cycle out the
>>>> +	 * transaction
>>>> +	 */
>>>> +	args->dac.blk = blk;
>>>> +	args->dac.da_state = state;
>>>> +
>>>>    	if (args->rmtblkno > 0) {
>>>>    		/*
>>>>    		 * Fill in disk block numbers in the state structure
>>>> @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
>>>>    		if (error)
>>>>    			goto out;
>>>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>> +		error = xfs_attr_rmtval_invalidate(args);
>>>
>>> Remind me why we lose the above trans roll? I vaguely recall that this
>>> was intentional, but I could be mistaken...
>> I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE
>> state, but then we reasoned that because these are just in-core changes, we
>> didnt need it, so we eliminated this state entirely.
>>
>> Maybe i just add a comment here?  Just as a reminder
>>
> 
> Ah, Ok. Normally I'd say document things like this in the commit log so
> we don't lose track, though I don't know how much space we have there.
> ;)
Ok, I'll see if I can squeeze in a few more lines :-)

> 
>>>
>>>>    		if (error)
>>>>    			goto out;
>>>> +	}
>>>> -		error = xfs_attr_rmtval_remove(args);
>>>> -		if (error)
>>>> -			goto out;
>>>> +rm_node_blks:
>>>> +
>>>> +	if (args->rmtblkno > 0) {
>>>> +		error = xfs_attr_rmtval_unmap(args);
>>>> +
>>>> +		if (error) {
>>>> +			if (error == -EAGAIN)
>>>> +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
>>>
>>> Might be helpful for the code labels to match the state names. I.e., use
>>> das_rmtval_remove: for the label above.
>> Sure, I can update add the das prefix.
>>
>>>
>>>> +			return error;
>>>> +		}
>>>>    		/*
>>>>    		 * Refill the state structure with buffers, the prior calls
>>>> @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
>>>>    		error = xfs_da3_join(state);
>>>>    		if (error)
>>>>    			goto out;
>>>> -		error = xfs_defer_finish(&args->trans);
>>>> -		if (error)
>>>> -			goto out;
>>>> -		/*
>>>> -		 * Commit the Btree join operation and start a new trans.
>>>> -		 */
>>>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>>>> -		if (error)
>>>> -			goto out;
>>>> +
>>>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>>> +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
>>>> +		return -EAGAIN;
>>>>    	}
>>>> +rm_shrink:
>>>> +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
>>>> +
>>>
>>> There's an xfs_defer_finish() call further down this function. Should
>>> that be replaced with the flag?
>>>
>>> Finally, I mentioned in a previous review that this function should
>>> probably be further broken down before fitting in the state management
>>> stuff. It doesn't look like that happened so I've attached a diff that
>>> is just intended to give an idea of what I mean by sectioning off the
>>> hunks that might be able to break down into helpers. The helpers
>>> wouldn't contain any state management, so we create a clear separation
>>> between the state code and functional components.
>> Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch to
>> try and keep the activity in this one to a minimum.  Apologies if it
>> surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS
>> flag with it.  I meant to keep all the state machine stuff here.  Will fix!
>>
> 
> Ok, I might have just not got there yet.
> 
>> I think this initial
>>> refactoring would make the introduction of state much more simple
>>
>> I guess I didn't think people would be partial to introducing helpers before
>> or after the state logic.  I put them after in this set because the states
>> are visible now, so I though it would make the goal of modularizing code
>> between the states more clear to folks.  Do you think I should move it back
>> behind the state machine patches?
>>
> 
> I do think the refactoring should be done first. This does make it more
> challenging for the developer (IMO) because I know I'd probably have to
> hack around with the state bits to have a better idea of how to refactor
> things in some cases, and then go back and retrofit the refactoring.
> 
> The advantage is that the heavy lifting in this series becomes agnostic
> to the state bits. Refactoring patches are easier to review and we can
> make progress because there's less of a need to carry those out of tree
> through however many versions of the state code we'll need before
> getting it merged. Once the code is sufficiently factored, the state
> code should be much simpler to introduce and review since we hopefully
> won't be jumping around into the middle of functions, multiple branches
> of logic deep, etc.
> 
> (I see Dave commented similarly on a couple of the subsequent patches. I
> 100% agree with the approach he describes there and that is similar to
> what I was trying to describe with the diff I attached in my earlier
> mail...)
> 
> Brian

Alrighty then, will move back.  Thanks, and thanks again for the reviews!!

Allison

> 
>> (and
>>> perhaps alleviate the need for the huge diagram).
>> Well, I get the impression that people find the series sort of scary and
>> maybe the diagrams help them a bit.  Maybe we can take them out later after
>> people feel like they are comfortable with things?
>>
>> It might also be
>>> interesting to see how much of the result could be folded up further
>>> into _removename_iter()...
>>
>> Yes, I think that is the goal we're reaching for.  I will add the other
>> helpers I see in your diff too.
>>
>> Thanks for the reviews!
>> Allison
>>
>>>
>>> Brian
>>>
>>>>    	/*
>>>>    	 * If the result is small enough, push it all into the inode.
>>>>    	 */
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>> index ce7b039..ea873a5 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>>>    int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>>>    int xfs_has_attr(struct xfs_da_args *args);
>>>>    int xfs_attr_remove_args(struct xfs_da_args *args);
>>>> +int xfs_attr_remove_iter(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);
>>>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>>>> index 14f1be3..3c78498 100644
>>>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>>>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>>>> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>>>>    };
>>>>    /*
>>>> + * Enum values for xfs_delattr_context.da_state
>>>> + *
>>>> + * These values are used by delayed attribute operations to keep track  of where
>>>> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
>>>> + * calling function to roll the transaction, and then recall the subroutine to
>>>> + * finish the operation.  The enum is then used by the subroutine to jump back
>>>> + * to where it was and resume executing where it left off.
>>>> + */
>>>> +enum xfs_delattr_state {
>>>> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
>>>> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
>>>> +};
>>>> +
>>>> +/*
>>>> + * Defines for xfs_delattr_context.flags
>>>> + */
>>>> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
>>>> +
>>>> +/*
>>>> + * Context used for keeping track of delayed attribute operations
>>>> + */
>>>> +struct xfs_delattr_context {
>>>> +	struct xfs_da_state	*da_state;
>>>> +	struct xfs_da_state_blk *blk;
>>>> +	unsigned int		flags;
>>>> +	enum xfs_delattr_state	dela_state;
>>>> +};
>>>> +
>>>> +/*
>>>>     * Structure to ease passing around component names.
>>>>     */
>>>>    typedef struct xfs_da_args {
>>>> +	struct xfs_delattr_context dac; /* context used for delay attr ops */
>>>>    	struct xfs_da_geometry *geo;	/* da block geometry */
>>>>    	struct xfs_name	name;		/* name, length and argument  flags*/
>>>>    	uint8_t		filetype;	/* filetype of inode for directories */
>>>> 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 42ac847..d65e6d8 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 "xfs_error.h"
>>>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>>>> index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
>>>> -- 
>>>> 2.7.4
>>>>
>>>
>>
> 

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

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-26  3:29         ` Allison Collins
@ 2020-02-26 13:47           ` Brian Foster
  0 siblings, 0 replies; 135+ messages in thread
From: Brian Foster @ 2020-02-26 13:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Feb 25, 2020 at 08:29:06PM -0700, Allison Collins wrote:
> 
> 
> On 2/25/20 6:27 AM, Brian Foster wrote:
> > On Mon, Feb 24, 2020 at 02:44:14PM -0700, Allison Collins wrote:
> > > 
> > > 
> > > On 2/24/20 6:40 AM, Brian Foster wrote:
> > > > On Sat, Feb 22, 2020 at 07:06:04PM -0700, Allison Collins wrote:
> > > > > This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
> > > > > new transactions. We will use this later when we introduce delayed attributes
> > > > > 
> > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > ---
> > > > >    fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
> > > > >    fs/xfs/libxfs/xfs_attr_remote.h |  1 +
> > > > >    2 files changed, 29 insertions(+)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> > > > > index 3de2eec..da40f85 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr_remote.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> > > > > @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
> > > > >    	}
> > > > >    	return 0;
> > > > >    }
> > > > > +
> > > > > +/*
> > > > > + * Remove the value associated with an attribute by deleting the out-of-line
> > > > > + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
> > > > > + * transaction and recall the function
> > > > > + */
> > > > > +int
> > > > > +xfs_attr_rmtval_unmap(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	int	error, done;
> > > > > +
> > > > > +	/*
> > > > > +	 * Unmap value blocks for this attr.  This is similar to
> > > > > +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> > > > > +	 * for new transactions
> > > > > +	 */
> > > > > +	error = xfs_bunmapi(args->trans, args->dp,
> > > > > +		    args->rmtblkno, args->rmtblkcnt,
> > > > > +		    XFS_BMAPI_ATTRFORK, 1, &done);
> > > > > +	if (error)
> > > > > +		return error;
> > > > > +
> > > > > +	if (!done)
> > > > > +		return -EAGAIN;
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > 
> > > > Hmm.. any reason this isn't a refactor of the existing remove function?
> > > > Just skipping to the end of the series, I see we leave the reference to
> > > > xfs_attr_rmtval_remove() (which no longer exists and so is not very
> > > > useful) in this comment as well as a stale function declaration in
> > > > xfs_attr_remote.h.
> > > > 
> > > > I haven't grokked how this is used yet, but it seems like it would be
> > > > more appropriate to lift out the transaction handling from the original
> > > > function as we have throughout the rest of the code. That could also
> > > > mean creating a temporary wrapper (i.e., rmtval_remove() calls
> > > > rmtval_unmap()) for the loop/transaction code that could be removed
> > > > later if it ends up unused. Either way is much easier to follow than
> > > > creating a (currently unused) replacement..
> > > Yes, this came up in one of the other reviews.  I thought about it, but then
> > > decided against it.  xfs_attr_rmtval_remove disappears across patches 13 and
> > > 14.  The use of xfs_attr_rmtval_remove is replaced with
> > > xfs_attr_rmtval_unmap when we finally yank out all the transaction code.
> > > The reason I dont want to do it all at once is because that would mean
> > > patches 12, 13, 14 and 19 would lump together to make the swap instantaneous
> > > in once patch.
> > > 
> > 
> > Hmm.. I don't think we're talking about the same thing. If
> > xfs_attr_rmtval_remove() was broken down into two functions such that
> > one of the two looks exactly like the _unmap() variant, can't we just
> > remove the other half when it becomes unused and allow the _remove()
> > variant to exist with the implementation of _unmap() proposed here? This
> > seems fairly mechanical to me..
> Oh, I see what you mean.  No, I had done a review of the uses of
> xfs_attr_rmtval_remove and realized that it appears in both the set and
> remove paths. We use it in the set path when we're doing a rename, and need
> to remove the old attr.
> 
> So in patch 13, we replace xfs_attr_rmtval_remove with xfs_attr_rmtval_unmap
> for the remove routines.  But it's still in the set routines.  So we cant
> take it away yet.  Once we get through patch 14, it is no longer used and we
> can remove it.  Did that make sense?
> 

I don't think you need to take it away in this patch. What I'm
suggesting is breaking existing code into something like this:

int
__xfs_attr_rmtval_remove()
{
	...
	error = xfs_bunmapi(...);
	...

	if (!done)
		return -EAGAIN;

	...
}

int
xfs_attr_rmtval_remove()
{
	error = xfs_attr_rmtval_invalidate();

	do {
		error = __xfs_attr_rmtval_remove();
		...
		xfs_defer_finish();
		...
		xfs_trans_roll_inode(...);
	} while (-EAGAIN);

	...
}

So we can continue to use both as needed without duplication and remove
the bits that become unused as the series progresses. Eventually we
could rename __xfs_attr_rmtval_remove() back to xfs_attr_rmtval_remove()
to maintain that it's essentially the same function and only the
transaction rolling bits are being factored out and eventually removed.

Brian

> > 
> > > I've been getting feedback that the set is really complicated, so I've been
> > > trying to find a way to organize it to help make it easier to review.  So I
> > > thought isolating 13 and 14 to just the state machine would help.  Thus I
> > > decided to keep patch 12 separate to take as much craziness out of 13 and 14
> > > as possible.  Patches 12 and 19 seem like otherwise easy things for people
> > > to look at.  Let me know your thoughts on this. :-)
> > > 
> > 
> > I think doing as much refactoring of existing code as early as possible
> > will go a long way towards simplifying the complexity around the
> > introduction of the state bits.
> 
> Alrighty, I was thinking that if I reordered things such that modularizing
> appeared at the end of the set, that it would help people to see it in
> context with the states.  But it sounds like people like it the other way
> around, it's easy enough to put back.  Though I think we may still be stuck
> with 12 and 19 being apart unless 13 and 14 come together.  :-(
> 
> Allison
> 
> > 
> > Brian
> > 
> > > You are right about the stale comment though, I missed it while going back
> > > over the commentary at the top.  Will fix.
> > > 
> > > Allison
> > > 
> > > > 
> > > > Brian
> > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> > > > > index eff5f95..e06299a 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr_remote.h
> > > > > +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> > > > > @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> > > > >    int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
> > > > >    		xfs_buf_flags_t incore_flags);
> > > > >    int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
> > > > > +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
> > > > >    #endif /* __XFS_ATTR_REMOTE_H__ */
> > > > > -- 
> > > > > 2.7.4
> > > > > 
> > > > 
> > > 
> > 
> 


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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-26  5:36         ` Allison Collins
@ 2020-02-26 13:48           ` Brian Foster
  2020-02-26 19:23             ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Brian Foster @ 2020-02-26 13:48 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Feb 25, 2020 at 10:36:18PM -0700, Allison Collins wrote:
> 
> 
> On 2/25/20 6:34 AM, Brian Foster wrote:
> > On Mon, Feb 24, 2020 at 04:14:48PM -0700, Allison Collins wrote:
> > > On 2/24/20 8:25 AM, Brian Foster wrote:
> > > > On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> > > > > This patch modifies the attr remove routines to be delay ready. This means they no
> > > > > longer roll or commit transactions, but instead return -EAGAIN to have the calling
> > > > > routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> > > > > become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> > > > > track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> > > > > been modified to use the switch, and a  new version of xfs_attr_remove_args
> > > > > consists of a simple loop to refresh the transaction until the operation is
> > > > > completed.
> > > > > 
> > > > > This patch also adds a new struct xfs_delattr_context, which we will use to keep
> > > > > track of the current state of an attribute operation. The new xfs_delattr_state
> > > > > enum is used to track various operations that are in progress so that we know not
> > > > > to repeat them, and resume where we left off before EAGAIN was returned to cycle
> > > > > out the transaction. Other members take the place of local variables that need
> > > > > to retain their values across multiple function recalls.
> > > > > 
> > > > > Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> > > > > indicate places where the function would return -EAGAIN, and then immediately
> > > > > resume from after being recalled by the calling function.  States marked as a
> > > > > "subroutine state" indicate that they belong to a subroutine, and so the calling
> > > > > function needs to pass them back to that subroutine to allow it to finish where
> > > > > it left off. But they otherwise do not have a role in the calling function other
> > > > > than just passing through.
> > > > > 
> > > > >    xfs_attr_remove_iter()
> > > > >            XFS_DAS_RM_SHRINK     ─┐
> > > > >            (subroutine state)     │
> > > > >                                   │
> > > > >            XFS_DAS_RMTVAL_REMOVE ─┤
> > > > >            (subroutine state)     │
> > > > >                                   └─>xfs_attr_node_removename()
> > > > >                                                    │
> > > > >                                                    v
> > > > >                                            need to remove
> > > > >                                      ┌─n──  rmt blocks?
> > > > >                                      │             │
> > > > >                                      │             y
> > > > >                                      │             │
> > > > >                                      │             v
> > > > >                                      │  ┌─>XFS_DAS_RMTVAL_REMOVE
> > > > >                                      │  │          │
> > > > >                                      │  │          v
> > > > >                                      │  └──y── more blks
> > > > >                                      │         to remove?
> > > > >                                      │             │
> > > > >                                      │             n
> > > > >                                      │             │
> > > > >                                      │             v
> > > > >                                      │         need to
> > > > >                                      └─────> shrink tree? ─n─┐
> > > > >                                                    │         │
> > > > >                                                    y         │
> > > > >                                                    │         │
> > > > >                                                    v         │
> > > > >                                            XFS_DAS_RM_SHRINK │
> > > > >                                                    │         │
> > > > >                                                    v         │
> > > > >                                                   done <─────┘
> > > > > 
> > > > 
> > > > Wow. :P I guess I have nothing against verbose commit logs, but I wonder
> > > > how useful this level of documentation is for a patch that shouldn't
> > > > really change the existing flow of the operation.
> > > 
> > > Yes Darrick had requested a diagram in the last review, so I had put this
> > > together.  I wasnt sure where the best place to put it even was, so I put it
> > > here at least for now.  I have no idea if there is a limit on commit message
> > > length, but if there is, I'm pretty sure I blew right past it in this patch
> > > and the next.  Maybe if anything it can just be here for now while we work
> > > through things?
> > > 
> > 
> > No problem.. if it's useful it's good to have a record of out around
> > somewhere until the end result is more stabilized and we can determine
> > whether this warrants a permanent home somewhere in the code.
> > 
> > > > 
> > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > ---
> > > > >    fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
> > > > >    fs/xfs/libxfs/xfs_attr.h     |   1 +
> > > > >    fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
> > > > >    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 +
> > > > >    10 files changed, 141 insertions(+), 16 deletions(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > index 5d73bdf..cd3a3f7 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > > @@ -368,11 +368,60 @@ xfs_has_attr(
> > > > >     */
> > > > >    int
> > > > >    xfs_attr_remove_args(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	int			error = 0;
> > > > > +	int			err2 = 0;
> > > > > +
> > > > > +	do {
> > > > > +		error = xfs_attr_remove_iter(args);
> > > > > +		if (error && error != -EAGAIN)
> > > > > +			goto out;
> > > > > +
> > > > 
> > > > I'm a little confused on the logic of this loop given that the only
> > > > caller commits the transaction (which also finishes dfops). IOW, it
> > > > seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
> > > > that is the case, this can be simplified to something like:
> > > Well, we need to do it when error == -EAGAIN or 0, right? Which I think
> > > better imitates the defer_finish routines.  That's why a lot of the existing
> > > code that just finishes off with a transaction just sort of gets sawed off
> > > at the end. Otherwise they would need one more state just to return -EAGAIN
> > > as the last thing they have to do. Did that make sense?
> > > 
> > 
> > Hmm.. I could just be missing something or not far along enough in the
> > series. Can you point me at an example of where we need to finish/roll
> > before the caller of xfs_attr_remove_args() commits the transaction?
> > 
> Ok, in looking for an example, realized all such examples appear in the next
> patch ;-)  So maybe we can get away with simplifying it in this patch.
> 

Ah, Ok. Yeah, I think that would be best so long as it is correct, since
right now at least we have separate xfs_attr_[set|remove]_args() loop
functions and I didn't see any code that warranted the extra roll in the
remove path.

> For the next patch though, it's any place the roll/finish disappears, and an
> "return -EAGAIN" does not.  For example, at the end of
> xfs_attr_leaf_addname.
> 

I see, thanks. Hmmm... so I think that particular example is basically a
programming pattern thing moreso than a functional requirement. I.e.,
the current _clearflag() function clears the flag and rolls the
transaction perhaps simply so it can be reliably used in different
contexts. The use in the _addname() case is functionally spurious afaict
because we roll the transaction only to make no further changes and then
commit the final transaction in the higher level code.

I could see leaving the loop as is if this were the case for every exit
path back to xfs_attr_set_args(), but is that really the case? If not,
haven't we introduced a spurious roll for any zero return back to the
_args() function? I think it might be best to fix up the loop to not
roll on error == 0, explicitly plumb in the -EAGAIN in those spurious
cases like _addname() where we currently roll, and then come up with a
follow up patch to remove the ones that end up as spurious. That way
we're not conflating too much refactoring with functional change and can
review/document the functional change independently (i.e., if removing
one of those rolls ends up introducing a bug, we don't have to revert an
entire refactoring patch to restore original behavior).

Now that I think of it, the better option is probably to remove the
xfs_trans_roll_inode() call from _addname() first, before these patches
introduce the delay ready infrastructure, since it's already isolated as
spurious at that point. That should be a simple patch with a
clear/obvious explanation.

Brian

> > > > 
> > > > int
> > > > xfs_attr_remove_args(
> > > >           struct xfs_da_args      *args)
> > > > {
> > > >           int                     error;
> > > > 
> > > >           do {
> > > >                   error = xfs_attr_remove_iter(args);
> > > >                   if (error != -EAGAIN)
> > > >                           break;
> > > > 
> > > >                   if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> > > >                           args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> > > >                           error = xfs_defer_finish(&args->trans);
> > > >                           if (error)
> > > >                                   break;
> > > >                   }
> > > > 
> > > >                   error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > >                   if (error)
> > > >                           break;
> > > >           } while (true);
> > > > 
> > > >           return error;
> > > > }
> > > > 
> > > > That has the added benefit of eliminating the whole err2 pattern, which
> > > > always strikes me as a landmine.
> > > > 
> > > > > +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> > > > 
> > > > BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
> > > > operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
> > > Sure, will update
> > > 
> > > > 
> > > > > +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> > > > > +
> > > > > +			err2 = xfs_defer_finish(&args->trans);
> > > > > +			if (err2) {
> > > > > +				error = err2;
> > > > > +				goto out;
> > > > > +			}
> > > > > +		}
> > > > > +
> > > > > +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> > > > > +		if (err2) {
> > > > > +			error = err2;
> > > > > +			goto out;
> > > > > +		}
> > > > > +
> > > > > +	} while (error == -EAGAIN);
> > > > > +out:
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +/*
> > > > > + * Remove the attribute specified in @args.
> > > > > + *
> > > > > + * This function may return -EAGAIN to signal that the transaction needs to be
> > > > > + * rolled.  Callers should continue calling this function until they receive a
> > > > > + * return value other than -EAGAIN.
> > > > > + */
> > > > > +int
> > > > > +xfs_attr_remove_iter(
> > > > >    	struct xfs_da_args      *args)
> > > > >    {
> > > > >    	struct xfs_inode	*dp = args->dp;
> > > > >    	int			error;
> > > > > +	/* State machine switch */
> > > > > +	switch (args->dac.dela_state) {
> > > > > +	case XFS_DAS_RM_SHRINK:
> > > > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > > > +		goto node;
> > > > > +	default:
> > > > > +		break;
> > > > > +	}
> > > > > +
> > > > >    	if (!xfs_inode_hasattr(dp)) {
> > > > >    		error = -ENOATTR;
> > > > >    	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > > > > @@ -381,6 +430,7 @@ xfs_attr_remove_args(
> > > > >    	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > > >    		error = xfs_attr_leaf_removename(args);
> > > > >    	} else {
> > > > > +node:
> > > > >    		error = xfs_attr_node_removename(args);
> > > > >    	}
> > > > > @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
> > > > >    		/* bp is gone due to xfs_da_shrink_inode */
> > > > >    		if (error)
> > > > >    			return error;
> > > > > -		error = xfs_defer_finish(&args->trans);
> > > > > -		if (error)
> > > > > -			return error;
> > > > > +
> > > > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > > > >    	}
> > > > >    	return 0;
> > > > >    }
> > > > > @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
> > > > >     * This will involve walking down the Btree, and may involve joining
> > > > >     * leaf nodes and even joining intermediate nodes up to and including
> > > > >     * the root node (a special case of an intermediate node).
> > > > > + *
> > > > > + * This routine is meant to function as either an inline or delayed operation,
> > > > > + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
> > > > > + * functions will need to handle this, and recall the function until a
> > > > > + * successful error code is returned.
> > > > >     */
> > > > >    STATIC int
> > > > >    xfs_attr_node_removename(
> > > > > @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
> > > > >    	struct xfs_inode	*dp = args->dp;
> > > > >    	trace_xfs_attr_node_removename(args);
> > > > > +	state = args->dac.da_state;
> > > > > +	blk = args->dac.blk;
> > > > > +
> > > > > +	/* State machine switch */
> > > > > +	switch (args->dac.dela_state) {
> > > > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > > > +		goto rm_node_blks;
> > > > > +	case XFS_DAS_RM_SHRINK:
> > > > > +		goto rm_shrink;
> > > > > +	default:
> > > > > +		break;
> > > > > +	}
> > > > >    	error = xfs_attr_node_hasname(args, &state);
> > > > >    	if (error != -EEXIST)
> > > > >    		goto out;
> > > > > +	else
> > > > > +		error = 0;
> > > > 
> > > > This doesn't look necessary.
> > > Well, at this point error has to be -EEXIST.  Which is great because we need
> > > the attr to exist, but we dont want to return that as error for this
> > > function.  Which can happen if error is not otherwise set.
> > > 
> > 
> > AFAICT every codepath after this assigns error one way or another before
> > it's returned. There's another error = 0 assignment just before the out:
> > label.
> Ok, I see it.  Will remove.
> 
> > 
> > > > 
> > > > >    	/*
> > > > >    	 * If there is an out-of-line value, de-allocate the blocks.
> > > > > @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
> > > > >    	blk = &state->path.blk[ state->path.active-1 ];
> > > > >    	ASSERT(blk->bp != NULL);
> > > > >    	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > +
> > > > > +	/*
> > > > > +	 * Store blk and state in the context incase we need to cycle out the
> > > > > +	 * transaction
> > > > > +	 */
> > > > > +	args->dac.blk = blk;
> > > > > +	args->dac.da_state = state;
> > > > > +
> > > > >    	if (args->rmtblkno > 0) {
> > > > >    		/*
> > > > >    		 * Fill in disk block numbers in the state structure
> > > > > @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > > > +		error = xfs_attr_rmtval_invalidate(args);
> > > > 
> > > > Remind me why we lose the above trans roll? I vaguely recall that this
> > > > was intentional, but I could be mistaken...
> > > I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE
> > > state, but then we reasoned that because these are just in-core changes, we
> > > didnt need it, so we eliminated this state entirely.
> > > 
> > > Maybe i just add a comment here?  Just as a reminder
> > > 
> > 
> > Ah, Ok. Normally I'd say document things like this in the commit log so
> > we don't lose track, though I don't know how much space we have there.
> > ;)
> Ok, I'll see if I can squeeze in a few more lines :-)
> 
> > 
> > > > 
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > +	}
> > > > > -		error = xfs_attr_rmtval_remove(args);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > +rm_node_blks:
> > > > > +
> > > > > +	if (args->rmtblkno > 0) {
> > > > > +		error = xfs_attr_rmtval_unmap(args);
> > > > > +
> > > > > +		if (error) {
> > > > > +			if (error == -EAGAIN)
> > > > > +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
> > > > 
> > > > Might be helpful for the code labels to match the state names. I.e., use
> > > > das_rmtval_remove: for the label above.
> > > Sure, I can update add the das prefix.
> > > 
> > > > 
> > > > > +			return error;
> > > > > +		}
> > > > >    		/*
> > > > >    		 * Refill the state structure with buffers, the prior calls
> > > > > @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
> > > > >    		error = xfs_da3_join(state);
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > -		error = xfs_defer_finish(&args->trans);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > -		/*
> > > > > -		 * Commit the Btree join operation and start a new trans.
> > > > > -		 */
> > > > > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > +
> > > > > +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> > > > > +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > > > +		return -EAGAIN;
> > > > >    	}
> > > > > +rm_shrink:
> > > > > +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
> > > > > +
> > > > 
> > > > There's an xfs_defer_finish() call further down this function. Should
> > > > that be replaced with the flag?
> > > > 
> > > > Finally, I mentioned in a previous review that this function should
> > > > probably be further broken down before fitting in the state management
> > > > stuff. It doesn't look like that happened so I've attached a diff that
> > > > is just intended to give an idea of what I mean by sectioning off the
> > > > hunks that might be able to break down into helpers. The helpers
> > > > wouldn't contain any state management, so we create a clear separation
> > > > between the state code and functional components.
> > > Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch to
> > > try and keep the activity in this one to a minimum.  Apologies if it
> > > surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS
> > > flag with it.  I meant to keep all the state machine stuff here.  Will fix!
> > > 
> > 
> > Ok, I might have just not got there yet.
> > 
> > > I think this initial
> > > > refactoring would make the introduction of state much more simple
> > > 
> > > I guess I didn't think people would be partial to introducing helpers before
> > > or after the state logic.  I put them after in this set because the states
> > > are visible now, so I though it would make the goal of modularizing code
> > > between the states more clear to folks.  Do you think I should move it back
> > > behind the state machine patches?
> > > 
> > 
> > I do think the refactoring should be done first. This does make it more
> > challenging for the developer (IMO) because I know I'd probably have to
> > hack around with the state bits to have a better idea of how to refactor
> > things in some cases, and then go back and retrofit the refactoring.
> > 
> > The advantage is that the heavy lifting in this series becomes agnostic
> > to the state bits. Refactoring patches are easier to review and we can
> > make progress because there's less of a need to carry those out of tree
> > through however many versions of the state code we'll need before
> > getting it merged. Once the code is sufficiently factored, the state
> > code should be much simpler to introduce and review since we hopefully
> > won't be jumping around into the middle of functions, multiple branches
> > of logic deep, etc.
> > 
> > (I see Dave commented similarly on a couple of the subsequent patches. I
> > 100% agree with the approach he describes there and that is similar to
> > what I was trying to describe with the diff I attached in my earlier
> > mail...)
> > 
> > Brian
> 
> Alrighty then, will move back.  Thanks, and thanks again for the reviews!!
> 
> Allison
> 
> > 
> > > (and
> > > > perhaps alleviate the need for the huge diagram).
> > > Well, I get the impression that people find the series sort of scary and
> > > maybe the diagrams help them a bit.  Maybe we can take them out later after
> > > people feel like they are comfortable with things?
> > > 
> > > It might also be
> > > > interesting to see how much of the result could be folded up further
> > > > into _removename_iter()...
> > > 
> > > Yes, I think that is the goal we're reaching for.  I will add the other
> > > helpers I see in your diff too.
> > > 
> > > Thanks for the reviews!
> > > Allison
> > > 
> > > > 
> > > > Brian
> > > > 
> > > > >    	/*
> > > > >    	 * If the result is small enough, push it all into the inode.
> > > > >    	 */
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > index ce7b039..ea873a5 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > > > @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> > > > >    int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> > > > >    int xfs_has_attr(struct xfs_da_args *args);
> > > > >    int xfs_attr_remove_args(struct xfs_da_args *args);
> > > > > +int xfs_attr_remove_iter(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);
> > > > > diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> > > > > index 14f1be3..3c78498 100644
> > > > > --- a/fs/xfs/libxfs/xfs_da_btree.h
> > > > > +++ b/fs/xfs/libxfs/xfs_da_btree.h
> > > > > @@ -50,9 +50,39 @@ enum xfs_dacmp {
> > > > >    };
> > > > >    /*
> > > > > + * Enum values for xfs_delattr_context.da_state
> > > > > + *
> > > > > + * These values are used by delayed attribute operations to keep track  of where
> > > > > + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
> > > > > + * calling function to roll the transaction, and then recall the subroutine to
> > > > > + * finish the operation.  The enum is then used by the subroutine to jump back
> > > > > + * to where it was and resume executing where it left off.
> > > > > + */
> > > > > +enum xfs_delattr_state {
> > > > > +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
> > > > > +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
> > > > > +};
> > > > > +
> > > > > +/*
> > > > > + * Defines for xfs_delattr_context.flags
> > > > > + */
> > > > > +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
> > > > > +
> > > > > +/*
> > > > > + * Context used for keeping track of delayed attribute operations
> > > > > + */
> > > > > +struct xfs_delattr_context {
> > > > > +	struct xfs_da_state	*da_state;
> > > > > +	struct xfs_da_state_blk *blk;
> > > > > +	unsigned int		flags;
> > > > > +	enum xfs_delattr_state	dela_state;
> > > > > +};
> > > > > +
> > > > > +/*
> > > > >     * Structure to ease passing around component names.
> > > > >     */
> > > > >    typedef struct xfs_da_args {
> > > > > +	struct xfs_delattr_context dac; /* context used for delay attr ops */
> > > > >    	struct xfs_da_geometry *geo;	/* da block geometry */
> > > > >    	struct xfs_name	name;		/* name, length and argument  flags*/
> > > > >    	uint8_t		filetype;	/* filetype of inode for directories */
> > > > > 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 42ac847..d65e6d8 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 "xfs_error.h"
> > > > > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> > > > > index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
> > > > > -- 
> > > > > 2.7.4
> > > > > 
> > > > 
> > > 
> > 
> 


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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-26 13:48           ` Brian Foster
@ 2020-02-26 19:23             ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-26 19:23 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 2/26/20 6:48 AM, Brian Foster wrote:
> On Tue, Feb 25, 2020 at 10:36:18PM -0700, Allison Collins wrote:
>>
>>
>> On 2/25/20 6:34 AM, Brian Foster wrote:
>>> On Mon, Feb 24, 2020 at 04:14:48PM -0700, Allison Collins wrote:
>>>> On 2/24/20 8:25 AM, Brian Foster wrote:
>>>>> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
>>>>>> This patch modifies the attr remove routines to be delay ready. This means they no
>>>>>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>>>>>> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
>>>>>> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
>>>>>> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
>>>>>> been modified to use the switch, and a  new version of xfs_attr_remove_args
>>>>>> consists of a simple loop to refresh the transaction until the operation is
>>>>>> completed.
>>>>>>
>>>>>> This patch also adds a new struct xfs_delattr_context, which we will use to keep
>>>>>> track of the current state of an attribute operation. The new xfs_delattr_state
>>>>>> enum is used to track various operations that are in progress so that we know not
>>>>>> to repeat them, and resume where we left off before EAGAIN was returned to cycle
>>>>>> out the transaction. Other members take the place of local variables that need
>>>>>> to retain their values across multiple function recalls.
>>>>>>
>>>>>> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
>>>>>> indicate places where the function would return -EAGAIN, and then immediately
>>>>>> resume from after being recalled by the calling function.  States marked as a
>>>>>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>>>>>> function needs to pass them back to that subroutine to allow it to finish where
>>>>>> it left off. But they otherwise do not have a role in the calling function other
>>>>>> than just passing through.
>>>>>>
>>>>>>     xfs_attr_remove_iter()
>>>>>>             XFS_DAS_RM_SHRINK     ─┐
>>>>>>             (subroutine state)     │
>>>>>>                                    │
>>>>>>             XFS_DAS_RMTVAL_REMOVE ─┤
>>>>>>             (subroutine state)     │
>>>>>>                                    └─>xfs_attr_node_removename()
>>>>>>                                                     │
>>>>>>                                                     v
>>>>>>                                             need to remove
>>>>>>                                       ┌─n──  rmt blocks?
>>>>>>                                       │             │
>>>>>>                                       │             y
>>>>>>                                       │             │
>>>>>>                                       │             v
>>>>>>                                       │  ┌─>XFS_DAS_RMTVAL_REMOVE
>>>>>>                                       │  │          │
>>>>>>                                       │  │          v
>>>>>>                                       │  └──y── more blks
>>>>>>                                       │         to remove?
>>>>>>                                       │             │
>>>>>>                                       │             n
>>>>>>                                       │             │
>>>>>>                                       │             v
>>>>>>                                       │         need to
>>>>>>                                       └─────> shrink tree? ─n─┐
>>>>>>                                                     │         │
>>>>>>                                                     y         │
>>>>>>                                                     │         │
>>>>>>                                                     v         │
>>>>>>                                             XFS_DAS_RM_SHRINK │
>>>>>>                                                     │         │
>>>>>>                                                     v         │
>>>>>>                                                    done <─────┘
>>>>>>
>>>>>
>>>>> Wow. :P I guess I have nothing against verbose commit logs, but I wonder
>>>>> how useful this level of documentation is for a patch that shouldn't
>>>>> really change the existing flow of the operation.
>>>>
>>>> Yes Darrick had requested a diagram in the last review, so I had put this
>>>> together.  I wasnt sure where the best place to put it even was, so I put it
>>>> here at least for now.  I have no idea if there is a limit on commit message
>>>> length, but if there is, I'm pretty sure I blew right past it in this patch
>>>> and the next.  Maybe if anything it can just be here for now while we work
>>>> through things?
>>>>
>>>
>>> No problem.. if it's useful it's good to have a record of out around
>>> somewhere until the end result is more stabilized and we can determine
>>> whether this warrants a permanent home somewhere in the code.
>>>
>>>>>
>>>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>>>> ---
>>>>>>     fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>>>>>>     fs/xfs/libxfs/xfs_attr.h     |   1 +
>>>>>>     fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>>>>>>     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 +
>>>>>>     10 files changed, 141 insertions(+), 16 deletions(-)
>>>>>>
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>>>> index 5d73bdf..cd3a3f7 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>>>> @@ -368,11 +368,60 @@ xfs_has_attr(
>>>>>>      */
>>>>>>     int
>>>>>>     xfs_attr_remove_args(
>>>>>> +	struct xfs_da_args	*args)
>>>>>> +{
>>>>>> +	int			error = 0;
>>>>>> +	int			err2 = 0;
>>>>>> +
>>>>>> +	do {
>>>>>> +		error = xfs_attr_remove_iter(args);
>>>>>> +		if (error && error != -EAGAIN)
>>>>>> +			goto out;
>>>>>> +
>>>>>
>>>>> I'm a little confused on the logic of this loop given that the only
>>>>> caller commits the transaction (which also finishes dfops). IOW, it
>>>>> seems we shouldn't ever need to finish/roll when error != -EAGAIN. If
>>>>> that is the case, this can be simplified to something like:
>>>> Well, we need to do it when error == -EAGAIN or 0, right? Which I think
>>>> better imitates the defer_finish routines.  That's why a lot of the existing
>>>> code that just finishes off with a transaction just sort of gets sawed off
>>>> at the end. Otherwise they would need one more state just to return -EAGAIN
>>>> as the last thing they have to do. Did that make sense?
>>>>
>>>
>>> Hmm.. I could just be missing something or not far along enough in the
>>> series. Can you point me at an example of where we need to finish/roll
>>> before the caller of xfs_attr_remove_args() commits the transaction?
>>>
>> Ok, in looking for an example, realized all such examples appear in the next
>> patch ;-)  So maybe we can get away with simplifying it in this patch.
>>
> 
> Ah, Ok. Yeah, I think that would be best so long as it is correct, since
> right now at least we have separate xfs_attr_[set|remove]_args() loop
> functions and I didn't see any code that warranted the extra roll in the
> remove path.
> 
>> For the next patch though, it's any place the roll/finish disappears, and an
>> "return -EAGAIN" does not.  For example, at the end of
>> xfs_attr_leaf_addname.
>>
> 
> I see, thanks. Hmmm... so I think that particular example is basically a
> programming pattern thing moreso than a functional requirement. I.e.,
> the current _clearflag() function clears the flag and rolls the
> transaction perhaps simply so it can be reliably used in different
> contexts. The use in the _addname() case is functionally spurious afaict
> because we roll the transaction only to make no further changes and then
> commit the final transaction in the higher level code.
> 
> I could see leaving the loop as is if this were the case for every exit
> path back to xfs_attr_set_args(), but is that really the case? If not,
> haven't we introduced a spurious roll for any zero return back to the
> _args() function? I think it might be best to fix up the loop to not
> roll on error == 0, explicitly plumb in the -EAGAIN in those spurious
> cases like _addname() where we currently roll, and then come up with a
> follow up patch to remove the ones that end up as spurious. That way
> we're not conflating too much refactoring with functional change and can
> review/document the functional change independently (i.e., if removing
> one of those rolls ends up introducing a bug, we don't have to revert an
> entire refactoring patch to restore original behavior).
> 
> Now that I think of it, the better option is probably to remove the
> xfs_trans_roll_inode() call from _addname() first, before these patches
> introduce the delay ready infrastructure, since it's already isolated as
> spurious at that point. That should be a simple patch with a
> clear/obvious explanation.
Alrighty then, got it.  I will add these suggestions into the next 
version.  Thanks again for all the reviews!

Allison

> 
> Brian
> 
>>>>>
>>>>> int
>>>>> xfs_attr_remove_args(
>>>>>            struct xfs_da_args      *args)
>>>>> {
>>>>>            int                     error;
>>>>>
>>>>>            do {
>>>>>                    error = xfs_attr_remove_iter(args);
>>>>>                    if (error != -EAGAIN)
>>>>>                            break;
>>>>>
>>>>>                    if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>>>>>                            args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>>>>>                            error = xfs_defer_finish(&args->trans);
>>>>>                            if (error)
>>>>>                                    break;
>>>>>                    }
>>>>>
>>>>>                    error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>                    if (error)
>>>>>                            break;
>>>>>            } while (true);
>>>>>
>>>>>            return error;
>>>>> }
>>>>>
>>>>> That has the added benefit of eliminating the whole err2 pattern, which
>>>>> always strikes me as a landmine.
>>>>>
>>>>>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>>>>>
>>>>> BTW, _FINISH_TRANS also seems misnamed given that we finish deferred
>>>>> operations, not necessarily the transaction. XFS_DAC_DEFER_FINISH?
>>>> Sure, will update
>>>>
>>>>>
>>>>>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>>>>>> +
>>>>>> +			err2 = xfs_defer_finish(&args->trans);
>>>>>> +			if (err2) {
>>>>>> +				error = err2;
>>>>>> +				goto out;
>>>>>> +			}
>>>>>> +		}
>>>>>> +
>>>>>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>> +		if (err2) {
>>>>>> +			error = err2;
>>>>>> +			goto out;
>>>>>> +		}
>>>>>> +
>>>>>> +	} while (error == -EAGAIN);
>>>>>> +out:
>>>>>> +	return error;
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Remove the attribute specified in @args.
>>>>>> + *
>>>>>> + * This function may return -EAGAIN to signal that the transaction needs to be
>>>>>> + * rolled.  Callers should continue calling this function until they receive a
>>>>>> + * return value other than -EAGAIN.
>>>>>> + */
>>>>>> +int
>>>>>> +xfs_attr_remove_iter(
>>>>>>     	struct xfs_da_args      *args)
>>>>>>     {
>>>>>>     	struct xfs_inode	*dp = args->dp;
>>>>>>     	int			error;
>>>>>> +	/* State machine switch */
>>>>>> +	switch (args->dac.dela_state) {
>>>>>> +	case XFS_DAS_RM_SHRINK:
>>>>>> +	case XFS_DAS_RMTVAL_REMOVE:
>>>>>> +		goto node;
>>>>>> +	default:
>>>>>> +		break;
>>>>>> +	}
>>>>>> +
>>>>>>     	if (!xfs_inode_hasattr(dp)) {
>>>>>>     		error = -ENOATTR;
>>>>>>     	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>>>> @@ -381,6 +430,7 @@ xfs_attr_remove_args(
>>>>>>     	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>>>>     		error = xfs_attr_leaf_removename(args);
>>>>>>     	} else {
>>>>>> +node:
>>>>>>     		error = xfs_attr_node_removename(args);
>>>>>>     	}
>>>>>> @@ -895,9 +945,8 @@ xfs_attr_leaf_removename(
>>>>>>     		/* bp is gone due to xfs_da_shrink_inode */
>>>>>>     		if (error)
>>>>>>     			return error;
>>>>>> -		error = xfs_defer_finish(&args->trans);
>>>>>> -		if (error)
>>>>>> -			return error;
>>>>>> +
>>>>>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>>>>>     	}
>>>>>>     	return 0;
>>>>>>     }
>>>>>> @@ -1218,6 +1267,11 @@ xfs_attr_node_addname(
>>>>>>      * This will involve walking down the Btree, and may involve joining
>>>>>>      * leaf nodes and even joining intermediate nodes up to and including
>>>>>>      * the root node (a special case of an intermediate node).
>>>>>> + *
>>>>>> + * This routine is meant to function as either an inline or delayed operation,
>>>>>> + * and may return -EAGAIN when the transaction needs to be rolled.  Calling
>>>>>> + * functions will need to handle this, and recall the function until a
>>>>>> + * successful error code is returned.
>>>>>>      */
>>>>>>     STATIC int
>>>>>>     xfs_attr_node_removename(
>>>>>> @@ -1230,10 +1284,24 @@ xfs_attr_node_removename(
>>>>>>     	struct xfs_inode	*dp = args->dp;
>>>>>>     	trace_xfs_attr_node_removename(args);
>>>>>> +	state = args->dac.da_state;
>>>>>> +	blk = args->dac.blk;
>>>>>> +
>>>>>> +	/* State machine switch */
>>>>>> +	switch (args->dac.dela_state) {
>>>>>> +	case XFS_DAS_RMTVAL_REMOVE:
>>>>>> +		goto rm_node_blks;
>>>>>> +	case XFS_DAS_RM_SHRINK:
>>>>>> +		goto rm_shrink;
>>>>>> +	default:
>>>>>> +		break;
>>>>>> +	}
>>>>>>     	error = xfs_attr_node_hasname(args, &state);
>>>>>>     	if (error != -EEXIST)
>>>>>>     		goto out;
>>>>>> +	else
>>>>>> +		error = 0;
>>>>>
>>>>> This doesn't look necessary.
>>>> Well, at this point error has to be -EEXIST.  Which is great because we need
>>>> the attr to exist, but we dont want to return that as error for this
>>>> function.  Which can happen if error is not otherwise set.
>>>>
>>>
>>> AFAICT every codepath after this assigns error one way or another before
>>> it's returned. There's another error = 0 assignment just before the out:
>>> label.
>> Ok, I see it.  Will remove.
>>
>>>
>>>>>
>>>>>>     	/*
>>>>>>     	 * If there is an out-of-line value, de-allocate the blocks.
>>>>>> @@ -1243,6 +1311,14 @@ xfs_attr_node_removename(
>>>>>>     	blk = &state->path.blk[ state->path.active-1 ];
>>>>>>     	ASSERT(blk->bp != NULL);
>>>>>>     	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Store blk and state in the context incase we need to cycle out the
>>>>>> +	 * transaction
>>>>>> +	 */
>>>>>> +	args->dac.blk = blk;
>>>>>> +	args->dac.da_state = state;
>>>>>> +
>>>>>>     	if (args->rmtblkno > 0) {
>>>>>>     		/*
>>>>>>     		 * Fill in disk block numbers in the state structure
>>>>>> @@ -1261,13 +1337,21 @@ xfs_attr_node_removename(
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>> +		error = xfs_attr_rmtval_invalidate(args);
>>>>>
>>>>> Remind me why we lose the above trans roll? I vaguely recall that this
>>>>> was intentional, but I could be mistaken...
>>>> I think we removed it in v5.  We used to have a  XFS_DAS_RM_INVALIDATE
>>>> state, but then we reasoned that because these are just in-core changes, we
>>>> didnt need it, so we eliminated this state entirely.
>>>>
>>>> Maybe i just add a comment here?  Just as a reminder
>>>>
>>>
>>> Ah, Ok. Normally I'd say document things like this in the commit log so
>>> we don't lose track, though I don't know how much space we have there.
>>> ;)
>> Ok, I'll see if I can squeeze in a few more lines :-)
>>
>>>
>>>>>
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> +	}
>>>>>> -		error = xfs_attr_rmtval_remove(args);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> +rm_node_blks:
>>>>>> +
>>>>>> +	if (args->rmtblkno > 0) {
>>>>>> +		error = xfs_attr_rmtval_unmap(args);
>>>>>> +
>>>>>> +		if (error) {
>>>>>> +			if (error == -EAGAIN)
>>>>>> +				args->dac.dela_state = XFS_DAS_RMTVAL_REMOVE;
>>>>>
>>>>> Might be helpful for the code labels to match the state names. I.e., use
>>>>> das_rmtval_remove: for the label above.
>>>> Sure, I can update add the das prefix.
>>>>
>>>>>
>>>>>> +			return error;
>>>>>> +		}
>>>>>>     		/*
>>>>>>     		 * Refill the state structure with buffers, the prior calls
>>>>>> @@ -1293,17 +1377,15 @@ xfs_attr_node_removename(
>>>>>>     		error = xfs_da3_join(state);
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> -		error = xfs_defer_finish(&args->trans);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> -		/*
>>>>>> -		 * Commit the Btree join operation and start a new trans.
>>>>>> -		 */
>>>>>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> +
>>>>>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>>>>>> +		args->dac.dela_state = XFS_DAS_RM_SHRINK;
>>>>>> +		return -EAGAIN;
>>>>>>     	}
>>>>>> +rm_shrink:
>>>>>> +	args->dac.dela_state = XFS_DAS_RM_SHRINK;
>>>>>> +
>>>>>
>>>>> There's an xfs_defer_finish() call further down this function. Should
>>>>> that be replaced with the flag?
>>>>>
>>>>> Finally, I mentioned in a previous review that this function should
>>>>> probably be further broken down before fitting in the state management
>>>>> stuff. It doesn't look like that happened so I've attached a diff that
>>>>> is just intended to give an idea of what I mean by sectioning off the
>>>>> hunks that might be able to break down into helpers. The helpers
>>>>> wouldn't contain any state management, so we create a clear separation
>>>>> between the state code and functional components.
>>>> Yes, it's xfs_attr_node_shrink in patch 15.  I moved it to another patch to
>>>> try and keep the activity in this one to a minimum.  Apologies if it
>>>> surprised you!  And then i mistakenly had taken the XFS_DAC_FINISH_TRANS
>>>> flag with it.  I meant to keep all the state machine stuff here.  Will fix!
>>>>
>>>
>>> Ok, I might have just not got there yet.
>>>
>>>> I think this initial
>>>>> refactoring would make the introduction of state much more simple
>>>>
>>>> I guess I didn't think people would be partial to introducing helpers before
>>>> or after the state logic.  I put them after in this set because the states
>>>> are visible now, so I though it would make the goal of modularizing code
>>>> between the states more clear to folks.  Do you think I should move it back
>>>> behind the state machine patches?
>>>>
>>>
>>> I do think the refactoring should be done first. This does make it more
>>> challenging for the developer (IMO) because I know I'd probably have to
>>> hack around with the state bits to have a better idea of how to refactor
>>> things in some cases, and then go back and retrofit the refactoring.
>>>
>>> The advantage is that the heavy lifting in this series becomes agnostic
>>> to the state bits. Refactoring patches are easier to review and we can
>>> make progress because there's less of a need to carry those out of tree
>>> through however many versions of the state code we'll need before
>>> getting it merged. Once the code is sufficiently factored, the state
>>> code should be much simpler to introduce and review since we hopefully
>>> won't be jumping around into the middle of functions, multiple branches
>>> of logic deep, etc.
>>>
>>> (I see Dave commented similarly on a couple of the subsequent patches. I
>>> 100% agree with the approach he describes there and that is similar to
>>> what I was trying to describe with the diff I attached in my earlier
>>> mail...)
>>>
>>> Brian
>>
>> Alrighty then, will move back.  Thanks, and thanks again for the reviews!!
>>
>> Allison
>>
>>>
>>>> (and
>>>>> perhaps alleviate the need for the huge diagram).
>>>> Well, I get the impression that people find the series sort of scary and
>>>> maybe the diagrams help them a bit.  Maybe we can take them out later after
>>>> people feel like they are comfortable with things?
>>>>
>>>> It might also be
>>>>> interesting to see how much of the result could be folded up further
>>>>> into _removename_iter()...
>>>>
>>>> Yes, I think that is the goal we're reaching for.  I will add the other
>>>> helpers I see in your diff too.
>>>>
>>>> Thanks for the reviews!
>>>> Allison
>>>>
>>>>>
>>>>> Brian
>>>>>
>>>>>>     	/*
>>>>>>     	 * If the result is small enough, push it all into the inode.
>>>>>>     	 */
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>>>> index ce7b039..ea873a5 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>>>> @@ -155,6 +155,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>>>>>     int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>>>>>     int xfs_has_attr(struct xfs_da_args *args);
>>>>>>     int xfs_attr_remove_args(struct xfs_da_args *args);
>>>>>> +int xfs_attr_remove_iter(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);
>>>>>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>>>>>> index 14f1be3..3c78498 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>>>>>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>>>>>> @@ -50,9 +50,39 @@ enum xfs_dacmp {
>>>>>>     };
>>>>>>     /*
>>>>>> + * Enum values for xfs_delattr_context.da_state
>>>>>> + *
>>>>>> + * These values are used by delayed attribute operations to keep track  of where
>>>>>> + * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
>>>>>> + * calling function to roll the transaction, and then recall the subroutine to
>>>>>> + * finish the operation.  The enum is then used by the subroutine to jump back
>>>>>> + * to where it was and resume executing where it left off.
>>>>>> + */
>>>>>> +enum xfs_delattr_state {
>>>>>> +	XFS_DAS_RM_SHRINK,	/* We are shrinking the tree */
>>>>>> +	XFS_DAS_RMTVAL_REMOVE,	/* We are removing remote value blocks */
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * Defines for xfs_delattr_context.flags
>>>>>> + */
>>>>>> +#define	XFS_DAC_FINISH_TRANS	0x1 /* indicates to finish the transaction */
>>>>>> +
>>>>>> +/*
>>>>>> + * Context used for keeping track of delayed attribute operations
>>>>>> + */
>>>>>> +struct xfs_delattr_context {
>>>>>> +	struct xfs_da_state	*da_state;
>>>>>> +	struct xfs_da_state_blk *blk;
>>>>>> +	unsigned int		flags;
>>>>>> +	enum xfs_delattr_state	dela_state;
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>>      * Structure to ease passing around component names.
>>>>>>      */
>>>>>>     typedef struct xfs_da_args {
>>>>>> +	struct xfs_delattr_context dac; /* context used for delay attr ops */
>>>>>>     	struct xfs_da_geometry *geo;	/* da block geometry */
>>>>>>     	struct xfs_name	name;		/* name, length and argument  flags*/
>>>>>>     	uint8_t		filetype;	/* filetype of inode for directories */
>>>>>> 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 42ac847..d65e6d8 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 "xfs_error.h"
>>>>>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>>>>>> index d37743b..881b9a4 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 28c07c9..7c1d9da 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 769581a..d504f8f 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 e85bbf5..a2d299f 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 74133a5..d8dc72d 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 "xfs_acl.h"
>>>>>> -- 
>>>>>> 2.7.4
>>>>>>
>>>>>
>>>>
>>>
>>
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-26  0:57     ` Allison Collins
@ 2020-02-26 22:34       ` Dave Chinner
  2020-02-27  4:18         ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Dave Chinner @ 2020-02-26 22:34 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Feb 25, 2020 at 04:57:46PM -0800, Allison Collins wrote:
> On 2/25/20 1:57 AM, Dave Chinner wrote:
> > On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
> > > +out:
> > > +	return error;
> > > +}
> > 
> > Brian commented on the structure of this loop better than I could.
> > 
> > > +
> > > +/*
> > > + * Remove the attribute specified in @args.
> > > + *
> > > + * This function may return -EAGAIN to signal that the transaction needs to be
> > > + * rolled.  Callers should continue calling this function until they receive a
> > > + * return value other than -EAGAIN.
> > > + */
> > > +int
> > > +xfs_attr_remove_iter(
> > >   	struct xfs_da_args      *args)
> > >   {
> > >   	struct xfs_inode	*dp = args->dp;
> > >   	int			error;
> > > +	/* State machine switch */
> > > +	switch (args->dac.dela_state) {
> > > +	case XFS_DAS_RM_SHRINK:
> > > +	case XFS_DAS_RMTVAL_REMOVE:
> > > +		goto node;
> > > +	default:
> > > +		break;
> > > +	}
> > 
> > Why separate out the state machine? Doesn't this shortcut the
> > xfs_inode_hasattr() check? Shouldn't that come first?
> Well, the idea is that when we first start the routine, we come in with
> neither state set, and we fall through to the break.  So we execute the
> check the first time through.
> 
> Though now that you point it out, I should probably go back and put the
> explicit numbering back in the enum (starting with 1) or they will default
> to zero, which would be incorrect.  I had pulled it out in one of the last
> reviews thinking it would be ok, but it should go back in.
> 
> > 
> > As it is:
> > 
> > 	case XFS_DAS_RM_SHRINK:
> > 	case XFS_DAS_RMTVAL_REMOVE:
> > 		return xfs_attr_node_removename(args);
> > 	default:
> > 		break;
> > 
> > would be nicer, and if this is the only way we can get to
> > xfs_attr_node_removename(c, getting rid of it from the code
> > below could be done, too.
> Well, the remove path is a lot simpler than the set path, so that trick does
> work here :-)
> 
> The idea though was to establish "jump points" with the "XFS_DAS_*" states.
> Based on the state, we jump back to where we were.  We could break this
> pattern for the remove path, but I dont think we'd want to do the same for
> the others.  The set routine is a really big function that would end up
> being inside a really big switch!

Right, which is why I think it should be factored into function
calls first, then the switch statement simply becomes a small set of
function calls.

We use that pattern quite a bit in the da_btree code to call
the correct dir/attr function based on the type of block we are
manipulating (i.e. based on da_state context). e.g. xfs_da3_split(),
xfs_da3_join(), etc.

> > >   	struct xfs_da_geometry *geo;	/* da block geometry */
> > >   	struct xfs_name	name;		/* name, length and argument  flags*/
> > >   	uint8_t		filetype;	/* filetype of inode for directories */
> > > 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"
> > 
> > Hmmm - why are these new includes necessary? You didn't add anything
> > new to these files or common header files to make the includes
> > needed....
> 
> Because the delayed attr context uses things from those headers.  And we put
> the context in xfs_da_args.  Now everything that uses xfs_da_args needs
> those includes.  But maybe if we do what you suggest above, we wont need to.
> :-)

put:

struct xfs_da_state;

and whatever other forward declarations are require for the pointer
types used in the delayed attr context at the top of xfs_attr.h.

These are just pointers in the structure, so we don't need the full
structure definitions if the pointers aren't actually dereferenced
by the code that includes the header file.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-26  2:13     ` Allison Collins
@ 2020-02-26 22:39       ` Dave Chinner
  0 siblings, 0 replies; 135+ messages in thread
From: Dave Chinner @ 2020-02-26 22:39 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Feb 25, 2020 at 07:13:42PM -0700, Allison Collins wrote:
> On 2/25/20 2:21 AM, Dave Chinner wrote:
> > Heh. This is an example of exactly why I think this should be
> > factored into functions first. Move all the code you just
> > re-indented into xfs_attr_set_shortform(), and the goto disappears
> > because this code becomes:
> > 
> > 	if (xfs_attr_is_shortform(dp))
> > 		return xfs_attr_set_shortform(dp, args);
> > 
> > add_leaf:
> > 
> > That massively improves the readability of the code - it separates
> > the operation implementation from the decision logic nice and
> > cleanly, and lends itself to being implemented in the delayed attr
> > state machine without needing gotos at all.
> Sure, I actually had it more like that in the last version.  I flipped it
> around because I thought it would help people understand what the
> refactoring was for if they could see it in context with the states. But if
> the other way is more helpful, its easy to put back.  Will move :-)

In general, factoring first is best. Factoring should not change
behaviour, nor change the actual code much. Then when the logic
surrounding the new function gets changed later on, it's much easier
to see and understand the logic changes as they aren't hidden
amongst mass code movements (like re-indenting).

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-26 22:34       ` Dave Chinner
@ 2020-02-27  4:18         ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-27  4:18 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs



On 2/26/20 3:34 PM, Dave Chinner wrote:
> On Tue, Feb 25, 2020 at 04:57:46PM -0800, Allison Collins wrote:
>> On 2/25/20 1:57 AM, Dave Chinner wrote:
>>> On Sat, Feb 22, 2020 at 07:06:05PM -0700, Allison Collins wrote:
>>>> +out:
>>>> +	return error;
>>>> +}
>>>
>>> Brian commented on the structure of this loop better than I could.
>>>
>>>> +
>>>> +/*
>>>> + * Remove the attribute specified in @args.
>>>> + *
>>>> + * This function may return -EAGAIN to signal that the transaction needs to be
>>>> + * rolled.  Callers should continue calling this function until they receive a
>>>> + * return value other than -EAGAIN.
>>>> + */
>>>> +int
>>>> +xfs_attr_remove_iter(
>>>>    	struct xfs_da_args      *args)
>>>>    {
>>>>    	struct xfs_inode	*dp = args->dp;
>>>>    	int			error;
>>>> +	/* State machine switch */
>>>> +	switch (args->dac.dela_state) {
>>>> +	case XFS_DAS_RM_SHRINK:
>>>> +	case XFS_DAS_RMTVAL_REMOVE:
>>>> +		goto node;
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>
>>> Why separate out the state machine? Doesn't this shortcut the
>>> xfs_inode_hasattr() check? Shouldn't that come first?
>> Well, the idea is that when we first start the routine, we come in with
>> neither state set, and we fall through to the break.  So we execute the
>> check the first time through.
>>
>> Though now that you point it out, I should probably go back and put the
>> explicit numbering back in the enum (starting with 1) or they will default
>> to zero, which would be incorrect.  I had pulled it out in one of the last
>> reviews thinking it would be ok, but it should go back in.
>>
>>>
>>> As it is:
>>>
>>> 	case XFS_DAS_RM_SHRINK:
>>> 	case XFS_DAS_RMTVAL_REMOVE:
>>> 		return xfs_attr_node_removename(args);
>>> 	default:
>>> 		break;
>>>
>>> would be nicer, and if this is the only way we can get to
>>> xfs_attr_node_removename(c, getting rid of it from the code
>>> below could be done, too.
>> Well, the remove path is a lot simpler than the set path, so that trick does
>> work here :-)
>>
>> The idea though was to establish "jump points" with the "XFS_DAS_*" states.
>> Based on the state, we jump back to where we were.  We could break this
>> pattern for the remove path, but I dont think we'd want to do the same for
>> the others.  The set routine is a really big function that would end up
>> being inside a really big switch!
> 
> Right, which is why I think it should be factored into function
> calls first, then the switch statement simply becomes a small set of
> function calls.
> 
> We use that pattern quite a bit in the da_btree code to call
> the correct dir/attr function based on the type of block we are
> manipulating (i.e. based on da_state context). e.g. xfs_da3_split(),
> xfs_da3_join(), etc.
I see, sure will do.  The patches were ordered much that way in the last 
version, so it wouldnt be hard to undo.

> 
>>>>    	struct xfs_da_geometry *geo;	/* da block geometry */
>>>>    	struct xfs_name	name;		/* name, length and argument  flags*/
>>>>    	uint8_t		filetype;	/* filetype of inode for directories */
>>>> 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"
>>>
>>> Hmmm - why are these new includes necessary? You didn't add anything
>>> new to these files or common header files to make the includes
>>> needed....
>>
>> Because the delayed attr context uses things from those headers.  And we put
>> the context in xfs_da_args.  Now everything that uses xfs_da_args needs
>> those includes.  But maybe if we do what you suggest above, we wont need to.
>> :-)
> 
> put:
> 
> struct xfs_da_state;
> 
> and whatever other forward declarations are require for the pointer
> types used in the delayed attr context at the top of xfs_attr.h.
> 
> These are just pointers in the structure, so we don't need the full
> structure definitions if the pointers aren't actually dereferenced
> by the code that includes the header file.
Alrighty, will fix.

Thanks for the reviews!
Allison

> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags
  2020-02-23  2:05 ` [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags Allison Collins
  2020-02-23 12:30   ` Amir Goldstein
@ 2020-02-28  4:56   ` Chandan Rajendra
  1 sibling, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28  4:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM Allison Collins wrote: 
> Since delayed operations cannot roll transactions, factor up the transaction
> handling into the calling function
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  7 +------
>  2 files changed, 15 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index a2f812f..cf0cba7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -739,6 +739,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
> @@ -1081,6 +1088,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 9d6b68c..d691509 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
>  			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> -
> -	return error;
> +	return 0;
>  }
> 


-- 
chandan




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

* Re: [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper
  2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
  2020-02-23 12:42   ` Amir Goldstein
  2020-02-25  6:42   ` Dave Chinner
@ 2020-02-28  6:51   ` Chandan Rajendra
  2 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28  6:51 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:35 AM 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, and move the commit into the calling function.
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 88 +++++++++++++++++++++++++++++++-----------------
>  1 file changed, 57 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index cf0cba7..b2f0780 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -305,10 +305,30 @@ xfs_attr_set_args(
>  		}
>  	}
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_addname(args);
> -	else
> -		error = xfs_attr_node_addname(args);
> +		if (error != -ENOSPC)
> +			return error;
> +
> +		/*
> +		 * Commit that transaction so that the node_addname()
> +		 * call can manage its own transactions.
> +		 */
> +		error = xfs_defer_finish(&args->trans);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Commit the current trans (including the inode) and
> +		 * start a new one.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, dp);
> +		if (error)
> +			return error;
> +
> +	}
> +
> +	error = xfs_attr_node_addname(args);
>  	return error;
>  }
>  
> @@ -620,20 +640,21 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>   *========================================================================*/
>  
>  /*
> - * Add a name to the leaf attribute list structure
> + * Tries to add an attribute to an inode in leaf form
>   *
> - * 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 function is meant to execute as part of a delayed operation and leaves
> + * the transaction handling to the caller.  On success the attribute is added
> + * and the inode and transaction are left dirty.  If there is not enough space,
> + * the attr data is converted to node format and -ENOSPC is returned. Caller is
> + * responsible for handling the dirty inode and transaction or adding the attr
> + * in node format.
>   */
>  STATIC int
> -xfs_attr_leaf_addname(
> -	struct xfs_da_args	*args)
> +xfs_attr_leaf_try_add(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf		*bp)
>  {
> -	struct xfs_buf		*bp;
> -	int			retval, error, forkoff;
> -	struct xfs_inode	*dp = args->dp;
> -
> -	trace_xfs_attr_leaf_addname(args);
> +	int			retval, error;
>  
>  	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
> @@ -679,31 +700,36 @@ xfs_attr_leaf_addname(
>  	retval = xfs_attr3_leaf_add(bp, args);
>  	if (retval == -ENOSPC) {
>  		/*
> -		 * Promote the attribute list to the Btree format, then
> -		 * Commit that transaction so that the node_addname() call
> -		 * can manage its own transactions.
> +		 * Promote the attribute list to the Btree format.
> +		 * Unless an error occurs, retain the -ENOSPC retval
>  		 */
>  		error = xfs_attr3_leaf_to_node(args);
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +	}
> +	return retval;
> +}
>  
> -		/*
> -		 * Commit the current trans (including the inode) and start
> -		 * a new one.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			return error;
>  
> -		/*
> -		 * Fob the whole rest of the problem off on the Btree code.
> -		 */
> -		error = xfs_attr_node_addname(args);
> +/*
> + * Add a name to the leaf attribute list structure
> + *
> + * This leaf block cannot have a "remote" value, we only call this routine
> + * if bmap_one_block() says there is only one block (ie: no remote blks).
> + */
> +STATIC int
> +xfs_attr_leaf_addname(
> +	struct xfs_da_args	*args)
> +{
> +	int			error, forkoff;
> +	struct xfs_buf		*bp = NULL;
> +	struct xfs_inode	*dp = args->dp;
> +
> +	trace_xfs_attr_leaf_addname(args);
> +
> +	error = xfs_attr_leaf_try_add(args, bp);
> +	if (error)
>  		return error;
> -	}
>  
>  	/*
>  	 * Commit the transaction that added the attr name so that
> 


-- 
chandan




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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
  2020-02-23 13:04   ` Amir Goldstein
  2020-02-24 13:08   ` Brian Foster
@ 2020-02-28  7:42   ` Chandan Rajendra
  2020-02-28 18:14     ` Allison Collins
  2 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28  7:42 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
> while modularizing the adjacent code down into helpers. In this patch, hoist the
> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
> attr list creation down.
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index b2f0780..71298b9 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -227,8 +227,13 @@ xfs_attr_try_sf_addname(
>  	struct xfs_da_args	*args)
>  {
>  
> -	struct xfs_mount	*mp = dp->i_mount;
> -	int			error, error2;
> +	int			error;
> +
> +	/*
> +	 * Build initial attribute list (if required).
> +	 */
> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> +		xfs_attr_shortform_create(args);
>  
>  	error = xfs_attr_shortform_addname(args);
>  	if (error == -ENOSPC)
> @@ -241,12 +246,10 @@ xfs_attr_try_sf_addname(
>  	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>  
> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
> +	if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args->trans);
>  
> -	error2 = xfs_trans_commit(args->trans);
> -	args->trans = NULL;
> -	return error ? error : error2;
> +	return error;
>  }
>  
>  /*
> @@ -258,7 +261,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,
> @@ -269,17 +272,14 @@ xfs_attr_set_args(
>  	     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;
> +		if (error != -ENOSPC) {
> +			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.
> 


-- 
chandan




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

* Re: [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag
  2020-02-23  2:06 ` [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2020-02-28  7:59   ` Chandan Rajendra
  0 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28  7:59 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> New delayed allocation routines cannot be handling transactions so factor them up
> into the calling functions
>
I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> 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 71298b9..26412da 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1244,6 +1244,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 d691509..67339f0 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2855,10 +2855,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 0;
>  }
>  
>  /*
> 


-- 
chandan




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

* Re: [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate
  2020-02-23  2:06 ` [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2020-02-28 10:42   ` Chandan Rajendra
  0 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28 10:42 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM 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.
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 26 +++++++++++++++++++++-----
>  fs/xfs/libxfs/xfs_attr_remote.h |  2 +-
>  2 files changed, 22 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index d1eee24..3de2eec 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -634,15 +634,12 @@ xfs_attr_rmtval_set(
>   * out-of-line buffer that it is stored on.
>   */
>  int
> -xfs_attr_rmtval_remove(
> +xfs_attr_rmtval_invalidate(
>  	struct xfs_da_args	*args)
>  {
>  	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.
> @@ -670,13 +667,32 @@ xfs_attr_rmtval_remove(
>  		lblkno += map.br_blockcount;
>  		blkcnt -= map.br_blockcount;
>  	}
> +	return 0;
> +}
>  
> +/*
> + * Remove the value associated with an attribute by deleting the
> + * out-of-line buffer that it is stored on.
> + */
> +int
> +xfs_attr_rmtval_remove(
> +	struct xfs_da_args      *args)
> +{
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +	int			error = 0;
> +	int			done = 0;
> +
> +	trace_xfs_attr_rmtval_remove(args);
> +
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
>  	/*
>  	 * Keep de-allocating extents until the remote-value region is gone.
>  	 */
>  	lblkno = args->rmtblkno;
>  	blkcnt = args->rmtblkcnt;
> -	done = 0;
>  	while (!done) {
>  		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
>  				    XFS_BMAPI_ATTRFORK, 1, &done);
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 6fb4572..eff5f95 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -13,5 +13,5 @@ int xfs_attr_rmtval_set(struct xfs_da_args *args);
>  int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>  int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
>  		xfs_buf_flags_t incore_flags);
> -
> +int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> 


-- 
chandan




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

* Re: [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag
  2020-02-23  2:06 ` [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2020-02-28 10:56   ` Chandan Rajendra
  0 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28 10:56 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> New delayed allocation routines cannot be handling transactions so factor them out
> into the calling functions
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>  2 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 26412da..5d73bdf 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -822,6 +822,14 @@ xfs_attr_leaf_addname(
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	return error;
>  }
> @@ -1185,6 +1193,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 67339f0..1742f0a 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2804,10 +2804,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 0;
>  }
>  
>  /*
> 


-- 
chandan




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

* Re: [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap
  2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
  2020-02-24 13:40   ` Brian Foster
  2020-02-25  7:21   ` Dave Chinner
@ 2020-02-28 14:22   ` Chandan Rajendra
  2 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-02-28 14:22 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> This function is similar to xfs_attr_rmtval_remove, but adapted to return EAGAIN for
> new transactions. We will use this later when we introduce delayed attributes
>
I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 28 ++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 29 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 3de2eec..da40f85 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -711,3 +711,31 @@ xfs_attr_rmtval_remove(
>  	}
>  	return 0;
>  }
> +
> +/*
> + * Remove the value associated with an attribute by deleting the out-of-line
> + * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
> + * transaction and recall the function
> + */
> +int
> +xfs_attr_rmtval_unmap(
> +	struct xfs_da_args	*args)
> +{
> +	int	error, done;
> +
> +	/*
> +	 * Unmap value blocks for this attr.  This is similar to
> +	 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> +	 * for new transactions
> +	 */
> +	error = xfs_bunmapi(args->trans, args->dp,
> +		    args->rmtblkno, args->rmtblkcnt,
> +		    XFS_BMAPI_ATTRFORK, 1, &done);
> +	if (error)
> +		return error;
> +
> +	if (!done)
> +		return -EAGAIN;
> +
> +	return 0;
> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index eff5f95..e06299a 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -14,4 +14,5 @@ int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>  int xfs_attr_rmtval_stale(struct xfs_inode *ip, struct xfs_bmbt_irec *map,
>  		xfs_buf_flags_t incore_flags);
>  int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
> +int xfs_attr_rmtval_unmap(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> 


-- 
chandan




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

* Re: [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname
  2020-02-28  7:42   ` Chandan Rajendra
@ 2020-02-28 18:14     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-02-28 18:14 UTC (permalink / raw)
  To: Chandan Rajendra, linux-xfs



On 2/28/20 12:42 AM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
>> To help pre-simplify xfs_attr_set_args, we need to hoist transacation handling up,
>> while modularizing the adjacent code down into helpers. In this patch, hoist the
>> commit in xfs_attr_try_sf_addname up into the calling function, and also pull the
>> attr list creation down.
>>
> 
> I don't see any logical errors.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Alrighty, thank you!

Allison

> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 30 +++++++++++++++---------------
>>   1 file changed, 15 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index b2f0780..71298b9 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -227,8 +227,13 @@ xfs_attr_try_sf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>>   
>> -	struct xfs_mount	*mp = dp->i_mount;
>> -	int			error, error2;
>> +	int			error;
>> +
>> +	/*
>> +	 * Build initial attribute list (if required).
>> +	 */
>> +	if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> +		xfs_attr_shortform_create(args);
>>   
>>   	error = xfs_attr_shortform_addname(args);
>>   	if (error == -ENOSPC)
>> @@ -241,12 +246,10 @@ xfs_attr_try_sf_addname(
>>   	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>   
>> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
>> +	if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args->trans);
>>   
>> -	error2 = xfs_trans_commit(args->trans);
>> -	args->trans = NULL;
>> -	return error ? error : error2;
>> +	return error;
>>   }
>>   
>>   /*
>> @@ -258,7 +261,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,
>> @@ -269,17 +272,14 @@ xfs_attr_set_args(
>>   	     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;
>> +		if (error != -ENOSPC) {
>> +			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.
>>
> 
> 

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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
  2020-02-24 15:25   ` Brian Foster
  2020-02-25  8:57   ` Dave Chinner
@ 2020-03-03  5:03   ` Chandan Rajendra
  2020-03-03  5:40     ` Allison Collins
  2 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-03  5:03 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> This patch modifies the attr remove routines to be delay ready. This means they no
> longer roll or commit transactions, but instead return -EAGAIN to have the calling
> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
> been modified to use the switch, and a  new version of xfs_attr_remove_args
> consists of a simple loop to refresh the transaction until the operation is
> completed.
> 
> This patch also adds a new struct xfs_delattr_context, which we will use to keep
> track of the current state of an attribute operation. The new xfs_delattr_state
> enum is used to track various operations that are in progress so that we know not
> to repeat them, and resume where we left off before EAGAIN was returned to cycle
> out the transaction. Other members take the place of local variables that need
> to retain their values across multiple function recalls.
> 
> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
> indicate places where the function would return -EAGAIN, and then immediately
> resume from after being recalled by the calling function.  States marked as a
> "subroutine state" indicate that they belong to a subroutine, and so the calling
> function needs to pass them back to that subroutine to allow it to finish where
> it left off. But they otherwise do not have a role in the calling function other
> than just passing through.
> 
>  xfs_attr_remove_iter()
>          XFS_DAS_RM_SHRINK     ─┐
>          (subroutine state)     │
>                                 │
>          XFS_DAS_RMTVAL_REMOVE ─┤
>          (subroutine state)     │
>                                 └─>xfs_attr_node_removename()
>                                                  │
>                                                  v
>                                          need to remove
>                                    ┌─n──  rmt blocks?
>                                    │             │
>                                    │             y
>                                    │             │
>                                    │             v
>                                    │  ┌─>XFS_DAS_RMTVAL_REMOVE
>                                    │  │          │
>                                    │  │          v
>                                    │  └──y── more blks
>                                    │         to remove?
>                                    │             │
>                                    │             n
>                                    │             │
>                                    │             v
>                                    │         need to
>                                    └─────> shrink tree? ─n─┐
>                                                  │         │
>                                                  y         │
>                                                  │         │
>                                                  v         │
>                                          XFS_DAS_RM_SHRINK │
>                                                  │         │
>                                                  v         │
>                                                 done <─────┘
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>  fs/xfs/libxfs/xfs_attr.h     |   1 +
>  fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>  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 +
>  10 files changed, 141 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5d73bdf..cd3a3f7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -368,11 +368,60 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	int			err2 = 0;
> +
> +	do {
> +		error = xfs_attr_remove_iter(args);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> +
> +			err2 = xfs_defer_finish(&args->trans);
> +			if (err2) {
> +				error = err2;
> +				goto out;
> +			}
> +		}
> +
> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +	} while (error == -EAGAIN);
> +out:
> +	return error;
> +}
> +
> +/*
> + * Remove the attribute specified in @args.
> + *
> + * This function may return -EAGAIN to signal that the transaction needs to be
> + * rolled.  Callers should continue calling this function until they receive a
> + * return value other than -EAGAIN.
> + */
> +int
> +xfs_attr_remove_iter(
>  	struct xfs_da_args      *args)
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	int			error;
>  
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_RM_SHRINK:
> +	case XFS_DAS_RMTVAL_REMOVE:
> +		goto node;
> +	default:
> +		break;
> +	}
> +

On the very first invocation of xfs_attr_remote_iter() from
xfs_attr_remove_args() (via a call from xfs_attr_remove()),
args->dac.dela_state is set to a value of 0. This happens because
xfs_attr_args_init() invokes memset() on args. A value of 0 for
args->dac.dela_state maps to XFS_DAS_RM_SHRINK.

If the xattr was stored in say local or leaf format we end up incorrectly
invoking xfs_attr_node_removename() right?

-- 
chandan




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

* Re: [PATCH v7 13/19] xfs: Add delay ready attr remove routines
  2020-03-03  5:03   ` Chandan Rajendra
@ 2020-03-03  5:40     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-03-03  5:40 UTC (permalink / raw)
  To: Chandan Rajendra; +Cc: linux-xfs



On 3/2/20 10:03 PM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
>> This patch modifies the attr remove routines to be delay ready. This means they no
>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>> routine roll and refresh the transaction. In this series, xfs_attr_remove_args has
>> become xfs_attr_remove_iter, which uses a sort of state machine like switch to keep
>> track of where it was when EAGAIN was returned. xfs_attr_node_removename has also
>> been modified to use the switch, and a  new version of xfs_attr_remove_args
>> consists of a simple loop to refresh the transaction until the operation is
>> completed.
>>
>> This patch also adds a new struct xfs_delattr_context, which we will use to keep
>> track of the current state of an attribute operation. The new xfs_delattr_state
>> enum is used to track various operations that are in progress so that we know not
>> to repeat them, and resume where we left off before EAGAIN was returned to cycle
>> out the transaction. Other members take the place of local variables that need
>> to retain their values across multiple function recalls.
>>
>> Below is a state machine diagram for attr remove operations. The XFS_DAS_* states
>> indicate places where the function would return -EAGAIN, and then immediately
>> resume from after being recalled by the calling function.  States marked as a
>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>> function needs to pass them back to that subroutine to allow it to finish where
>> it left off. But they otherwise do not have a role in the calling function other
>> than just passing through.
>>
>>   xfs_attr_remove_iter()
>>           XFS_DAS_RM_SHRINK     ─┐
>>           (subroutine state)     │
>>                                  │
>>           XFS_DAS_RMTVAL_REMOVE ─┤
>>           (subroutine state)     │
>>                                  └─>xfs_attr_node_removename()
>>                                                   │
>>                                                   v
>>                                           need to remove
>>                                     ┌─n──  rmt blocks?
>>                                     │             │
>>                                     │             y
>>                                     │             │
>>                                     │             v
>>                                     │  ┌─>XFS_DAS_RMTVAL_REMOVE
>>                                     │  │          │
>>                                     │  │          v
>>                                     │  └──y── more blks
>>                                     │         to remove?
>>                                     │             │
>>                                     │             n
>>                                     │             │
>>                                     │             v
>>                                     │         need to
>>                                     └─────> shrink tree? ─n─┐
>>                                                   │         │
>>                                                   y         │
>>                                                   │         │
>>                                                   v         │
>>                                           XFS_DAS_RM_SHRINK │
>>                                                   │         │
>>                                                   v         │
>>                                                  done <─────┘
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c     | 114 +++++++++++++++++++++++++++++++++++++------
>>   fs/xfs/libxfs/xfs_attr.h     |   1 +
>>   fs/xfs/libxfs/xfs_da_btree.h |  30 ++++++++++++
>>   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 +
>>   10 files changed, 141 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5d73bdf..cd3a3f7 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -368,11 +368,60 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +
>> +	do {
>> +		error = xfs_attr_remove_iter(args);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>> +
>> +			err2 = xfs_defer_finish(&args->trans);
>> +			if (err2) {
>> +				error = err2;
>> +				goto out;
>> +			}
>> +		}
>> +
>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + *
>> + * This function may return -EAGAIN to signal that the transaction needs to be
>> + * rolled.  Callers should continue calling this function until they receive a
>> + * return value other than -EAGAIN.
>> + */
>> +int
>> +xfs_attr_remove_iter(
>>   	struct xfs_da_args      *args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	int			error;
>>   
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_RM_SHRINK:
>> +	case XFS_DAS_RMTVAL_REMOVE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
> 
> On the very first invocation of xfs_attr_remote_iter() from
> xfs_attr_remove_args() (via a call from xfs_attr_remove()),
> args->dac.dela_state is set to a value of 0. This happens because
> xfs_attr_args_init() invokes memset() on args. A value of 0 for
> args->dac.dela_state maps to XFS_DAS_RM_SHRINK.
> 
> If the xattr was stored in say local or leaf format we end up incorrectly
> invoking xfs_attr_node_removename() right?
> 
Hi Chandan,

Yes, this came up in one of the other reviews too.  The indexing for the 
XFS_DAS_* enum should start at 1, not zero.  I had pulled it out of the 
last version thinking it would be ok, but I should have kept the 
indexing starting at 1, allowing the switch to fall through to default.

Allison

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

* Re: [PATCH v7 14/19] xfs: Add delay ready attr set routines
  2020-02-23  2:06 ` [PATCH v7 14/19] xfs: Add delay ready attr set routines Allison Collins
@ 2020-03-03 13:41   ` Chandan Rajendra
  2020-03-03 17:07     ` Allison Collins
  0 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-03 13:41 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> This patch modifies the attr set routines to be delay ready. This means they no
> longer roll or commit transactions, but instead return -EAGAIN to have the calling
> routine roll and refresh the transaction.  In this series, xfs_attr_set_args has
> become xfs_attr_set_iter, which uses a state machine like switch to keep track of
> where it was when EAGAIN was returned.
> 
> Part of xfs_attr_leaf_addname has been factored out into a new helper function
> xfs_attr_leaf_try_add to allow transaction cycling between the two routines.
> 
> Two new helper functions have been added: xfs_attr_rmtval_set_init and
> xfs_attr_rmtval_set_blk.  They provide a subset of logic similar to
> xfs_attr_rmtval_set, but they store the current block in the delay attr
> context to allow the caller to roll the transaction between allocations. This helps
> to simplify and consolidate code used by xfs_attr_leaf_addname and
> xfs_attr_node_addname. Finally, xfs_attr_set_args has become a simple loop to
> refresh the transaction until the operation is completed.
> 
> Below is a state machine diagram for attr set operations. The XFS_DAS_* states
> indicate places where the function would return -EAGAIN, and then immediately
> resume from after being recalled by the calling function.  States marked as a
> "subroutine state" indicate that they belong to a subroutine, and so the calling
> function needs to pass them back to that subroutine to allow it to finish where it
> left off.  But they otherwise do not have a role in the calling function other
> than just passing through.
> 
>  xfs_attr_set_iter()
>                  │
>                  v
>            need to upgrade
>           from sf to leaf? ──n─┐
>                  │             │
>                  y             │
>                  │             │
>                  V             │
>           XFS_DAS_ADD_LEAF     │
>                  │             │
>                  v             │
>   ┌──────n── fork has   <──────┘
>   │         only 1 blk?
>   │              │
>   │              y
>   │              │
>   │              v
>   │     xfs_attr_leaf_try_add()
>   │              │
>   │              v
>   │          had enough
>   ├──────n──   space?
>   │              │
>   │              y
>   │              │
>   │              v
>   │      XFS_DAS_FOUND_LBLK  ──┐
>   │                            │
>   │      XFS_DAS_FLIP_LFLAG  ──┤
>   │      (subroutine state)    │
>   │                            │
>   │      XFS_DAS_ALLOC_LEAF  ──┤
>   │      (subroutine state)    │
>   │                            └─>xfs_attr_leaf_addname()
>   │                                              │
>   │                                              v
>   │                                ┌─────n──  need to
>   │                                │        alloc blks?
>   │                                │             │
>   │                                │             y
>   │                                │             │
>   │                                │             v
>   │                                │  ┌─>XFS_DAS_ALLOC_LEAF
>   │                                │  │          │
>   │                                │  │          v
>   │                                │  └──y── need to alloc
>   │                                │         more blocks?
>   │                                │             │
>   │                                │             n
>   │                                │             │
>   │                                │             v
>   │                                │          was this
>   │                                └────────> a rename? ──n─┐
>   │                                              │          │
>   │                                              y          │
>   │                                              │          │
>   │                                              v          │
>   │                                        flip incomplete  │
>   │                                            flag         │
>   │                                              │          │
>   │                                              v          │
>   │                                   ┌─>XFS_DAS_FLIP_LFLAG │
>   │                                   │          │          │
>   │                                   │          v          │
>   │                                   │        remove       │
>   │                                   │       old name      │
>   │                                   │          │          │
>   │                                   │          v          │
>   │                                   └────y── more to      │
>   │                                            remove       │
>   │                                              │          │
>   │                                              n          │
>   │                                              │          │
>   │                                              v          │
>   │                                             done <──────┘
>   └────> XFS_DAS_LEAF_TO_NODE ─┐
>                                │
>          XFS_DAS_FOUND_NBLK  ──┤
>          (subroutine state)    │
>                                │
>          XFS_DAS_ALLOC_NODE  ──┤
>          (subroutine state)    │
>                                │
>          XFS_DAS_FLIP_NFLAG  ──┤
>          (subroutine state)    │
>                                │
>                                └─>xfs_attr_node_addname()
>                                                  │
>                                                  v
>                                          find space to store
>                                         attr. Split if needed
>                                                  │
>                                                  v
>                                          XFS_DAS_FOUND_NBLK
>                                                  │
>                                                  v
>                                    ┌─────n──  need to
>                                    │        alloc blks?
>                                    │             │
>                                    │             y
>                                    │             │
>                                    │             v
>                                    │  ┌─>XFS_DAS_ALLOC_NODE
>                                    │  │          │
>                                    │  │          v
>                                    │  └──y── need to alloc
>                                    │         more blocks?
>                                    │             │
>                                    │             n
>                                    │             │
>                                    │             v
>                                    │          was this
>                                    └────────> a rename? ──n─┐
>                                                  │          │
>                                                  y          │
>                                                  │          │
>                                                  v          │
>                                            flip incomplete  │
>                                                flag         │
>                                                  │          │
>                                                  v          │
>                                       ┌─>XFS_DAS_FLIP_NFLAG │
>                                       │          │          │
>                                       │          v          │
>                                       │        remove       │
>                                       │       old name      │
>                                       │          │          │
>                                       │          v          │
>                                       └────y── more to      │
>                                                remove       │
>                                                  │          │
>                                                  n          │
>                                                  │          │
>                                                  v          │
>                                                 done <──────┘
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        | 368 ++++++++++++++++++++++++++--------------
>  fs/xfs/libxfs/xfs_attr.h        |   1 +
>  fs/xfs/libxfs/xfs_attr_remote.c |  67 +++++++-
>  fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>  fs/xfs/libxfs/xfs_da_btree.h    |  13 ++
>  5 files changed, 319 insertions(+), 134 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index cd3a3f7..4b788f2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>  				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>  
>  
>  STATIC int
> @@ -259,9 +260,86 @@ int
>  xfs_attr_set_args(
>  	struct xfs_da_args	*args)
>  {
> +	int			error = 0;
> +	int			err2 = 0;
> +	struct xfs_buf		*leaf_bp = NULL;
> +
> +	do {
> +		error = xfs_attr_set_iter(args, &leaf_bp);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
> +
> +			err2 = xfs_defer_finish(&args->trans);
> +			if (err2) {
> +				error = err2;
> +				goto out;
> +			}
> +		}
> +
> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +		if (leaf_bp) {
> +			xfs_trans_bjoin(args->trans, leaf_bp);
> +			xfs_trans_bhold(args->trans, leaf_bp);
> +		}
> +
> +	} while (error == -EAGAIN);
> +
> +out:
> +	return error;
> +}
> +
> +/*
> + * Set the attribute specified in @args.
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
> + */
> +int
> +xfs_attr_set_iter(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf          **leaf_bp)
> +{
>  	struct xfs_inode	*dp = args->dp;
> -	struct xfs_buf          *leaf_bp = NULL;
> -	int			error, error2 = 0;
> +	int			error = 0;
> +	int			sf_size;
> +
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_ADD_LEAF:
> +		goto add_leaf;
> +	case XFS_DAS_ALLOC_LEAF:
> +	case XFS_DAS_FLIP_LFLAG:
> +	case XFS_DAS_FOUND_LBLK:
> +		goto leaf;
> +	case XFS_DAS_FOUND_NBLK:
> +	case XFS_DAS_FLIP_NFLAG:
> +	case XFS_DAS_ALLOC_NODE:
> +	case XFS_DAS_LEAF_TO_NODE:
> +		goto node;
> +	default:
> +		break;
> +	}
> +
> +	/*
> +	 * New inodes may not have an attribute fork yet. So set the attribute
> +	 * fork appropriately
> +	 */
> +	if (XFS_IFORK_Q((args->dp)) == 0) {
> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
> +	}
>  
>  	/*
>  	 * If the attribute list is non-existent or a shortform list,
> @@ -275,17 +353,16 @@ 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) {
> -			error2 = xfs_trans_commit(args->trans);
> -			args->trans = NULL;
> -			return error ? error : error2;
> -		}
> +
> +		/* Should only be 0, -EEXIST or ENOSPC */
> +		if (error != -ENOSPC)
> +			return error;
>  
>  		/*
>  		 * It won't fit in the shortform, transform to a leaf block.
>  		 * GROT: another possible req'mt for a double-split btree op.
>  		 */
> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>  		if (error)
>  			return error;
>  
> @@ -293,41 +370,48 @@ xfs_attr_set_args(
>  		 * Prevent the leaf buffer from being unlocked so that a
>  		 * concurrent AIL push cannot grab the half-baked leaf
>  		 * buffer and run into problems with the write verifier.
> -		 * Once we're done rolling the transaction we can release
> -		 * the hold and add the attr to the leaf.
>  		 */
> -		xfs_trans_bhold(args->trans, leaf_bp);
> -		error = xfs_defer_finish(&args->trans);
> -		xfs_trans_bhold_release(args->trans, leaf_bp);
> -		if (error) {
> -			xfs_trans_brelse(args->trans, leaf_bp);
> -			return error;
> -		}
> +		xfs_trans_bhold(args->trans, *leaf_bp);
> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +		args->dac.dela_state = XFS_DAS_ADD_LEAF;
> +		return -EAGAIN;
>  	}
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_addname(args);
> -		if (error != -ENOSPC)
> -			return error;
> +add_leaf:
>  
> -		/*
> -		 * Commit that transaction so that the node_addname()
> -		 * call can manage its own transactions.
> -		 */
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +	/*
> +	 * 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;
> +	}
>  
> -		/*
> -		 * Commit the current trans (including the inode) and
> -		 * start a new one.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +		switch (error) {
> +		case -ENOSPC:
> +			args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
> +			return -EAGAIN;
> +		case 0:
> +			args->dac.dela_state = XFS_DAS_FOUND_LBLK;
> +			return -EAGAIN;
> +		default:
>  			return error;
> -
> +		}
> +leaf:
> +		error = xfs_attr_leaf_addname(args);
> +		if (error == -ENOSPC) {
> +			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
> +			return -EAGAIN;
> +		}
> +		return error;
>  	}
> -
> +	args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
> +node:
>  	error = xfs_attr_node_addname(args);
>  	return error;
>  }
> @@ -766,28 +850,29 @@ xfs_attr_leaf_try_add(
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
>   * if bmap_one_block() says there is only one block (ie: no remote blks).
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
>   */
>  STATIC int
>  xfs_attr_leaf_addname(
>  	struct xfs_da_args	*args)
>  {
> -	int			error, forkoff;
>  	struct xfs_buf		*bp = NULL;
> +	int			error, forkoff;
>  	struct xfs_inode	*dp = args->dp;
>  
> -	trace_xfs_attr_leaf_addname(args);
> -
> -	error = xfs_attr_leaf_try_add(args, bp);
> -	if (error)
> -		return error;
> -
> -	/*
> -	 * Commit the transaction that added the attr name so that
> -	 * later routines can manage their own transactions.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, dp);
> -	if (error)
> -		return error;
> +	/* State machine switch */
> +	switch (args->dac.dela_state) {
> +	case XFS_DAS_FLIP_LFLAG:
> +		goto flip_flag;
> +	case XFS_DAS_ALLOC_LEAF:
> +		goto alloc_leaf;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -796,7 +881,28 @@ xfs_attr_leaf_addname(
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> +
> +		/* Open coded xfs_attr_rmtval_set without trans handling */
> +		error = xfs_attr_rmtval_set_init(args);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
> +		 */
> +alloc_leaf:
> +		while (args->dac.blkcnt > 0) {
> +			error = xfs_attr_rmtval_set_blk(args);
> +			if (error)
> +				return error;
> +
> +			args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +			args->dac.dela_state = XFS_DAS_ALLOC_LEAF;
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
>  			return error;
>  	}
> @@ -815,13 +921,6 @@ 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
> @@ -832,8 +931,17 @@ xfs_attr_leaf_addname(
>  		args->rmtblkno = args->rmtblkno2;
>  		args->rmtblkcnt = args->rmtblkcnt2;
>  		args->rmtvaluelen = args->rmtvaluelen2;
> +
> +		args->dac.dela_state = XFS_DAS_FLIP_LFLAG;
> +		return -EAGAIN;
> +flip_flag:
>  		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_remove(args);
> +			error = xfs_attr_rmtval_unmap(args);
> +
> +			/*
> +			 * if (error == -EAGAIN), we will repeat this until
> +			 * args->rmtblkno is zero
> +			 */
>  			if (error)
>  				return error;
>  		}
Hi Allison,

In the case where args->rmtblkno is non-zero, xfs_attr_rmtval_unmap() invokes
xfs_bunmapi() for unmapping the file block range starting at
args->rmtblkno. If xfs_bunmapi() frees a subset of the range of blocks, it
returns with 'done' set to 0 and in turn xfs_attr_rmtval_unmap() returns with
-EAGAIN error. This will cause xfs_attr_leaf_addname() to return -EAGAIN to
its caller i.e. xfs_attr_set_iter(). In turn xfs_attr_set_iter() returns back
to xfs_attr_set_args(). Here the loop is executed once again and hence
xfs_attr_set_iter() is invoked with args->dac.dela_state set to
XFS_DAS_FLIP_LFLAG. Hence xfs_attr_leaf_addname() is invoked once again with
args->dac.dela_state set to XFS_DAS_FLIP_LFLAG. Here xfs_attr_rmtval_unmap()
is invoked once again with an unmodified args->rmtblkno.

-- 
chandan




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

* Re: [PATCH v7 14/19] xfs: Add delay ready attr set routines
  2020-03-03 13:41   ` Chandan Rajendra
@ 2020-03-03 17:07     ` Allison Collins
  0 siblings, 0 replies; 135+ messages in thread
From: Allison Collins @ 2020-03-03 17:07 UTC (permalink / raw)
  To: Chandan Rajendra; +Cc: linux-xfs



On 3/3/20 6:41 AM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready. This means they no
>> longer roll or commit transactions, but instead return -EAGAIN to have the calling
>> routine roll and refresh the transaction.  In this series, xfs_attr_set_args has
>> become xfs_attr_set_iter, which uses a state machine like switch to keep track of
>> where it was when EAGAIN was returned.
>>
>> Part of xfs_attr_leaf_addname has been factored out into a new helper function
>> xfs_attr_leaf_try_add to allow transaction cycling between the two routines.
>>
>> Two new helper functions have been added: xfs_attr_rmtval_set_init and
>> xfs_attr_rmtval_set_blk.  They provide a subset of logic similar to
>> xfs_attr_rmtval_set, but they store the current block in the delay attr
>> context to allow the caller to roll the transaction between allocations. This helps
>> to simplify and consolidate code used by xfs_attr_leaf_addname and
>> xfs_attr_node_addname. Finally, xfs_attr_set_args has become a simple loop to
>> refresh the transaction until the operation is completed.
>>
>> Below is a state machine diagram for attr set operations. The XFS_DAS_* states
>> indicate places where the function would return -EAGAIN, and then immediately
>> resume from after being recalled by the calling function.  States marked as a
>> "subroutine state" indicate that they belong to a subroutine, and so the calling
>> function needs to pass them back to that subroutine to allow it to finish where it
>> left off.  But they otherwise do not have a role in the calling function other
>> than just passing through.
>>
>>   xfs_attr_set_iter()
>>                   │
>>                   v
>>             need to upgrade
>>            from sf to leaf? ──n─┐
>>                   │             │
>>                   y             │
>>                   │             │
>>                   V             │
>>            XFS_DAS_ADD_LEAF     │
>>                   │             │
>>                   v             │
>>    ┌──────n── fork has   <──────┘
>>    │         only 1 blk?
>>    │              │
>>    │              y
>>    │              │
>>    │              v
>>    │     xfs_attr_leaf_try_add()
>>    │              │
>>    │              v
>>    │          had enough
>>    ├──────n──   space?
>>    │              │
>>    │              y
>>    │              │
>>    │              v
>>    │      XFS_DAS_FOUND_LBLK  ──┐
>>    │                            │
>>    │      XFS_DAS_FLIP_LFLAG  ──┤
>>    │      (subroutine state)    │
>>    │                            │
>>    │      XFS_DAS_ALLOC_LEAF  ──┤
>>    │      (subroutine state)    │
>>    │                            └─>xfs_attr_leaf_addname()
>>    │                                              │
>>    │                                              v
>>    │                                ┌─────n──  need to
>>    │                                │        alloc blks?
>>    │                                │             │
>>    │                                │             y
>>    │                                │             │
>>    │                                │             v
>>    │                                │  ┌─>XFS_DAS_ALLOC_LEAF
>>    │                                │  │          │
>>    │                                │  │          v
>>    │                                │  └──y── need to alloc
>>    │                                │         more blocks?
>>    │                                │             │
>>    │                                │             n
>>    │                                │             │
>>    │                                │             v
>>    │                                │          was this
>>    │                                └────────> a rename? ──n─┐
>>    │                                              │          │
>>    │                                              y          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                        flip incomplete  │
>>    │                                            flag         │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                   ┌─>XFS_DAS_FLIP_LFLAG │
>>    │                                   │          │          │
>>    │                                   │          v          │
>>    │                                   │        remove       │
>>    │                                   │       old name      │
>>    │                                   │          │          │
>>    │                                   │          v          │
>>    │                                   └────y── more to      │
>>    │                                            remove       │
>>    │                                              │          │
>>    │                                              n          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                             done <──────┘
>>    └────> XFS_DAS_LEAF_TO_NODE ─┐
>>                                 │
>>           XFS_DAS_FOUND_NBLK  ──┤
>>           (subroutine state)    │
>>                                 │
>>           XFS_DAS_ALLOC_NODE  ──┤
>>           (subroutine state)    │
>>                                 │
>>           XFS_DAS_FLIP_NFLAG  ──┤
>>           (subroutine state)    │
>>                                 │
>>                                 └─>xfs_attr_node_addname()
>>                                                   │
>>                                                   v
>>                                           find space to store
>>                                          attr. Split if needed
>>                                                   │
>>                                                   v
>>                                           XFS_DAS_FOUND_NBLK
>>                                                   │
>>                                                   v
>>                                     ┌─────n──  need to
>>                                     │        alloc blks?
>>                                     │             │
>>                                     │             y
>>                                     │             │
>>                                     │             v
>>                                     │  ┌─>XFS_DAS_ALLOC_NODE
>>                                     │  │          │
>>                                     │  │          v
>>                                     │  └──y── need to alloc
>>                                     │         more blocks?
>>                                     │             │
>>                                     │             n
>>                                     │             │
>>                                     │             v
>>                                     │          was this
>>                                     └────────> a rename? ──n─┐
>>                                                   │          │
>>                                                   y          │
>>                                                   │          │
>>                                                   v          │
>>                                             flip incomplete  │
>>                                                 flag         │
>>                                                   │          │
>>                                                   v          │
>>                                        ┌─>XFS_DAS_FLIP_NFLAG │
>>                                        │          │          │
>>                                        │          v          │
>>                                        │        remove       │
>>                                        │       old name      │
>>                                        │          │          │
>>                                        │          v          │
>>                                        └────y── more to      │
>>                                                 remove       │
>>                                                   │          │
>>                                                   n          │
>>                                                   │          │
>>                                                   v          │
>>                                                  done <──────┘
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        | 368 ++++++++++++++++++++++++++--------------
>>   fs/xfs/libxfs/xfs_attr.h        |   1 +
>>   fs/xfs/libxfs/xfs_attr_remote.c |  67 +++++++-
>>   fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>>   fs/xfs/libxfs/xfs_da_btree.h    |  13 ++
>>   5 files changed, 319 insertions(+), 134 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index cd3a3f7..4b788f2 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>   				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>>   
>>   
>>   STATIC int
>> @@ -259,9 +260,86 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +	struct xfs_buf		*leaf_bp = NULL;
>> +
>> +	do {
>> +		error = xfs_attr_set_iter(args, &leaf_bp);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		if (args->dac.flags & XFS_DAC_FINISH_TRANS) {
>> +			args->dac.flags &= ~XFS_DAC_FINISH_TRANS;
>> +
>> +			err2 = xfs_defer_finish(&args->trans);
>> +			if (err2) {
>> +				error = err2;
>> +				goto out;
>> +			}
>> +		}
>> +
>> +		err2 = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Set the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_set_iter(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf          **leaf_bp)
>> +{
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error, error2 = 0;
>> +	int			error = 0;
>> +	int			sf_size;
>> +
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_ADD_LEAF:
>> +		goto add_leaf;
>> +	case XFS_DAS_ALLOC_LEAF:
>> +	case XFS_DAS_FLIP_LFLAG:
>> +	case XFS_DAS_FOUND_LBLK:
>> +		goto leaf;
>> +	case XFS_DAS_FOUND_NBLK:
>> +	case XFS_DAS_FLIP_NFLAG:
>> +	case XFS_DAS_ALLOC_NODE:
>> +	case XFS_DAS_LEAF_TO_NODE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	/*
>> +	 * New inodes may not have an attribute fork yet. So set the attribute
>> +	 * fork appropriately
>> +	 */
>> +	if (XFS_IFORK_Q((args->dp)) == 0) {
>> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
>> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> +	}
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -275,17 +353,16 @@ 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) {
>> -			error2 = xfs_trans_commit(args->trans);
>> -			args->trans = NULL;
>> -			return error ? error : error2;
>> -		}
>> +
>> +		/* Should only be 0, -EEXIST or ENOSPC */
>> +		if (error != -ENOSPC)
>> +			return error;
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>>   		 * GROT: another possible req'mt for a double-split btree op.
>>   		 */
>> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
>> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>>   		if (error)
>>   			return error;
>>   
>> @@ -293,41 +370,48 @@ xfs_attr_set_args(
>>   		 * Prevent the leaf buffer from being unlocked so that a
>>   		 * concurrent AIL push cannot grab the half-baked leaf
>>   		 * buffer and run into problems with the write verifier.
>> -		 * Once we're done rolling the transaction we can release
>> -		 * the hold and add the attr to the leaf.
>>   		 */
>> -		xfs_trans_bhold(args->trans, leaf_bp);
>> -		error = xfs_defer_finish(&args->trans);
>> -		xfs_trans_bhold_release(args->trans, leaf_bp);
>> -		if (error) {
>> -			xfs_trans_brelse(args->trans, leaf_bp);
>> -			return error;
>> -		}
>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>> +		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +		args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> +		return -EAGAIN;
>>   	}
>>   
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -		error = xfs_attr_leaf_addname(args);
>> -		if (error != -ENOSPC)
>> -			return error;
>> +add_leaf:
>>   
>> -		/*
>> -		 * Commit that transaction so that the node_addname()
>> -		 * call can manage its own transactions.
>> -		 */
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +	/*
>> +	 * 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;
>> +	}
>>   
>> -		/*
>> -		 * Commit the current trans (including the inode) and
>> -		 * start a new one.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		switch (error) {
>> +		case -ENOSPC:
>> +			args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
>> +			return -EAGAIN;
>> +		case 0:
>> +			args->dac.dela_state = XFS_DAS_FOUND_LBLK;
>> +			return -EAGAIN;
>> +		default:
>>   			return error;
>> -
>> +		}
>> +leaf:
>> +		error = xfs_attr_leaf_addname(args);
>> +		if (error == -ENOSPC) {
>> +			args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
>> +			return -EAGAIN;
>> +		}
>> +		return error;
>>   	}
>> -
>> +	args->dac.dela_state = XFS_DAS_LEAF_TO_NODE;
>> +node:
>>   	error = xfs_attr_node_addname(args);
>>   	return error;
>>   }
>> @@ -766,28 +850,29 @@ xfs_attr_leaf_try_add(
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>>    * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>>    */
>>   STATIC int
>>   xfs_attr_leaf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	int			error, forkoff;
>>   	struct xfs_buf		*bp = NULL;
>> +	int			error, forkoff;
>>   	struct xfs_inode	*dp = args->dp;
>>   
>> -	trace_xfs_attr_leaf_addname(args);
>> -
>> -	error = xfs_attr_leaf_try_add(args, bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>> -	 * Commit the transaction that added the attr name so that
>> -	 * later routines can manage their own transactions.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		return error;
>> +	/* State machine switch */
>> +	switch (args->dac.dela_state) {
>> +	case XFS_DAS_FLIP_LFLAG:
>> +		goto flip_flag;
>> +	case XFS_DAS_ALLOC_LEAF:
>> +		goto alloc_leaf;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -796,7 +881,28 @@ xfs_attr_leaf_addname(
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> +
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>> +		error = xfs_attr_rmtval_set_init(args);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>> +		 */
>> +alloc_leaf:
>> +		while (args->dac.blkcnt > 0) {
>> +			error = xfs_attr_rmtval_set_blk(args);
>> +			if (error)
>> +				return error;
>> +
>> +			args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +			args->dac.dela_state = XFS_DAS_ALLOC_LEAF;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -815,13 +921,6 @@ 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
>> @@ -832,8 +931,17 @@ xfs_attr_leaf_addname(
>>   		args->rmtblkno = args->rmtblkno2;
>>   		args->rmtblkcnt = args->rmtblkcnt2;
>>   		args->rmtvaluelen = args->rmtvaluelen2;
>> +
>> +		args->dac.dela_state = XFS_DAS_FLIP_LFLAG;
>> +		return -EAGAIN;
>> +flip_flag:
>>   		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> +			error = xfs_attr_rmtval_unmap(args);
>> +
>> +			/*
>> +			 * if (error == -EAGAIN), we will repeat this until
>> +			 * args->rmtblkno is zero
>> +			 */
>>   			if (error)
>>   				return error;
>>   		}
> Hi Allison,
> 
> In the case where args->rmtblkno is non-zero, xfs_attr_rmtval_unmap() invokes
> xfs_bunmapi() for unmapping the file block range starting at
> args->rmtblkno. If xfs_bunmapi() frees a subset of the range of blocks, it
> returns with 'done' set to 0 and in turn xfs_attr_rmtval_unmap() returns with
> -EAGAIN error. This will cause xfs_attr_leaf_addname() to return -EAGAIN to
> its caller i.e. xfs_attr_set_iter(). In turn xfs_attr_set_iter() returns back
> to xfs_attr_set_args(). Here the loop is executed once again and hence
> xfs_attr_set_iter() is invoked with args->dac.dela_state set to
> XFS_DAS_FLIP_LFLAG. Hence xfs_attr_leaf_addname() is invoked once again with
> args->dac.dela_state set to XFS_DAS_FLIP_LFLAG. Here xfs_attr_rmtval_unmap()
> is invoked once again with an unmodified args->rmtblkno.
> 

Hi Chandan!

Thanks for the digging!  I think what I'm missing here is the 
xfs_attr_rmtval_invalidate, and an extra state for the remove.  Similar 
to how patch 13 handles xfs_attr_rmtval_unmap.  Will update!  Thank you!

Allison

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
  2020-02-23 13:26   ` Amir Goldstein
  2020-02-25  9:21   ` Dave Chinner
@ 2020-03-04  4:30   ` Chandan Rajendra
  2020-03-04 17:04     ` Allison Collins
  2 siblings, 1 reply; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-04  4:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> Delayed attribute mechanics make frequent use of goto statements.  We can use this
> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
> conditions, we can invert the if logic and jump to the goto. This helps to reduce
> indentation and simplify things.
>

I don't see any logical errors.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 42 insertions(+), 29 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 30a16fe..dd935ff 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>  }
>  
>  /*
> + * Check to see if the attr should be upgraded from non-existent or shortform to
> + * single-leaf-block attribute list.
> + */
> +static inline bool
> +xfs_attr_fmt_needs_update(
> +	struct xfs_inode    *dp)
> +{
> +	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> +	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> +	      dp->i_d.di_anextents == 0);
> +}
> +
> +/*
>   * Set the attribute specified in @args.
>   */
>  int
> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>  	}
>  
>  	/*
> -	 * If the attribute list is non-existent or a shortform list,
> -	 * upgrade it to a single-leaf-block attribute list.
> +	 * If the attribute list is already in leaf format, jump straight to
> +	 * leaf handling.  Otherwise, try to add the attribute to the shortform
> +	 * list; if there's no room then convert the list to leaf format and try
> +	 * again.
>  	 */
> -	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)) {
> +	if (!xfs_attr_fmt_needs_update(dp))
> +		goto add_leaf;
>  
> -		/*
> -		 * Try to add the attr to the attribute list in the inode.
> -		 */
> -		error = xfs_attr_try_sf_addname(dp, args);
> +	/*
> +	 * Try to add the attr to the attribute list in the inode.
> +	 */
> +	error = xfs_attr_try_sf_addname(dp, args);
>  
> -		/* Should only be 0, -EEXIST or ENOSPC */
> -		if (error != -ENOSPC)
> -			return error;
> +	/* Should only be 0, -EEXIST or ENOSPC */
> +	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;
> +	/*
> +	 * 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);
> -		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> -		args->dac.dela_state = XFS_DAS_ADD_LEAF;
> -		return -EAGAIN;
> -	}
> +	/*
> +	 * 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);
> +	args->dac.flags |= XFS_DAC_FINISH_TRANS;
> +	args->dac.dela_state = XFS_DAS_ADD_LEAF;
> +	return -EAGAIN;
>  
>  add_leaf:
>  
> 


-- 
chandan




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

* Re: [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
  2020-02-23 13:47   ` Amir Goldstein
  2020-02-25  9:31   ` Dave Chinner
@ 2020-03-04  4:37   ` Chandan Rajendra
  2 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-04  4:37 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Collins

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> This patch helps to simplify xfs_attr_node_removename by modularizing the code
> around the transactions into helper functions.  This will make the function easier
> to follow when we introduce delayed attributes.
>

The changes look good to me.

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 45 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 31 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index dd935ff..b9728d1 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1416,6 +1416,36 @@ xfs_attr_node_shrink(
>  }
>  
>  /*
> + * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
> + * for later deletion of the entry.
> + */
> +STATIC int
> +xfs_attr_leaf_mark_incomplete(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	*state)
> +{
> +	int error;
> +
> +	/*
> +	 * 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)
> +		return error;
> +
> +	/*
> +	 * Mark the attribute as INCOMPLETE
> +	 */
> +	error = xfs_attr3_leaf_setflag(args);
> +	if (error)
> +		return error;
> +
> +	return 0;
> +}
> +
> +/*
>   * Remove a name from a B-tree attribute list.
>   *
>   * This will involve walking down the Btree, and may involve joining
> @@ -1473,20 +1503,7 @@ xfs_attr_node_removename(
>  	args->dac.da_state = state;
>  
>  	if (args->rmtblkno > 0) {
> -		/*
> -		 * 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);
> +		error = xfs_attr_leaf_mark_incomplete(args, state);
>  		if (error)
>  			goto out;
>  
> 


-- 
chandan




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

* Re: [PATCH v7 18/19] xfs: Add remote block helper functions
  2020-02-23  2:06 ` [PATCH v7 18/19] xfs: Add remote block helper functions Allison Collins
  2020-02-23 13:45   ` Amir Goldstein
@ 2020-03-04  4:59   ` Chandan Rajendra
  1 sibling, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-04  4:59 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sunday, February 23, 2020 7:36 AM Allison Collins wrote: 
> This patch adds two new helper functions xfs_attr_store_rmt_blk and
> xfs_attr_restore_rmt_blk. These two helpers assist to remove redunant code
> associated with storing and retrieving remote blocks during the attr set operations.
>

The changes look good to me,

Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 48 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 28 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index b9728d1..f88be36 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -786,6 +786,30 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>   * External routines when attribute list is one block
>   *========================================================================*/
>  
> +/* Store info about a remote block */
> +STATIC void
> +xfs_attr_store_rmt_blk(
> +	struct xfs_da_args	*args)
> +{
> +	args->blkno2 = args->blkno;
> +	args->index2 = args->index;
> +	args->rmtblkno2 = args->rmtblkno;
> +	args->rmtblkcnt2 = args->rmtblkcnt;
> +	args->rmtvaluelen2 = args->rmtvaluelen;
> +}
> +
> +/* Set stored info about a remote block */
> +STATIC void
> +xfs_attr_restore_rmt_blk(
> +	struct xfs_da_args	*args)
> +{
> +	args->blkno = args->blkno2;
> +	args->index = args->index2;
> +	args->rmtblkno = args->rmtblkno2;
> +	args->rmtblkcnt = args->rmtblkcnt2;
> +	args->rmtvaluelen = args->rmtvaluelen2;
> +}
> +
>  /*
>   * Tries to add an attribute to an inode in leaf form
>   *
> @@ -824,11 +848,7 @@ xfs_attr_leaf_try_add(
>  
>  		/* save the attribute state for later removal*/
>  		args->op_flags |= XFS_DA_OP_RENAME;	/* an atomic rename */
> -		args->blkno2 = args->blkno;		/* set 2nd entry info*/
> -		args->index2 = args->index;
> -		args->rmtblkno2 = args->rmtblkno;
> -		args->rmtblkcnt2 = args->rmtblkcnt;
> -		args->rmtvaluelen2 = args->rmtvaluelen;
> +		xfs_attr_store_rmt_blk(args);
>  
>  		/*
>  		 * clear the remote attr state now that it is saved so that the
> @@ -939,11 +959,7 @@ xfs_attr_leaf_addname(
>  		 * Dismantle the "old" attribute/value pair by removing
>  		 * a "remote" value (if it exists).
>  		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> +		xfs_attr_restore_rmt_blk(args);
>  
>  		args->dac.dela_state = XFS_DAS_FLIP_LFLAG;
>  		return -EAGAIN;
> @@ -1189,11 +1205,7 @@ xfs_attr_node_addname(
>  
>  		/* 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;
> +		xfs_attr_store_rmt_blk(args);
>  
>  		/*
>  		 * clear the remote attr state now that it is saved so that the
> @@ -1306,11 +1318,7 @@ xfs_attr_node_addname(
>  		 * Dismantle the "old" attribute/value pair by removing
>  		 * a "remote" value (if it exists).
>  		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> +		xfs_attr_restore_rmt_blk(args);
>  
>  		/*
>  		 * Commit the flag value change and start the next trans in
> 


-- 
chandan




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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-03-04  4:30   ` Chandan Rajendra
@ 2020-03-04 17:04     ` Allison Collins
  2020-03-05  3:39       ` Chandan Rajendra
  0 siblings, 1 reply; 135+ messages in thread
From: Allison Collins @ 2020-03-04 17:04 UTC (permalink / raw)
  To: Chandan Rajendra; +Cc: linux-xfs



On 3/3/20 9:30 PM, Chandan Rajendra wrote:
> On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
>> Delayed attribute mechanics make frequent use of goto statements.  We can use this
>> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
>> conditions, we can invert the if logic and jump to the goto. This helps to reduce
>> indentation and simplify things.
>>
> 
> I don't see any logical errors.
> 
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Alrighty, thanks for the reviews!  I got some feed back in other reviews 
to move the patches 13 and 14 to the end of the set.  Which means the 
patches ahead of them may change a bit in order to seat correctly.  For 
example, this patch will likely go back to being more like it's v6 version:

https://www.spinics.net/lists/linux-xfs/msg36072.html

Would you prefer I keep or drop your RVB's in this case?  Functionally 
they wont change much, but I understand that function is a lot of what 
your are analyzing too.  Let me know what you are comfortable with.  Thanks!

Allison

> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
>>   1 file changed, 42 insertions(+), 29 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 30a16fe..dd935ff 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
>>   }
>>   
>>   /*
>> + * Check to see if the attr should be upgraded from non-existent or shortform to
>> + * single-leaf-block attribute list.
>> + */
>> +static inline bool
>> +xfs_attr_fmt_needs_update(
>> +	struct xfs_inode    *dp)
>> +{
>> +	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> +	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> +	      dp->i_d.di_anextents == 0);
>> +}
>> +
>> +/*
>>    * Set the attribute specified in @args.
>>    */
>>   int
>> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
>>   	}
>>   
>>   	/*
>> -	 * If the attribute list is non-existent or a shortform list,
>> -	 * upgrade it to a single-leaf-block attribute list.
>> +	 * If the attribute list is already in leaf format, jump straight to
>> +	 * leaf handling.  Otherwise, try to add the attribute to the shortform
>> +	 * list; if there's no room then convert the list to leaf format and try
>> +	 * again.
>>   	 */
>> -	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)) {
>> +	if (!xfs_attr_fmt_needs_update(dp))
>> +		goto add_leaf;
>>   
>> -		/*
>> -		 * Try to add the attr to the attribute list in the inode.
>> -		 */
>> -		error = xfs_attr_try_sf_addname(dp, args);
>> +	/*
>> +	 * Try to add the attr to the attribute list in the inode.
>> +	 */
>> +	error = xfs_attr_try_sf_addname(dp, args);
>>   
>> -		/* Should only be 0, -EEXIST or ENOSPC */
>> -		if (error != -ENOSPC)
>> -			return error;
>> +	/* Should only be 0, -EEXIST or ENOSPC */
>> +	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;
>> +	/*
>> +	 * 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);
>> -		args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> -		args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> -		return -EAGAIN;
>> -	}
>> +	/*
>> +	 * 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);
>> +	args->dac.flags |= XFS_DAC_FINISH_TRANS;
>> +	args->dac.dela_state = XFS_DAS_ADD_LEAF;
>> +	return -EAGAIN;
>>   
>>   add_leaf:
>>   
>>
> 
> 

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

* Re: [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter
  2020-03-04 17:04     ` Allison Collins
@ 2020-03-05  3:39       ` Chandan Rajendra
  0 siblings, 0 replies; 135+ messages in thread
From: Chandan Rajendra @ 2020-03-05  3:39 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wednesday, March 4, 2020 10:34 PM Allison Collins wrote: 
> 
> On 3/3/20 9:30 PM, Chandan Rajendra wrote:
> > On Sunday, February 23, 2020 7:36 AM Allison Collins wrote:
> >> Delayed attribute mechanics make frequent use of goto statements.  We can use this
> >> to further simplify xfs_attr_set_iter.  Because states tend to fall between if
> >> conditions, we can invert the if logic and jump to the goto. This helps to reduce
> >> indentation and simplify things.
> >>
> > 
> > I don't see any logical errors.
> > 
> > Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> Alrighty, thanks for the reviews!  I got some feed back in other reviews 
> to move the patches 13 and 14 to the end of the set.  Which means the 
> patches ahead of them may change a bit in order to seat correctly.  For 
> example, this patch will likely go back to being more like it's v6 version:
> 
> https://www.spinics.net/lists/linux-xfs/msg36072.html
> 
> Would you prefer I keep or drop your RVB's in this case?  Functionally 
> they wont change much, but I understand that function is a lot of what 
> your are analyzing too.  Let me know what you are comfortable with.  Thanks!

If functionalilty changes trivally then you can retain my RVBs.

> 
> Allison
> 
> > 
> >> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> >> ---
> >>   fs/xfs/libxfs/xfs_attr.c | 71 ++++++++++++++++++++++++++++--------------------
> >>   1 file changed, 42 insertions(+), 29 deletions(-)
> >>
> >> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >> index 30a16fe..dd935ff 100644
> >> --- a/fs/xfs/libxfs/xfs_attr.c
> >> +++ b/fs/xfs/libxfs/xfs_attr.c
> >> @@ -254,6 +254,19 @@ xfs_attr_try_sf_addname(
> >>   }
> >>   
> >>   /*
> >> + * Check to see if the attr should be upgraded from non-existent or shortform to
> >> + * single-leaf-block attribute list.
> >> + */
> >> +static inline bool
> >> +xfs_attr_fmt_needs_update(
> >> +	struct xfs_inode    *dp)
> >> +{
> >> +	return dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> >> +	      (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> >> +	      dp->i_d.di_anextents == 0);
> >> +}
> >> +
> >> +/*
> >>    * Set the attribute specified in @args.
> >>    */
> >>   int
> >> @@ -342,40 +355,40 @@ xfs_attr_set_iter(
> >>   	}
> >>   
> >>   	/*
> >> -	 * If the attribute list is non-existent or a shortform list,
> >> -	 * upgrade it to a single-leaf-block attribute list.
> >> +	 * If the attribute list is already in leaf format, jump straight to
> >> +	 * leaf handling.  Otherwise, try to add the attribute to the shortform
> >> +	 * list; if there's no room then convert the list to leaf format and try
> >> +	 * again.
> >>   	 */
> >> -	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)) {
> >> +	if (!xfs_attr_fmt_needs_update(dp))
> >> +		goto add_leaf;
> >>   
> >> -		/*
> >> -		 * Try to add the attr to the attribute list in the inode.
> >> -		 */
> >> -		error = xfs_attr_try_sf_addname(dp, args);
> >> +	/*
> >> +	 * Try to add the attr to the attribute list in the inode.
> >> +	 */
> >> +	error = xfs_attr_try_sf_addname(dp, args);
> >>   
> >> -		/* Should only be 0, -EEXIST or ENOSPC */
> >> -		if (error != -ENOSPC)
> >> -			return error;
> >> +	/* Should only be 0, -EEXIST or ENOSPC */
> >> +	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;
> >> +	/*
> >> +	 * 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);
> >> -		args->dac.flags |= XFS_DAC_FINISH_TRANS;
> >> -		args->dac.dela_state = XFS_DAS_ADD_LEAF;
> >> -		return -EAGAIN;
> >> -	}
> >> +	/*
> >> +	 * 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);
> >> +	args->dac.flags |= XFS_DAC_FINISH_TRANS;
> >> +	args->dac.dela_state = XFS_DAS_ADD_LEAF;
> >> +	return -EAGAIN;
> >>   
> >>   add_leaf:
> >>   
> >>
> > 
> > 
> 


-- 
chandan




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

end of thread, other threads:[~2020-03-05  3:36 UTC | newest]

Thread overview: 135+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-23  2:05 [PATCH v7 00/19] xfs: Delayed Ready Attrs Allison Collins
2020-02-23  2:05 ` [PATCH v7 01/19] xfs: Replace attribute parameters with struct xfs_name Allison Collins
2020-02-23  9:34   ` Amir Goldstein
2020-02-23 16:03     ` Allison Collins
2020-02-25  0:49       ` Dave Chinner
2020-02-24 12:08   ` Chandan Rajendra
2020-02-24 16:25     ` Allison Collins
2020-02-24 13:06   ` Brian Foster
2020-02-24 16:25     ` Allison Collins
2020-02-23  2:05 ` [PATCH v7 02/19] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
2020-02-23 11:54   ` Amir Goldstein
2020-02-23 16:51     ` Allison Collins
2020-02-24  6:50       ` Amir Goldstein
2020-02-24  7:36         ` Allison Collins
2020-02-24  7:43           ` Amir Goldstein
2020-02-25  0:57   ` Dave Chinner
2020-02-25  2:00     ` Allison Collins
2020-02-25  4:06       ` Dave Chinner
2020-02-25  4:19         ` Allison Collins
2020-02-25  4:27           ` Darrick J. Wong
2020-02-25  6:07             ` Allison Collins
2020-02-25  6:30               ` Dave Chinner
2020-02-25 17:21             ` Christoph Hellwig
2020-02-25  6:56   ` Chandan Rajendra
2020-02-25 23:26     ` Allison Collins
2020-02-23  2:05 ` [PATCH v7 03/19] xfs: Add xfs_has_attr and subroutines Allison Collins
2020-02-23 12:20   ` Amir Goldstein
2020-02-23 17:28     ` Allison Collins
2020-02-24  6:58       ` Amir Goldstein
2020-02-25  6:26     ` Dave Chinner
2020-02-25  6:43       ` Amir Goldstein
2020-02-25 22:27         ` Dave Chinner
2020-02-24 13:08   ` Brian Foster
2020-02-24 21:18     ` Allison Collins
2020-02-25 13:25       ` Brian Foster
2020-02-26  2:31         ` Allison Collins
2020-02-25  9:49   ` Chandan Rajendra
2020-02-25 10:15     ` Chandan Rajendra
2020-02-26  2:19       ` Allison Collins
2020-02-26  2:18     ` Allison Collins
2020-02-23  2:05 ` [PATCH v7 04/19] xfs: Check for -ENOATTR or -EEXIST Allison Collins
2020-02-23 12:25   ` Amir Goldstein
2020-02-23 17:33     ` Allison Collins
2020-02-24 13:08   ` Brian Foster
2020-02-24 21:18     ` Allison Collins
2020-02-23  2:05 ` [PATCH v7 05/19] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2020-02-25 12:53   ` Chandan Rajendra
2020-02-26  2:20     ` Allison Collins
2020-02-23  2:05 ` [PATCH v7 06/19] xfs: Factor out trans handling in xfs_attr3_leaf_flipflags Allison Collins
2020-02-23 12:30   ` Amir Goldstein
2020-02-23 17:36     ` Allison Collins
2020-02-28  4:56   ` Chandan Rajendra
2020-02-23  2:05 ` [PATCH v7 07/19] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
2020-02-23 12:42   ` Amir Goldstein
2020-02-23 18:38     ` Allison Collins
2020-02-24  6:38       ` Amir Goldstein
2020-02-24  7:09         ` Allison Collins
2020-02-24  7:27           ` Amir Goldstein
2020-02-25  6:42   ` Dave Chinner
2020-02-25 13:26     ` Brian Foster
2020-02-25 23:26     ` Allison Collins
2020-02-28  6:51   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 08/19] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
2020-02-23 13:04   ` Amir Goldstein
2020-02-23 17:51     ` Allison Collins
2020-02-24 13:08   ` Brian Foster
2020-02-24 21:19     ` Allison Collins
2020-02-28  7:42   ` Chandan Rajendra
2020-02-28 18:14     ` Allison Collins
2020-02-23  2:06 ` [PATCH v7 09/19] xfs: Factor out trans roll from xfs_attr3_leaf_setflag Allison Collins
2020-02-28  7:59   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 10/19] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
2020-02-28 10:42   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 11/19] xfs: Factor out trans roll in xfs_attr3_leaf_clearflag Allison Collins
2020-02-28 10:56   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 12/19] xfs: Add helper function xfs_attr_rmtval_unmap Allison Collins
2020-02-24 13:40   ` Brian Foster
2020-02-24 21:44     ` Allison Collins
2020-02-25 13:27       ` Brian Foster
2020-02-26  3:29         ` Allison Collins
2020-02-26 13:47           ` Brian Foster
2020-02-25  7:21   ` Dave Chinner
2020-02-25 23:27     ` Allison Collins
2020-02-28 14:22   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 13/19] xfs: Add delay ready attr remove routines Allison Collins
2020-02-24 15:25   ` Brian Foster
2020-02-24 17:03     ` Brian Foster
2020-02-24 23:14     ` Allison Collins
2020-02-24 23:56       ` Darrick J. Wong
2020-02-25 13:34       ` Brian Foster
2020-02-26  5:36         ` Allison Collins
2020-02-26 13:48           ` Brian Foster
2020-02-26 19:23             ` Allison Collins
2020-02-25  8:57   ` Dave Chinner
2020-02-26  0:57     ` Allison Collins
2020-02-26 22:34       ` Dave Chinner
2020-02-27  4:18         ` Allison Collins
2020-03-03  5:03   ` Chandan Rajendra
2020-03-03  5:40     ` Allison Collins
2020-02-23  2:06 ` [PATCH v7 14/19] xfs: Add delay ready attr set routines Allison Collins
2020-03-03 13:41   ` Chandan Rajendra
2020-03-03 17:07     ` Allison Collins
2020-02-23  2:06 ` [PATCH v7 15/19] xfs: Add helper function xfs_attr_node_shrink Allison Collins
2020-02-23 13:22   ` Amir Goldstein
2020-02-23 18:41     ` Allison Collins
2020-02-25  9:05   ` Dave Chinner
2020-02-26  1:48     ` Allison Collins
2020-02-23  2:06 ` [PATCH v7 16/19] xfs: Simplify xfs_attr_set_iter Allison Collins
2020-02-23 13:26   ` Amir Goldstein
2020-02-23 18:42     ` Allison Collins
2020-02-25  9:21   ` Dave Chinner
2020-02-26  2:13     ` Allison Collins
2020-02-26 22:39       ` Dave Chinner
2020-03-04  4:30   ` Chandan Rajendra
2020-03-04 17:04     ` Allison Collins
2020-03-05  3:39       ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 17/19] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
2020-02-23 13:47   ` Amir Goldstein
2020-02-23 18:43     ` Allison Collins
2020-02-25  9:31   ` Dave Chinner
2020-02-26  2:17     ` Allison Collins
2020-03-04  4:37   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 18/19] xfs: Add remote block helper functions Allison Collins
2020-02-23 13:45   ` Amir Goldstein
2020-03-04  4:59   ` Chandan Rajendra
2020-02-23  2:06 ` [PATCH v7 19/19] xfs: Remove xfs_attr_rmtval_remove Allison Collins
2020-02-23 13:54   ` Amir Goldstein
2020-02-23 18:50     ` Allison Collins
2020-02-23  7:55 ` [PATCH v7 00/19] xfs: Delayed Ready Attrs Amir Goldstein
2020-02-23 16:02   ` Allison Collins
2020-02-24  6:30     ` Amir Goldstein
2020-02-24 16:23       ` Allison Collins
2020-02-25  5:53         ` Amir Goldstein
2020-02-24  8:31   ` Chandan Rajendra
2020-02-25  9:52   ` Dave Chinner

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