All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 00/24] xfs: Delay Ready Attributes
@ 2020-04-30 22:49 Allison Collins
  2020-04-30 22:49 ` [PATCH v9 01/24] xfs: Add xfs_has_attr and subroutines Allison Collins
                   ` (23 more replies)
  0 siblings, 24 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 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 to 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.

To help organize the set, I've arranged 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 4 different phases:

Error code filtering (patches 1-2):
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 internal 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 3-10): 
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: Pull up trans handling in xfs_attr3_leaf_flipflags
   xfs: Split apart xfs_attr_leaf_addname
   xfs: Refactor xfs_attr_try_sf_addname
   xfs: Pull up trans roll from xfs_attr3_leaf_setflag
   xfs: Factor out xfs_attr_rmtval_invalidate
   xfs: Pull up trans roll in xfs_attr3_leaf_clearflag
   xfs: Add helper function __xfs_attr_rmtval_remove

Modularizing and cleanups (patches 11-18):
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: Remove unneeded xfs_trans_roll_inode calls
   xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
   xfs: Add helper function xfs_attr_leaf_mark_incomplete
   xfs: Add remote block helper functions
   xfs: Add helper function xfs_attr_node_removename_setup
   xfs: Add helper function xfs_attr_node_removename_rmt
   xfs: Simplify xfs_attr_leaf_addname
   xfs: Simplify xfs_attr_node_addname
   xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname

Introduce statemachine (patches 18-20):
Now that we have re-arranged the code such that we can remove the transaction
handling, 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
   xfs: Rename __xfs_attr_rmtval_remove


Changes since v8:
Theres a lot of activity that goes around with each set, so to help people
recall the discussion I've outlined the changes for each patch, which are new,
and which are unchanged:

xfs: Add xfs_has_attr and subroutines
  Fixed ENOATTR check
  Inverted error check handler in xfs_attr_node_hasname
  Indentation fixes

xfs: Check for -ENOATTR or -EEXIST
  Removed whitespace

xfs: Factor out new helper functions xfs_attr_rmtval_set
xfs: Pull up trans handling in xfs_attr3_leaf_flipflags
xfs: Split apart xfs_attr_leaf_addname
xfs: Refactor xfs_attr_try_sf_addname
xfs: Pull up trans roll from xfs_attr3_leaf_setflag
xfs: Factor out xfs_attr_rmtval_invalidate
xfs: Pull up trans roll in xfs_attr3_leaf_clearflag
   No change 

xfs: Add helper function __xfs_attr_rmtval_remove
   __xfs_attr_rmtval_remove becomes a helper function of xfs_attr_rmtval_remove
   instead of a new function
   Retain xfs_defer_finish in the helper so that we can replace it with the
   DEFER_FINISH flag later

xfs: Add helper function xfs_attr_leaf_mark_incomplete
   NEW

xfs: Add helper function xfs_attr_node_shrink
   Removed trailing error = 0

xfs: Remove unneeded xfs_trans_roll_inode calls
   More unneeded xfs_defer_finish calls removed
   Commit message verbage fix

xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
   Indentation adjustment
   Fixed comment verbage

xfs: Add helper function xfs_attr_leaf_mark_incomplete
   Simplified error handler

xfs: Add remote block helper functions
   No change

xfs: Add helper function xfs_attr_node_removename_setup
   Move the invalidate addd from new patch 12 into the helper function in this patch

xfs: Add helper function xfs_attr_node_removename_rmt
   Widen comment
   Simplify error handler

xfs: Simplify xfs_attr_leaf_addname
   NEW

xfs: Simplify xfs_attr_node_addname
   NEW

xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
   NEW

xfs: Add delay ready attr remove routines
  Replaced XFS_DAS_RMTVAL_REMOVE state with XFS_DAC_NODE_RMVNAME_INIT flag
  Extra XFS_DAC_DEFER_FINISH set added to __xfs_attr_rmtval_remove
  Temporary XFS_DAC_DEFER_FINISH hander plumbed into xfs_attr_rmtval_remove until we delete it in the next patch
  Simplify xfs_attr_remove_iter with less states to handle
  New helper function xfs_attr_defer_finish
  Indentation fixes
  Comments added to xfs_delattr_context
  Commit message update
  Flow chart update
  Added flow chart to xfs_attr.h

xfs: Add delay ready attr set routines
  Add fork code moved further up the set into parent pointers
  Replace XFS_DAS_ADD_LEAF state with shortform check
  Replace XFS_DAS_LEAF_TO_NODE state with leaf form check
  Replace XFS_DAS_ALLOC_LEAF with XFS_DAC_LEAF_ADDNAME_INIT flag
  Comments added to xfs_delattr_context, some unused feilds removed
  Rebase adjustments
  Flow chart update

xfs: Rename __xfs_attr_rmtval_remove
   Rebase adjustments


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

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

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

In order to run the test cases, you will need have the corresponding xfsprogs
changes as well.  Which can be found here:
https://github.com/allisonhenderson/xfs_work/tree/delay_ready_attrs_xfsprogs_v9
https://github.com/allisonhenderson/xfs_work/tree/delay_ready_attrs_xfsprogs_v9_extended

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


I've also made the corresponding updates to the user space side as well, and ported anything
they need to seat correctly.

Questions, comment and feedback appreciated! 

Thanks all!
Allison


Allison Collins (24):
  xfs: Add xfs_has_attr and subroutines
  xfs: Check for -ENOATTR or -EEXIST
  xfs: Factor out new helper functions xfs_attr_rmtval_set
  xfs: Pull up trans handling in xfs_attr3_leaf_flipflags
  xfs: Split apart xfs_attr_leaf_addname
  xfs: Refactor xfs_attr_try_sf_addname
  xfs: Pull up trans roll from xfs_attr3_leaf_setflag
  xfs: Factor out xfs_attr_rmtval_invalidate
  xfs: Pull up trans roll in xfs_attr3_leaf_clearflag
  xfs: Add helper function __xfs_attr_rmtval_remove
  xfs: Pull up xfs_attr_rmtval_invalidate
  xfs: Add helper function xfs_attr_node_shrink
  xfs: Remove unneeded xfs_trans_roll_inode calls
  xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
  xfs: Add helper function xfs_attr_leaf_mark_incomplete
  xfs: Add remote block helper functions
  xfs: Add helper function xfs_attr_node_removename_setup
  xfs: Add helper function xfs_attr_node_removename_rmt
  xfs: Simplify xfs_attr_leaf_addname
  xfs: Simplify xfs_attr_node_addname
  xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  xfs: Add delay ready attr remove routines
  xfs: Add delay ready attr set routines
  xfs: Rename __xfs_attr_rmtval_remove

 fs/xfs/libxfs/xfs_attr.c        | 1229 ++++++++++++++++++++++++++-------------
 fs/xfs/libxfs/xfs_attr.h        |  199 +++++++
 fs/xfs/libxfs/xfs_attr_leaf.c   |  116 ++--
 fs/xfs/libxfs/xfs_attr_leaf.h   |    3 +
 fs/xfs/libxfs/xfs_attr_remote.c |  259 ++++++---
 fs/xfs/libxfs/xfs_attr_remote.h |    8 +-
 fs/xfs/xfs_attr_inactive.c      |    2 +-
 fs/xfs/xfs_trace.h              |    1 -
 8 files changed, 1281 insertions(+), 536 deletions(-)

-- 
2.7.4


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

* [PATCH v9 01/24] xfs: Add xfs_has_attr and subroutines
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:49 ` [PATCH v9 02/24] xfs: Check for -ENOATTR or -EEXIST Allison Collins
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 UTC (permalink / raw)
  To: linux-xfs

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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 182 ++++++++++++++++++++++++++++--------------
 fs/xfs/libxfs/xfs_attr.h      |   1 +
 fs/xfs/libxfs/xfs_attr_leaf.c |  97 +++++++++++++++-------
 fs/xfs/libxfs/xfs_attr_leaf.h |   3 +
 4 files changed, 191 insertions(+), 92 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e4fe3dc..a1deac6 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);
 
@@ -261,6 +264,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
@@ -469,26 +503,19 @@ 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 (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
 		goto out_brelse;
 	if (retval == -EEXIST) {
@@ -640,6 +667,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
@@ -659,16 +707,14 @@ 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)
-		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
+	error = xfs_attr_leaf_hasname(args, &bp);
+
 	if (error == -ENOATTR) {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
-	}
+	} else if (error != -EEXIST)
+		return error;
 
 	xfs_attr3_leaf_remove(bp, args);
 
@@ -703,21 +749,56 @@ 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)
-		return error;
+	error = xfs_attr_leaf_hasname(args, &bp);
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
-	if (error != -EEXIST)  {
+	if (error == -ENOATTR)  {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
-	}
+	} else if (error != -EEXIST)
+		return error;
+
+
 	error = xfs_attr3_leaf_getvalue(bp, args);
 	xfs_trans_brelse(args->trans, bp);
 	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) {
+		xfs_da_state_free(state);
+		return error;
+	}
+
+	if (statep != NULL)
+		*statep = state;
+	else
+		xfs_da_state_free(state);
+	return retval;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
@@ -750,17 +831,14 @@ xfs_attr_node_addname(
 	dp = args->dp;
 	mp = dp->i_mount;
 restart:
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = mp;
-
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error)
+	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 (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
@@ -965,29 +1043,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.
@@ -1082,7 +1146,8 @@ xfs_attr_node_removename(
 	error = 0;
 
 out:
-	xfs_da_state_free(state);
+	if (state)
+		xfs_da_state_free(state);
 	return error;
 }
 
@@ -1202,31 +1267,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.
@@ -1237,8 +1294,9 @@ xfs_attr_node_get(xfs_da_args_t *args)
 		state->path.blk[i].bp = NULL;
 	}
 
-	xfs_da_state_free(state);
-	return retval;
+	if (state)
+		xfs_da_state_free(state);
+	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 0d2d059..66575b8 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -89,6 +89,7 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_args(struct xfs_da_args *args);
+int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 bool xfs_attr_namecheck(const void *name, size_t length);
 
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 863444e..9f39e7a 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -664,18 +664,63 @@ 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 (!xfs_attr_match(args, sfe->namelen, sfe->nameval,
+				    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);
 
@@ -686,11 +731,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++) {
-		ASSERT(!xfs_attr_match(args, sfe->namelen, sfe->nameval,
-			sfe->flags));
-	}
+	error = xfs_attr_sf_findname(args, &sfe, NULL);
+	ASSERT(error != -EEXIST);
 
 	offset = (char *)sfe - (char *)sf;
 	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
@@ -733,31 +775,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 (xfs_attr_match(args, sfe->namelen, sfe->nameval,
-				sfe->flags))
-			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 6dd2d93..88ec042 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -52,6 +52,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] 76+ messages in thread

* [PATCH v9 02/24] xfs: Check for -ENOATTR or -EEXIST
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
  2020-04-30 22:49 ` [PATCH v9 01/24] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:49 ` [PATCH v9 03/24] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 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>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index a1deac6..5467af6 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -404,6 +404,15 @@ xfs_attr_set(
 				args->total, 0, quota_flags);
 		if (error)
 			goto out_trans_cancel;
+
+		error = xfs_has_attr(args);
+		if (error == -EEXIST && (args->attr_flags & XATTR_CREATE))
+			goto out_trans_cancel;
+		if (error == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
+			goto out_trans_cancel;
+		if (error != -ENOATTR && error != -EEXIST)
+			goto out_trans_cancel;
+
 		error = xfs_attr_set_args(args);
 		if (error)
 			goto out_trans_cancel;
@@ -411,6 +420,10 @@ xfs_attr_set(
 		if (!args->trans)
 			goto out_unlock;
 	} else {
+		error = xfs_has_attr(args);
+		if (error != -EEXIST)
+			goto out_trans_cancel;
+
 		error = xfs_attr_remove_args(args);
 		if (error)
 			goto out_trans_cancel;
-- 
2.7.4


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

* [PATCH v9 03/24] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
  2020-04-30 22:49 ` [PATCH v9 01/24] xfs: Add xfs_has_attr and subroutines Allison Collins
  2020-04-30 22:49 ` [PATCH v9 02/24] xfs: Check for -ENOATTR or -EEXIST Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:49 ` [PATCH v9 04/24] xfs: Pull up trans handling in xfs_attr3_leaf_flipflags Allison Collins
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 01ad7f3..f825eed 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] 76+ messages in thread

* [PATCH v9 04/24] xfs: Pull up trans handling in xfs_attr3_leaf_flipflags
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (2 preceding siblings ...)
  2020-04-30 22:49 ` [PATCH v9 03/24] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:49 ` [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname Allison Collins
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 UTC (permalink / raw)
  To: linux-xfs

Since delayed operations cannot roll transactions, pull 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 5467af6..dcbc475 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -622,6 +622,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
@@ -968,6 +975,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 9f39e7a..ab87bae 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2953,10 +2953,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] 76+ messages in thread

* [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (3 preceding siblings ...)
  2020-04-30 22:49 ` [PATCH v9 04/24] xfs: Pull up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-05-04 17:33   ` Darrick J. Wong
  2020-04-30 22:49 ` [PATCH v9 06/24] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 UTC (permalink / raw)
  To: linux-xfs

Split out new helper function xfs_attr_leaf_try_add from
xfs_attr_leaf_addname. Because new delayed attribute routines cannot
roll transactions, we split 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_attr.c | 94 ++++++++++++++++++++++++++++++------------------
 1 file changed, 60 insertions(+), 34 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index dcbc475..b3b21a7 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -256,10 +256,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;
 }
 
@@ -507,20 +527,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
@@ -562,31 +583,39 @@ 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;
+out_brelse:
+	xfs_trans_brelse(args->trans, bp);
+	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
@@ -681,9 +710,6 @@ xfs_attr_leaf_addname(
 		error = xfs_attr3_leaf_clearflag(args);
 	}
 	return error;
-out_brelse:
-	xfs_trans_brelse(args->trans, bp);
-	return retval;
 }
 
 /*
-- 
2.7.4


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

* [PATCH v9 06/24] xfs: Refactor xfs_attr_try_sf_addname
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (4 preceding siblings ...)
  2020-04-30 22:49 ` [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:49 ` [PATCH v9 07/24] xfs: Pull up trans roll from xfs_attr3_leaf_setflag Allison Collins
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 UTC (permalink / raw)
  To: linux-xfs

To help pre-simplify xfs_attr_set_args, we need to hoist transaction
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: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 b3b21a7..6eda505 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -178,8 +178,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)
@@ -192,12 +197,10 @@ xfs_attr_try_sf_addname(
 	if (!error && !(args->op_flags & XFS_DA_OP_NOTIME))
 		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;
 }
 
 /*
@@ -209,7 +212,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,
@@ -220,17 +223,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] 76+ messages in thread

* [PATCH v9 07/24] xfs: Pull up trans roll from xfs_attr3_leaf_setflag
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (5 preceding siblings ...)
  2020-04-30 22:49 ` [PATCH v9 06/24] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
@ 2020-04-30 22:49 ` Allison Collins
  2020-04-30 22:50 ` [PATCH v9 08/24] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:49 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling transactions so
pull 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 6eda505..f25493c 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1131,6 +1131,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 ab87bae..b588f8e 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2835,10 +2835,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] 76+ messages in thread

* [PATCH v9 08/24] xfs: Factor out xfs_attr_rmtval_invalidate
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (6 preceding siblings ...)
  2020-04-30 22:49 ` [PATCH v9 07/24] xfs: Pull up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-04-30 22:50 ` [PATCH v9 09/24] xfs: Pull up trans roll in xfs_attr3_leaf_clearflag Allison Collins
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 f825eed..4d51969 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] 76+ messages in thread

* [PATCH v9 09/24] xfs: Pull up trans roll in xfs_attr3_leaf_clearflag
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (7 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 08/24] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-04-30 22:50 ` [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling transactions so
pull 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>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.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 f25493c..0fc6436 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -708,6 +708,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;
 }
@@ -1072,6 +1080,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 b588f8e..f55402b 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2784,10 +2784,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] 76+ messages in thread

* [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (8 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 09/24] xfs: Pull up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 13:27   ` Brian Foster
  2020-05-04 17:41   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate Allison Collins
                   ` (13 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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.  This function will eventually replace
xfs_attr_rmtval_remove

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
 fs/xfs/libxfs/xfs_attr_remote.h |  1 +
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 4d51969..02d1a44 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
 	xfs_dablk_t		lblkno;
 	int			blkcnt;
 	int			error = 0;
-	int			done = 0;
+	int			retval = 0;
 
 	trace_xfs_attr_rmtval_remove(args);
 
@@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
 	 */
 	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;
+	do {
+		retval = __xfs_attr_rmtval_remove(args);
+		if (retval && retval != EAGAIN)
+			return retval;
 
 		/*
 		 * Close out trans and start the next one in the chain.
@@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
 		error = xfs_trans_roll_inode(&args->trans, args->dp);
 		if (error)
 			return error;
-	}
+	} while (retval == -EAGAIN);
+
 	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_remove(
+	struct xfs_da_args	*args)
+{
+	int			error, done;
+
+	/*
+	 * Unmap value blocks for this attr.
+	 */
+	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
+			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
+	if (error)
+		return error;
+
+	error = xfs_defer_finish(&args->trans);
+	if (error)
+		return error;
+
+	if (!done)
+		return -EAGAIN;
+
+	return error;
+}
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4


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

* [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (9 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 13:27   ` Brian Foster
  2020-05-04 17:41   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink Allison Collins
                   ` (12 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

This patch pulls xfs_attr_rmtval_invalidate out of
xfs_attr_rmtval_remove and into the calling functions.  Eventually
__xfs_attr_rmtval_remove will replace xfs_attr_rmtval_remove when we
introduce delayed attributes.  These functions are exepcted to return
-EAGAIN when they need a new transaction.  Because the invalidate does
not need a new transaction, we need to separate it from the rest of the
function that does.  This will enable __xfs_attr_rmtval_remove to
smoothly replace xfs_attr_rmtval_remove later.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c        | 12 ++++++++++++
 fs/xfs/libxfs/xfs_attr_remote.c |  3 ---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 0fc6436..4fdfab9 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -669,6 +669,10 @@ xfs_attr_leaf_addname(
 		args->rmtblkcnt = args->rmtblkcnt2;
 		args->rmtvaluelen = args->rmtvaluelen2;
 		if (args->rmtblkno) {
+			error = xfs_attr_rmtval_invalidate(args);
+			if (error)
+				return error;
+
 			error = xfs_attr_rmtval_remove(args);
 			if (error)
 				return error;
@@ -1027,6 +1031,10 @@ xfs_attr_node_addname(
 		args->rmtblkcnt = args->rmtblkcnt2;
 		args->rmtvaluelen = args->rmtvaluelen2;
 		if (args->rmtblkno) {
+			error = xfs_attr_rmtval_invalidate(args);
+			if (error)
+				return error;
+
 			error = xfs_attr_rmtval_remove(args);
 			if (error)
 				return error;
@@ -1152,6 +1160,10 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 
+		error = xfs_attr_rmtval_invalidate(args);
+		if (error)
+			return error;
+
 		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			goto out;
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 02d1a44..f770159 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -685,9 +685,6 @@ xfs_attr_rmtval_remove(
 
 	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.
 	 */
-- 
2.7.4


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

* [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (10 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 13:27   ` Brian Foster
  2020-05-04 17:42   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls Allison Collins
                   ` (11 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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 | 68 ++++++++++++++++++++++++++++++------------------
 1 file changed, 42 insertions(+), 26 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 4fdfab9..d83443c 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1108,6 +1108,45 @@ 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;
+
+		error = xfs_defer_finish(&args->trans);
+		if (error)
+			return error;
+	} 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
@@ -1120,8 +1159,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);
@@ -1206,30 +1244,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] 76+ messages in thread

* [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (11 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 13:30   ` Brian Foster
  2020-04-30 22:50 ` [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform Allison Collins
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

Some calls to xfs_trans_roll_inode and xfs_defer_finish routines are not
needed. If they are the last operations executed in these functions, and
no further changes are made, then higher level routines will roll or
commit the tranactions. The xfs_trans_roll in _removename is also not
needed because invalidating blocks is an incore-only change.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index d83443c..af47566 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -697,16 +697,8 @@ xfs_attr_leaf_addname(
 			/* 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);
-
 	} else if (args->rmtblkno > 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
@@ -714,12 +706,6 @@ xfs_attr_leaf_addname(
 		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;
 }
@@ -784,9 +770,6 @@ xfs_attr_leaf_removename(
 		/* bp is gone due to xfs_da_shrink_inode */
 		if (error)
 			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
 	}
 	return 0;
 }
@@ -1074,13 +1057,6 @@ xfs_attr_node_addname(
 				goto out;
 		}
 
-		/*
-		 * Commit and start the next trans in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			goto out;
-
 	} else if (args->rmtblkno > 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
@@ -1088,14 +1064,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;
 
@@ -1136,10 +1104,6 @@ xfs_attr_node_shrink(
 		/* bp is gone due to xfs_da_shrink_inode */
 		if (error)
 			return error;
-
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
 	} else
 		xfs_trans_brelse(args->trans, bp);
 
@@ -1194,10 +1158,6 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			goto out;
-
 		error = xfs_attr_rmtval_invalidate(args);
 		if (error)
 			return error;
-- 
2.7.4


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

* [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (12 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 18:46   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

In this patch, we hoist code from xfs_attr_set_args into two new helpers
xfs_attr_is_shortform and xfs_attr_set_shortform.  These two will help
to simplify xfs_attr_set_args when we get into delayed attrs later.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_attr.c | 107 +++++++++++++++++++++++++++++++----------------
 1 file changed, 72 insertions(+), 35 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index af47566..d112910 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -204,6 +204,66 @@ 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_is_shortform(
+	struct xfs_inode    *ip)
+{
+	return ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+	       (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+	        ip->i_d.di_anextents == 0);
+}
+
+/*
+ * Attempts to set an attr in shortform, or converts short form to leaf form if
+ * there is not enough room.  If the attr is set, the transaction is committed
+ * and set to NULL.
+ */
+STATIC int
+xfs_attr_set_shortform(
+	struct xfs_da_args	*args,
+	struct xfs_buf		**leaf_bp)
+{
+	struct xfs_inode	*dp = args->dp;
+	int			error, error2 = 0;
+
+	/*
+	 * 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;
+	}
+	/*
+	 * 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. 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;
+	}
+
+	return 0;
+}
+
+/*
  * Set the attribute specified in @args.
  */
 int
@@ -212,48 +272,25 @@ xfs_attr_set_args(
 {
 	struct xfs_inode	*dp = args->dp;
 	struct xfs_buf          *leaf_bp = NULL;
-	int			error, error2 = 0;
+	int			error = 0;
 
 	/*
-	 * 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_is_shortform(dp)) {
 
 		/*
-		 * Try to add the attr to the attribute list in the inode.
+		 * If the attr was successfully set in shortform, the
+		 * transaction is committed and set to NULL.  Otherwise, is it
+		 * converted from shortform to leaf, and the transaction is
+		 * retained.
 		 */
-		error = xfs_attr_try_sf_addname(dp, args);
-		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.
-		 * 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.
-		 * 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);
+		error = xfs_attr_set_shortform(args, &leaf_bp);
+		if (error || !args->trans)
 			return error;
-		}
 	}
 
 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-- 
2.7.4


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

* [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (13 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 18:47   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 16/24] xfs: Add remote block helper functions Allison Collins
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c | 41 +++++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index d112910..df77a3c 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1148,6 +1148,32 @@ 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
+	 */
+	return xfs_attr3_leaf_setflag(args);
+}
+
+/*
  * Remove a name from a B-tree attribute list.
  *
  * This will involve walking down the Btree, and may involve joining
@@ -1178,20 +1204,7 @@ xfs_attr_node_removename(
 	ASSERT(blk->bp != NULL);
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 	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] 76+ messages in thread

* [PATCH v9 16/24] xfs: Add remote block helper functions
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (14 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 18:55   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup Allison Collins
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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 redundant
code associated with storing and retrieving remote blocks during the
attr set operations.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c | 50 +++++++++++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index df77a3c..feae122 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -563,6 +563,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_save_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
  *
@@ -597,11 +621,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_save_rmt_blk(args);
 
 		/*
 		 * clear the remote attr state now that it is saved so that the
@@ -700,11 +720,8 @@ 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);
+
 		if (args->rmtblkno) {
 			error = xfs_attr_rmtval_invalidate(args);
 			if (error)
@@ -929,11 +946,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_save_rmt_blk(args);
 
 		/*
 		 * clear the remote attr state now that it is saved so that the
@@ -1045,11 +1058,8 @@ 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);
+
 		if (args->rmtblkno) {
 			error = xfs_attr_rmtval_invalidate(args);
 			if (error)
-- 
2.7.4


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

* [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (15 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 16/24] xfs: Add remote block helper functions Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 18:58   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt Allison Collins
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new helper function xfs_attr_node_removename_setup.
This will help modularize xfs_attr_node_removename when we add delay
ready attributes later.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_attr.c | 48 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index feae122..c8226c6 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1184,6 +1184,39 @@ xfs_attr_leaf_mark_incomplete(
 }
 
 /*
+ * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
+ * the blocks are valid.  Any remote blocks will be marked incomplete.
+ */
+STATIC
+int xfs_attr_node_removename_setup(
+	struct xfs_da_args	*args,
+	struct xfs_da_state	**state)
+{
+	int			error;
+	struct xfs_da_state_blk	*blk;
+
+	error = xfs_attr_node_hasname(args, state);
+	if (error != -EEXIST)
+		return error;
+
+	blk = &(*state)->path.blk[(*state)->path.active - 1];
+	ASSERT(blk->bp != NULL);
+	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+
+	if (args->rmtblkno > 0) {
+		error = xfs_attr_leaf_mark_incomplete(args, *state);
+		if (error)
+			return error;
+
+		error = xfs_attr_rmtval_invalidate(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
@@ -1201,8 +1234,8 @@ xfs_attr_node_removename(
 
 	trace_xfs_attr_node_removename(args);
 
-	error = xfs_attr_node_hasname(args, &state);
-	if (error != -EEXIST)
+	error = xfs_attr_node_removename_setup(args, &state);
+	if (error)
 		goto out;
 
 	/*
@@ -1210,18 +1243,7 @@ xfs_attr_node_removename(
 	 * This is done before we remove the attribute so that we don't
 	 * overflow the maximum size of a transaction and/or hit a deadlock.
 	 */
-	blk = &state->path.blk[ state->path.active-1 ];
-	ASSERT(blk->bp != NULL);
-	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_leaf_mark_incomplete(args, state);
-		if (error)
-			goto out;
-
-		error = xfs_attr_rmtval_invalidate(args);
-		if (error)
-			return error;
-
 		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			goto out;
-- 
2.7.4


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

* [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (16 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:00   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname Allison Collins
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

This patch adds another new helper function
xfs_attr_node_removename_rmt. This will also help modularize
xfs_attr_node_removename when we add delay ready attributes later.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_attr.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index c8226c6..ab1c9fa 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1216,6 +1216,24 @@ int xfs_attr_node_removename_setup(
 	return 0;
 }
 
+STATIC int
+xfs_attr_node_removename_rmt (
+	struct xfs_da_args	*args,
+	struct xfs_da_state	*state)
+{
+	int			error = 0;
+
+	error = xfs_attr_rmtval_remove(args);
+	if (error)
+		return error;
+
+	/*
+	 * Refill the state structure with buffers, the prior calls released our
+	 * buffers.
+	 */
+	return xfs_attr_refillstate(state);
+}
+
 /*
  * Remove a name from a B-tree attribute list.
  *
@@ -1244,15 +1262,7 @@ xfs_attr_node_removename(
 	 * overflow the maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_remove(args);
-		if (error)
-			goto out;
-
-		/*
-		 * Refill the state structure with buffers, the prior calls
-		 * released our buffers.
-		 */
-		error = xfs_attr_refillstate(state);
+		error = xfs_attr_node_removename_rmt(args, state);
 		if (error)
 			goto out;
 	}
-- 
2.7.4


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

* [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (17 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:03   ` Darrick J. Wong
  2020-05-05 13:11   ` Brian Foster
  2020-04-30 22:50 ` [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname Allison Collins
                   ` (4 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

Quick patch to unnest the rename logic in the leaf code path.  This will
help simplify delayed attr logic later.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index ab1c9fa..1810f90 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -694,73 +694,71 @@ xfs_attr_leaf_addname(
 			return error;
 	}
 
-	/*
-	 * If this is an atomic rename operation, we must "flip" the
-	 * incomplete flags on the "new" and "old" attribute/value pairs
-	 * so that one disappears and one appears atomically.  Then we
-	 * must remove the "old" attribute/value pair.
-	 */
-	if (args->op_flags & XFS_DA_OP_RENAME) {
+	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
 		/*
-		 * In a separate transaction, set the incomplete flag on the
-		 * "old" attr and clear the incomplete flag on the "new" attr.
-		 */
-		error = xfs_attr3_leaf_flipflags(args);
-		if (error)
-			return error;
-		/*
-		 * Commit the flag value change and start the next trans in
-		 * series.
+		 * Added a "remote" value, just clear the incomplete flag.
 		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			return error;
+		if (args->rmtblkno > 0)
+			error = xfs_attr3_leaf_clearflag(args);
 
-		/*
-		 * Dismantle the "old" attribute/value pair by removing
-		 * a "remote" value (if it exists).
-		 */
-		xfs_attr_restore_rmt_blk(args);
+		return error;
+	}
 
-		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_invalidate(args);
-			if (error)
-				return error;
+	/*
+	 * If this is an atomic rename operation, we must "flip" the incomplete
+	 * flags on the "new" and "old" attribute/value pairs so that one
+	 * disappears and one appears atomically.  Then we must remove the "old"
+	 * attribute/value pair.
+	 *
+	 * In a separate transaction, set the incomplete flag on the "old" attr
+	 * and clear the incomplete flag on the "new" attr.
+	 */
 
-			error = xfs_attr_rmtval_remove(args);
-			if (error)
-				return error;
-		}
+	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;
 
-		/*
-		 * Read in the block containing the "old" attr, then
-		 * remove the "old" attr from that block (neat, huh!)
-		 */
-		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-					   &bp);
+	/*
+	 * Dismantle the "old" attribute/value pair by removing a "remote" value
+	 * (if it exists).
+	 */
+	xfs_attr_restore_rmt_blk(args);
+
+	if (args->rmtblkno) {
+		error = xfs_attr_rmtval_invalidate(args);
 		if (error)
 			return error;
 
-		xfs_attr3_leaf_remove(bp, args);
-
-		/*
-		 * If the result is small enough, shrink it all into the inode.
-		 */
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
-			/* bp is gone due to xfs_da_shrink_inode */
-			if (error)
-				return error;
-		}
-
-	} else if (args->rmtblkno > 0) {
-		/*
-		 * Added a "remote" value, just clear the incomplete flag.
-		 */
-		error = xfs_attr3_leaf_clearflag(args);
+		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			return error;
 	}
+
+	/*
+	 * Read in the block containing the "old" attr, then remove the "old"
+	 * attr from that block (neat, huh!)
+	 */
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				   &bp);
+	if (error)
+		return error;
+
+	xfs_attr3_leaf_remove(bp, args);
+
+	/*
+	 * If the result is small enough, shrink it all into the inode.
+	 */
+	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 */
+
 	return error;
 }
 
-- 
2.7.4


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

* [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (18 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:06   ` Darrick J. Wong
  2020-05-05 13:12   ` Brian Foster
  2020-04-30 22:50 ` [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname Allison Collins
                   ` (3 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

Quick patch to unnest the rename logic in the node code path.  This will
help simplify delayed attr logic later.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 1810f90..9171895 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1030,83 +1030,80 @@ xfs_attr_node_addname(
 			return error;
 	}
 
-	/*
-	 * If this is an atomic rename operation, we must "flip" the
-	 * incomplete flags on the "new" and "old" attribute/value pairs
-	 * so that one disappears and one appears atomically.  Then we
-	 * must remove the "old" attribute/value pair.
-	 */
-	if (args->op_flags & XFS_DA_OP_RENAME) {
-		/*
-		 * In a separate transaction, set the incomplete flag on the
-		 * "old" attr and clear the incomplete flag on the "new" attr.
-		 */
-		error = xfs_attr3_leaf_flipflags(args);
-		if (error)
-			goto out;
+	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
 		/*
-		 * Commit the flag value change and start the next trans in
-		 * series
+		 * Added a "remote" value, just clear the incomplete flag.
 		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			goto out;
+		if (args->rmtblkno > 0)
+			error = xfs_attr3_leaf_clearflag(args);
+		retval = error;
+		goto out;
+	}
 
-		/*
-		 * Dismantle the "old" attribute/value pair by removing
-		 * a "remote" value (if it exists).
-		 */
-		xfs_attr_restore_rmt_blk(args);
+	/*
+	 * If this is an atomic rename operation, we must "flip" the incomplete
+	 * flags on the "new" and "old" attribute/value pairs so that one
+	 * disappears and one appears atomically.  Then we must remove the "old"
+	 * attribute/value pair.
+	 *
+	 * In a separate transaction, set the incomplete flag on the "old" attr
+	 * and clear the incomplete flag on the "new" attr.
+	 */
+	error = xfs_attr3_leaf_flipflags(args);
+	if (error)
+		goto out;
+	/*
+	 * Commit the flag value change and start the next trans in series
+	 */
+	error = xfs_trans_roll_inode(&args->trans, args->dp);
+	if (error)
+		goto out;
 
-		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_invalidate(args);
-			if (error)
-				return error;
+	/*
+	 * Dismantle the "old" attribute/value pair by removing a "remote" value
+	 * (if it exists).
+	 */
+	xfs_attr_restore_rmt_blk(args);
 
-			error = xfs_attr_rmtval_remove(args);
-			if (error)
-				return error;
-		}
+	if (args->rmtblkno) {
+		error = xfs_attr_rmtval_invalidate(args);
+		if (error)
+			return error;
 
-		/*
-		 * Re-find the "old" attribute entry after any split ops.
-		 * The INCOMPLETE flag means that we will find the "old"
-		 * attr, not the "new" one.
-		 */
-		args->attr_filter |= XFS_ATTR_INCOMPLETE;
-		state = xfs_da_state_alloc();
-		state->args = args;
-		state->mp = mp;
-		state->inleaf = 0;
-		error = xfs_da3_node_lookup_int(state, &retval);
+		error = xfs_attr_rmtval_remove(args);
 		if (error)
-			goto out;
+			return error;
+	}
 
-		/*
-		 * Remove the name and update the hashvals in the tree.
-		 */
-		blk = &state->path.blk[ state->path.active-1 ];
-		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
-		error = xfs_attr3_leaf_remove(blk->bp, args);
-		xfs_da3_fixhashpath(state, &state->path);
+	/*
+	 * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
+	 * flag means that we will find the "old" attr, not the "new" one.
+	 */
+	args->attr_filter |= XFS_ATTR_INCOMPLETE;
+	state = xfs_da_state_alloc();
+	state->args = args;
+	state->mp = mp;
+	state->inleaf = 0;
+	error = xfs_da3_node_lookup_int(state, &retval);
+	if (error)
+		goto out;
 
-		/*
-		 * Check to see if the tree needs to be collapsed.
-		 */
-		if (retval && (state->path.active > 1)) {
-			error = xfs_da3_join(state);
-			if (error)
-				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
-		}
+	/*
+	 * Remove the name and update the hashvals in the tree.
+	 */
+	blk = &state->path.blk[state->path.active-1];
+	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+	error = xfs_attr3_leaf_remove(blk->bp, args);
+	xfs_da3_fixhashpath(state, &state->path);
 
-	} else if (args->rmtblkno > 0) {
-		/*
-		 * Added a "remote" value, just clear the incomplete flag.
-		 */
-		error = xfs_attr3_leaf_clearflag(args);
+	/*
+	 * Check to see if the tree needs to be collapsed.
+	 */
+	if (retval && (state->path.active > 1)) {
+		error = xfs_da3_join(state);
+		if (error)
+			goto out;
+		error = xfs_defer_finish(&args->trans);
 		if (error)
 			goto out;
 	}
-- 
2.7.4


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

* [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (19 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:10   ` Darrick J. Wong
  2020-05-05 13:12   ` Brian Foster
  2020-04-30 22:50 ` [PATCH v9 22/24] xfs: Add delay ready attr remove routines Allison Collins
                   ` (2 subsequent siblings)
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

Lift -ENOSPC handler from xfs_attr_leaf_addname.  This will help to
reorganize transitions between the attr forms later.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 9171895..c8cae68 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -299,6 +299,13 @@ xfs_attr_set_args(
 			return error;
 
 		/*
+		 * Promote the attribute list to the Btree format.
+		 */
+		error = xfs_attr3_leaf_to_node(args);
+		if (error)
+			return error;
+
+		/*
 		 * Commit that transaction so that the node_addname()
 		 * call can manage its own transactions.
 		 */
@@ -602,7 +609,7 @@ xfs_attr_leaf_try_add(
 	struct xfs_da_args	*args,
 	struct xfs_buf		*bp)
 {
-	int			retval, error;
+	int			retval;
 
 	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
@@ -634,20 +641,10 @@ xfs_attr_leaf_try_add(
 	}
 
 	/*
-	 * Add the attribute to the leaf block, transitioning to a Btree
-	 * if required.
+	 * Add the attribute to the leaf block
 	 */
-	retval = xfs_attr3_leaf_add(bp, args);
-	if (retval == -ENOSPC) {
-		/*
-		 * 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;
-	}
-	return retval;
+	return xfs_attr3_leaf_add(bp, args);
+
 out_brelse:
 	xfs_trans_brelse(args->trans, bp);
 	return retval;
-- 
2.7.4


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

* [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (20 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:33   ` Darrick J. Wong
  2020-05-07 11:54   ` Brian Foster
  2020-04-30 22:50 ` [PATCH v9 23/24] xfs: Add delay ready attr set routines Allison Collins
  2020-04-30 22:50 ` [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove Allison Collins
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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.  A new XFS_DAC_DEFER_FINISH flag is used to finish the
transaction where ever the existing code used to.

Calls to xfs_attr_rmtval_remove are replaced with the delay ready
version __xfs_attr_rmtval_remove. We will rename
__xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
done.

xfs_attr_rmtval_remove itself is still in use by the set routines (used
during a rename).  For reasons of perserving existing function, we
modify xfs_attr_rmtval_remove to call xfs_defer_finish when the flag is
set.  Similar to how xfs_attr_remove_args does here.  Once we transition
the set routines to be delay ready, xfs_attr_rmtval_remove is no longer
used and will be removed.

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_attr_node_removename()
                                                 │
                                                 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        | 159 ++++++++++++++++++++++++++++++----------
 fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
 fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
 fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
 fs/xfs/xfs_attr_inactive.c      |   2 +-
 6 files changed, 215 insertions(+), 54 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index c8cae68..7213589 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -53,12 +53,21 @@ STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
  */
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
-STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
 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);
 
+void
+xfs_delattr_context_init(
+	struct xfs_delattr_context	*dac,
+	struct xfs_da_args		*args)
+{
+	memset(dac, 0, sizeof(struct xfs_delattr_context));
+	dac->da_args = args;
+}
+
 int
 xfs_inode_hasattr(
 	struct xfs_inode	*ip)
@@ -263,6 +272,18 @@ xfs_attr_set_shortform(
 	return 0;
 }
 
+int xfs_attr_defer_finish(
+	struct xfs_delattr_context      *dac)
+{
+	struct xfs_da_args              *args = dac->da_args;
+
+	if (!(dac->flags & XFS_DAC_DEFER_FINISH))
+		return 0;
+
+	dac->flags &= ~XFS_DAC_DEFER_FINISH;
+	return xfs_defer_finish(&args->trans);
+}
+
 /*
  * Set the attribute specified in @args.
  */
@@ -363,23 +384,57 @@ xfs_has_attr(
  */
 int
 xfs_attr_remove_args(
-	struct xfs_da_args      *args)
+	struct xfs_da_args	*args)
+{
+	int			error = 0;
+	struct			xfs_delattr_context dac;
+
+	xfs_delattr_context_init(&dac, args);
+
+	do {
+		error = xfs_attr_remove_iter(&dac);
+		if (error != -EAGAIN)
+			break;
+
+		error = xfs_attr_defer_finish(&dac);
+		if (error)
+			break;
+
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			break;
+	} while (true);
+
+	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_delattr_context *dac)
 {
+	struct xfs_da_args	*args = dac->da_args;
 	struct xfs_inode	*dp = args->dp;
-	int			error;
+
+	if (dac->dela_state == XFS_DAS_RM_SHRINK)
+		goto node;
 
 	if (!xfs_inode_hasattr(dp)) {
-		error = -ENOATTR;
+		return -ENOATTR;
 	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
-		error = xfs_attr_shortform_remove(args);
+		return xfs_attr_shortform_remove(args);
 	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_removename(args);
-	} else {
-		error = xfs_attr_node_removename(args);
+		return xfs_attr_leaf_removename(args);
 	}
-
-	return error;
+node:
+	return  xfs_attr_node_removename(dac);
 }
 
 /*
@@ -1177,15 +1232,17 @@ xfs_attr_leaf_mark_incomplete(
 
 /*
  * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
- * the blocks are valid.  Any remote blocks will be marked incomplete.
+ * the blocks are valid.  Any remote blocks will be marked incomplete and
+ * invalidated.
  */
 STATIC
 int xfs_attr_node_removename_setup(
-	struct xfs_da_args	*args,
-	struct xfs_da_state	**state)
+	struct xfs_delattr_context	*dac,
+	struct xfs_da_state		**state)
 {
-	int			error;
-	struct xfs_da_state_blk	*blk;
+	struct xfs_da_args		*args = dac->da_args;
+	int				error;
+	struct xfs_da_state_blk		*blk;
 
 	error = xfs_attr_node_hasname(args, state);
 	if (error != -EEXIST)
@@ -1195,6 +1252,13 @@ int xfs_attr_node_removename_setup(
 	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
+	 */
+	dac->blk = blk;
+	dac->da_state = *state;
+
 	if (args->rmtblkno > 0) {
 		error = xfs_attr_leaf_mark_incomplete(args, *state);
 		if (error)
@@ -1210,12 +1274,15 @@ int xfs_attr_node_removename_setup(
 
 STATIC int
 xfs_attr_node_removename_rmt (
-	struct xfs_da_args	*args,
-	struct xfs_da_state	*state)
+	struct xfs_delattr_context	*dac,
+	struct xfs_da_state		*state)
 {
-	int			error = 0;
+	int				error = 0;
 
-	error = xfs_attr_rmtval_remove(args);
+	/*
+	 * May return -EAGAIN to request that the caller recall this function
+	 */
+	error = __xfs_attr_rmtval_remove(dac);
 	if (error)
 		return error;
 
@@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
  * 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(
-	struct xfs_da_args	*args)
+	struct xfs_delattr_context	*dac)
 {
-	struct xfs_da_state	*state;
-	struct xfs_da_state_blk	*blk;
-	int			retval, error;
-	struct xfs_inode	*dp = args->dp;
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_da_state		*state;
+	struct xfs_da_state_blk		*blk;
+	int				retval, error;
+	struct xfs_inode		*dp = args->dp;
 
 	trace_xfs_attr_node_removename(args);
+	state = dac->da_state;
+	blk = dac->blk;
 
-	error = xfs_attr_node_removename_setup(args, &state);
-	if (error)
-		goto out;
+	if (dac->dela_state == XFS_DAS_RM_SHRINK)
+		goto das_rm_shrink;
+
+	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
+		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
+		error = xfs_attr_node_removename_setup(dac, &state);
+		if (error)
+			goto out;
+	}
 
 	/*
 	 * If there is an out-of-line value, de-allocate the blocks.
@@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
 	 * overflow the maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_node_removename_rmt(args, state);
-		if (error)
+		/*
+		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
+		 */
+		error = xfs_attr_node_removename_rmt(dac, state);
+		if (error == -EAGAIN)
+			return error;
+		else if (error)
 			goto out;
 	}
 
@@ -1274,17 +1360,14 @@ 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;
+
+		dac->flags |= XFS_DAC_DEFER_FINISH;
+		dac->dela_state = XFS_DAS_RM_SHRINK;
+		return -EAGAIN;
 	}
 
+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 66575b8..0430c79 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -74,6 +74,75 @@ struct xfs_attr_list_context {
 };
 
 
+/*
+ * ========================================================================
+ * Structure used to pass context around among the delayed routines.
+ * ========================================================================
+ */
+
+/*
+ * 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_attr_node_removename()
+ *	                                      │
+ *	                                      v
+ *	                                   need to
+ *	                                shrink tree? ─n─┐
+ *	                                      │         │
+ *	                                      y         │
+ *	                                      │         │
+ *	                                      v         │
+ *	                              XFS_DAS_RM_SHRINK │
+ *	                                      │         │
+ *	                                      v         │
+ *	                                     done <─────┘
+ *
+ */
+
+/*
+ * 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 {
+				      /* Zero is uninitalized */
+	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
+};
+
+/*
+ * Defines for xfs_delattr_context.flags
+ */
+#define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
+#define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
+
+/*
+ * Context used for keeping track of delayed attribute operations
+ */
+struct xfs_delattr_context {
+	struct xfs_da_args      *da_args;
+
+	/* Used in xfs_attr_node_removename to roll through removing blocks */
+	struct xfs_da_state     *da_state;
+	struct xfs_da_state_blk *blk;
+
+	/* Used to keep track of current state of delayed operation */
+	unsigned int            flags;
+	enum xfs_delattr_state  dela_state;
+};
+
 /*========================================================================
  * Function prototypes for the kernel.
  *========================================================================*/
@@ -91,6 +160,10 @@ int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_args(struct xfs_da_args *args);
 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_delattr_context *dac);
+int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
 bool xfs_attr_namecheck(const void *name, size_t length);
+void xfs_delattr_context_init(struct xfs_delattr_context *dac,
+			      struct xfs_da_args *args);
 
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index f55402b..2e36c8b 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -19,8 +19,8 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_attr_sf.h"
-#include "xfs_attr_remote.h"
 #include "xfs_attr.h"
+#include "xfs_attr_remote.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index f770159..f2d46c7 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -676,14 +676,16 @@ xfs_attr_rmtval_invalidate(
  */
 int
 xfs_attr_rmtval_remove(
-	struct xfs_da_args      *args)
+	struct xfs_da_args		*args)
 {
-	xfs_dablk_t		lblkno;
-	int			blkcnt;
-	int			error = 0;
-	int			retval = 0;
+	struct xfs_delattr_context	dac;
+	xfs_dablk_t			lblkno;
+	int				blkcnt;
+	int				error = 0;
+	int				retval = 0;
 
 	trace_xfs_attr_rmtval_remove(args);
+	xfs_delattr_context_init(&dac, args);
 
 	/*
 	 * Keep de-allocating extents until the remote-value region is gone.
@@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
 	lblkno = args->rmtblkno;
 	blkcnt = args->rmtblkcnt;
 	do {
-		retval = __xfs_attr_rmtval_remove(args);
+		retval = __xfs_attr_rmtval_remove(&dac);
 		if (retval && retval != EAGAIN)
 			return retval;
 
+		error = xfs_attr_defer_finish(&dac);
+		if (error)
+			break;
+
 		/*
 		 * Close out trans and start the next one in the chain.
 		 */
@@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
  */
 int
 __xfs_attr_rmtval_remove(
-	struct xfs_da_args	*args)
+	struct xfs_delattr_context	*dac)
 {
-	int			error, done;
+	struct xfs_da_args		*args = dac->da_args;
+	int				error, done;
 
 	/*
 	 * Unmap value blocks for this attr.
@@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
 	if (error)
 		return error;
 
-	error = xfs_defer_finish(&args->trans);
-	if (error)
-		return error;
-
-	if (!done)
+	if (!done) {
+		dac->flags &= ~XFS_DAC_DEFER_FINISH;
 		return -EAGAIN;
+	}
 
 	return error;
 }
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index ee3337b..351da00 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -14,5 +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_remove(struct xfs_da_args *args);
+int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
 #endif /* __XFS_ATTR_REMOTE_H__ */
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
index c42f90e..b2150fa 100644
--- a/fs/xfs/xfs_attr_inactive.c
+++ b/fs/xfs/xfs_attr_inactive.c
@@ -15,10 +15,10 @@
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
+#include "xfs_attr.h"
 #include "xfs_attr_remote.h"
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
-#include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_quota.h"
 #include "xfs_dir2.h"
-- 
2.7.4


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

* [PATCH v9 23/24] xfs: Add delay ready attr set routines
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (21 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 22/24] xfs: Add delay ready attr remove routines Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:49   ` Darrick J. Wong
  2020-05-04 22:36   ` Darrick J. Wong
  2020-04-30 22:50 ` [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove Allison Collins
  23 siblings, 2 replies; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 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.

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. xfs_attr_set_args has
now become a simple loop to refresh the transaction until the operation
is completed.  Lastly, xfs_attr_rmtval_remove is no longer used, and is
removed.

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
  ┌──────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_attr_leaf_addname()
  │                                              │
  │                                              v
  │                                            was this
  │                                           a rename? ──n─┐
  │                                              │          │
  │                                              y          │
  │                                              │          │
  │                                              v          │
  │                                        flip incomplete  │
  │                                            flag         │
  │                                              │          │
  │                                              v          │
  │                                      XFS_DAS_FLIP_LFLAG │
  │                                              │          │
  │                                              v          │
  │                                            remove       │
  │                        XFS_DAS_RM_LBLK ─> old name      │
  │                                 ^            │          │
  │                                 │            v          │
  │                                 └──────y── more to      │
  │                                            remove       │
  │                                              │          │
  │                                              n          │
  │                                              │          │
  │                                              v          │
  │                                             done <──────┘
  └────> 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       │
                           XFS_DAS_RM_NBLK ─> 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        | 371 +++++++++++++++++++++++++++-------------
 fs/xfs/libxfs/xfs_attr.h        | 127 +++++++++++++-
 fs/xfs/libxfs/xfs_attr_remote.c | 110 +++++++-----
 fs/xfs/libxfs/xfs_attr_remote.h |   4 +
 fs/xfs/xfs_trace.h              |   1 -
 5 files changed, 445 insertions(+), 168 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7213589..0751231 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -44,7 +44,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
  * Internal routines when attribute list is one block.
  */
 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_addname(struct xfs_delattr_context *dac);
 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);
 
@@ -52,12 +52,13 @@ 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.
  */
 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_addname(struct xfs_delattr_context *dac);
 STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
 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);
 
 void
 xfs_delattr_context_init(
@@ -227,8 +228,11 @@ xfs_attr_is_shortform(
 
 /*
  * Attempts to set an attr in shortform, or converts short form to leaf form if
- * there is not enough room.  If the attr is set, the transaction is committed
- * and set to NULL.
+ * there is not enough room.  This function is meant to operate as a helper
+ * routine to the delayed attribute functions.  It returns -EAGAIN to indicate
+ * that the calling function should roll the transaction, and then proceed to
+ * add the attr in leaf form.  This subroutine does not expect to be recalled
+ * again like the other delayed attr routines do.
  */
 STATIC int
 xfs_attr_set_shortform(
@@ -236,16 +240,16 @@ xfs_attr_set_shortform(
 	struct xfs_buf		**leaf_bp)
 {
 	struct xfs_inode	*dp = args->dp;
-	int			error, error2 = 0;
+	int			error = 0;
 
 	/*
 	 * 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) {
-		error2 = xfs_trans_commit(args->trans);
-		args->trans = NULL;
-		return error ? error : error2;
+		return error;
 	}
 	/*
 	 * It won't fit in the shortform, transform to a leaf block.  GROT:
@@ -258,20 +262,13 @@ xfs_attr_set_shortform(
 	/*
 	 * 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.
+	 * with the write verifier.
 	 */
 	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;
-	}
-
-	return 0;
+	return -EAGAIN;
 }
 
+STATIC
 int xfs_attr_defer_finish(
 	struct xfs_delattr_context      *dac)
 {
@@ -291,60 +288,128 @@ int
 xfs_attr_set_args(
 	struct xfs_da_args	*args)
 {
-	struct xfs_inode	*dp = args->dp;
-	struct xfs_buf          *leaf_bp = NULL;
-	int			error = 0;
+	struct xfs_buf			*leaf_bp = NULL;
+	int				error = 0;
+	struct xfs_delattr_context	dac;
+
+	xfs_delattr_context_init(&dac, args);
+
+	do {
+		error = xfs_attr_set_iter(&dac, &leaf_bp);
+		if (error != -EAGAIN)
+			break;
+
+		error = xfs_attr_defer_finish(&dac);
+		if (error)
+			break;
+
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			break;
+
+		if (leaf_bp) {
+			xfs_trans_bjoin(args->trans, leaf_bp);
+			xfs_trans_bhold(args->trans, leaf_bp);
+		}
+
+	} while (true);
+
+	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_delattr_context	*dac,
+	struct xfs_buf			**leaf_bp)
+{
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_inode		*dp = args->dp;
+	int				error = 0;
+
+	/* State machine switch */
+	switch (dac->dela_state) {
+	case XFS_DAS_FLIP_LFLAG:
+	case XFS_DAS_FOUND_LBLK:
+		goto das_leaf;
+	case XFS_DAS_FOUND_NBLK:
+	case XFS_DAS_FLIP_NFLAG:
+	case XFS_DAS_ALLOC_NODE:
+		goto das_node;
+	default:
+		break;
+	}
 
 	/*
 	 * 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.
+	 * again. No need to set state as we will be in leaf form when we come
+	 * back
 	 */
 	if (xfs_attr_is_shortform(dp)) {
 
 		/*
-		 * If the attr was successfully set in shortform, the
-		 * transaction is committed and set to NULL.  Otherwise, is it
-		 * converted from shortform to leaf, and the transaction is
-		 * retained.
+		 * If the attr was successfully set in shortform, no need to
+		 * continue.  Otherwise, is it converted from shortform to leaf
+		 * and -EAGAIN is returned.
 		 */
-		error = xfs_attr_set_shortform(args, &leaf_bp);
-		if (error || !args->trans)
-			return error;
-	}
+		error = xfs_attr_set_shortform(args, leaf_bp);
+		if (error == -EAGAIN)
+			dac->flags |= XFS_DAC_DEFER_FINISH;
 
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_addname(args);
-		if (error != -ENOSPC)
-			return error;
+		return error;
+	}
 
-		/*
-		 * Promote the attribute list to the Btree format.
-		 */
-		error = xfs_attr3_leaf_to_node(args);
-		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_bhold_release(args->trans, *leaf_bp);
+		*leaf_bp = NULL;
+	}
 
-		/*
-		 * Commit that transaction so that the node_addname()
-		 * call can manage its own transactions.
-		 */
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_try_add(args, *leaf_bp);
+		switch (error) {
+		case -ENOSPC:
+			/*
+			 * Promote the attribute list to the Btree format.
+			 */
+			error = xfs_attr3_leaf_to_node(args);
+			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)
+			/*
+			 * Commit that transaction so that the node_addname()
+			 * call can manage its own transactions.
+			 */
+			dac->flags |= XFS_DAC_DEFER_FINISH;
+			return -EAGAIN;
+		case 0:
+			dac->dela_state = XFS_DAS_FOUND_LBLK;
+			return -EAGAIN;
+		default:
 			return error;
+		}
+das_leaf:
+		error = xfs_attr_leaf_addname(dac);
+		if (error == -ENOSPC)
+			/* We will be in node form when we return */
+			return -EAGAIN;
 
+		return error;
 	}
-
-	error = xfs_attr_node_addname(args);
+das_node:
+	error = xfs_attr_node_addname(dac);
 	return error;
 }
 
@@ -711,28 +776,30 @@ 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)
+	struct xfs_delattr_context	*dac)
 {
-	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;
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_buf			*bp = NULL;
+	int				error, forkoff;
+	struct xfs_inode		*dp = args->dp;
 
-	/*
-	 * 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 (dac->dela_state) {
+	case XFS_DAS_FLIP_LFLAG:
+		goto das_flip_flag;
+	case XFS_DAS_RM_LBLK:
+		goto das_rm_lblk;
+	default:
+		break;
+	}
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -740,12 +807,34 @@ xfs_attr_leaf_addname(
 	 * after we create the attribute so that we don't overflow the
 	 * maximum size of a transaction and/or hit a deadlock.
 	 */
-	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_set(args);
+
+	/* Open coded xfs_attr_rmtval_set without trans handling */
+	if ((dac->flags & XFS_DAC_LEAF_ADDNAME_INIT) == 0) {
+		dac->flags |= XFS_DAC_LEAF_ADDNAME_INIT;
+		if (args->rmtblkno > 0) {
+			error = xfs_attr_rmtval_set_init(dac);
+			if (error)
+				return error;
+		}
+	}
+
+	/*
+	 * Roll through the "value", allocating blocks on disk as
+	 * required.
+	 */
+	while (dac->blkcnt > 0) {
+		error = xfs_attr_rmtval_set_blk(dac);
 		if (error)
 			return error;
+
+		dac->flags |= XFS_DAC_DEFER_FINISH;
+		return -EAGAIN;
 	}
 
+	error = xfs_attr_rmtval_set_value(args);
+	if (error)
+		return error;
+
 	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
@@ -765,29 +854,33 @@ xfs_attr_leaf_addname(
 	 * In a separate transaction, set the incomplete flag on the "old" attr
 	 * and clear the incomplete flag on the "new" attr.
 	 */
-
 	error = xfs_attr3_leaf_flipflags(args);
 	if (error)
 		return error;
 	/*
 	 * Commit the flag value change and start the next trans in series.
 	 */
-	error = xfs_trans_roll_inode(&args->trans, args->dp);
-	if (error)
-		return error;
-
+	dac->dela_state = XFS_DAS_FLIP_LFLAG;
+	return -EAGAIN;
+das_flip_flag:
 	/*
 	 * Dismantle the "old" attribute/value pair by removing a "remote" value
 	 * (if it exists).
 	 */
 	xfs_attr_restore_rmt_blk(args);
 
+	error = xfs_attr_rmtval_invalidate(args);
+	if (error)
+		return error;
+das_rm_lblk:
 	if (args->rmtblkno) {
-		error = xfs_attr_rmtval_invalidate(args);
-		if (error)
-			return error;
+		error = __xfs_attr_rmtval_remove(dac);
+
+		if (error == -EAGAIN) {
+			dac->dela_state = XFS_DAS_RM_LBLK;
+			return -EAGAIN;
+		}
 
-		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			return error;
 	}
@@ -957,16 +1050,23 @@ xfs_attr_node_hasname(
  *
  * "Remote" attribute values confuse the issue and atomic rename operations
  * add a whole extra layer of confusion on top of that.
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ *returned.
  */
 STATIC int
 xfs_attr_node_addname(
-	struct xfs_da_args	*args)
+	struct xfs_delattr_context	*dac)
 {
-	struct xfs_da_state	*state;
-	struct xfs_da_state_blk	*blk;
-	struct xfs_inode	*dp;
-	struct xfs_mount	*mp;
-	int			retval, error;
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_da_state		*state = NULL;
+	struct xfs_da_state_blk		*blk;
+	struct xfs_inode		*dp;
+	struct xfs_mount		*mp;
+	int				retval = 0;
+	int				error = 0;
 
 	trace_xfs_attr_node_addname(args);
 
@@ -975,7 +1075,21 @@ xfs_attr_node_addname(
 	 */
 	dp = args->dp;
 	mp = dp->i_mount;
-restart:
+
+	/* State machine switch */
+	switch (dac->dela_state) {
+	case XFS_DAS_FLIP_NFLAG:
+		goto das_flip_flag;
+	case XFS_DAS_FOUND_NBLK:
+		goto das_found_nblk;
+	case XFS_DAS_ALLOC_NODE:
+		goto das_alloc_node;
+	case XFS_DAS_RM_NBLK:
+		goto das_rm_nblk;
+	default:
+		break;
+	}
+
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
@@ -1021,19 +1135,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;
+			dac->flags |= XFS_DAC_DEFER_FINISH;
+			return -EAGAIN;
 		}
 
 		/*
@@ -1045,9 +1153,7 @@ xfs_attr_node_addname(
 		error = xfs_da3_split(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
+		dac->flags |= XFS_DAC_DEFER_FINISH;
 	} else {
 		/*
 		 * Addition succeeded, update Btree hashvals.
@@ -1062,13 +1168,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;
+	dac->dela_state = XFS_DAS_FOUND_NBLK;
+	return -EAGAIN;
+das_found_nblk:
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -1077,7 +1179,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(dac);
+		if (error)
+			return error;
+
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+das_alloc_node:
+		while (dac->blkcnt > 0) {
+			error = xfs_attr_rmtval_set_blk(dac);
+			if (error)
+				return error;
+
+			dac->flags |= XFS_DAC_DEFER_FINISH;
+			dac->dela_state = XFS_DAS_ALLOC_NODE;
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
 		if (error)
 			return error;
 	}
@@ -1107,22 +1229,28 @@ xfs_attr_node_addname(
 	/*
 	 * 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;
-
+	dac->dela_state = XFS_DAS_FLIP_NFLAG;
+	return -EAGAIN;
+das_flip_flag:
 	/*
 	 * Dismantle the "old" attribute/value pair by removing a "remote" value
 	 * (if it exists).
 	 */
 	xfs_attr_restore_rmt_blk(args);
 
+	error = xfs_attr_rmtval_invalidate(args);
+	if (error)
+		return error;
+
+das_rm_nblk:
 	if (args->rmtblkno) {
-		error = xfs_attr_rmtval_invalidate(args);
-		if (error)
-			return error;
+		error = __xfs_attr_rmtval_remove(dac);
+
+		if (error == -EAGAIN) {
+			dac->dela_state = XFS_DAS_RM_NBLK;
+			return -EAGAIN;
+		}
 
-		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			return error;
 	}
@@ -1155,9 +1283,8 @@ xfs_attr_node_addname(
 		error = xfs_da3_join(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
+
+		dac->flags |= XFS_DAC_DEFER_FINISH;
 	}
 	retval = error = 0;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 0430c79..5cbefa90 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -106,6 +106,118 @@ struct xfs_attr_list_context {
  *	                                      v         │
  *	                                     done <─────┘
  *
+ *
+ * Below is a state machine diagram for attr set operations.
+ *
+ *  xfs_attr_set_iter()
+ *             │
+ *             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_attr_leaf_addname()
+ *   │		                      │
+ *   │		                      v
+ *   │		                   was this
+ *   │		                   a rename? ──n─┐
+ *   │		                      │          │
+ *   │		                      y          │
+ *   │		                      │          │
+ *   │		                      v          │
+ *   │		                flip incomplete  │
+ *   │		                    flag         │
+ *   │		                      │          │
+ *   │		                      v          │
+ *   │		              XFS_DAS_FLIP_LFLAG │
+ *   │		                      │          │
+ *   │		                      v          │
+ *   │		                    remove       │
+ *   │		XFS_DAS_RM_LBLK ─> old name      │
+ *   │		         ^            │          │
+ *   │		         │            v          │
+ *   │		         └──────y── more to      │
+ *   │		                    remove       │
+ *   │		                      │          │
+ *   │		                      n          │
+ *   │		                      │          │
+ *   │		                      v          │
+ *   │		                     done <──────┘
+ *   └──> 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       │
+ *	         XFS_DAS_RM_NBLK ─> old name      │
+ *	                  ^            │          │
+ *	                  │            v          │
+ *	                  └──────y── more to      │
+ *	                             remove       │
+ *	                               │          │
+ *	                               n          │
+ *	                               │          │
+ *	                               v          │
+ *	                              done <──────┘
+ *
  */
 
 /*
@@ -120,6 +232,13 @@ struct xfs_attr_list_context {
 enum xfs_delattr_state {
 				      /* Zero is uninitalized */
 	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
+	XFS_DAS_FOUND_LBLK,	      /* We found leaf blk for attr */
+	XFS_DAS_FOUND_NBLK,	      /* We found node blk for attr */
+	XFS_DAS_FLIP_LFLAG,	      /* Flipped leaf INCOMPLETE attr flag */
+	XFS_DAS_RM_LBLK,	      /* A rename is removing leaf blocks */
+	XFS_DAS_ALLOC_NODE,	      /* We are allocating node blocks */
+	XFS_DAS_FLIP_NFLAG,	      /* Flipped node INCOMPLETE attr flag */
+	XFS_DAS_RM_NBLK,	      /* A rename is removing node blocks */
 };
 
 /*
@@ -127,6 +246,7 @@ enum xfs_delattr_state {
  */
 #define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
 #define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
+#define XFS_DAC_LEAF_ADDNAME_INIT	0x04 /* xfs_attr_leaf_addname init*/
 
 /*
  * Context used for keeping track of delayed attribute operations
@@ -134,6 +254,11 @@ enum xfs_delattr_state {
 struct xfs_delattr_context {
 	struct xfs_da_args      *da_args;
 
+	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
+
 	/* Used in xfs_attr_node_removename to roll through removing blocks */
 	struct xfs_da_state     *da_state;
 	struct xfs_da_state_blk *blk;
@@ -158,10 +283,10 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_args(struct xfs_da_args *args);
+int xfs_attr_set_iter(struct xfs_delattr_context *dac, struct xfs_buf **leaf_bp);
 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_delattr_context *dac);
-int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
 bool xfs_attr_namecheck(const void *name, size_t length);
 void xfs_delattr_context_init(struct xfs_delattr_context *dac,
 			      struct xfs_da_args *args);
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index f2d46c7..7a342f1 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,70 @@ 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_delattr_context	*dac)
+{
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_bmbt_irec		*map = &dac->map;
+	int error;
+
+	dac->lblkno = 0;
+	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;
+
+	dac->blkcnt = args->rmtblkcnt;
+	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_delattr_context	*dac)
+{
+	struct xfs_da_args		*args = dac->da_args;
+	struct xfs_inode		*dp = args->dp;
+	struct xfs_bmbt_irec		*map = &dac->map;
+	int nmap;
+	int error;
+
+	nmap = 1;
+	error = xfs_bmapi_write(args->trans, dp,
+		  (xfs_fileoff_t)dac->lblkno,
+		  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 */
+	dac->lblkno += map->br_blockcount;
+	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.
  */
@@ -671,48 +735,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)
-{
-	struct xfs_delattr_context	dac;
-	xfs_dablk_t			lblkno;
-	int				blkcnt;
-	int				error = 0;
-	int				retval = 0;
-
-	trace_xfs_attr_rmtval_remove(args);
-	xfs_delattr_context_init(&dac, args);
-
-	/*
-	 * Keep de-allocating extents until the remote-value region is gone.
-	 */
-	lblkno = args->rmtblkno;
-	blkcnt = args->rmtblkcnt;
-	do {
-		retval = __xfs_attr_rmtval_remove(&dac);
-		if (retval && retval != EAGAIN)
-			return retval;
-
-		error = xfs_attr_defer_finish(&dac);
-		if (error)
-			break;
-
-		/*
-		 * Close out trans and start the next one in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			return error;
-	} while (retval == -EAGAIN);
-
-	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/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 351da00..51a1c91 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_remove(struct xfs_delattr_context *dac);
+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_delattr_context *dac);
+int xfs_attr_rmtval_set_init(struct xfs_delattr_context *dac);
 #endif /* __XFS_ATTR_REMOTE_H__ */
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index a4323a6..26dc8bf 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1784,7 +1784,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] 76+ messages in thread

* [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove
  2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
                   ` (22 preceding siblings ...)
  2020-04-30 22:50 ` [PATCH v9 23/24] xfs: Add delay ready attr set routines Allison Collins
@ 2020-04-30 22:50 ` Allison Collins
  2020-05-04 19:34   ` Darrick J. Wong
  23 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-04-30 22:50 UTC (permalink / raw)
  To: linux-xfs

Now that xfs_attr_rmtval_remove is gone, rename __xfs_attr_rmtval_remove
to xfs_attr_rmtval_remove

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 0751231..d76a970 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -874,7 +874,7 @@ xfs_attr_leaf_addname(
 		return error;
 das_rm_lblk:
 	if (args->rmtblkno) {
-		error = __xfs_attr_rmtval_remove(dac);
+		error = xfs_attr_rmtval_remove(dac);
 
 		if (error == -EAGAIN) {
 			dac->dela_state = XFS_DAS_RM_LBLK;
@@ -1244,8 +1244,7 @@ xfs_attr_node_addname(
 
 das_rm_nblk:
 	if (args->rmtblkno) {
-		error = __xfs_attr_rmtval_remove(dac);
-
+		error = xfs_attr_rmtval_remove(dac);
 		if (error == -EAGAIN) {
 			dac->dela_state = XFS_DAS_RM_NBLK;
 			return -EAGAIN;
@@ -1409,7 +1408,7 @@ xfs_attr_node_removename_rmt (
 	/*
 	 * May return -EAGAIN to request that the caller recall this function
 	 */
-	error = __xfs_attr_rmtval_remove(dac);
+	error = xfs_attr_rmtval_remove(dac);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 7a342f1..21c7aa9 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -740,7 +740,7 @@ xfs_attr_rmtval_invalidate(
  * transaction and recall the function
  */
 int
-__xfs_attr_rmtval_remove(
+xfs_attr_rmtval_remove(
 	struct xfs_delattr_context	*dac)
 {
 	struct xfs_da_args		*args = dac->da_args;
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 51a1c91..09fda56 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -10,11 +10,10 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
 
 int xfs_attr_rmtval_get(struct xfs_da_args *args);
 int xfs_attr_rmtval_set(struct xfs_da_args *args);
-int xfs_attr_rmtval_remove(struct xfs_da_args *args);
 int xfs_attr_rmtval_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_remove(struct xfs_delattr_context *dac);
+int xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
 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_delattr_context *dac);
-- 
2.7.4


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

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-04-30 22:50 ` [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
@ 2020-05-04 13:27   ` Brian Foster
  2020-05-04 21:36     ` Allison Collins
  2020-05-04 17:41   ` Darrick J. Wong
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-04 13:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
> xfs_attr_rmtval_remove
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> ---

Looks like the commit log needs some rewording now that this is a
refactor patch. With that fixed:

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

>  fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 37 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 4d51969..02d1a44 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
>  	xfs_dablk_t		lblkno;
>  	int			blkcnt;
>  	int			error = 0;
> -	int			done = 0;
> +	int			retval = 0;
>  
>  	trace_xfs_attr_rmtval_remove(args);
>  
> @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
>  	 */
>  	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;
> +	do {
> +		retval = __xfs_attr_rmtval_remove(args);
> +		if (retval && retval != EAGAIN)
> +			return retval;
>  
>  		/*
>  		 * Close out trans and start the next one in the chain.
> @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
>  		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  		if (error)
>  			return error;
> -	}
> +	} while (retval == -EAGAIN);
> +
>  	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_remove(
> +	struct xfs_da_args	*args)
> +{
> +	int			error, done;
> +
> +	/*
> +	 * Unmap value blocks for this attr.
> +	 */
> +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
> +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
> +	if (error)
> +		return error;
> +
> +	error = xfs_defer_finish(&args->trans);
> +	if (error)
> +		return error;
> +
> +	if (!done)
> +		return -EAGAIN;
> +
> +	return error;
> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate
  2020-04-30 22:50 ` [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate Allison Collins
@ 2020-05-04 13:27   ` Brian Foster
  2020-05-04 21:37     ` Allison Collins
  2020-05-04 17:41   ` Darrick J. Wong
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-04 13:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:03PM -0700, Allison Collins wrote:
> This patch pulls xfs_attr_rmtval_invalidate out of
> xfs_attr_rmtval_remove and into the calling functions.  Eventually
> __xfs_attr_rmtval_remove will replace xfs_attr_rmtval_remove when we
> introduce delayed attributes.  These functions are exepcted to return
> -EAGAIN when they need a new transaction.  Because the invalidate does
> not need a new transaction, we need to separate it from the rest of the
> function that does.  This will enable __xfs_attr_rmtval_remove to
> smoothly replace xfs_attr_rmtval_remove later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

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

>  fs/xfs/libxfs/xfs_attr.c        | 12 ++++++++++++
>  fs/xfs/libxfs/xfs_attr_remote.c |  3 ---
>  2 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0fc6436..4fdfab9 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -669,6 +669,10 @@ xfs_attr_leaf_addname(
>  		args->rmtblkcnt = args->rmtblkcnt2;
>  		args->rmtvaluelen = args->rmtvaluelen2;
>  		if (args->rmtblkno) {
> +			error = xfs_attr_rmtval_invalidate(args);
> +			if (error)
> +				return error;
> +
>  			error = xfs_attr_rmtval_remove(args);
>  			if (error)
>  				return error;
> @@ -1027,6 +1031,10 @@ xfs_attr_node_addname(
>  		args->rmtblkcnt = args->rmtblkcnt2;
>  		args->rmtvaluelen = args->rmtvaluelen2;
>  		if (args->rmtblkno) {
> +			error = xfs_attr_rmtval_invalidate(args);
> +			if (error)
> +				return error;
> +
>  			error = xfs_attr_rmtval_remove(args);
>  			if (error)
>  				return error;
> @@ -1152,6 +1160,10 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> +		error = xfs_attr_rmtval_invalidate(args);
> +		if (error)
> +			return error;
> +
>  		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			goto out;
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 02d1a44..f770159 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -685,9 +685,6 @@ xfs_attr_rmtval_remove(
>  
>  	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.
>  	 */
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink
  2020-04-30 22:50 ` [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink Allison Collins
@ 2020-05-04 13:27   ` Brian Foster
  2020-05-04 21:37     ` Allison Collins
  2020-05-04 17:42   ` Darrick J. Wong
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-04 13:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:04PM -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>
> ---

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

>  fs/xfs/libxfs/xfs_attr.c | 68 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 42 insertions(+), 26 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 4fdfab9..d83443c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1108,6 +1108,45 @@ 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;
> +
> +		error = xfs_defer_finish(&args->trans);
> +		if (error)
> +			return error;
> +	} 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
> @@ -1120,8 +1159,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);
> @@ -1206,30 +1244,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] 76+ messages in thread

* Re: [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls
  2020-04-30 22:50 ` [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls Allison Collins
@ 2020-05-04 13:30   ` Brian Foster
  2020-05-04 22:15     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-04 13:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:05PM -0700, Allison Collins wrote:
> Some calls to xfs_trans_roll_inode and xfs_defer_finish routines are not
> needed. If they are the last operations executed in these functions, and
> no further changes are made, then higher level routines will roll or
> commit the tranactions. The xfs_trans_roll in _removename is also not
> needed because invalidating blocks is an incore-only change.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 40 ----------------------------------------
>  1 file changed, 40 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index d83443c..af47566 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -784,9 +770,6 @@ xfs_attr_leaf_removename(
>  		/* bp is gone due to xfs_da_shrink_inode */
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
>  	}
>  	return 0;

Looks like this could be simplified to return error at the end of the
function. Some of the others might have similar simplifications
available.

>  }
> @@ -1074,13 +1057,6 @@ xfs_attr_node_addname(
>  				goto out;
>  		}
>  
> -		/*
> -		 * Commit and start the next trans in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			goto out;
> -

There's an xfs_defer_finish() before this roll. Is that not also
extraneous? It looks like we return straight up to xfs_attr_set() (trans
commit) from here..

>  	} else if (args->rmtblkno > 0) {
>  		/*
>  		 * Added a "remote" value, just clear the incomplete flag.
...
> @@ -1194,10 +1158,6 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			goto out;
> -

I'm still a bit on the fence about this one. At first glance it looks
like it's not necessary, but technically we're changing behavior by
combining setting the inactive flag and the first remote block unmap,
right? If so, that seems fairly reasonable, but it's hard to say for
sure with the state of the xattr transaction reservations...

Looking around some more, I suppose this could be analogous to the
!remote remove case where an entry is removed and a potential dabtree
join occurs under the same transaction. If that's the best argument we
have, however, I might suggest to split this one out into an independent
patch and let the commit log describe what's going on in more detail.
That way it's more obvious to reviewers and if it's wrong it's easier to
revert.

Brian

>  		error = xfs_attr_rmtval_invalidate(args);
>  		if (error)
>  			return error;
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname
  2020-04-30 22:49 ` [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname Allison Collins
@ 2020-05-04 17:33   ` Darrick J. Wong
  2020-05-04 22:34     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 17:33 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:49:57PM -0700, Allison Collins wrote:
> Split out new helper function xfs_attr_leaf_try_add from
> xfs_attr_leaf_addname. Because new delayed attribute routines cannot
> roll transactions, we split 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>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

<groan> I just replied to the xfsprogs version of this patch by accident. :(

Modulo the comments I made in that reply, the rest of the patch looks
ok.

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 94 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 60 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index dcbc475..b3b21a7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -256,10 +256,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;
>  }
>  
> @@ -507,20 +527,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
> @@ -562,31 +583,39 @@ 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;
> +out_brelse:
> +	xfs_trans_brelse(args->trans, bp);
> +	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
> @@ -681,9 +710,6 @@ xfs_attr_leaf_addname(
>  		error = xfs_attr3_leaf_clearflag(args);
>  	}
>  	return error;
> -out_brelse:
> -	xfs_trans_brelse(args->trans, bp);
> -	return retval;
>  }
>  
>  /*
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-04-30 22:50 ` [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 17:41   ` Darrick J. Wong
  2020-05-04 22:53     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 17:41 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
> xfs_attr_rmtval_remove

Like Brian suggested, this changelog could probably just say that we're
hoisting the loop body into a separate function so that delayed attrs
can manage the transaction rolling.

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 37 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 4d51969..02d1a44 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
>  	xfs_dablk_t		lblkno;
>  	int			blkcnt;
>  	int			error = 0;
> -	int			done = 0;
> +	int			retval = 0;
>  
>  	trace_xfs_attr_rmtval_remove(args);
>  
> @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
>  	 */
>  	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;
> +	do {
> +		retval = __xfs_attr_rmtval_remove(args);
> +		if (retval && retval != EAGAIN)
> +			return retval;
>  
>  		/*
>  		 * Close out trans and start the next one in the chain.
> @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
>  		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  		if (error)
>  			return error;
> -	}
> +	} while (retval == -EAGAIN);
> +
>  	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

recall the function...?

Oh.  "re-call" the function.

> + */
> +int
> +__xfs_attr_rmtval_remove(

xfs_attr_rmtval_remove_extent() ?

--D

> +	struct xfs_da_args	*args)
> +{
> +	int			error, done;
> +
> +	/*
> +	 * Unmap value blocks for this attr.
> +	 */
> +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
> +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
> +	if (error)
> +		return error;
> +
> +	error = xfs_defer_finish(&args->trans);
> +	if (error)
> +		return error;
> +
> +	if (!done)
> +		return -EAGAIN;
> +
> +	return error;
> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate
  2020-04-30 22:50 ` [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate Allison Collins
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 17:41   ` Darrick J. Wong
  2020-05-04 22:55     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 17:41 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:03PM -0700, Allison Collins wrote:
> This patch pulls xfs_attr_rmtval_invalidate out of
> xfs_attr_rmtval_remove and into the calling functions.  Eventually
> __xfs_attr_rmtval_remove will replace xfs_attr_rmtval_remove when we
> introduce delayed attributes.  These functions are exepcted to return
> -EAGAIN when they need a new transaction.  Because the invalidate does
> not need a new transaction, we need to separate it from the rest of the
> function that does.  This will enable __xfs_attr_rmtval_remove to
> smoothly replace xfs_attr_rmtval_remove later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c        | 12 ++++++++++++
>  fs/xfs/libxfs/xfs_attr_remote.c |  3 ---
>  2 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0fc6436..4fdfab9 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -669,6 +669,10 @@ xfs_attr_leaf_addname(
>  		args->rmtblkcnt = args->rmtblkcnt2;
>  		args->rmtvaluelen = args->rmtvaluelen2;
>  		if (args->rmtblkno) {
> +			error = xfs_attr_rmtval_invalidate(args);
> +			if (error)
> +				return error;
> +
>  			error = xfs_attr_rmtval_remove(args);
>  			if (error)
>  				return error;
> @@ -1027,6 +1031,10 @@ xfs_attr_node_addname(
>  		args->rmtblkcnt = args->rmtblkcnt2;
>  		args->rmtvaluelen = args->rmtvaluelen2;
>  		if (args->rmtblkno) {
> +			error = xfs_attr_rmtval_invalidate(args);
> +			if (error)
> +				return error;
> +
>  			error = xfs_attr_rmtval_remove(args);
>  			if (error)
>  				return error;
> @@ -1152,6 +1160,10 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> +		error = xfs_attr_rmtval_invalidate(args);
> +		if (error)
> +			return error;
> +
>  		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			goto out;
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 02d1a44..f770159 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -685,9 +685,6 @@ xfs_attr_rmtval_remove(
>  
>  	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.
>  	 */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink
  2020-04-30 22:50 ` [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink Allison Collins
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 17:42   ` Darrick J. Wong
  2020-05-04 22:55     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 17:42 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:04PM -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>

Simple enough looking hoist;
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 68 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 42 insertions(+), 26 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 4fdfab9..d83443c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1108,6 +1108,45 @@ 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;
> +
> +		error = xfs_defer_finish(&args->trans);
> +		if (error)
> +			return error;
> +	} 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
> @@ -1120,8 +1159,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);
> @@ -1206,30 +1244,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] 76+ messages in thread

* Re: [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
  2020-04-30 22:50 ` [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform Allison Collins
@ 2020-05-04 18:46   ` Darrick J. Wong
  2020-05-05  0:29     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 18:46 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:06PM -0700, Allison Collins wrote:
> In this patch, we hoist code from xfs_attr_set_args into two new helpers
> xfs_attr_is_shortform and xfs_attr_set_shortform.  These two will help
> to simplify xfs_attr_set_args when we get into delayed attrs later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 107 +++++++++++++++++++++++++++++++----------------
>  1 file changed, 72 insertions(+), 35 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index af47566..d112910 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -204,6 +204,66 @@ 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_is_shortform(
> +	struct xfs_inode    *ip)
> +{
> +	return ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> +	       (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> +	        ip->i_d.di_anextents == 0);
> +}
> +
> +/*
> + * Attempts to set an attr in shortform, or converts short form to leaf form if
> + * there is not enough room.  If the attr is set, the transaction is committed
> + * and set to NULL.
> + */
> +STATIC int
> +xfs_attr_set_shortform(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf		**leaf_bp)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	int			error, error2 = 0;
> +
> +	/*
> +	 * 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;
> +	}
> +	/*
> +	 * 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. 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;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
>   * Set the attribute specified in @args.
>   */
>  int
> @@ -212,48 +272,25 @@ xfs_attr_set_args(
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	struct xfs_buf          *leaf_bp = NULL;
> -	int			error, error2 = 0;
> +	int			error = 0;
>  
>  	/*
> -	 * 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_is_shortform(dp)) {
>  
>  		/*
> -		 * Try to add the attr to the attribute list in the inode.
> +		 * If the attr was successfully set in shortform, the
> +		 * transaction is committed and set to NULL.  Otherwise, is it
> +		 * converted from shortform to leaf, and the transaction is
> +		 * retained.
>  		 */
> -		error = xfs_attr_try_sf_addname(dp, args);
> -		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.
> -		 * 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.
> -		 * 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);
> +		error = xfs_attr_set_shortform(args, &leaf_bp);
> +		if (error || !args->trans)
>  			return error;
> -		}
>  	}
>  
>  	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete
  2020-04-30 22:50 ` [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
@ 2020-05-04 18:47   ` Darrick J. Wong
  0 siblings, 0 replies; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 18:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:07PM -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>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 41 +++++++++++++++++++++++++++--------------
>  1 file changed, 27 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index d112910..df77a3c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1148,6 +1148,32 @@ 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
> +	 */
> +	return xfs_attr3_leaf_setflag(args);
> +}
> +
> +/*
>   * Remove a name from a B-tree attribute list.
>   *
>   * This will involve walking down the Btree, and may involve joining
> @@ -1178,20 +1204,7 @@ xfs_attr_node_removename(
>  	ASSERT(blk->bp != NULL);
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>  	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] 76+ messages in thread

* Re: [PATCH v9 16/24] xfs: Add remote block helper functions
  2020-04-30 22:50 ` [PATCH v9 16/24] xfs: Add remote block helper functions Allison Collins
@ 2020-05-04 18:55   ` Darrick J. Wong
  2020-05-04 23:01     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 18:55 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:08PM -0700, 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 redundant
> code associated with storing and retrieving remote blocks during the
> attr set operations.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Hmm.  This is an ok-enough refactoring of the same idiom repeated over
and over, but ...ugh, there has got to be a less weird way of pushing
and popping state like this.

Unfortunately, the only thing I can think of would be to pass a "which
attr state?" argument to all the attr functions, and that might just
make things worse, particularly since we already have da state that gets
passed around everywhere, and afaict there's on a few users of this.

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 50 +++++++++++++++++++++++++++++-------------------
>  1 file changed, 30 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index df77a3c..feae122 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -563,6 +563,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_save_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
>   *
> @@ -597,11 +621,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_save_rmt_blk(args);
>  
>  		/*
>  		 * clear the remote attr state now that it is saved so that the
> @@ -700,11 +720,8 @@ 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);
> +
>  		if (args->rmtblkno) {
>  			error = xfs_attr_rmtval_invalidate(args);
>  			if (error)
> @@ -929,11 +946,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_save_rmt_blk(args);
>  
>  		/*
>  		 * clear the remote attr state now that it is saved so that the
> @@ -1045,11 +1058,8 @@ 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);
> +
>  		if (args->rmtblkno) {
>  			error = xfs_attr_rmtval_invalidate(args);
>  			if (error)
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup
  2020-04-30 22:50 ` [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup Allison Collins
@ 2020-05-04 18:58   ` Darrick J. Wong
  2020-05-04 23:02     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 18:58 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:09PM -0700, Allison Collins wrote:
> This patch adds a new helper function xfs_attr_node_removename_setup.
> This will help modularize xfs_attr_node_removename when we add delay
> ready attributes later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 48 +++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 35 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index feae122..c8226c6 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1184,6 +1184,39 @@ xfs_attr_leaf_mark_incomplete(
>  }
>  
>  /*
> + * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
> + * the blocks are valid.  Any remote blocks will be marked incomplete.

"Attr keys with remote blocks will be marked incomplete."

> + */
> +STATIC
> +int xfs_attr_node_removename_setup(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**state)
> +{
> +	int			error;
> +	struct xfs_da_state_blk	*blk;
> +
> +	error = xfs_attr_node_hasname(args, state);
> +	if (error != -EEXIST)
> +		return error;
> +
> +	blk = &(*state)->path.blk[(*state)->path.active - 1];
> +	ASSERT(blk->bp != NULL);
> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +
> +	if (args->rmtblkno > 0) {
> +		error = xfs_attr_leaf_mark_incomplete(args, *state);
> +		if (error)
> +			return error;
> +
> +		error = xfs_attr_rmtval_invalidate(args);
> +		if (error)
> +			return error;

		return xfs_attr_rmtval_invalidate(args);

With those two things changed,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> +	}
> +
> +	return 0;
> +}
> +
> +/*
>   * Remove a name from a B-tree attribute list.
>   *
>   * This will involve walking down the Btree, and may involve joining
> @@ -1201,8 +1234,8 @@ xfs_attr_node_removename(
>  
>  	trace_xfs_attr_node_removename(args);
>  
> -	error = xfs_attr_node_hasname(args, &state);
> -	if (error != -EEXIST)
> +	error = xfs_attr_node_removename_setup(args, &state);
> +	if (error)
>  		goto out;
>  
>  	/*
> @@ -1210,18 +1243,7 @@ xfs_attr_node_removename(
>  	 * This is done before we remove the attribute so that we don't
>  	 * overflow the maximum size of a transaction and/or hit a deadlock.
>  	 */
> -	blk = &state->path.blk[ state->path.active-1 ];
> -	ASSERT(blk->bp != NULL);
> -	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_leaf_mark_incomplete(args, state);
> -		if (error)
> -			goto out;
> -
> -		error = xfs_attr_rmtval_invalidate(args);
> -		if (error)
> -			return error;
> -
>  		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			goto out;
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt
  2020-04-30 22:50 ` [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt Allison Collins
@ 2020-05-04 19:00   ` Darrick J. Wong
  2020-05-04 23:04     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:00 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:10PM -0700, Allison Collins wrote:
> This patch adds another new helper function
> xfs_attr_node_removename_rmt. This will also help modularize
> xfs_attr_node_removename when we add delay ready attributes later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 28 +++++++++++++++++++---------
>  1 file changed, 19 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index c8226c6..ab1c9fa 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1216,6 +1216,24 @@ int xfs_attr_node_removename_setup(
>  	return 0;
>  }
>  
> +STATIC int
> +xfs_attr_node_removename_rmt (

xfs_attr_node_remove_rmt?

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

--D

> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	*state)
> +{
> +	int			error = 0;
> +
> +	error = xfs_attr_rmtval_remove(args);
> +	if (error)
> +		return error;
> +
> +	/*
> +	 * Refill the state structure with buffers, the prior calls released our
> +	 * buffers.
> +	 */
> +	return xfs_attr_refillstate(state);
> +}
> +
>  /*
>   * Remove a name from a B-tree attribute list.
>   *
> @@ -1244,15 +1262,7 @@ xfs_attr_node_removename(
>  	 * overflow the maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_remove(args);
> -		if (error)
> -			goto out;
> -
> -		/*
> -		 * Refill the state structure with buffers, the prior calls
> -		 * released our buffers.
> -		 */
> -		error = xfs_attr_refillstate(state);
> +		error = xfs_attr_node_removename_rmt(args, state);
>  		if (error)
>  			goto out;
>  	}
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname
  2020-04-30 22:50 ` [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname Allison Collins
@ 2020-05-04 19:03   ` Darrick J. Wong
  2020-05-04 23:06     ` Allison Collins
  2020-05-05 13:11   ` Brian Foster
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:03 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:11PM -0700, Allison Collins wrote:
> Quick patch to unnest the rename logic in the leaf code path.  This will
> help simplify delayed attr logic later.

This isn't really an unnesting, is it?  We're inverting the if logic and
flipping the subordinate blocks.

"Invert the rename logic in xfs_attr_leaf_addname to simplify the
delayed attr logic later."

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 108 +++++++++++++++++++++++------------------------
>  1 file changed, 53 insertions(+), 55 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index ab1c9fa..1810f90 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -694,73 +694,71 @@ xfs_attr_leaf_addname(
>  			return error;
>  	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {

	if (!(args->op_flags & XFS_DA_OP_RENAME)) {

--D

>  		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			return error;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> +		if (args->rmtblkno > 0)
> +			error = xfs_attr3_leaf_clearflag(args);
>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		xfs_attr_restore_rmt_blk(args);
> +		return error;
> +	}
>  
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_invalidate(args);
> -			if (error)
> -				return error;
> +	/*
> +	 * If this is an atomic rename operation, we must "flip" the incomplete
> +	 * flags on the "new" and "old" attribute/value pairs so that one
> +	 * disappears and one appears atomically.  Then we must remove the "old"
> +	 * attribute/value pair.
> +	 *
> +	 * In a separate transaction, set the incomplete flag on the "old" attr
> +	 * and clear the incomplete flag on the "new" attr.
> +	 */
>  
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +	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;
>  
> -		/*
> -		 * Read in the block containing the "old" attr, then
> -		 * remove the "old" attr from that block (neat, huh!)
> -		 */
> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -					   &bp);
> +	/*
> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
> +	 * (if it exists).
> +	 */
> +	xfs_attr_restore_rmt_blk(args);
> +
> +	if (args->rmtblkno) {
> +		error = xfs_attr_rmtval_invalidate(args);
>  		if (error)
>  			return error;
>  
> -		xfs_attr3_leaf_remove(bp, args);
> -
> -		/*
> -		 * If the result is small enough, shrink it all into the inode.
> -		 */
> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> -			/* bp is gone due to xfs_da_shrink_inode */
> -			if (error)
> -				return error;
> -		}
> -
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;
>  	}
> +
> +	/*
> +	 * Read in the block containing the "old" attr, then remove the "old"
> +	 * attr from that block (neat, huh!)
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> +				   &bp);
> +	if (error)
> +		return error;
> +
> +	xfs_attr3_leaf_remove(bp, args);
> +
> +	/*
> +	 * If the result is small enough, shrink it all into the inode.
> +	 */
> +	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 */
> +
>  	return error;
>  }
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname
  2020-04-30 22:50 ` [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname Allison Collins
@ 2020-05-04 19:06   ` Darrick J. Wong
  2020-05-04 23:16     ` Allison Collins
  2020-05-05 13:12   ` Brian Foster
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:06 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:12PM -0700, Allison Collins wrote:
> Quick patch to unnest the rename logic in the node code path.  This will
> help simplify delayed attr logic later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 131 +++++++++++++++++++++++------------------------
>  1 file changed, 64 insertions(+), 67 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 1810f90..9171895 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1030,83 +1030,80 @@ xfs_attr_node_addname(
>  			return error;
>  	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			goto out;
> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {

Same comments about the commit message and the if test as the previous
patch.

Admittedly I'm now starting to wonder if this patch and the previous one
should really just hoist the taken and not-taken branches into separate
functions, but maybe you've already gone around and around on that, and
everyone else already thought we have too many small functions...

--D

>  		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			goto out;
> +		if (args->rmtblkno > 0)
> +			error = xfs_attr3_leaf_clearflag(args);
> +		retval = error;
> +		goto out;
> +	}
>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		xfs_attr_restore_rmt_blk(args);
> +	/*
> +	 * If this is an atomic rename operation, we must "flip" the incomplete
> +	 * flags on the "new" and "old" attribute/value pairs so that one
> +	 * disappears and one appears atomically.  Then we must remove the "old"
> +	 * attribute/value pair.
> +	 *
> +	 * In a separate transaction, set the incomplete flag on the "old" attr
> +	 * and clear the incomplete flag on the "new" attr.
> +	 */
> +	error = xfs_attr3_leaf_flipflags(args);
> +	if (error)
> +		goto out;
> +	/*
> +	 * Commit the flag value change and start the next trans in series
> +	 */
> +	error = xfs_trans_roll_inode(&args->trans, args->dp);
> +	if (error)
> +		goto out;
>  
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_invalidate(args);
> -			if (error)
> -				return error;
> +	/*
> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
> +	 * (if it exists).
> +	 */
> +	xfs_attr_restore_rmt_blk(args);
>  
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +	if (args->rmtblkno) {
> +		error = xfs_attr_rmtval_invalidate(args);
> +		if (error)
> +			return error;
>  
> -		/*
> -		 * Re-find the "old" attribute entry after any split ops.
> -		 * The INCOMPLETE flag means that we will find the "old"
> -		 * attr, not the "new" one.
> -		 */
> -		args->attr_filter |= XFS_ATTR_INCOMPLETE;
> -		state = xfs_da_state_alloc();
> -		state->args = args;
> -		state->mp = mp;
> -		state->inleaf = 0;
> -		error = xfs_da3_node_lookup_int(state, &retval);
> +		error = xfs_attr_rmtval_remove(args);
>  		if (error)
> -			goto out;
> +			return error;
> +	}
>  
> -		/*
> -		 * Remove the name and update the hashvals in the tree.
> -		 */
> -		blk = &state->path.blk[ state->path.active-1 ];
> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -		error = xfs_attr3_leaf_remove(blk->bp, args);
> -		xfs_da3_fixhashpath(state, &state->path);
> +	/*
> +	 * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
> +	 * flag means that we will find the "old" attr, not the "new" one.
> +	 */
> +	args->attr_filter |= XFS_ATTR_INCOMPLETE;
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = mp;
> +	state->inleaf = 0;
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error)
> +		goto out;
>  
> -		/*
> -		 * Check to see if the tree needs to be collapsed.
> -		 */
> -		if (retval && (state->path.active > 1)) {
> -			error = xfs_da3_join(state);
> -			if (error)
> -				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
> -		}
> +	/*
> +	 * Remove the name and update the hashvals in the tree.
> +	 */
> +	blk = &state->path.blk[state->path.active-1];
> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +	error = xfs_attr3_leaf_remove(blk->bp, args);
> +	xfs_da3_fixhashpath(state, &state->path);
>  
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +	/*
> +	 * Check to see if the tree needs to be collapsed.
> +	 */
> +	if (retval && (state->path.active > 1)) {
> +		error = xfs_da3_join(state);
> +		if (error)
> +			goto out;
> +		error = xfs_defer_finish(&args->trans);
>  		if (error)
>  			goto out;
>  	}
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  2020-04-30 22:50 ` [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname Allison Collins
@ 2020-05-04 19:10   ` Darrick J. Wong
  2020-05-04 23:17     ` Allison Collins
  2020-05-05 13:12   ` Brian Foster
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:10 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:13PM -0700, Allison Collins wrote:
> Lift -ENOSPC handler from xfs_attr_leaf_addname.  This will help to
> reorganize transitions between the attr forms later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++--------------
>  1 file changed, 11 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9171895..c8cae68 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -299,6 +299,13 @@ xfs_attr_set_args(
>  			return error;
>  
>  		/*
> +		 * Promote the attribute list to the Btree format.
> +		 */
> +		error = xfs_attr3_leaf_to_node(args);
> +		if (error)
> +			return error;
> +
> +		/*
>  		 * Commit that transaction so that the node_addname()
>  		 * call can manage its own transactions.
>  		 */
> @@ -602,7 +609,7 @@ xfs_attr_leaf_try_add(
>  	struct xfs_da_args	*args,
>  	struct xfs_buf		*bp)
>  {
> -	int			retval, error;
> +	int			retval;
>  
>  	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
> @@ -634,20 +641,10 @@ xfs_attr_leaf_try_add(
>  	}
>  
>  	/*
> -	 * Add the attribute to the leaf block, transitioning to a Btree
> -	 * if required.
> +	 * Add the attribute to the leaf block
>  	 */
> -	retval = xfs_attr3_leaf_add(bp, args);
> -	if (retval == -ENOSPC) {
> -		/*
> -		 * 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;
> -	}
> -	return retval;
> +	return xfs_attr3_leaf_add(bp, args);
> +
>  out_brelse:
>  	xfs_trans_brelse(args->trans, bp);
>  	return retval;
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-04-30 22:50 ` [PATCH v9 22/24] xfs: Add delay ready attr remove routines Allison Collins
@ 2020-05-04 19:33   ` Darrick J. Wong
  2020-05-05  0:26     ` Allison Collins
  2020-05-07 11:54   ` Brian Foster
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:33 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:14PM -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.  A new XFS_DAC_DEFER_FINISH flag is used to finish the
> transaction where ever the existing code used to.
> 
> Calls to xfs_attr_rmtval_remove are replaced with the delay ready
> version __xfs_attr_rmtval_remove. We will rename
> __xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
> done.
> 
> xfs_attr_rmtval_remove itself is still in use by the set routines (used
> during a rename).  For reasons of perserving existing function, we
> modify xfs_attr_rmtval_remove to call xfs_defer_finish when the flag is
> set.  Similar to how xfs_attr_remove_args does here.  Once we transition
> the set routines to be delay ready, xfs_attr_rmtval_remove is no longer
> used and will be removed.
> 
> 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_attr_node_removename()
>                                                  │
>                                                  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        | 159 ++++++++++++++++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
>  fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
>  fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
>  fs/xfs/xfs_attr_inactive.c      |   2 +-
>  6 files changed, 215 insertions(+), 54 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index c8cae68..7213589 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -53,12 +53,21 @@ STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>   */
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>  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);
>  
> +void
> +xfs_delattr_context_init(
> +	struct xfs_delattr_context	*dac,
> +	struct xfs_da_args		*args)
> +{
> +	memset(dac, 0, sizeof(struct xfs_delattr_context));
> +	dac->da_args = args;

Couldn't this could be open coded as:

struct xfs_delattr_context	dac = {
	.da_args		= args,
};

in the callers?  One less helper function, and it means that the stack
contents will always be fully initialized.

> +}
> +
>  int
>  xfs_inode_hasattr(
>  	struct xfs_inode	*ip)
> @@ -263,6 +272,18 @@ xfs_attr_set_shortform(
>  	return 0;
>  }
>  
> +int xfs_attr_defer_finish(

static inline int
xfs_attr_defer_finish(

> +	struct xfs_delattr_context      *dac)
> +{
> +	struct xfs_da_args              *args = dac->da_args;
> +
> +	if (!(dac->flags & XFS_DAC_DEFER_FINISH))
> +		return 0;
> +
> +	dac->flags &= ~XFS_DAC_DEFER_FINISH;
> +	return xfs_defer_finish(&args->trans);

I also wonder if you want to hoist the trans_roll_inode to here too?

Actually, what if this instead became:

static inline bool
xfs_attr_roll_again(
	struct xfs_delattr_context	*dac,
	int				*error)
{
	if (*error != -EAGAIN)
		return false;

	if (dac->flags & XFS_DAC_DEFER_FINISH)) {
		dac->flags &= ~XFS_DAC_DEFER_FINISH;
		*error = xfs_defer_finish(&args->trans);
		if (*error)
			return false;
	}

	*error = xfs_trans_roll_inode(&dac->da_args->trans, dac->da_args->dp);
	return *error == 0;
}

> +}
> +
>  /*
>   * Set the attribute specified in @args.
>   */
> @@ -363,23 +384,57 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> -	struct xfs_da_args      *args)
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	struct			xfs_delattr_context dac;
> +
> +	xfs_delattr_context_init(&dac, args);
> +
> +	do {
> +		error = xfs_attr_remove_iter(&dac);
> +		if (error != -EAGAIN)
> +			break;
> +
> +		error = xfs_attr_defer_finish(&dac);
> +		if (error)
> +			break;
> +
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			break;
> +	} while (true);

and then this whole function becomes:

int
xfs_attr_remove_args(
	struct xfs_da_args		*args)
{
	struct xfs_delattr_context	dac = {
		.da_args		= args,
	};

	do {
		error = xfs_attr_remove_iter(&dac);
	} while (xfs_attr_roll_again(&dac, &error));

	return error;
}

> +
> +	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_delattr_context *dac)
>  {
> +	struct xfs_da_args	*args = dac->da_args;
>  	struct xfs_inode	*dp = args->dp;
> -	int			error;
> +
> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> +		goto node;
>  
>  	if (!xfs_inode_hasattr(dp)) {
> -		error = -ENOATTR;
> +		return -ENOATTR;
>  	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>  		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> -		error = xfs_attr_shortform_remove(args);
> +		return xfs_attr_shortform_remove(args);
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_removename(args);
> -	} else {
> -		error = xfs_attr_node_removename(args);
> +		return xfs_attr_leaf_removename(args);
>  	}
> -
> -	return error;
> +node:
> +	return  xfs_attr_node_removename(dac);
>  }
>  
>  /*
> @@ -1177,15 +1232,17 @@ xfs_attr_leaf_mark_incomplete(
>  
>  /*
>   * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
> - * the blocks are valid.  Any remote blocks will be marked incomplete.
> + * the blocks are valid.  Any remote blocks will be marked incomplete and
> + * invalidated.
>   */
>  STATIC
>  int xfs_attr_node_removename_setup(
> -	struct xfs_da_args	*args,
> -	struct xfs_da_state	**state)
> +	struct xfs_delattr_context	*dac,
> +	struct xfs_da_state		**state)
>  {
> -	int			error;
> -	struct xfs_da_state_blk	*blk;
> +	struct xfs_da_args		*args = dac->da_args;
> +	int				error;
> +	struct xfs_da_state_blk		*blk;
>  
>  	error = xfs_attr_node_hasname(args, state);
>  	if (error != -EEXIST)
> @@ -1195,6 +1252,13 @@ int xfs_attr_node_removename_setup(
>  	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
> +	 */
> +	dac->blk = blk;
> +	dac->da_state = *state;
> +
>  	if (args->rmtblkno > 0) {
>  		error = xfs_attr_leaf_mark_incomplete(args, *state);
>  		if (error)
> @@ -1210,12 +1274,15 @@ int xfs_attr_node_removename_setup(
>  
>  STATIC int
>  xfs_attr_node_removename_rmt (
> -	struct xfs_da_args	*args,
> -	struct xfs_da_state	*state)
> +	struct xfs_delattr_context	*dac,
> +	struct xfs_da_state		*state)
>  {
> -	int			error = 0;
> +	int				error = 0;
>  
> -	error = xfs_attr_rmtval_remove(args);
> +	/*
> +	 * May return -EAGAIN to request that the caller recall this function
> +	 */
> +	error = __xfs_attr_rmtval_remove(dac);
>  	if (error)
>  		return error;
>  
> @@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
>   * 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(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	struct xfs_da_state	*state;
> -	struct xfs_da_state_blk	*blk;
> -	int			retval, error;
> -	struct xfs_inode	*dp = args->dp;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_da_state		*state;
> +	struct xfs_da_state_blk		*blk;
> +	int				retval, error;
> +	struct xfs_inode		*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = dac->da_state;
> +	blk = dac->blk;
>  
> -	error = xfs_attr_node_removename_setup(args, &state);
> -	if (error)
> -		goto out;
> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> +		goto das_rm_shrink;
> +
> +	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
> +		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
> +		error = xfs_attr_node_removename_setup(dac, &state);

Shouldn't XFS_DAC_NODE_RMVNAME_INIT be set by
xfs_attr_node_removename_setup?

> +		if (error)
> +			goto out;
> +	}
>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
>  	 * overflow the maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_node_removename_rmt(args, state);
> -		if (error)
> +		/*
> +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
> +		 */
> +		error = xfs_attr_node_removename_rmt(dac, state);
> +		if (error == -EAGAIN)
> +			return error;
> +		else if (error)
>  			goto out;
>  	}
>  
> @@ -1274,17 +1360,14 @@ 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;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
> +		dac->dela_state = XFS_DAS_RM_SHRINK;
> +		return -EAGAIN;
>  	}
>  
> +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 66575b8..0430c79 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -74,6 +74,75 @@ struct xfs_attr_list_context {
>  };
>  
>  
> +/*
> + * ========================================================================
> + * Structure used to pass context around among the delayed routines.
> + * ========================================================================
> + */
> +
> +/*
> + * 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_attr_node_removename()
> + *	                                      │
> + *	                                      v
> + *	                                   need to
> + *	                                shrink tree? ─n─┐
> + *	                                      │         │
> + *	                                      y         │
> + *	                                      │         │
> + *	                                      v         │
> + *	                              XFS_DAS_RM_SHRINK │
> + *	                                      │         │
> + *	                                      v         │
> + *	                                     done <─────┘
> + *
> + */
> +
> +/*
> + * 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 {
> +				      /* Zero is uninitalized */
> +	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
> +};
> +
> +/*
> + * Defines for xfs_delattr_context.flags
> + */
> +#define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
> +#define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delattr_context {
> +	struct xfs_da_args      *da_args;
> +
> +	/* Used in xfs_attr_node_removename to roll through removing blocks */
> +	struct xfs_da_state     *da_state;
> +	struct xfs_da_state_blk *blk;
> +
> +	/* Used to keep track of current state of delayed operation */
> +	unsigned int            flags;
> +	enum xfs_delattr_state  dela_state;
> +};
> +
>  /*========================================================================
>   * Function prototypes for the kernel.
>   *========================================================================*/
> @@ -91,6 +160,10 @@ int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_args(struct xfs_da_args *args);
>  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_delattr_context *dac);
> +int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>  bool xfs_attr_namecheck(const void *name, size_t length);
> +void xfs_delattr_context_init(struct xfs_delattr_context *dac,
> +			      struct xfs_da_args *args);
>  
>  #endif	/* __XFS_ATTR_H__ */
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index f55402b..2e36c8b 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -19,8 +19,8 @@
>  #include "xfs_bmap_btree.h"
>  #include "xfs_bmap.h"
>  #include "xfs_attr_sf.h"
> -#include "xfs_attr_remote.h"
>  #include "xfs_attr.h"
> +#include "xfs_attr_remote.h"
>  #include "xfs_attr_leaf.h"
>  #include "xfs_error.h"
>  #include "xfs_trace.h"
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index f770159..f2d46c7 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -676,14 +676,16 @@ xfs_attr_rmtval_invalidate(
>   */
>  int
>  xfs_attr_rmtval_remove(
> -	struct xfs_da_args      *args)
> +	struct xfs_da_args		*args)
>  {
> -	xfs_dablk_t		lblkno;
> -	int			blkcnt;
> -	int			error = 0;
> -	int			retval = 0;
> +	struct xfs_delattr_context	dac;
> +	xfs_dablk_t			lblkno;
> +	int				blkcnt;
> +	int				error = 0;
> +	int				retval = 0;
>  
>  	trace_xfs_attr_rmtval_remove(args);
> +	xfs_delattr_context_init(&dac, args);
>  
>  	/*
>  	 * Keep de-allocating extents until the remote-value region is gone.
> @@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
>  	lblkno = args->rmtblkno;
>  	blkcnt = args->rmtblkcnt;
>  	do {
> -		retval = __xfs_attr_rmtval_remove(args);
> +		retval = __xfs_attr_rmtval_remove(&dac);
>  		if (retval && retval != EAGAIN)
>  			return retval;
>  
> +		error = xfs_attr_defer_finish(&dac);
> +		if (error)
> +			break;
> +
>  		/*
>  		 * Close out trans and start the next one in the chain.
>  		 */
> @@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
>   */
>  int
>  __xfs_attr_rmtval_remove(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	int			error, done;
> +	struct xfs_da_args		*args = dac->da_args;
> +	int				error, done;
>  
>  	/*
>  	 * Unmap value blocks for this attr.
> @@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
>  	if (error)
>  		return error;
>  
> -	error = xfs_defer_finish(&args->trans);
> -	if (error)
> -		return error;
> -
> -	if (!done)
> +	if (!done) {
> +		dac->flags &= ~XFS_DAC_DEFER_FINISH;

Why do we strip off DEFER_FINISH here?  Is it because we're making
xfs_attr_rmtval_remove invoke xfs_defer_finish unconditionally to clear
out any pending rmap items?

If you transformed the do-while loop in xfs_attr_rmtval_remove to use
xfs_attr_roll_again, then you could make this set DEFER_FINISH, which
would make me a lot less suspicious that we're dropping state here.

(It would also clean up a lot of the defer_finish -> trans_roll_inode
code that's scattering everywhere...)

--D

>  		return -EAGAIN;
> +	}
>  
>  	return error;
>  }
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index ee3337b..351da00 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -14,5 +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_remove(struct xfs_da_args *args);
> +int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> index c42f90e..b2150fa 100644
> --- a/fs/xfs/xfs_attr_inactive.c
> +++ b/fs/xfs/xfs_attr_inactive.c
> @@ -15,10 +15,10 @@
>  #include "xfs_da_format.h"
>  #include "xfs_da_btree.h"
>  #include "xfs_inode.h"
> +#include "xfs_attr.h"
>  #include "xfs_attr_remote.h"
>  #include "xfs_trans.h"
>  #include "xfs_bmap.h"
> -#include "xfs_attr.h"
>  #include "xfs_attr_leaf.h"
>  #include "xfs_quota.h"
>  #include "xfs_dir2.h"
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove
  2020-04-30 22:50 ` [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove Allison Collins
@ 2020-05-04 19:34   ` Darrick J. Wong
  2020-05-05  0:27     ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:34 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:16PM -0700, Allison Collins wrote:
> Now that xfs_attr_rmtval_remove is gone, rename __xfs_attr_rmtval_remove
> to xfs_attr_rmtval_remove
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c        | 7 +++----
>  fs/xfs/libxfs/xfs_attr_remote.c | 2 +-
>  fs/xfs/libxfs/xfs_attr_remote.h | 3 +--
>  3 files changed, 5 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0751231..d76a970 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -874,7 +874,7 @@ xfs_attr_leaf_addname(
>  		return error;
>  das_rm_lblk:
>  	if (args->rmtblkno) {
> -		error = __xfs_attr_rmtval_remove(dac);
> +		error = xfs_attr_rmtval_remove(dac);
>  
>  		if (error == -EAGAIN) {
>  			dac->dela_state = XFS_DAS_RM_LBLK;
> @@ -1244,8 +1244,7 @@ xfs_attr_node_addname(
>  
>  das_rm_nblk:
>  	if (args->rmtblkno) {
> -		error = __xfs_attr_rmtval_remove(dac);
> -
> +		error = xfs_attr_rmtval_remove(dac);
>  		if (error == -EAGAIN) {
>  			dac->dela_state = XFS_DAS_RM_NBLK;
>  			return -EAGAIN;
> @@ -1409,7 +1408,7 @@ xfs_attr_node_removename_rmt (
>  	/*
>  	 * May return -EAGAIN to request that the caller recall this function
>  	 */
> -	error = __xfs_attr_rmtval_remove(dac);
> +	error = xfs_attr_rmtval_remove(dac);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 7a342f1..21c7aa9 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -740,7 +740,7 @@ xfs_attr_rmtval_invalidate(
>   * transaction and recall the function
>   */
>  int
> -__xfs_attr_rmtval_remove(
> +xfs_attr_rmtval_remove(
>  	struct xfs_delattr_context	*dac)
>  {
>  	struct xfs_da_args		*args = dac->da_args;
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 51a1c91..09fda56 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -10,11 +10,10 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>  
>  int xfs_attr_rmtval_get(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set(struct xfs_da_args *args);
> -int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>  int xfs_attr_rmtval_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_remove(struct xfs_delattr_context *dac);
> +int xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>  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_delattr_context *dac);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v9 23/24] xfs: Add delay ready attr set routines
  2020-04-30 22:50 ` [PATCH v9 23/24] xfs: Add delay ready attr set routines Allison Collins
@ 2020-05-04 19:49   ` Darrick J. Wong
  2020-05-05  1:31     ` Allison Collins
  2020-05-04 22:36   ` Darrick J. Wong
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 19:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:15PM -0700, Allison Collins wrote:
> This patch modifies the attr set routines to be delay ready. This means
> they no longer roll or commit transactions, but instead return -EAGAIN
> to have the calling routine roll and refresh the transaction.  In this
> series, xfs_attr_set_args has become xfs_attr_set_iter, which uses a
> state machine like switch to keep track of where it was when EAGAIN was
> returned.
> 
> 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. xfs_attr_set_args has
> now become a simple loop to refresh the transaction until the operation
> is completed.  Lastly, xfs_attr_rmtval_remove is no longer used, and is
> removed.
> 
> 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
>   ┌──────n── fork has
>   │         only 1 blk?

"Refer to the state machine diagram in xfs_attr.h for exact details of
how this works."

>   │              │
>   │              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_attr_leaf_addname()
>   │                                              │
>   │                                              v
>   │                                            was this
>   │                                           a rename? ──n─┐
>   │                                              │          │
>   │                                              y          │
>   │                                              │          │
>   │                                              v          │
>   │                                        flip incomplete  │
>   │                                            flag         │
>   │                                              │          │
>   │                                              v          │
>   │                                      XFS_DAS_FLIP_LFLAG │
>   │                                              │          │
>   │                                              v          │
>   │                                            remove       │
>   │                        XFS_DAS_RM_LBLK ─> old name      │
>   │                                 ^            │          │
>   │                                 │            v          │
>   │                                 └──────y── more to      │
>   │                                            remove       │
>   │                                              │          │
>   │                                              n          │
>   │                                              │          │
>   │                                              v          │
>   │                                             done <──────┘
>   └────> 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       │
>                            XFS_DAS_RM_NBLK ─> 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        | 371 +++++++++++++++++++++++++++-------------
>  fs/xfs/libxfs/xfs_attr.h        | 127 +++++++++++++-
>  fs/xfs/libxfs/xfs_attr_remote.c | 110 +++++++-----
>  fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>  fs/xfs/xfs_trace.h              |   1 -
>  5 files changed, 445 insertions(+), 168 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7213589..0751231 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -44,7 +44,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>   * Internal routines when attribute list is one block.
>   */
>  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_addname(struct xfs_delattr_context *dac);
>  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);
>  
> @@ -52,12 +52,13 @@ 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.
>   */
>  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_addname(struct xfs_delattr_context *dac);
>  STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>  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);
>  
>  void
>  xfs_delattr_context_init(
> @@ -227,8 +228,11 @@ xfs_attr_is_shortform(
>  
>  /*
>   * Attempts to set an attr in shortform, or converts short form to leaf form if
> - * there is not enough room.  If the attr is set, the transaction is committed
> - * and set to NULL.
> + * there is not enough room.  This function is meant to operate as a helper
> + * routine to the delayed attribute functions.  It returns -EAGAIN to indicate
> + * that the calling function should roll the transaction, and then proceed to
> + * add the attr in leaf form.  This subroutine does not expect to be recalled
> + * again like the other delayed attr routines do.
>   */
>  STATIC int
>  xfs_attr_set_shortform(
> @@ -236,16 +240,16 @@ xfs_attr_set_shortform(
>  	struct xfs_buf		**leaf_bp)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	int			error, error2 = 0;
> +	int			error = 0;
>  
>  	/*
>  	 * 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) {
> -		error2 = xfs_trans_commit(args->trans);
> -		args->trans = NULL;
> -		return error ? error : error2;
> +		return error;
>  	}
>  	/*
>  	 * It won't fit in the shortform, transform to a leaf block.  GROT:
> @@ -258,20 +262,13 @@ xfs_attr_set_shortform(
>  	/*
>  	 * 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.
> +	 * with the write verifier.
>  	 */
>  	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;
> -	}
> -
> -	return 0;
> +	return -EAGAIN;
>  }
>  
> +STATIC
>  int xfs_attr_defer_finish(
>  	struct xfs_delattr_context      *dac)
>  {
> @@ -291,60 +288,128 @@ int
>  xfs_attr_set_args(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_inode	*dp = args->dp;
> -	struct xfs_buf          *leaf_bp = NULL;
> -	int			error = 0;
> +	struct xfs_buf			*leaf_bp = NULL;
> +	int				error = 0;
> +	struct xfs_delattr_context	dac;
> +
> +	xfs_delattr_context_init(&dac, args);
> +
> +	do {
> +		error = xfs_attr_set_iter(&dac, &leaf_bp);
> +		if (error != -EAGAIN)
> +			break;
> +
> +		error = xfs_attr_defer_finish(&dac);
> +		if (error)
> +			break;
> +
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			break;

	if (!xfs_attr_roll_again(&dac, &error))
		break;

> +
> +		if (leaf_bp) {
> +			xfs_trans_bjoin(args->trans, leaf_bp);
> +			xfs_trans_bhold(args->trans, leaf_bp);
> +		}
> +
> +	} while (true);
> +
> +	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_delattr_context	*dac,
> +	struct xfs_buf			**leaf_bp)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	/* State machine switch */
> +	switch (dac->dela_state) {
> +	case XFS_DAS_FLIP_LFLAG:
> +	case XFS_DAS_FOUND_LBLK:
> +		goto das_leaf;
> +	case XFS_DAS_FOUND_NBLK:
> +	case XFS_DAS_FLIP_NFLAG:
> +	case XFS_DAS_ALLOC_NODE:
> +		goto das_node;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * 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.
> +	 * again. No need to set state as we will be in leaf form when we come
> +	 * back
>  	 */
>  	if (xfs_attr_is_shortform(dp)) {
>  
>  		/*
> -		 * If the attr was successfully set in shortform, the
> -		 * transaction is committed and set to NULL.  Otherwise, is it
> -		 * converted from shortform to leaf, and the transaction is
> -		 * retained.
> +		 * If the attr was successfully set in shortform, no need to
> +		 * continue.  Otherwise, is it converted from shortform to leaf
> +		 * and -EAGAIN is returned.
>  		 */
> -		error = xfs_attr_set_shortform(args, &leaf_bp);
> -		if (error || !args->trans)
> -			return error;
> -	}
> +		error = xfs_attr_set_shortform(args, leaf_bp);
> +		if (error == -EAGAIN)
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_addname(args);
> -		if (error != -ENOSPC)
> -			return error;
> +		return error;
> +	}
>  
> -		/*
> -		 * Promote the attribute list to the Btree format.
> -		 */
> -		error = xfs_attr3_leaf_to_node(args);
> -		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_bhold_release(args->trans, *leaf_bp);
> +		*leaf_bp = NULL;
> +	}
>  
> -		/*
> -		 * Commit that transaction so that the node_addname()
> -		 * call can manage its own transactions.
> -		 */
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +		switch (error) {
> +		case -ENOSPC:
> +			/*
> +			 * Promote the attribute list to the Btree format.
> +			 */
> +			error = xfs_attr3_leaf_to_node(args);
> +			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)
> +			/*
> +			 * Commit that transaction so that the node_addname()
> +			 * call can manage its own transactions.
> +			 */
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			return -EAGAIN;
> +		case 0:
> +			dac->dela_state = XFS_DAS_FOUND_LBLK;
> +			return -EAGAIN;
> +		default:
>  			return error;
> +		}
> +das_leaf:
> +		error = xfs_attr_leaf_addname(dac);
> +		if (error == -ENOSPC)
> +			/* We will be in node form when we return */
> +			return -EAGAIN;
>  
> +		return error;
>  	}
> -
> -	error = xfs_attr_node_addname(args);
> +das_node:
> +	error = xfs_attr_node_addname(dac);
>  	return error;
>  }
>  
> @@ -711,28 +776,30 @@ 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)
> +	struct xfs_delattr_context	*dac)
>  {
> -	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;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_buf			*bp = NULL;
> +	int				error, forkoff;
> +	struct xfs_inode		*dp = args->dp;
>  
> -	/*
> -	 * 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 (dac->dela_state) {
> +	case XFS_DAS_FLIP_LFLAG:
> +		goto das_flip_flag;
> +	case XFS_DAS_RM_LBLK:
> +		goto das_rm_lblk;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -740,12 +807,34 @@ xfs_attr_leaf_addname(
>  	 * after we create the attribute so that we don't overflow the
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
> -	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> +
> +	/* Open coded xfs_attr_rmtval_set without trans handling */
> +	if ((dac->flags & XFS_DAC_LEAF_ADDNAME_INIT) == 0) {
> +		dac->flags |= XFS_DAC_LEAF_ADDNAME_INIT;
> +		if (args->rmtblkno > 0) {
> +			error = xfs_attr_rmtval_set_init(dac);
> +			if (error)
> +				return error;
> +		}
> +	}
> +
> +	/*
> +	 * Roll through the "value", allocating blocks on disk as
> +	 * required.
> +	 */
> +	while (dac->blkcnt > 0) {

if() ?

> +		error = xfs_attr_rmtval_set_blk(dac);
>  		if (error)
>  			return error;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
> +		return -EAGAIN;
>  	}
>  
> +	error = xfs_attr_rmtval_set_value(args);
> +	if (error)
> +		return error;
> +
>  	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>  		/*
>  		 * Added a "remote" value, just clear the incomplete flag.
> @@ -765,29 +854,33 @@ xfs_attr_leaf_addname(
>  	 * In a separate transaction, set the incomplete flag on the "old" attr
>  	 * and clear the incomplete flag on the "new" attr.
>  	 */
> -
>  	error = xfs_attr3_leaf_flipflags(args);
>  	if (error)
>  		return error;
>  	/*
>  	 * Commit the flag value change and start the next trans in series.
>  	 */
> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> -	if (error)
> -		return error;
> -
> +	dac->dela_state = XFS_DAS_FLIP_LFLAG;
> +	return -EAGAIN;
> +das_flip_flag:
>  	/*
>  	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>  	 * (if it exists).
>  	 */
>  	xfs_attr_restore_rmt_blk(args);
>  
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
> +das_rm_lblk:
>  	if (args->rmtblkno) {
> -		error = xfs_attr_rmtval_invalidate(args);
> -		if (error)
> -			return error;
> +		error = __xfs_attr_rmtval_remove(dac);
> +
> +		if (error == -EAGAIN) {
> +			dac->dela_state = XFS_DAS_RM_LBLK;
> +			return -EAGAIN;
> +		}
>  
> -		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;
>  	}
> @@ -957,16 +1050,23 @@ xfs_attr_node_hasname(
>   *
>   * "Remote" attribute values confuse the issue and atomic rename operations
>   * add a whole extra layer of confusion on top of that.
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + *returned.
>   */
>  STATIC int
>  xfs_attr_node_addname(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	struct xfs_da_state	*state;
> -	struct xfs_da_state_blk	*blk;
> -	struct xfs_inode	*dp;
> -	struct xfs_mount	*mp;
> -	int			retval, error;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_da_state		*state = NULL;
> +	struct xfs_da_state_blk		*blk;
> +	struct xfs_inode		*dp;
> +	struct xfs_mount		*mp;
> +	int				retval = 0;
> +	int				error = 0;
>  
>  	trace_xfs_attr_node_addname(args);
>  
> @@ -975,7 +1075,21 @@ xfs_attr_node_addname(
>  	 */
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -restart:
> +
> +	/* State machine switch */
> +	switch (dac->dela_state) {
> +	case XFS_DAS_FLIP_NFLAG:
> +		goto das_flip_flag;
> +	case XFS_DAS_FOUND_NBLK:
> +		goto das_found_nblk;
> +	case XFS_DAS_ALLOC_NODE:
> +		goto das_alloc_node;
> +	case XFS_DAS_RM_NBLK:
> +		goto das_rm_nblk;
> +	default:
> +		break;
> +	}
> +
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
> @@ -1021,19 +1135,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;
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			return -EAGAIN;
>  		}
>  
>  		/*
> @@ -1045,9 +1153,7 @@ xfs_attr_node_addname(
>  		error = xfs_da3_split(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>  	} else {
>  		/*
>  		 * Addition succeeded, update Btree hashvals.
> @@ -1062,13 +1168,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;
> +	dac->dela_state = XFS_DAS_FOUND_NBLK;
> +	return -EAGAIN;
> +das_found_nblk:
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -1077,7 +1179,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(dac);

Do we need to test/set LEAF_ADDNAME_INIT here too?

> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
> +		 */
> +das_alloc_node:
> +		while (dac->blkcnt > 0) {

if() ?

> +			error = xfs_attr_rmtval_set_blk(dac);
> +			if (error)
> +				return error;
> +
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			dac->dela_state = XFS_DAS_ALLOC_NODE;
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
>  			return error;
>  	}
> @@ -1107,22 +1229,28 @@ xfs_attr_node_addname(
>  	/*
>  	 * 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;
> -
> +	dac->dela_state = XFS_DAS_FLIP_NFLAG;
> +	return -EAGAIN;
> +das_flip_flag:
>  	/*
>  	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>  	 * (if it exists).
>  	 */
>  	xfs_attr_restore_rmt_blk(args);
>  
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
> +
> +das_rm_nblk:
>  	if (args->rmtblkno) {
> -		error = xfs_attr_rmtval_invalidate(args);
> -		if (error)
> -			return error;
> +		error = __xfs_attr_rmtval_remove(dac);
> +
> +		if (error == -EAGAIN) {
> +			dac->dela_state = XFS_DAS_RM_NBLK;
> +			return -EAGAIN;
> +		}
>  
> -		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;
>  	}
> @@ -1155,9 +1283,8 @@ xfs_attr_node_addname(
>  		error = xfs_da3_join(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 0430c79..5cbefa90 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -106,6 +106,118 @@ struct xfs_attr_list_context {
>   *	                                      v         │
>   *	                                     done <─────┘
>   *
> + *
> + * Below is a state machine diagram for attr set operations.
> + *
> + *  xfs_attr_set_iter()
> + *             │
> + *             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_attr_leaf_addname()
> + *   │		                      │
> + *   │		                      v
> + *   │		                   was this
> + *   │		                   a rename? ──n─┐
> + *   │		                      │          │
> + *   │		                      y          │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                flip incomplete  │
> + *   │		                    flag         │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		              XFS_DAS_FLIP_LFLAG │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                    remove       │
> + *   │		XFS_DAS_RM_LBLK ─> old name      │
> + *   │		         ^            │          │
> + *   │		         │            v          │
> + *   │		         └──────y── more to      │
> + *   │		                    remove       │
> + *   │		                      │          │
> + *   │		                      n          │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                     done <──────┘
> + *   └──> 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       │
> + *	         XFS_DAS_RM_NBLK ─> old name      │
> + *	                  ^            │          │
> + *	                  │            v          │
> + *	                  └──────y── more to      │
> + *	                             remove       │
> + *	                               │          │
> + *	                               n          │
> + *	                               │          │
> + *	                               v          │
> + *	                              done <──────┘
> + *
>   */
>  
>  /*
> @@ -120,6 +232,13 @@ struct xfs_attr_list_context {
>  enum xfs_delattr_state {
>  				      /* Zero is uninitalized */
>  	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
> +	XFS_DAS_FOUND_LBLK,	      /* We found leaf blk for attr */
> +	XFS_DAS_FOUND_NBLK,	      /* We found node blk for attr */
> +	XFS_DAS_FLIP_LFLAG,	      /* Flipped leaf INCOMPLETE attr flag */
> +	XFS_DAS_RM_LBLK,	      /* A rename is removing leaf blocks */
> +	XFS_DAS_ALLOC_NODE,	      /* We are allocating node blocks */
> +	XFS_DAS_FLIP_NFLAG,	      /* Flipped node INCOMPLETE attr flag */
> +	XFS_DAS_RM_NBLK,	      /* A rename is removing node blocks */
>  };
>  
>  /*
> @@ -127,6 +246,7 @@ enum xfs_delattr_state {
>   */
>  #define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>  #define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
> +#define XFS_DAC_LEAF_ADDNAME_INIT	0x04 /* xfs_attr_leaf_addname init*/
>  
>  /*
>   * Context used for keeping track of delayed attribute operations
> @@ -134,6 +254,11 @@ enum xfs_delattr_state {
>  struct xfs_delattr_context {
>  	struct xfs_da_args      *da_args;
>  
> +	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +
>  	/* Used in xfs_attr_node_removename to roll through removing blocks */
>  	struct xfs_da_state     *da_state;
>  	struct xfs_da_state_blk *blk;
> @@ -158,10 +283,10 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
>  int xfs_attr_get(struct xfs_da_args *args);
>  int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> +int xfs_attr_set_iter(struct xfs_delattr_context *dac, struct xfs_buf **leaf_bp);
>  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_delattr_context *dac);
> -int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>  bool xfs_attr_namecheck(const void *name, size_t length);
>  void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>  			      struct xfs_da_args *args);
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index f2d46c7..7a342f1 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,70 @@ 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(

/me wonders if this ought to be named xfs_attr_rmtval_find_space() ?

That's more or less what it's getting ready to do, right?

> +	struct xfs_delattr_context	*dac)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_bmbt_irec		*map = &dac->map;
> +	int error;

	int				error;

> +
> +	dac->lblkno = 0;
> +	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;
> +
> +	dac->blkcnt = args->rmtblkcnt;
> +	dac->lblkno = args->rmtblkno;
> +
> +	return error;

This could be return 0;.

> +}
> +
> +/*
> + * 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_delattr_context	*dac)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_inode		*dp = args->dp;
> +	struct xfs_bmbt_irec		*map = &dac->map;
> +	int nmap;
> +	int error;
> +
> +	nmap = 1;
> +	error = xfs_bmapi_write(args->trans, dp,
> +		  (xfs_fileoff_t)dac->lblkno,
> +		  dac->blkcnt, XFS_BMAPI_ATTRFORK,
> +		  args->total, map, &nmap);

The indenting here could be improved.

Whee, ok, it's lunchtime.  I'll look at the state machine after eating.

--D

> +	if (error)
> +		return error;
> +
> +	ASSERT(nmap == 1);
> +	ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
> +	       (map->br_startblock != HOLESTARTBLOCK));
> +
> +	/* roll attribute extent map forwards */
> +	dac->lblkno += map->br_blockcount;
> +	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.
>   */
> @@ -671,48 +735,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)
> -{
> -	struct xfs_delattr_context	dac;
> -	xfs_dablk_t			lblkno;
> -	int				blkcnt;
> -	int				error = 0;
> -	int				retval = 0;
> -
> -	trace_xfs_attr_rmtval_remove(args);
> -	xfs_delattr_context_init(&dac, args);
> -
> -	/*
> -	 * Keep de-allocating extents until the remote-value region is gone.
> -	 */
> -	lblkno = args->rmtblkno;
> -	blkcnt = args->rmtblkcnt;
> -	do {
> -		retval = __xfs_attr_rmtval_remove(&dac);
> -		if (retval && retval != EAGAIN)
> -			return retval;
> -
> -		error = xfs_attr_defer_finish(&dac);
> -		if (error)
> -			break;
> -
> -		/*
> -		 * Close out trans and start the next one in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> -	} while (retval == -EAGAIN);
> -
> -	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/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 351da00..51a1c91 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_remove(struct xfs_delattr_context *dac);
> +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_delattr_context *dac);
> +int xfs_attr_rmtval_set_init(struct xfs_delattr_context *dac);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index a4323a6..26dc8bf 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -1784,7 +1784,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] 76+ messages in thread

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 21:36     ` Allison Collins
  2020-05-05 12:03       ` Brian Foster
  0 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-05-04 21:36 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/4/20 6:27 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
>> xfs_attr_rmtval_remove
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>> ---
> 
> Looks like the commit log needs some rewording now that this is a
> refactor patch. With that fixed:
Ok, maybe just an extra line like "Refactor xfs_attr_rmtval_remove to 
add helper function __xfs_attr_rmtval_remove" ?

> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Alrighty, thank you!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 37 insertions(+), 10 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 4d51969..02d1a44 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
>>   	xfs_dablk_t		lblkno;
>>   	int			blkcnt;
>>   	int			error = 0;
>> -	int			done = 0;
>> +	int			retval = 0;
>>   
>>   	trace_xfs_attr_rmtval_remove(args);
>>   
>> @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
>>   	 */
>>   	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;
>> +	do {
>> +		retval = __xfs_attr_rmtval_remove(args);
>> +		if (retval && retval != EAGAIN)
>> +			return retval;
>>   
>>   		/*
>>   		 * Close out trans and start the next one in the chain.
>> @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
>>   		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   		if (error)
>>   			return error;
>> -	}
>> +	} while (retval == -EAGAIN);
>> +
>>   	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_remove(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error, done;
>> +
>> +	/*
>> +	 * Unmap value blocks for this attr.
>> +	 */
>> +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
>> +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
>> +	if (error)
>> +		return error;
>> +
>> +	error = xfs_defer_finish(&args->trans);
>> +	if (error)
>> +		return error;
>> +
>> +	if (!done)
>> +		return -EAGAIN;
>> +
>> +	return error;
>> +}
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 21:37     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 21:37 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/4/20 6:27 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:03PM -0700, Allison Collins wrote:
>> This patch pulls xfs_attr_rmtval_invalidate out of
>> xfs_attr_rmtval_remove and into the calling functions.  Eventually
>> __xfs_attr_rmtval_remove will replace xfs_attr_rmtval_remove when we
>> introduce delayed attributes.  These functions are exepcted to return
>> -EAGAIN when they need a new transaction.  Because the invalidate does
>> not need a new transaction, we need to separate it from the rest of the
>> function that does.  This will enable __xfs_attr_rmtval_remove to
>> smoothly replace xfs_attr_rmtval_remove later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Ok, thank you!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c        | 12 ++++++++++++
>>   fs/xfs/libxfs/xfs_attr_remote.c |  3 ---
>>   2 files changed, 12 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0fc6436..4fdfab9 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -669,6 +669,10 @@ xfs_attr_leaf_addname(
>>   		args->rmtblkcnt = args->rmtblkcnt2;
>>   		args->rmtvaluelen = args->rmtvaluelen2;
>>   		if (args->rmtblkno) {
>> +			error = xfs_attr_rmtval_invalidate(args);
>> +			if (error)
>> +				return error;
>> +
>>   			error = xfs_attr_rmtval_remove(args);
>>   			if (error)
>>   				return error;
>> @@ -1027,6 +1031,10 @@ xfs_attr_node_addname(
>>   		args->rmtblkcnt = args->rmtblkcnt2;
>>   		args->rmtvaluelen = args->rmtvaluelen2;
>>   		if (args->rmtblkno) {
>> +			error = xfs_attr_rmtval_invalidate(args);
>> +			if (error)
>> +				return error;
>> +
>>   			error = xfs_attr_rmtval_remove(args);
>>   			if (error)
>>   				return error;
>> @@ -1152,6 +1160,10 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> +		error = xfs_attr_rmtval_invalidate(args);
>> +		if (error)
>> +			return error;
>> +
>>   		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			goto out;
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 02d1a44..f770159 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -685,9 +685,6 @@ xfs_attr_rmtval_remove(
>>   
>>   	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.
>>   	 */
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink
  2020-05-04 13:27   ` Brian Foster
@ 2020-05-04 21:37     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 21:37 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/4/20 6:27 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:04PM -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>
>> ---
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Great!  Thanks!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c | 68 ++++++++++++++++++++++++++++++------------------
>>   1 file changed, 42 insertions(+), 26 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 4fdfab9..d83443c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1108,6 +1108,45 @@ 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;
>> +
>> +		error = xfs_defer_finish(&args->trans);
>> +		if (error)
>> +			return error;
>> +	} 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
>> @@ -1120,8 +1159,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);
>> @@ -1206,30 +1244,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] 76+ messages in thread

* Re: [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls
  2020-05-04 13:30   ` Brian Foster
@ 2020-05-04 22:15     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 22:15 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/4/20 6:30 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:05PM -0700, Allison Collins wrote:
>> Some calls to xfs_trans_roll_inode and xfs_defer_finish routines are not
>> needed. If they are the last operations executed in these functions, and
>> no further changes are made, then higher level routines will roll or
>> commit the tranactions. The xfs_trans_roll in _removename is also not
>> needed because invalidating blocks is an incore-only change.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 40 ----------------------------------------
>>   1 file changed, 40 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index d83443c..af47566 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
> ...
>> @@ -784,9 +770,6 @@ xfs_attr_leaf_removename(
>>   		/* bp is gone due to xfs_da_shrink_inode */
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>>   	}
>>   	return 0;
> 
> Looks like this could be simplified to return error at the end of the
> function. Some of the others might have similar simplifications
> available.
Sure, will do
> 
>>   }
>> @@ -1074,13 +1057,6 @@ xfs_attr_node_addname(
>>   				goto out;
>>   		}
>>   
>> -		/*
>> -		 * Commit and start the next trans in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			goto out;
>> -
> 
> There's an xfs_defer_finish() before this roll. Is that not also
> extraneous? It looks like we return straight up to xfs_attr_set() (trans
> commit) from here..
Ok, I see it.  Yes I think so, I will see if I can take it out

> 
>>   	} else if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
> ...
>> @@ -1194,10 +1158,6 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>> -
> 
> I'm still a bit on the fence about this one. At first glance it looks
> like it's not necessary, but technically we're changing behavior by
> combining setting the inactive flag and the first remote block unmap,
> right? If so, that seems fairly reasonable, but it's hard to say for
> sure with the state of the xattr transaction reservations...
> 
As I recall, I had initially not removed this roll in v5, and I had an 
extra XFS_DAS_RM_INVALIDATE state to roll the transaction here.  And 
then I think we reasoned that because invalidating blocks didnt have in 
core changes, we could just remove it, thus getting rid of the extra 
state.  Later I split it out into this separate patch along with a few 
other transaction rolls that we identified as not being necessary.

link just for reference...
https://patchwork.kernel.org/patch/11287029/


> Looking around some more, I suppose this could be analogous to the
> !remote remove case where an entry is removed and a potential dabtree
> join occurs under the same transaction. If that's the best argument we
> have, however, I might suggest to split this one out into an independent
> patch and let the commit log describe what's going on in more detail.
> That way it's more obvious to reviewers and if it's wrong it's easier to
> revert.
I'm not sure that was the argument at the time, but I think it makes 
sense. :-)  Will split off into separate patch.

Thanks for the reviews!

Allison

> 
> Brian



> 
>>   		error = xfs_attr_rmtval_invalidate(args);
>>   		if (error)
>>   			return error;
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname
  2020-05-04 17:33   ` Darrick J. Wong
@ 2020-05-04 22:34     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 22:34 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 10:33 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:49:57PM -0700, Allison Collins wrote:
>> Split out new helper function xfs_attr_leaf_try_add from
>> xfs_attr_leaf_addname. Because new delayed attribute routines cannot
>> roll transactions, we split 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>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> 
> <groan> I just replied to the xfsprogs version of this patch by accident. :(
> 
> Modulo the comments I made in that reply, the rest of the patch looks
> ok.
> 
> --D
No worries, will apply same feed back here :-)

Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 94 ++++++++++++++++++++++++++++++------------------
>>   1 file changed, 60 insertions(+), 34 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index dcbc475..b3b21a7 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -256,10 +256,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;
>>   }
>>   
>> @@ -507,20 +527,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
>> @@ -562,31 +583,39 @@ 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;
>> +out_brelse:
>> +	xfs_trans_brelse(args->trans, bp);
>> +	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
>> @@ -681,9 +710,6 @@ xfs_attr_leaf_addname(
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   	}
>>   	return error;
>> -out_brelse:
>> -	xfs_trans_brelse(args->trans, bp);
>> -	return retval;
>>   }
>>   
>>   /*
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 23/24] xfs: Add delay ready attr set routines
  2020-04-30 22:50 ` [PATCH v9 23/24] xfs: Add delay ready attr set routines Allison Collins
  2020-05-04 19:49   ` Darrick J. Wong
@ 2020-05-04 22:36   ` Darrick J. Wong
  2020-05-05  1:32     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 22:36 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:15PM -0700, Allison Collins wrote:
> This patch modifies the attr set routines to be delay ready. This means
> they no longer roll or commit transactions, but instead return -EAGAIN
> to have the calling routine roll and refresh the transaction.  In this
> series, xfs_attr_set_args has become xfs_attr_set_iter, which uses a
> state machine like switch to keep track of where it was when EAGAIN was
> returned.
> 
> 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. xfs_attr_set_args has
> now become a simple loop to refresh the transaction until the operation
> is completed.  Lastly, xfs_attr_rmtval_remove is no longer used, and is
> removed.
> 
> 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
>   ┌──────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_attr_leaf_addname()
>   │                                              │
>   │                                              v
>   │                                            was this
>   │                                           a rename? ──n─┐
>   │                                              │          │
>   │                                              y          │
>   │                                              │          │
>   │                                              v          │
>   │                                        flip incomplete  │
>   │                                            flag         │
>   │                                              │          │
>   │                                              v          │
>   │                                      XFS_DAS_FLIP_LFLAG │
>   │                                              │          │
>   │                                              v          │
>   │                                            remove       │
>   │                        XFS_DAS_RM_LBLK ─> old name      │
>   │                                 ^            │          │
>   │                                 │            v          │
>   │                                 └──────y── more to      │
>   │                                            remove       │
>   │                                              │          │
>   │                                              n          │
>   │                                              │          │
>   │                                              v          │
>   │                                             done <──────┘
>   └────> 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       │
>                            XFS_DAS_RM_NBLK ─> 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        | 371 +++++++++++++++++++++++++++-------------
>  fs/xfs/libxfs/xfs_attr.h        | 127 +++++++++++++-
>  fs/xfs/libxfs/xfs_attr_remote.c | 110 +++++++-----
>  fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>  fs/xfs/xfs_trace.h              |   1 -
>  5 files changed, 445 insertions(+), 168 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7213589..0751231 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -44,7 +44,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>   * Internal routines when attribute list is one block.
>   */
>  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_addname(struct xfs_delattr_context *dac);
>  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);
>  
> @@ -52,12 +52,13 @@ 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.
>   */
>  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_addname(struct xfs_delattr_context *dac);
>  STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>  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);
>  
>  void
>  xfs_delattr_context_init(
> @@ -227,8 +228,11 @@ xfs_attr_is_shortform(
>  
>  /*
>   * Attempts to set an attr in shortform, or converts short form to leaf form if
> - * there is not enough room.  If the attr is set, the transaction is committed
> - * and set to NULL.
> + * there is not enough room.  This function is meant to operate as a helper
> + * routine to the delayed attribute functions.  It returns -EAGAIN to indicate
> + * that the calling function should roll the transaction, and then proceed to
> + * add the attr in leaf form.  This subroutine does not expect to be recalled
> + * again like the other delayed attr routines do.
>   */
>  STATIC int
>  xfs_attr_set_shortform(
> @@ -236,16 +240,16 @@ xfs_attr_set_shortform(
>  	struct xfs_buf		**leaf_bp)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	int			error, error2 = 0;
> +	int			error = 0;
>  
>  	/*
>  	 * 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) {
> -		error2 = xfs_trans_commit(args->trans);
> -		args->trans = NULL;
> -		return error ? error : error2;
> +		return error;
>  	}
>  	/*
>  	 * It won't fit in the shortform, transform to a leaf block.  GROT:
> @@ -258,20 +262,13 @@ xfs_attr_set_shortform(
>  	/*
>  	 * 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.
> +	 * with the write verifier.
>  	 */
>  	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;
> -	}
> -
> -	return 0;
> +	return -EAGAIN;
>  }
>  
> +STATIC
>  int xfs_attr_defer_finish(
>  	struct xfs_delattr_context      *dac)
>  {
> @@ -291,60 +288,128 @@ int
>  xfs_attr_set_args(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_inode	*dp = args->dp;
> -	struct xfs_buf          *leaf_bp = NULL;
> -	int			error = 0;
> +	struct xfs_buf			*leaf_bp = NULL;
> +	int				error = 0;
> +	struct xfs_delattr_context	dac;
> +
> +	xfs_delattr_context_init(&dac, args);
> +
> +	do {
> +		error = xfs_attr_set_iter(&dac, &leaf_bp);
> +		if (error != -EAGAIN)
> +			break;
> +
> +		error = xfs_attr_defer_finish(&dac);
> +		if (error)
> +			break;
> +
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			break;
> +
> +		if (leaf_bp) {
> +			xfs_trans_bjoin(args->trans, leaf_bp);
> +			xfs_trans_bhold(args->trans, leaf_bp);
> +		}
> +
> +	} while (true);
> +
> +	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(

Could this be a static function above xfs_attr_set()?  Or is this
something that will need to be exported in a later series?

> +	struct xfs_delattr_context	*dac,
> +	struct xfs_buf			**leaf_bp)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	/* State machine switch */
> +	switch (dac->dela_state) {
> +	case XFS_DAS_FLIP_LFLAG:
> +	case XFS_DAS_FOUND_LBLK:
> +		goto das_leaf;
> +	case XFS_DAS_FOUND_NBLK:
> +	case XFS_DAS_FLIP_NFLAG:
> +	case XFS_DAS_ALLOC_NODE:
> +		goto das_node;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * 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.
> +	 * again. No need to set state as we will be in leaf form when we come
> +	 * back
>  	 */
>  	if (xfs_attr_is_shortform(dp)) {
>  
>  		/*
> -		 * If the attr was successfully set in shortform, the
> -		 * transaction is committed and set to NULL.  Otherwise, is it
> -		 * converted from shortform to leaf, and the transaction is
> -		 * retained.
> +		 * If the attr was successfully set in shortform, no need to
> +		 * continue.  Otherwise, is it converted from shortform to leaf
> +		 * and -EAGAIN is returned.
>  		 */
> -		error = xfs_attr_set_shortform(args, &leaf_bp);
> -		if (error || !args->trans)
> -			return error;
> -	}
> +		error = xfs_attr_set_shortform(args, leaf_bp);
> +		if (error == -EAGAIN)
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_addname(args);
> -		if (error != -ENOSPC)
> -			return error;
> +		return error;
> +	}
>  
> -		/*
> -		 * Promote the attribute list to the Btree format.
> -		 */
> -		error = xfs_attr3_leaf_to_node(args);
> -		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

"cycle"

> +	 * the leaf.
> +	 */
> +	if (*leaf_bp != NULL) {
> +		xfs_trans_bhold_release(args->trans, *leaf_bp);
> +		*leaf_bp = NULL;
> +	}
>  
> -		/*
> -		 * Commit that transaction so that the node_addname()
> -		 * call can manage its own transactions.
> -		 */
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +		switch (error) {
> +		case -ENOSPC:
> +			/*
> +			 * Promote the attribute list to the Btree format.
> +			 */
> +			error = xfs_attr3_leaf_to_node(args);
> +			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)
> +			/*
> +			 * Commit that transaction so that the node_addname()
> +			 * call can manage its own transactions.
> +			 */
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			return -EAGAIN;
> +		case 0:
> +			dac->dela_state = XFS_DAS_FOUND_LBLK;
> +			return -EAGAIN;
> +		default:
>  			return error;
> +		}
> +das_leaf:
> +		error = xfs_attr_leaf_addname(dac);
> +		if (error == -ENOSPC)
> +			/* We will be in node form when we return */

Er, how does this happen?  Is this comment merely referencing the node
conversion that just happened 20 lines above?  Or does something else do
the conversion too?

> +			return -EAGAIN;
>  
> +		return error;
>  	}
> -
> -	error = xfs_attr_node_addname(args);
> +das_node:
> +	error = xfs_attr_node_addname(dac);
>  	return error;
>  }
>  
> @@ -711,28 +776,30 @@ 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)
> +	struct xfs_delattr_context	*dac)
>  {
> -	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;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_buf			*bp = NULL;
> +	int				error, forkoff;
> +	struct xfs_inode		*dp = args->dp;
>  
> -	/*
> -	 * 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 (dac->dela_state) {
> +	case XFS_DAS_FLIP_LFLAG:
> +		goto das_flip_flag;
> +	case XFS_DAS_RM_LBLK:
> +		goto das_rm_lblk;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -740,12 +807,34 @@ xfs_attr_leaf_addname(
>  	 * after we create the attribute so that we don't overflow the
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
> -	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> +
> +	/* Open coded xfs_attr_rmtval_set without trans handling */
> +	if ((dac->flags & XFS_DAC_LEAF_ADDNAME_INIT) == 0) {
> +		dac->flags |= XFS_DAC_LEAF_ADDNAME_INIT;
> +		if (args->rmtblkno > 0) {
> +			error = xfs_attr_rmtval_set_init(dac);
> +			if (error)
> +				return error;
> +		}
> +	}
> +
> +	/*
> +	 * Roll through the "value", allocating blocks on disk as
> +	 * required.
> +	 */
> +	while (dac->blkcnt > 0) {
> +		error = xfs_attr_rmtval_set_blk(dac);
>  		if (error)
>  			return error;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
> +		return -EAGAIN;
>  	}
>  
> +	error = xfs_attr_rmtval_set_value(args);
> +	if (error)
> +		return error;
> +
>  	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>  		/*
>  		 * Added a "remote" value, just clear the incomplete flag.
> @@ -765,29 +854,33 @@ xfs_attr_leaf_addname(
>  	 * In a separate transaction, set the incomplete flag on the "old" attr
>  	 * and clear the incomplete flag on the "new" attr.
>  	 */
> -
>  	error = xfs_attr3_leaf_flipflags(args);
>  	if (error)
>  		return error;
>  	/*
>  	 * Commit the flag value change and start the next trans in series.
>  	 */
> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> -	if (error)
> -		return error;
> -
> +	dac->dela_state = XFS_DAS_FLIP_LFLAG;
> +	return -EAGAIN;
> +das_flip_flag:
>  	/*
>  	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>  	 * (if it exists).
>  	 */
>  	xfs_attr_restore_rmt_blk(args);
>  
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
> +das_rm_lblk:
>  	if (args->rmtblkno) {
> -		error = xfs_attr_rmtval_invalidate(args);
> -		if (error)
> -			return error;
> +		error = __xfs_attr_rmtval_remove(dac);
> +
> +		if (error == -EAGAIN) {
> +			dac->dela_state = XFS_DAS_RM_LBLK;
> +			return -EAGAIN;
> +		}
>  
> -		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;

This whole bit could condense to:

		error = __xfs_attr_rmtval_remove(dac);
		if (error == -EAGAIN)
			dac->dela_state = XFS_DAS_RM_LBLK;
		if (error)
			return error;


>  	}
> @@ -957,16 +1050,23 @@ xfs_attr_node_hasname(
>   *
>   * "Remote" attribute values confuse the issue and atomic rename operations
>   * add a whole extra layer of confusion on top of that.
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + *returned.
>   */
>  STATIC int
>  xfs_attr_node_addname(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	struct xfs_da_state	*state;
> -	struct xfs_da_state_blk	*blk;
> -	struct xfs_inode	*dp;
> -	struct xfs_mount	*mp;
> -	int			retval, error;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_da_state		*state = NULL;
> +	struct xfs_da_state_blk		*blk;
> +	struct xfs_inode		*dp;
> +	struct xfs_mount		*mp;
> +	int				retval = 0;
> +	int				error = 0;
>  
>  	trace_xfs_attr_node_addname(args);
>  
> @@ -975,7 +1075,21 @@ xfs_attr_node_addname(
>  	 */
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -restart:
> +
> +	/* State machine switch */
> +	switch (dac->dela_state) {
> +	case XFS_DAS_FLIP_NFLAG:
> +		goto das_flip_flag;
> +	case XFS_DAS_FOUND_NBLK:
> +		goto das_found_nblk;
> +	case XFS_DAS_ALLOC_NODE:
> +		goto das_alloc_node;
> +	case XFS_DAS_RM_NBLK:
> +		goto das_rm_nblk;
> +	default:
> +		break;
> +	}
> +
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
> @@ -1021,19 +1135,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;
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			return -EAGAIN;
>  		}
>  
>  		/*
> @@ -1045,9 +1153,7 @@ xfs_attr_node_addname(
>  		error = xfs_da3_split(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>  	} else {
>  		/*
>  		 * Addition succeeded, update Btree hashvals.
> @@ -1062,13 +1168,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;
> +	dac->dela_state = XFS_DAS_FOUND_NBLK;
> +	return -EAGAIN;
> +das_found_nblk:
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -1077,7 +1179,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(dac);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
> +		 */
> +das_alloc_node:
> +		while (dac->blkcnt > 0) {
> +			error = xfs_attr_rmtval_set_blk(dac);
> +			if (error)
> +				return error;
> +
> +			dac->flags |= XFS_DAC_DEFER_FINISH;
> +			dac->dela_state = XFS_DAS_ALLOC_NODE;
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
>  			return error;
>  	}
> @@ -1107,22 +1229,28 @@ xfs_attr_node_addname(
>  	/*
>  	 * 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;
> -
> +	dac->dela_state = XFS_DAS_FLIP_NFLAG;
> +	return -EAGAIN;
> +das_flip_flag:
>  	/*
>  	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>  	 * (if it exists).
>  	 */
>  	xfs_attr_restore_rmt_blk(args);
>  
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
> +
> +das_rm_nblk:
>  	if (args->rmtblkno) {
> -		error = xfs_attr_rmtval_invalidate(args);
> -		if (error)
> -			return error;
> +		error = __xfs_attr_rmtval_remove(dac);
> +
> +		if (error == -EAGAIN) {
> +			dac->dela_state = XFS_DAS_RM_NBLK;
> +			return -EAGAIN;
> +		}
>  
> -		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;
>  	}
> @@ -1155,9 +1283,8 @@ xfs_attr_node_addname(
>  		error = xfs_da3_join(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 0430c79..5cbefa90 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -106,6 +106,118 @@ struct xfs_attr_list_context {
>   *	                                      v         │
>   *	                                     done <─────┘
>   *
> + *
> + * Below is a state machine diagram for attr set operations.
> + *
> + *  xfs_attr_set_iter()
> + *             │
> + *             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_attr_leaf_addname()
> + *   │		                      │
> + *   │		                      v
> + *   │		                   was this
> + *   │		                   a rename? ──n─┐
> + *   │		                      │          │
> + *   │		                      y          │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                flip incomplete  │
> + *   │		                    flag         │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		              XFS_DAS_FLIP_LFLAG │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                    remove       │
> + *   │		XFS_DAS_RM_LBLK ─> old name      │
> + *   │		         ^            │          │
> + *   │		         │            v          │
> + *   │		         └──────y── more to      │
> + *   │		                    remove       │
> + *   │		                      │          │
> + *   │		                      n          │
> + *   │		                      │          │
> + *   │		                      v          │
> + *   │		                     done <──────┘
> + *   └──> 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       │
> + *	         XFS_DAS_RM_NBLK ─> old name      │
> + *	                  ^            │          │
> + *	                  │            v          │
> + *	                  └──────y── more to      │
> + *	                             remove       │
> + *	                               │          │
> + *	                               n          │
> + *	                               │          │
> + *	                               v          │
> + *	                              done <──────┘

Ok, I traced through all this and I /think/ the state machine
accurately reflects the code paths before all the surgery started.
Whoever knew that implementing a key-value store was so complex?

--D

> + *
>   */
>  
>  /*
> @@ -120,6 +232,13 @@ struct xfs_attr_list_context {
>  enum xfs_delattr_state {
>  				      /* Zero is uninitalized */
>  	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
> +	XFS_DAS_FOUND_LBLK,	      /* We found leaf blk for attr */
> +	XFS_DAS_FOUND_NBLK,	      /* We found node blk for attr */
> +	XFS_DAS_FLIP_LFLAG,	      /* Flipped leaf INCOMPLETE attr flag */
> +	XFS_DAS_RM_LBLK,	      /* A rename is removing leaf blocks */
> +	XFS_DAS_ALLOC_NODE,	      /* We are allocating node blocks */
> +	XFS_DAS_FLIP_NFLAG,	      /* Flipped node INCOMPLETE attr flag */
> +	XFS_DAS_RM_NBLK,	      /* A rename is removing node blocks */
>  };
>  
>  /*
> @@ -127,6 +246,7 @@ enum xfs_delattr_state {
>   */
>  #define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>  #define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
> +#define XFS_DAC_LEAF_ADDNAME_INIT	0x04 /* xfs_attr_leaf_addname init*/
>  
>  /*
>   * Context used for keeping track of delayed attribute operations
> @@ -134,6 +254,11 @@ enum xfs_delattr_state {
>  struct xfs_delattr_context {
>  	struct xfs_da_args      *da_args;
>  
> +	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +
>  	/* Used in xfs_attr_node_removename to roll through removing blocks */
>  	struct xfs_da_state     *da_state;
>  	struct xfs_da_state_blk *blk;
> @@ -158,10 +283,10 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
>  int xfs_attr_get(struct xfs_da_args *args);
>  int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> +int xfs_attr_set_iter(struct xfs_delattr_context *dac, struct xfs_buf **leaf_bp);
>  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_delattr_context *dac);
> -int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>  bool xfs_attr_namecheck(const void *name, size_t length);
>  void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>  			      struct xfs_da_args *args);
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index f2d46c7..7a342f1 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,70 @@ 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_delattr_context	*dac)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_bmbt_irec		*map = &dac->map;
> +	int error;
> +
> +	dac->lblkno = 0;
> +	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;
> +
> +	dac->blkcnt = args->rmtblkcnt;
> +	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_delattr_context	*dac)
> +{
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_inode		*dp = args->dp;
> +	struct xfs_bmbt_irec		*map = &dac->map;
> +	int nmap;
> +	int error;
> +
> +	nmap = 1;
> +	error = xfs_bmapi_write(args->trans, dp,
> +		  (xfs_fileoff_t)dac->lblkno,
> +		  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 */
> +	dac->lblkno += map->br_blockcount;
> +	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.
>   */
> @@ -671,48 +735,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)
> -{
> -	struct xfs_delattr_context	dac;
> -	xfs_dablk_t			lblkno;
> -	int				blkcnt;
> -	int				error = 0;
> -	int				retval = 0;
> -
> -	trace_xfs_attr_rmtval_remove(args);
> -	xfs_delattr_context_init(&dac, args);
> -
> -	/*
> -	 * Keep de-allocating extents until the remote-value region is gone.
> -	 */
> -	lblkno = args->rmtblkno;
> -	blkcnt = args->rmtblkcnt;
> -	do {
> -		retval = __xfs_attr_rmtval_remove(&dac);
> -		if (retval && retval != EAGAIN)
> -			return retval;
> -
> -		error = xfs_attr_defer_finish(&dac);
> -		if (error)
> -			break;
> -
> -		/*
> -		 * Close out trans and start the next one in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> -	} while (retval == -EAGAIN);
> -
> -	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/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 351da00..51a1c91 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_remove(struct xfs_delattr_context *dac);
> +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_delattr_context *dac);
> +int xfs_attr_rmtval_set_init(struct xfs_delattr_context *dac);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index a4323a6..26dc8bf 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -1784,7 +1784,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] 76+ messages in thread

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-05-04 17:41   ` Darrick J. Wong
@ 2020-05-04 22:53     ` Allison Collins
  2020-05-04 22:57       ` Darrick J. Wong
  0 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-05-04 22:53 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 10:41 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
>> xfs_attr_rmtval_remove
> 
> Like Brian suggested, this changelog could probably just say that we're
> hoisting the loop body into a separate function so that delayed attrs
> can manage the transaction rolling.
> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 37 insertions(+), 10 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 4d51969..02d1a44 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
>>   	xfs_dablk_t		lblkno;
>>   	int			blkcnt;
>>   	int			error = 0;
>> -	int			done = 0;
>> +	int			retval = 0;
>>   
>>   	trace_xfs_attr_rmtval_remove(args);
>>   
>> @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
>>   	 */
>>   	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;
>> +	do {
>> +		retval = __xfs_attr_rmtval_remove(args);
>> +		if (retval && retval != EAGAIN)
>> +			return retval;
>>   
>>   		/*
>>   		 * Close out trans and start the next one in the chain.
>> @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
>>   		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   		if (error)
>>   			return error;
>> -	}
>> +	} while (retval == -EAGAIN);
>> +
>>   	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
> 
> recall the function...?
> 
> Oh.  "re-call" the function.
Will fix

> 
>> + */
>> +int
>> +__xfs_attr_rmtval_remove(
> 
> xfs_attr_rmtval_remove_extent() ?
Well, this would be the third rename for this function though. 
Initially I think we named it xfs_attr_rmtval_unmap, and then later we 
changed it to __xfs_attr_rmtval_remove.  Ultimatly, it really doesn't 
matter what the name is, because it's going to get renamed at the end of 
the set anyway.  Eventually it replaces the calling function and becomes 
xfs_attr_rmtval_remove.

So the name it gets here is just sort of a transient name, and it doesnt 
effect much in the greater scheme of things.  If people really feel 
strongly about it though, it wont hurt much to change it again.  I do 
try to point out the history of it though to avoid too much churn.  :-)

Allison

> 
> --D
> 
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error, done;
>> +
>> +	/*
>> +	 * Unmap value blocks for this attr.
>> +	 */
>> +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
>> +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
>> +	if (error)
>> +		return error;
>> +
>> +	error = xfs_defer_finish(&args->trans);
>> +	if (error)
>> +		return error;
>> +
>> +	if (!done)
>> +		return -EAGAIN;
>> +
>> +	return error;
>> +}
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate
  2020-05-04 17:41   ` Darrick J. Wong
@ 2020-05-04 22:55     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 22:55 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 10:41 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:03PM -0700, Allison Collins wrote:
>> This patch pulls xfs_attr_rmtval_invalidate out of
>> xfs_attr_rmtval_remove and into the calling functions.  Eventually
>> __xfs_attr_rmtval_remove will replace xfs_attr_rmtval_remove when we
>> introduce delayed attributes.  These functions are exepcted to return
>> -EAGAIN when they need a new transaction.  Because the invalidate does
>> not need a new transaction, we need to separate it from the rest of the
>> function that does.  This will enable __xfs_attr_rmtval_remove to
>> smoothly replace xfs_attr_rmtval_remove later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks good to me,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

Thank you!

Allison
> 
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        | 12 ++++++++++++
>>   fs/xfs/libxfs/xfs_attr_remote.c |  3 ---
>>   2 files changed, 12 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0fc6436..4fdfab9 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -669,6 +669,10 @@ xfs_attr_leaf_addname(
>>   		args->rmtblkcnt = args->rmtblkcnt2;
>>   		args->rmtvaluelen = args->rmtvaluelen2;
>>   		if (args->rmtblkno) {
>> +			error = xfs_attr_rmtval_invalidate(args);
>> +			if (error)
>> +				return error;
>> +
>>   			error = xfs_attr_rmtval_remove(args);
>>   			if (error)
>>   				return error;
>> @@ -1027,6 +1031,10 @@ xfs_attr_node_addname(
>>   		args->rmtblkcnt = args->rmtblkcnt2;
>>   		args->rmtvaluelen = args->rmtvaluelen2;
>>   		if (args->rmtblkno) {
>> +			error = xfs_attr_rmtval_invalidate(args);
>> +			if (error)
>> +				return error;
>> +
>>   			error = xfs_attr_rmtval_remove(args);
>>   			if (error)
>>   				return error;
>> @@ -1152,6 +1160,10 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> +		error = xfs_attr_rmtval_invalidate(args);
>> +		if (error)
>> +			return error;
>> +
>>   		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			goto out;
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 02d1a44..f770159 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -685,9 +685,6 @@ xfs_attr_rmtval_remove(
>>   
>>   	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.
>>   	 */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink
  2020-05-04 17:42   ` Darrick J. Wong
@ 2020-05-04 22:55     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 22:55 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 10:42 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:04PM -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>
> 
> Simple enough looking hoist;
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Great, thanks!

Allison
> 
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 68 ++++++++++++++++++++++++++++++------------------
>>   1 file changed, 42 insertions(+), 26 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 4fdfab9..d83443c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1108,6 +1108,45 @@ 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;
>> +
>> +		error = xfs_defer_finish(&args->trans);
>> +		if (error)
>> +			return error;
>> +	} 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
>> @@ -1120,8 +1159,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);
>> @@ -1206,30 +1244,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] 76+ messages in thread

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-05-04 22:53     ` Allison Collins
@ 2020-05-04 22:57       ` Darrick J. Wong
  0 siblings, 0 replies; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-04 22:57 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, May 04, 2020 at 03:53:25PM -0700, Allison Collins wrote:
> 
> 
> On 5/4/20 10:41 AM, Darrick J. Wong wrote:
> > On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
> > > xfs_attr_rmtval_remove
> > 
> > Like Brian suggested, this changelog could probably just say that we're
> > hoisting the loop body into a separate function so that delayed attrs
> > can manage the transaction rolling.
> > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
> > >   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
> > >   2 files changed, 37 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> > > index 4d51969..02d1a44 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> > > @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
> > >   	xfs_dablk_t		lblkno;
> > >   	int			blkcnt;
> > >   	int			error = 0;
> > > -	int			done = 0;
> > > +	int			retval = 0;
> > >   	trace_xfs_attr_rmtval_remove(args);
> > > @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
> > >   	 */
> > >   	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;
> > > +	do {
> > > +		retval = __xfs_attr_rmtval_remove(args);
> > > +		if (retval && retval != EAGAIN)
> > > +			return retval;
> > >   		/*
> > >   		 * Close out trans and start the next one in the chain.
> > > @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
> > >   		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > >   		if (error)
> > >   			return error;
> > > -	}
> > > +	} while (retval == -EAGAIN);
> > > +
> > >   	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
> > 
> > recall the function...?
> > 
> > Oh.  "re-call" the function.
> Will fix
> 
> > 
> > > + */
> > > +int
> > > +__xfs_attr_rmtval_remove(
> > 
> > xfs_attr_rmtval_remove_extent() ?
> Well, this would be the third rename for this function though. Initially I
> think we named it xfs_attr_rmtval_unmap, and then later we changed it to
> __xfs_attr_rmtval_remove.  Ultimatly, it really doesn't matter what the name
> is, because it's going to get renamed at the end of the set anyway.
> Eventually it replaces the calling function and becomes
> xfs_attr_rmtval_remove.
> 
> So the name it gets here is just sort of a transient name, and it doesnt
> effect much in the greater scheme of things.  If people really feel strongly
> about it though, it wont hurt much to change it again.  I do try to point
> out the history of it though to avoid too much churn.  :-)

Heh, ok.  /I/ don't care that much. :)

--D

> Allison
> 
> > 
> > --D
> > 
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error, done;
> > > +
> > > +	/*
> > > +	 * Unmap value blocks for this attr.
> > > +	 */
> > > +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
> > > +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	error = xfs_defer_finish(&args->trans);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	if (!done)
> > > +		return -EAGAIN;
> > > +
> > > +	return error;
> > > +}
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> > > index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
> > >   #endif /* __XFS_ATTR_REMOTE_H__ */
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v9 16/24] xfs: Add remote block helper functions
  2020-05-04 18:55   ` Darrick J. Wong
@ 2020-05-04 23:01     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:01 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 11:55 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:08PM -0700, 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 redundant
>> code associated with storing and retrieving remote blocks during the
>> attr set operations.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
> Hmm.  This is an ok-enough refactoring of the same idiom repeated over
> and over, but ...ugh, there has got to be a less weird way of pushing
> and popping state like this.
> 
> Unfortunately, the only thing I can think of would be to pass a "which
> attr state?" argument to all the attr functions, and that might just
> make things worse, particularly since we already have da state that gets
> passed around everywhere, and afaict there's on a few users of this.
> 
Hmm, ok, I'll give it some thought.  I just spotted it as a sort of 
clean up while trying to organize things.

> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Alrighty, thank you!

Allison
> 
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 50 +++++++++++++++++++++++++++++-------------------
>>   1 file changed, 30 insertions(+), 20 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index df77a3c..feae122 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -563,6 +563,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_save_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
>>    *
>> @@ -597,11 +621,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_save_rmt_blk(args);
>>   
>>   		/*
>>   		 * clear the remote attr state now that it is saved so that the
>> @@ -700,11 +720,8 @@ 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);
>> +
>>   		if (args->rmtblkno) {
>>   			error = xfs_attr_rmtval_invalidate(args);
>>   			if (error)
>> @@ -929,11 +946,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_save_rmt_blk(args);
>>   
>>   		/*
>>   		 * clear the remote attr state now that it is saved so that the
>> @@ -1045,11 +1058,8 @@ 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);
>> +
>>   		if (args->rmtblkno) {
>>   			error = xfs_attr_rmtval_invalidate(args);
>>   			if (error)
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup
  2020-05-04 18:58   ` Darrick J. Wong
@ 2020-05-04 23:02     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:02 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 11:58 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:09PM -0700, Allison Collins wrote:
>> This patch adds a new helper function xfs_attr_node_removename_setup.
>> This will help modularize xfs_attr_node_removename when we add delay
>> ready attributes later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 48 +++++++++++++++++++++++++++++++++++-------------
>>   1 file changed, 35 insertions(+), 13 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index feae122..c8226c6 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1184,6 +1184,39 @@ xfs_attr_leaf_mark_incomplete(
>>   }
>>   
>>   /*
>> + * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
>> + * the blocks are valid.  Any remote blocks will be marked incomplete.
> 
> "Attr keys with remote blocks will be marked incomplete."
Ok, will fix.

> 
>> + */
>> +STATIC
>> +int xfs_attr_node_removename_setup(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**state)
>> +{
>> +	int			error;
>> +	struct xfs_da_state_blk	*blk;
>> +
>> +	error = xfs_attr_node_hasname(args, state);
>> +	if (error != -EEXIST)
>> +		return error;
>> +
>> +	blk = &(*state)->path.blk[(*state)->path.active - 1];
>> +	ASSERT(blk->bp != NULL);
>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +
>> +	if (args->rmtblkno > 0) {
>> +		error = xfs_attr_leaf_mark_incomplete(args, *state);
>> +		if (error)
>> +			return error;
>> +
>> +		error = xfs_attr_rmtval_invalidate(args);
>> +		if (error)
>> +			return error;
> 
> 		return xfs_attr_rmtval_invalidate(args);
> 
> With those two things changed,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Ok, thank you!

Allison
> 
> --D
> 
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>>    * Remove a name from a B-tree attribute list.
>>    *
>>    * This will involve walking down the Btree, and may involve joining
>> @@ -1201,8 +1234,8 @@ xfs_attr_node_removename(
>>   
>>   	trace_xfs_attr_node_removename(args);
>>   
>> -	error = xfs_attr_node_hasname(args, &state);
>> -	if (error != -EEXIST)
>> +	error = xfs_attr_node_removename_setup(args, &state);
>> +	if (error)
>>   		goto out;
>>   
>>   	/*
>> @@ -1210,18 +1243,7 @@ xfs_attr_node_removename(
>>   	 * This is done before we remove the attribute so that we don't
>>   	 * overflow the maximum size of a transaction and/or hit a deadlock.
>>   	 */
>> -	blk = &state->path.blk[ state->path.active-1 ];
>> -	ASSERT(blk->bp != NULL);
>> -	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_leaf_mark_incomplete(args, state);
>> -		if (error)
>> -			goto out;
>> -
>> -		error = xfs_attr_rmtval_invalidate(args);
>> -		if (error)
>> -			return error;
>> -
>>   		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			goto out;
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt
  2020-05-04 19:00   ` Darrick J. Wong
@ 2020-05-04 23:04     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:04 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:00 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:10PM -0700, Allison Collins wrote:
>> This patch adds another new helper function
>> xfs_attr_node_removename_rmt. This will also help modularize
>> xfs_attr_node_removename when we add delay ready attributes later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 28 +++++++++++++++++++---------
>>   1 file changed, 19 insertions(+), 9 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index c8226c6..ab1c9fa 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1216,6 +1216,24 @@ int xfs_attr_node_removename_setup(
>>   	return 0;
>>   }
>>   
>> +STATIC int
>> +xfs_attr_node_removename_rmt (
> 
> xfs_attr_node_remove_rmt?
I believe this is a name Brian had asked for in a prior review, though I 
don't know how firmly set he is on it?

> 
> Otherwise looks ok,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Alrighty, thank you!

Allison

> 
> --D
> 
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	*state)
>> +{
>> +	int			error = 0;
>> +
>> +	error = xfs_attr_rmtval_remove(args);
>> +	if (error)
>> +		return error;
>> +
>> +	/*
>> +	 * Refill the state structure with buffers, the prior calls released our
>> +	 * buffers.
>> +	 */
>> +	return xfs_attr_refillstate(state);
>> +}
>> +
>>   /*
>>    * Remove a name from a B-tree attribute list.
>>    *
>> @@ -1244,15 +1262,7 @@ xfs_attr_node_removename(
>>   	 * overflow the maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_remove(args);
>> -		if (error)
>> -			goto out;
>> -
>> -		/*
>> -		 * Refill the state structure with buffers, the prior calls
>> -		 * released our buffers.
>> -		 */
>> -		error = xfs_attr_refillstate(state);
>> +		error = xfs_attr_node_removename_rmt(args, state);
>>   		if (error)
>>   			goto out;
>>   	}
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname
  2020-05-04 19:03   ` Darrick J. Wong
@ 2020-05-04 23:06     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:06 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:03 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:11PM -0700, Allison Collins wrote:
>> Quick patch to unnest the rename logic in the leaf code path.  This will
>> help simplify delayed attr logic later.
> 
> This isn't really an unnesting, is it?  We're inverting the if logic and
> flipping the subordinate blocks.
> 
> "Invert the rename logic in xfs_attr_leaf_addname to simplify the
> delayed attr logic later."
Alrighty, will fix

> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 108 +++++++++++++++++++++++------------------------
>>   1 file changed, 53 insertions(+), 55 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index ab1c9fa..1810f90 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -694,73 +694,71 @@ xfs_attr_leaf_addname(
>>   			return error;
>>   	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
> 
> 	if (!(args->op_flags & XFS_DA_OP_RENAME)) {
Sure, will flip.  Thanks!

Allison
> 
> --D
> 
>>   		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			return error;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> +		if (args->rmtblkno > 0)
>> +			error = xfs_attr3_leaf_clearflag(args);
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		xfs_attr_restore_rmt_blk(args);
>> +		return error;
>> +	}
>>   
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_invalidate(args);
>> -			if (error)
>> -				return error;
>> +	/*
>> +	 * If this is an atomic rename operation, we must "flip" the incomplete
>> +	 * flags on the "new" and "old" attribute/value pairs so that one
>> +	 * disappears and one appears atomically.  Then we must remove the "old"
>> +	 * attribute/value pair.
>> +	 *
>> +	 * In a separate transaction, set the incomplete flag on the "old" attr
>> +	 * and clear the incomplete flag on the "new" attr.
>> +	 */
>>   
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +	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;
>>   
>> -		/*
>> -		 * Read in the block containing the "old" attr, then
>> -		 * remove the "old" attr from that block (neat, huh!)
>> -		 */
>> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -					   &bp);
>> +	/*
>> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>> +	 * (if it exists).
>> +	 */
>> +	xfs_attr_restore_rmt_blk(args);
>> +
>> +	if (args->rmtblkno) {
>> +		error = xfs_attr_rmtval_invalidate(args);
>>   		if (error)
>>   			return error;
>>   
>> -		xfs_attr3_leaf_remove(bp, args);
>> -
>> -		/*
>> -		 * If the result is small enough, shrink it all into the inode.
>> -		 */
>> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -			/* bp is gone due to xfs_da_shrink_inode */
>> -			if (error)
>> -				return error;
>> -		}
>> -
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
>>   	}
>> +
>> +	/*
>> +	 * Read in the block containing the "old" attr, then remove the "old"
>> +	 * attr from that block (neat, huh!)
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> +				   &bp);
>> +	if (error)
>> +		return error;
>> +
>> +	xfs_attr3_leaf_remove(bp, args);
>> +
>> +	/*
>> +	 * If the result is small enough, shrink it all into the inode.
>> +	 */
>> +	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 */
>> +
>>   	return error;
>>   }
>>   
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname
  2020-05-04 19:06   ` Darrick J. Wong
@ 2020-05-04 23:16     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:16 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:06 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:12PM -0700, Allison Collins wrote:
>> Quick patch to unnest the rename logic in the node code path.  This will
>> help simplify delayed attr logic later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 131 +++++++++++++++++++++++------------------------
>>   1 file changed, 64 insertions(+), 67 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 1810f90..9171895 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1030,83 +1030,80 @@ xfs_attr_node_addname(
>>   			return error;
>>   	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			goto out;
>> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
> 
> Same comments about the commit message and the if test as the previous
> patch.
> 
> Admittedly I'm now starting to wonder if this patch and the previous one
> should really just hoist the taken and not-taken branches into separate
> functions, but maybe you've already gone around and around on that, and
> everyone else already thought we have too many small functions...
Yes, I had played with that and even suggested it myself in the last 
review.  What I didnt like about it after prototyping it, was having to 
plumb around the leaf_bp that is still needed for a rename, and also the 
state machine logic ends up getting plumbed downward, instead of trying 
to keep it up in one high level function.

Really the initial motivation for this patch was to just avoid putting 
xfs_das_* labels in the middle of if{} statements or loops when we get 
further down the set.  With that goal in mind, this solution seemed like 
the least amount of required surgery.  Though the patch itself tends to 
suggest a helper, I figure I'd let people consider this first before 
jumping to the later option which will end up with more plumbing.

Allison

> 
> --D
> 
>>   		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>> +		if (args->rmtblkno > 0)
>> +			error = xfs_attr3_leaf_clearflag(args);
>> +		retval = error;
>> +		goto out;
>> +	}
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		xfs_attr_restore_rmt_blk(args);
>> +	/*
>> +	 * If this is an atomic rename operation, we must "flip" the incomplete
>> +	 * flags on the "new" and "old" attribute/value pairs so that one
>> +	 * disappears and one appears atomically.  Then we must remove the "old"
>> +	 * attribute/value pair.
>> +	 *
>> +	 * In a separate transaction, set the incomplete flag on the "old" attr
>> +	 * and clear the incomplete flag on the "new" attr.
>> +	 */
>> +	error = xfs_attr3_leaf_flipflags(args);
>> +	if (error)
>> +		goto out;
>> +	/*
>> +	 * Commit the flag value change and start the next trans in series
>> +	 */
>> +	error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +	if (error)
>> +		goto out;
>>   
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_invalidate(args);
>> -			if (error)
>> -				return error;
>> +	/*
>> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>> +	 * (if it exists).
>> +	 */
>> +	xfs_attr_restore_rmt_blk(args);
>>   
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +	if (args->rmtblkno) {
>> +		error = xfs_attr_rmtval_invalidate(args);
>> +		if (error)
>> +			return error;
>>   
>> -		/*
>> -		 * Re-find the "old" attribute entry after any split ops.
>> -		 * The INCOMPLETE flag means that we will find the "old"
>> -		 * attr, not the "new" one.
>> -		 */
>> -		args->attr_filter |= XFS_ATTR_INCOMPLETE;
>> -		state = xfs_da_state_alloc();
>> -		state->args = args;
>> -		state->mp = mp;
>> -		state->inleaf = 0;
>> -		error = xfs_da3_node_lookup_int(state, &retval);
>> +		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>> +	}
>>   
>> -		/*
>> -		 * Remove the name and update the hashvals in the tree.
>> -		 */
>> -		blk = &state->path.blk[ state->path.active-1 ];
>> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -		error = xfs_attr3_leaf_remove(blk->bp, args);
>> -		xfs_da3_fixhashpath(state, &state->path);
>> +	/*
>> +	 * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
>> +	 * flag means that we will find the "old" attr, not the "new" one.
>> +	 */
>> +	args->attr_filter |= XFS_ATTR_INCOMPLETE;
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = mp;
>> +	state->inleaf = 0;
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error)
>> +		goto out;
>>   
>> -		/*
>> -		 * Check to see if the tree needs to be collapsed.
>> -		 */
>> -		if (retval && (state->path.active > 1)) {
>> -			error = xfs_da3_join(state);
>> -			if (error)
>> -				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>> -		}
>> +	/*
>> +	 * Remove the name and update the hashvals in the tree.
>> +	 */
>> +	blk = &state->path.blk[state->path.active-1];
>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +	error = xfs_attr3_leaf_remove(blk->bp, args);
>> +	xfs_da3_fixhashpath(state, &state->path);
>>   
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +	/*
>> +	 * Check to see if the tree needs to be collapsed.
>> +	 */
>> +	if (retval && (state->path.active > 1)) {
>> +		error = xfs_da3_join(state);
>> +		if (error)
>> +			goto out;
>> +		error = xfs_defer_finish(&args->trans);
>>   		if (error)
>>   			goto out;
>>   	}
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  2020-05-04 19:10   ` Darrick J. Wong
@ 2020-05-04 23:17     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-04 23:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:10 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:13PM -0700, Allison Collins wrote:
>> Lift -ENOSPC handler from xfs_attr_leaf_addname.  This will help to
>> reorganize transitions between the attr forms later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks decent,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
Ok, thank you!

Allison
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++--------------
>>   1 file changed, 11 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9171895..c8cae68 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -299,6 +299,13 @@ xfs_attr_set_args(
>>   			return error;
>>   
>>   		/*
>> +		 * Promote the attribute list to the Btree format.
>> +		 */
>> +		error = xfs_attr3_leaf_to_node(args);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>>   		 * Commit that transaction so that the node_addname()
>>   		 * call can manage its own transactions.
>>   		 */
>> @@ -602,7 +609,7 @@ xfs_attr_leaf_try_add(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_buf		*bp)
>>   {
>> -	int			retval, error;
>> +	int			retval;
>>   
>>   	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>> @@ -634,20 +641,10 @@ xfs_attr_leaf_try_add(
>>   	}
>>   
>>   	/*
>> -	 * Add the attribute to the leaf block, transitioning to a Btree
>> -	 * if required.
>> +	 * Add the attribute to the leaf block
>>   	 */
>> -	retval = xfs_attr3_leaf_add(bp, args);
>> -	if (retval == -ENOSPC) {
>> -		/*
>> -		 * 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;
>> -	}
>> -	return retval;
>> +	return xfs_attr3_leaf_add(bp, args);
>> +
>>   out_brelse:
>>   	xfs_trans_brelse(args->trans, bp);
>>   	return retval;
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-05-04 19:33   ` Darrick J. Wong
@ 2020-05-05  0:26     ` Allison Collins
  2020-05-05  1:44       ` Darrick J. Wong
  0 siblings, 1 reply; 76+ messages in thread
From: Allison Collins @ 2020-05-05  0:26 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:33 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:14PM -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.  A new XFS_DAC_DEFER_FINISH flag is used to finish the
>> transaction where ever the existing code used to.
>>
>> Calls to xfs_attr_rmtval_remove are replaced with the delay ready
>> version __xfs_attr_rmtval_remove. We will rename
>> __xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
>> done.
>>
>> xfs_attr_rmtval_remove itself is still in use by the set routines (used
>> during a rename).  For reasons of perserving existing function, we
>> modify xfs_attr_rmtval_remove to call xfs_defer_finish when the flag is
>> set.  Similar to how xfs_attr_remove_args does here.  Once we transition
>> the set routines to be delay ready, xfs_attr_rmtval_remove is no longer
>> used and will be removed.
>>
>> 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_attr_node_removename()
>>                                                   │
>>                                                   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        | 159 ++++++++++++++++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
>>   fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
>>   fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
>>   fs/xfs/xfs_attr_inactive.c      |   2 +-
>>   6 files changed, 215 insertions(+), 54 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index c8cae68..7213589 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -53,12 +53,21 @@ STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>    */
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>> -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>>   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);
>>   
>> +void
>> +xfs_delattr_context_init(
>> +	struct xfs_delattr_context	*dac,
>> +	struct xfs_da_args		*args)
>> +{
>> +	memset(dac, 0, sizeof(struct xfs_delattr_context));
>> +	dac->da_args = args;
> 
> Couldn't this could be open coded as:
> 
> struct xfs_delattr_context	dac = {
> 	.da_args		= args,
> };
> 
> in the callers?  One less helper function, and it means that the stack
> contents will always be fully initialized.
I believe Dave had suggested the initializer back when I had dac a 
member of args instead of the other way around.  I dont know that he was 
too particular about exactly what the initializer was though.  Is this 
generally the standard for initializers?

> 
>> +}
>> +
>>   int
>>   xfs_inode_hasattr(
>>   	struct xfs_inode	*ip)
>> @@ -263,6 +272,18 @@ xfs_attr_set_shortform(
>>   	return 0;
>>   }
>>   
>> +int xfs_attr_defer_finish(
> 
> static inline int
> xfs_attr_defer_finish(
> 
>> +	struct xfs_delattr_context      *dac)
>> +{
>> +	struct xfs_da_args              *args = dac->da_args;
>> +
>> +	if (!(dac->flags & XFS_DAC_DEFER_FINISH))
>> +		return 0;
>> +
>> +	dac->flags &= ~XFS_DAC_DEFER_FINISH;
>> +	return xfs_defer_finish(&args->trans);
> 
> I also wonder if you want to hoist the trans_roll_inode to here too?
> 
> Actually, what if this instead became:
> 
> static inline bool
> xfs_attr_roll_again(
> 	struct xfs_delattr_context	*dac,
> 	int				*error)
> {
> 	if (*error != -EAGAIN)
> 		return false;
> 
> 	if (dac->flags & XFS_DAC_DEFER_FINISH)) {
> 		dac->flags &= ~XFS_DAC_DEFER_FINISH;
> 		*error = xfs_defer_finish(&args->trans);
> 		if (*error)
> 			return false;
> 	}
> 
> 	*error = xfs_trans_roll_inode(&dac->da_args->trans, dac->da_args->dp);
> 	return *error == 0;
> }
> 
Sure, that should be fine

>> +}
>> +
>>   /*
>>    * Set the attribute specified in @args.
>>    */
>> @@ -363,23 +384,57 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> -	struct xfs_da_args      *args)
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error = 0;
>> +	struct			xfs_delattr_context dac;
>> +
>> +	xfs_delattr_context_init(&dac, args);
>> +
>> +	do {
>> +		error = xfs_attr_remove_iter(&dac);
>> +		if (error != -EAGAIN)
>> +			break;
>> +
>> +		error = xfs_attr_defer_finish(&dac);
>> +		if (error)
>> +			break;
>> +
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			break;
>> +	} while (true);
> 
> and then this whole function becomes:
> 
> int
> xfs_attr_remove_args(
> 	struct xfs_da_args		*args)
> {
> 	struct xfs_delattr_context	dac = {
> 		.da_args		= args,
> 	};
> 
> 	do {
> 		error = xfs_attr_remove_iter(&dac);
> 	} while (xfs_attr_roll_again(&dac, &error));
> 
> 	return error;
> }
Alrighty then

> 
>> +
>> +	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_delattr_context *dac)
>>   {
>> +	struct xfs_da_args	*args = dac->da_args;
>>   	struct xfs_inode	*dp = args->dp;
>> -	int			error;
>> +
>> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
>> +		goto node;
>>   
>>   	if (!xfs_inode_hasattr(dp)) {
>> -		error = -ENOATTR;
>> +		return -ENOATTR;
>>   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>   		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> -		error = xfs_attr_shortform_remove(args);
>> +		return xfs_attr_shortform_remove(args);
>>   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -		error = xfs_attr_leaf_removename(args);
>> -	} else {
>> -		error = xfs_attr_node_removename(args);
>> +		return xfs_attr_leaf_removename(args);
>>   	}
>> -
>> -	return error;
>> +node:
>> +	return  xfs_attr_node_removename(dac);
>>   }
>>   
>>   /*
>> @@ -1177,15 +1232,17 @@ xfs_attr_leaf_mark_incomplete(
>>   
>>   /*
>>    * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
>> - * the blocks are valid.  Any remote blocks will be marked incomplete.
>> + * the blocks are valid.  Any remote blocks will be marked incomplete and
>> + * invalidated.
>>    */
>>   STATIC
>>   int xfs_attr_node_removename_setup(
>> -	struct xfs_da_args	*args,
>> -	struct xfs_da_state	**state)
>> +	struct xfs_delattr_context	*dac,
>> +	struct xfs_da_state		**state)
>>   {
>> -	int			error;
>> -	struct xfs_da_state_blk	*blk;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	int				error;
>> +	struct xfs_da_state_blk		*blk;
>>   
>>   	error = xfs_attr_node_hasname(args, state);
>>   	if (error != -EEXIST)
>> @@ -1195,6 +1252,13 @@ int xfs_attr_node_removename_setup(
>>   	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
>> +	 */
>> +	dac->blk = blk;
>> +	dac->da_state = *state;
>> +
>>   	if (args->rmtblkno > 0) {
>>   		error = xfs_attr_leaf_mark_incomplete(args, *state);
>>   		if (error)
>> @@ -1210,12 +1274,15 @@ int xfs_attr_node_removename_setup(
>>   
>>   STATIC int
>>   xfs_attr_node_removename_rmt (
>> -	struct xfs_da_args	*args,
>> -	struct xfs_da_state	*state)
>> +	struct xfs_delattr_context	*dac,
>> +	struct xfs_da_state		*state)
>>   {
>> -	int			error = 0;
>> +	int				error = 0;
>>   
>> -	error = xfs_attr_rmtval_remove(args);
>> +	/*
>> +	 * May return -EAGAIN to request that the caller recall this function
>> +	 */
>> +	error = __xfs_attr_rmtval_remove(dac);
>>   	if (error)
>>   		return error;
>>   
>> @@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
>>    * 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(
>> -	struct xfs_da_args	*args)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	struct xfs_da_state	*state;
>> -	struct xfs_da_state_blk	*blk;
>> -	int			retval, error;
>> -	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_da_state		*state;
>> +	struct xfs_da_state_blk		*blk;
>> +	int				retval, error;
>> +	struct xfs_inode		*dp = args->dp;
>>   
>>   	trace_xfs_attr_node_removename(args);
>> +	state = dac->da_state;
>> +	blk = dac->blk;
>>   
>> -	error = xfs_attr_node_removename_setup(args, &state);
>> -	if (error)
>> -		goto out;
>> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
>> +		goto das_rm_shrink;
>> +
>> +	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
>> +		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
>> +		error = xfs_attr_node_removename_setup(dac, &state);
> 
> Shouldn't XFS_DAC_NODE_RMVNAME_INIT be set by
> xfs_attr_node_removename_setup?
I suppose it could be.  Initially this was a state not a flag, so that's 
why we see it here in this scope.

There may be reason to keep it there though.  These -EAGAIN functions 
are admittadly sort of jumpy, so when trying to trace them though, 
haveing the flag in the top level like that makes it clear that when we 
come back through on another iteration, we dont init twice.  Really, 
it's more to do with managing function re-entry than anything else going 
on in the init function.  I think Brian and I have been trying our best 
to keep code flow craziness in the same scope rather than letting them 
get burried in subfunctions.  Though I suppose it wouldnt be too hard to 
find if folks prefer the flag be in the subfunction?



> 
>> +		if (error)
>> +			goto out;
>> +	}
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
>>   	 * overflow the maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_node_removename_rmt(args, state);
>> -		if (error)
>> +		/*
>> +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
>> +		 */
>> +		error = xfs_attr_node_removename_rmt(dac, state);
>> +		if (error == -EAGAIN)
>> +			return error;
>> +		else if (error)
>>   			goto out;
>>   	}
>>   
>> @@ -1274,17 +1360,14 @@ 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;
>> +
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>> +		dac->dela_state = XFS_DAS_RM_SHRINK;
>> +		return -EAGAIN;
>>   	}
>>   
>> +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 66575b8..0430c79 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -74,6 +74,75 @@ struct xfs_attr_list_context {
>>   };
>>   
>>   
>> +/*
>> + * ========================================================================
>> + * Structure used to pass context around among the delayed routines.
>> + * ========================================================================
>> + */
>> +
>> +/*
>> + * 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_attr_node_removename()
>> + *	                                      │
>> + *	                                      v
>> + *	                                   need to
>> + *	                                shrink tree? ─n─┐
>> + *	                                      │         │
>> + *	                                      y         │
>> + *	                                      │         │
>> + *	                                      v         │
>> + *	                              XFS_DAS_RM_SHRINK │
>> + *	                                      │         │
>> + *	                                      v         │
>> + *	                                     done <─────┘
>> + *
>> + */
>> +
>> +/*
>> + * 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 {
>> +				      /* Zero is uninitalized */
>> +	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
>> +};
>> +
>> +/*
>> + * Defines for xfs_delattr_context.flags
>> + */
>> +#define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>> +#define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delattr_context {
>> +	struct xfs_da_args      *da_args;
>> +
>> +	/* Used in xfs_attr_node_removename to roll through removing blocks */
>> +	struct xfs_da_state     *da_state;
>> +	struct xfs_da_state_blk *blk;
>> +
>> +	/* Used to keep track of current state of delayed operation */
>> +	unsigned int            flags;
>> +	enum xfs_delattr_state  dela_state;
>> +};
>> +
>>   /*========================================================================
>>    * Function prototypes for the kernel.
>>    *========================================================================*/
>> @@ -91,6 +160,10 @@ int xfs_attr_set(struct xfs_da_args *args);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>>   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_delattr_context *dac);
>> +int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>> +void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>> +			      struct xfs_da_args *args);
>>   
>>   #endif	/* __XFS_ATTR_H__ */
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index f55402b..2e36c8b 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -19,8 +19,8 @@
>>   #include "xfs_bmap_btree.h"
>>   #include "xfs_bmap.h"
>>   #include "xfs_attr_sf.h"
>> -#include "xfs_attr_remote.h"
>>   #include "xfs_attr.h"
>> +#include "xfs_attr_remote.h"
>>   #include "xfs_attr_leaf.h"
>>   #include "xfs_error.h"
>>   #include "xfs_trace.h"
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index f770159..f2d46c7 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -676,14 +676,16 @@ xfs_attr_rmtval_invalidate(
>>    */
>>   int
>>   xfs_attr_rmtval_remove(
>> -	struct xfs_da_args      *args)
>> +	struct xfs_da_args		*args)
>>   {
>> -	xfs_dablk_t		lblkno;
>> -	int			blkcnt;
>> -	int			error = 0;
>> -	int			retval = 0;
>> +	struct xfs_delattr_context	dac;
>> +	xfs_dablk_t			lblkno;
>> +	int				blkcnt;
>> +	int				error = 0;
>> +	int				retval = 0;
>>   
>>   	trace_xfs_attr_rmtval_remove(args);
>> +	xfs_delattr_context_init(&dac, args);
>>   
>>   	/*
>>   	 * Keep de-allocating extents until the remote-value region is gone.
>> @@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
>>   	lblkno = args->rmtblkno;
>>   	blkcnt = args->rmtblkcnt;
>>   	do {
>> -		retval = __xfs_attr_rmtval_remove(args);
>> +		retval = __xfs_attr_rmtval_remove(&dac);
>>   		if (retval && retval != EAGAIN)
>>   			return retval;
>>   
>> +		error = xfs_attr_defer_finish(&dac);
>> +		if (error)
>> +			break;
>> +
>>   		/*
>>   		 * Close out trans and start the next one in the chain.
>>   		 */
>> @@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
>>    */
>>   int
>>   __xfs_attr_rmtval_remove(
>> -	struct xfs_da_args	*args)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	int			error, done;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	int				error, done;
>>   
>>   	/*
>>   	 * Unmap value blocks for this attr.
>> @@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
>>   	if (error)
>>   		return error;
>>   
>> -	error = xfs_defer_finish(&args->trans);
>> -	if (error)
>> -		return error;
>> -
>> -	if (!done)
>> +	if (!done) {
>> +		dac->flags &= ~XFS_DAC_DEFER_FINISH;
> 
> Why do we strip off DEFER_FINISH here?  Is it because we're making
> xfs_attr_rmtval_remove invoke xfs_defer_finish unconditionally to clear
> out any pending rmap items?
Sorry, that should have been a flag set, not a strip.  Will fix!

> 
> If you transformed the do-while loop in xfs_attr_rmtval_remove to use
> xfs_attr_roll_again, then you could make this set DEFER_FINISH, which
> would make me a lot less suspicious that we're dropping state here.
> 
> (It would also clean up a lot of the defer_finish -> trans_roll_inode
> code that's scattering everywhere...)
Yes, will do that.  Thanks for the review!

> 
> --D
> 
>>   		return -EAGAIN;
>> +	}
>>   
>>   	return error;
>>   }
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index ee3337b..351da00 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -14,5 +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_remove(struct xfs_da_args *args);
>> +int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
>> index c42f90e..b2150fa 100644
>> --- a/fs/xfs/xfs_attr_inactive.c
>> +++ b/fs/xfs/xfs_attr_inactive.c
>> @@ -15,10 +15,10 @@
>>   #include "xfs_da_format.h"
>>   #include "xfs_da_btree.h"
>>   #include "xfs_inode.h"
>> +#include "xfs_attr.h"
>>   #include "xfs_attr_remote.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_bmap.h"
>> -#include "xfs_attr.h"
>>   #include "xfs_attr_leaf.h"
>>   #include "xfs_quota.h"
>>   #include "xfs_dir2.h"
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove
  2020-05-04 19:34   ` Darrick J. Wong
@ 2020-05-05  0:27     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05  0:27 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:34 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:16PM -0700, Allison Collins wrote:
>> Now that xfs_attr_rmtval_remove is gone, rename __xfs_attr_rmtval_remove
>> to xfs_attr_rmtval_remove
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
Thanks!
Allison

> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        | 7 +++----
>>   fs/xfs/libxfs/xfs_attr_remote.c | 2 +-
>>   fs/xfs/libxfs/xfs_attr_remote.h | 3 +--
>>   3 files changed, 5 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0751231..d76a970 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -874,7 +874,7 @@ xfs_attr_leaf_addname(
>>   		return error;
>>   das_rm_lblk:
>>   	if (args->rmtblkno) {
>> -		error = __xfs_attr_rmtval_remove(dac);
>> +		error = xfs_attr_rmtval_remove(dac);
>>   
>>   		if (error == -EAGAIN) {
>>   			dac->dela_state = XFS_DAS_RM_LBLK;
>> @@ -1244,8 +1244,7 @@ xfs_attr_node_addname(
>>   
>>   das_rm_nblk:
>>   	if (args->rmtblkno) {
>> -		error = __xfs_attr_rmtval_remove(dac);
>> -
>> +		error = xfs_attr_rmtval_remove(dac);
>>   		if (error == -EAGAIN) {
>>   			dac->dela_state = XFS_DAS_RM_NBLK;
>>   			return -EAGAIN;
>> @@ -1409,7 +1408,7 @@ xfs_attr_node_removename_rmt (
>>   	/*
>>   	 * May return -EAGAIN to request that the caller recall this function
>>   	 */
>> -	error = __xfs_attr_rmtval_remove(dac);
>> +	error = xfs_attr_rmtval_remove(dac);
>>   	if (error)
>>   		return error;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 7a342f1..21c7aa9 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -740,7 +740,7 @@ xfs_attr_rmtval_invalidate(
>>    * transaction and recall the function
>>    */
>>   int
>> -__xfs_attr_rmtval_remove(
>> +xfs_attr_rmtval_remove(
>>   	struct xfs_delattr_context	*dac)
>>   {
>>   	struct xfs_da_args		*args = dac->da_args;
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 51a1c91..09fda56 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -10,11 +10,10 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>>   
>>   int xfs_attr_rmtval_get(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set(struct xfs_da_args *args);
>> -int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_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_remove(struct xfs_delattr_context *dac);
>> +int xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>>   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_delattr_context *dac);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
  2020-05-04 18:46   ` Darrick J. Wong
@ 2020-05-05  0:29     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05  0:29 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 11:46 AM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:06PM -0700, Allison Collins wrote:
>> In this patch, we hoist code from xfs_attr_set_args into two new helpers
>> xfs_attr_is_shortform and xfs_attr_set_shortform.  These two will help
>> to simplify xfs_attr_set_args when we get into delayed attrs later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> 
> Looks ok to me,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
Thank yoU!

Allison
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 107 +++++++++++++++++++++++++++++++----------------
>>   1 file changed, 72 insertions(+), 35 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index af47566..d112910 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -204,6 +204,66 @@ 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_is_shortform(
>> +	struct xfs_inode    *ip)
>> +{
>> +	return ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> +	       (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> +	        ip->i_d.di_anextents == 0);
>> +}
>> +
>> +/*
>> + * Attempts to set an attr in shortform, or converts short form to leaf form if
>> + * there is not enough room.  If the attr is set, the transaction is committed
>> + * and set to NULL.
>> + */
>> +STATIC int
>> +xfs_attr_set_shortform(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf		**leaf_bp)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	int			error, error2 = 0;
>> +
>> +	/*
>> +	 * 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;
>> +	}
>> +	/*
>> +	 * 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. 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;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>>    * Set the attribute specified in @args.
>>    */
>>   int
>> @@ -212,48 +272,25 @@ xfs_attr_set_args(
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error, error2 = 0;
>> +	int			error = 0;
>>   
>>   	/*
>> -	 * 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_is_shortform(dp)) {
>>   
>>   		/*
>> -		 * Try to add the attr to the attribute list in the inode.
>> +		 * If the attr was successfully set in shortform, the
>> +		 * transaction is committed and set to NULL.  Otherwise, is it
>> +		 * converted from shortform to leaf, and the transaction is
>> +		 * retained.
>>   		 */
>> -		error = xfs_attr_try_sf_addname(dp, args);
>> -		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.
>> -		 * 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.
>> -		 * 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);
>> +		error = xfs_attr_set_shortform(args, &leaf_bp);
>> +		if (error || !args->trans)
>>   			return error;
>> -		}
>>   	}
>>   
>>   	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v9 23/24] xfs: Add delay ready attr set routines
  2020-05-04 19:49   ` Darrick J. Wong
@ 2020-05-05  1:31     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05  1:31 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 12:49 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:15PM -0700, Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready. This means
>> they no longer roll or commit transactions, but instead return -EAGAIN
>> to have the calling routine roll and refresh the transaction.  In this
>> series, xfs_attr_set_args has become xfs_attr_set_iter, which uses a
>> state machine like switch to keep track of where it was when EAGAIN was
>> returned.
>>
>> 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. xfs_attr_set_args has
>> now become a simple loop to refresh the transaction until the operation
>> is completed.  Lastly, xfs_attr_rmtval_remove is no longer used, and is
>> removed.
>>
>> 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
>>    ┌──────n── fork has
>>    │         only 1 blk?
> 
> "Refer to the state machine diagram in xfs_attr.h for exact details of
> how this works."
Sure, that fine

> 
>>    │              │
>>    │              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_attr_leaf_addname()
>>    │                                              │
>>    │                                              v
>>    │                                            was this
>>    │                                           a rename? ──n─┐
>>    │                                              │          │
>>    │                                              y          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                        flip incomplete  │
>>    │                                            flag         │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                      XFS_DAS_FLIP_LFLAG │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                            remove       │
>>    │                        XFS_DAS_RM_LBLK ─> old name      │
>>    │                                 ^            │          │
>>    │                                 │            v          │
>>    │                                 └──────y── more to      │
>>    │                                            remove       │
>>    │                                              │          │
>>    │                                              n          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                             done <──────┘
>>    └────> 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       │
>>                             XFS_DAS_RM_NBLK ─> 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        | 371 +++++++++++++++++++++++++++-------------
>>   fs/xfs/libxfs/xfs_attr.h        | 127 +++++++++++++-
>>   fs/xfs/libxfs/xfs_attr_remote.c | 110 +++++++-----
>>   fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>>   fs/xfs/xfs_trace.h              |   1 -
>>   5 files changed, 445 insertions(+), 168 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7213589..0751231 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -44,7 +44,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>    * Internal routines when attribute list is one block.
>>    */
>>   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_addname(struct xfs_delattr_context *dac);
>>   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);
>>   
>> @@ -52,12 +52,13 @@ 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.
>>    */
>>   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_addname(struct xfs_delattr_context *dac);
>>   STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>>   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);
>>   
>>   void
>>   xfs_delattr_context_init(
>> @@ -227,8 +228,11 @@ xfs_attr_is_shortform(
>>   
>>   /*
>>    * Attempts to set an attr in shortform, or converts short form to leaf form if
>> - * there is not enough room.  If the attr is set, the transaction is committed
>> - * and set to NULL.
>> + * there is not enough room.  This function is meant to operate as a helper
>> + * routine to the delayed attribute functions.  It returns -EAGAIN to indicate
>> + * that the calling function should roll the transaction, and then proceed to
>> + * add the attr in leaf form.  This subroutine does not expect to be recalled
>> + * again like the other delayed attr routines do.
>>    */
>>   STATIC int
>>   xfs_attr_set_shortform(
>> @@ -236,16 +240,16 @@ xfs_attr_set_shortform(
>>   	struct xfs_buf		**leaf_bp)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	int			error, error2 = 0;
>> +	int			error = 0;
>>   
>>   	/*
>>   	 * 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) {
>> -		error2 = xfs_trans_commit(args->trans);
>> -		args->trans = NULL;
>> -		return error ? error : error2;
>> +		return error;
>>   	}
>>   	/*
>>   	 * It won't fit in the shortform, transform to a leaf block.  GROT:
>> @@ -258,20 +262,13 @@ xfs_attr_set_shortform(
>>   	/*
>>   	 * 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.
>> +	 * with the write verifier.
>>   	 */
>>   	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;
>> -	}
>> -
>> -	return 0;
>> +	return -EAGAIN;
>>   }
>>   
>> +STATIC
>>   int xfs_attr_defer_finish(
>>   	struct xfs_delattr_context      *dac)
>>   {
>> @@ -291,60 +288,128 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error = 0;
>> +	struct xfs_buf			*leaf_bp = NULL;
>> +	int				error = 0;
>> +	struct xfs_delattr_context	dac;
>> +
>> +	xfs_delattr_context_init(&dac, args);
>> +
>> +	do {
>> +		error = xfs_attr_set_iter(&dac, &leaf_bp);
>> +		if (error != -EAGAIN)
>> +			break;
>> +
>> +		error = xfs_attr_defer_finish(&dac);
>> +		if (error)
>> +			break;
>> +
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			break;
> 
> 	if (!xfs_attr_roll_again(&dac, &error))
> 		break;
Yep, ok

> 
>> +
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (true);
>> +
>> +	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_delattr_context	*dac,
>> +	struct xfs_buf			**leaf_bp)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	/* State machine switch */
>> +	switch (dac->dela_state) {
>> +	case XFS_DAS_FLIP_LFLAG:
>> +	case XFS_DAS_FOUND_LBLK:
>> +		goto das_leaf;
>> +	case XFS_DAS_FOUND_NBLK:
>> +	case XFS_DAS_FLIP_NFLAG:
>> +	case XFS_DAS_ALLOC_NODE:
>> +		goto das_node;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * 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.
>> +	 * again. No need to set state as we will be in leaf form when we come
>> +	 * back
>>   	 */
>>   	if (xfs_attr_is_shortform(dp)) {
>>   
>>   		/*
>> -		 * If the attr was successfully set in shortform, the
>> -		 * transaction is committed and set to NULL.  Otherwise, is it
>> -		 * converted from shortform to leaf, and the transaction is
>> -		 * retained.
>> +		 * If the attr was successfully set in shortform, no need to
>> +		 * continue.  Otherwise, is it converted from shortform to leaf
>> +		 * and -EAGAIN is returned.
>>   		 */
>> -		error = xfs_attr_set_shortform(args, &leaf_bp);
>> -		if (error || !args->trans)
>> -			return error;
>> -	}
>> +		error = xfs_attr_set_shortform(args, leaf_bp);
>> +		if (error == -EAGAIN)
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>>   
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -		error = xfs_attr_leaf_addname(args);
>> -		if (error != -ENOSPC)
>> -			return error;
>> +		return error;
>> +	}
>>   
>> -		/*
>> -		 * Promote the attribute list to the Btree format.
>> -		 */
>> -		error = xfs_attr3_leaf_to_node(args);
>> -		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_bhold_release(args->trans, *leaf_bp);
>> +		*leaf_bp = NULL;
>> +	}
>>   
>> -		/*
>> -		 * Commit that transaction so that the node_addname()
>> -		 * call can manage its own transactions.
>> -		 */
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		switch (error) {
>> +		case -ENOSPC:
>> +			/*
>> +			 * Promote the attribute list to the Btree format.
>> +			 */
>> +			error = xfs_attr3_leaf_to_node(args);
>> +			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)
>> +			/*
>> +			 * Commit that transaction so that the node_addname()
>> +			 * call can manage its own transactions.
>> +			 */
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			return -EAGAIN;
>> +		case 0:
>> +			dac->dela_state = XFS_DAS_FOUND_LBLK;
>> +			return -EAGAIN;
>> +		default:
>>   			return error;
>> +		}
>> +das_leaf:
>> +		error = xfs_attr_leaf_addname(dac);
>> +		if (error == -ENOSPC)
>> +			/* We will be in node form when we return */
>> +			return -EAGAIN;
>>   
>> +		return error;
>>   	}
>> -
>> -	error = xfs_attr_node_addname(args);
>> +das_node:
>> +	error = xfs_attr_node_addname(dac);
>>   	return error;
>>   }
>>   
>> @@ -711,28 +776,30 @@ 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)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	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;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_buf			*bp = NULL;
>> +	int				error, forkoff;
>> +	struct xfs_inode		*dp = args->dp;
>>   
>> -	/*
>> -	 * 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 (dac->dela_state) {
>> +	case XFS_DAS_FLIP_LFLAG:
>> +		goto das_flip_flag;
>> +	case XFS_DAS_RM_LBLK:
>> +		goto das_rm_lblk;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -740,12 +807,34 @@ xfs_attr_leaf_addname(
>>   	 * after we create the attribute so that we don't overflow the
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>> -	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> +
>> +	/* Open coded xfs_attr_rmtval_set without trans handling */
>> +	if ((dac->flags & XFS_DAC_LEAF_ADDNAME_INIT) == 0) {
>> +		dac->flags |= XFS_DAC_LEAF_ADDNAME_INIT;
>> +		if (args->rmtblkno > 0) {
>> +			error = xfs_attr_rmtval_set_init(dac);
>> +			if (error)
>> +				return error;
>> +		}
>> +	}
>> +
>> +	/*
>> +	 * Roll through the "value", allocating blocks on disk as
>> +	 * required.
>> +	 */
>> +	while (dac->blkcnt > 0) {
> 
> if() ?
> 
>> +		error = xfs_attr_rmtval_set_blk(dac);
>>   		if (error)
>>   			return error;
>> +
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>> +		return -EAGAIN;
>>   	}
>>   
>> +	error = xfs_attr_rmtval_set_value(args);
>> +	if (error)
>> +		return error;
>> +
>>   	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
>> @@ -765,29 +854,33 @@ xfs_attr_leaf_addname(
>>   	 * In a separate transaction, set the incomplete flag on the "old" attr
>>   	 * and clear the incomplete flag on the "new" attr.
>>   	 */
>> -
>>   	error = xfs_attr3_leaf_flipflags(args);
>>   	if (error)
>>   		return error;
>>   	/*
>>   	 * Commit the flag value change and start the next trans in series.
>>   	 */
>> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -	if (error)
>> -		return error;
>> -
>> +	dac->dela_state = XFS_DAS_FLIP_LFLAG;
>> +	return -EAGAIN;
>> +das_flip_flag:
>>   	/*
>>   	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>>   	 * (if it exists).
>>   	 */
>>   	xfs_attr_restore_rmt_blk(args);
>>   
>> +	error = xfs_attr_rmtval_invalidate(args);
>> +	if (error)
>> +		return error;
>> +das_rm_lblk:
>>   	if (args->rmtblkno) {
>> -		error = xfs_attr_rmtval_invalidate(args);
>> -		if (error)
>> -			return error;
>> +		error = __xfs_attr_rmtval_remove(dac);
>> +
>> +		if (error == -EAGAIN) {
>> +			dac->dela_state = XFS_DAS_RM_LBLK;
>> +			return -EAGAIN;
>> +		}
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -957,16 +1050,23 @@ xfs_attr_node_hasname(
>>    *
>>    * "Remote" attribute values confuse the issue and atomic rename operations
>>    * add a whole extra layer of confusion on top of that.
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + *returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_addname(
>> -	struct xfs_da_args	*args)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	struct xfs_da_state	*state;
>> -	struct xfs_da_state_blk	*blk;
>> -	struct xfs_inode	*dp;
>> -	struct xfs_mount	*mp;
>> -	int			retval, error;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_da_state		*state = NULL;
>> +	struct xfs_da_state_blk		*blk;
>> +	struct xfs_inode		*dp;
>> +	struct xfs_mount		*mp;
>> +	int				retval = 0;
>> +	int				error = 0;
>>   
>>   	trace_xfs_attr_node_addname(args);
>>   
>> @@ -975,7 +1075,21 @@ xfs_attr_node_addname(
>>   	 */
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -restart:
>> +
>> +	/* State machine switch */
>> +	switch (dac->dela_state) {
>> +	case XFS_DAS_FLIP_NFLAG:
>> +		goto das_flip_flag;
>> +	case XFS_DAS_FOUND_NBLK:
>> +		goto das_found_nblk;
>> +	case XFS_DAS_ALLOC_NODE:
>> +		goto das_alloc_node;
>> +	case XFS_DAS_RM_NBLK:
>> +		goto das_rm_nblk;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>> @@ -1021,19 +1135,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;
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			return -EAGAIN;
>>   		}
>>   
>>   		/*
>> @@ -1045,9 +1153,7 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_split(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>>   	} else {
>>   		/*
>>   		 * Addition succeeded, update Btree hashvals.
>> @@ -1062,13 +1168,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;
>> +	dac->dela_state = XFS_DAS_FOUND_NBLK;
>> +	return -EAGAIN;
>> +das_found_nblk:
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -1077,7 +1179,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(dac);
> 
> Do we need to test/set LEAF_ADDNAME_INIT here too?
> 
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>> +		 */
>> +das_alloc_node:
>> +		while (dac->blkcnt > 0) {
> 
> if() ?
> 
>> +			error = xfs_attr_rmtval_set_blk(dac);
>> +			if (error)
>> +				return error;
>> +
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			dac->dela_state = XFS_DAS_ALLOC_NODE;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -1107,22 +1229,28 @@ xfs_attr_node_addname(
>>   	/*
>>   	 * 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;
>> -
>> +	dac->dela_state = XFS_DAS_FLIP_NFLAG;
>> +	return -EAGAIN;
>> +das_flip_flag:
>>   	/*
>>   	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>>   	 * (if it exists).
>>   	 */
>>   	xfs_attr_restore_rmt_blk(args);
>>   
>> +	error = xfs_attr_rmtval_invalidate(args);
>> +	if (error)
>> +		return error;
>> +
>> +das_rm_nblk:
>>   	if (args->rmtblkno) {
>> -		error = xfs_attr_rmtval_invalidate(args);
>> -		if (error)
>> -			return error;
>> +		error = __xfs_attr_rmtval_remove(dac);
>> +
>> +		if (error == -EAGAIN) {
>> +			dac->dela_state = XFS_DAS_RM_NBLK;
>> +			return -EAGAIN;
>> +		}
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -1155,9 +1283,8 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_join(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> +
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 0430c79..5cbefa90 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -106,6 +106,118 @@ struct xfs_attr_list_context {
>>    *	                                      v         │
>>    *	                                     done <─────┘
>>    *
>> + *
>> + * Below is a state machine diagram for attr set operations.
>> + *
>> + *  xfs_attr_set_iter()
>> + *             │
>> + *             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_attr_leaf_addname()
>> + *   │		                      │
>> + *   │		                      v
>> + *   │		                   was this
>> + *   │		                   a rename? ──n─┐
>> + *   │		                      │          │
>> + *   │		                      y          │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                flip incomplete  │
>> + *   │		                    flag         │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		              XFS_DAS_FLIP_LFLAG │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                    remove       │
>> + *   │		XFS_DAS_RM_LBLK ─> old name      │
>> + *   │		         ^            │          │
>> + *   │		         │            v          │
>> + *   │		         └──────y── more to      │
>> + *   │		                    remove       │
>> + *   │		                      │          │
>> + *   │		                      n          │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                     done <──────┘
>> + *   └──> 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       │
>> + *	         XFS_DAS_RM_NBLK ─> old name      │
>> + *	                  ^            │          │
>> + *	                  │            v          │
>> + *	                  └──────y── more to      │
>> + *	                             remove       │
>> + *	                               │          │
>> + *	                               n          │
>> + *	                               │          │
>> + *	                               v          │
>> + *	                              done <──────┘
>> + *
>>    */
>>   
>>   /*
>> @@ -120,6 +232,13 @@ struct xfs_attr_list_context {
>>   enum xfs_delattr_state {
>>   				      /* Zero is uninitalized */
>>   	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
>> +	XFS_DAS_FOUND_LBLK,	      /* We found leaf blk for attr */
>> +	XFS_DAS_FOUND_NBLK,	      /* We found node blk for attr */
>> +	XFS_DAS_FLIP_LFLAG,	      /* Flipped leaf INCOMPLETE attr flag */
>> +	XFS_DAS_RM_LBLK,	      /* A rename is removing leaf blocks */
>> +	XFS_DAS_ALLOC_NODE,	      /* We are allocating node blocks */
>> +	XFS_DAS_FLIP_NFLAG,	      /* Flipped node INCOMPLETE attr flag */
>> +	XFS_DAS_RM_NBLK,	      /* A rename is removing node blocks */
>>   };
>>   
>>   /*
>> @@ -127,6 +246,7 @@ enum xfs_delattr_state {
>>    */
>>   #define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>>   #define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
>> +#define XFS_DAC_LEAF_ADDNAME_INIT	0x04 /* xfs_attr_leaf_addname init*/
>>   
>>   /*
>>    * Context used for keeping track of delayed attribute operations
>> @@ -134,6 +254,11 @@ enum xfs_delattr_state {
>>   struct xfs_delattr_context {
>>   	struct xfs_da_args      *da_args;
>>   
>> +	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	int			blkcnt;
>> +
>>   	/* Used in xfs_attr_node_removename to roll through removing blocks */
>>   	struct xfs_da_state     *da_state;
>>   	struct xfs_da_state_blk *blk;
>> @@ -158,10 +283,10 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
>>   int xfs_attr_get(struct xfs_da_args *args);
>>   int xfs_attr_set(struct xfs_da_args *args);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> +int xfs_attr_set_iter(struct xfs_delattr_context *dac, struct xfs_buf **leaf_bp);
>>   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_delattr_context *dac);
>> -int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>>   void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>>   			      struct xfs_da_args *args);
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index f2d46c7..7a342f1 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,70 @@ 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(
> 
> /me wonders if this ought to be named xfs_attr_rmtval_find_space() ?
> 
> That's more or less what it's getting ready to do, right?
This is one Brian had asked for, though I'm not sure how set he is about 
names?

> 
>> +	struct xfs_delattr_context	*dac)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_bmbt_irec		*map = &dac->map;
>> +	int error;
> 
> 	int				error;
> 
>> +
>> +	dac->lblkno = 0;
>> +	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;
>> +
>> +	dac->blkcnt = args->rmtblkcnt;
>> +	dac->lblkno = args->rmtblkno;
>> +
>> +	return error;
> 
> This could be return 0;.
Sure

> 
>> +}
>> +
>> +/*
>> + * 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_delattr_context	*dac)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_inode		*dp = args->dp;
>> +	struct xfs_bmbt_irec		*map = &dac->map;
>> +	int nmap;
>> +	int error;
>> +
>> +	nmap = 1;
>> +	error = xfs_bmapi_write(args->trans, dp,
>> +		  (xfs_fileoff_t)dac->lblkno,
>> +		  dac->blkcnt, XFS_BMAPI_ATTRFORK,
>> +		  args->total, map, &nmap);
> 
> The indenting here could be improved.
ok, will fix.  Will jump into cont' email now :-)

> 
> Whee, ok, it's lunchtime.  I'll look at the state machine after eating.
> 
> --D
> 
>> +	if (error)
>> +		return error;
>> +
>> +	ASSERT(nmap == 1);
>> +	ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +	       (map->br_startblock != HOLESTARTBLOCK));
>> +
>> +	/* roll attribute extent map forwards */
>> +	dac->lblkno += map->br_blockcount;
>> +	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.
>>    */
>> @@ -671,48 +735,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)
>> -{
>> -	struct xfs_delattr_context	dac;
>> -	xfs_dablk_t			lblkno;
>> -	int				blkcnt;
>> -	int				error = 0;
>> -	int				retval = 0;
>> -
>> -	trace_xfs_attr_rmtval_remove(args);
>> -	xfs_delattr_context_init(&dac, args);
>> -
>> -	/*
>> -	 * Keep de-allocating extents until the remote-value region is gone.
>> -	 */
>> -	lblkno = args->rmtblkno;
>> -	blkcnt = args->rmtblkcnt;
>> -	do {
>> -		retval = __xfs_attr_rmtval_remove(&dac);
>> -		if (retval && retval != EAGAIN)
>> -			return retval;
>> -
>> -		error = xfs_attr_defer_finish(&dac);
>> -		if (error)
>> -			break;
>> -
>> -		/*
>> -		 * Close out trans and start the next one in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> -	} while (retval == -EAGAIN);
>> -
>> -	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/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 351da00..51a1c91 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_remove(struct xfs_delattr_context *dac);
>> +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_delattr_context *dac);
>> +int xfs_attr_rmtval_set_init(struct xfs_delattr_context *dac);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
>> index a4323a6..26dc8bf 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -1784,7 +1784,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] 76+ messages in thread

* Re: [PATCH v9 23/24] xfs: Add delay ready attr set routines
  2020-05-04 22:36   ` Darrick J. Wong
@ 2020-05-05  1:32     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05  1:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 3:36 PM, Darrick J. Wong wrote:
> On Thu, Apr 30, 2020 at 03:50:15PM -0700, Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready. This means
>> they no longer roll or commit transactions, but instead return -EAGAIN
>> to have the calling routine roll and refresh the transaction.  In this
>> series, xfs_attr_set_args has become xfs_attr_set_iter, which uses a
>> state machine like switch to keep track of where it was when EAGAIN was
>> returned.
>>
>> 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. xfs_attr_set_args has
>> now become a simple loop to refresh the transaction until the operation
>> is completed.  Lastly, xfs_attr_rmtval_remove is no longer used, and is
>> removed.
>>
>> 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
>>    ┌──────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_attr_leaf_addname()
>>    │                                              │
>>    │                                              v
>>    │                                            was this
>>    │                                           a rename? ──n─┐
>>    │                                              │          │
>>    │                                              y          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                        flip incomplete  │
>>    │                                            flag         │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                      XFS_DAS_FLIP_LFLAG │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                            remove       │
>>    │                        XFS_DAS_RM_LBLK ─> old name      │
>>    │                                 ^            │          │
>>    │                                 │            v          │
>>    │                                 └──────y── more to      │
>>    │                                            remove       │
>>    │                                              │          │
>>    │                                              n          │
>>    │                                              │          │
>>    │                                              v          │
>>    │                                             done <──────┘
>>    └────> 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       │
>>                             XFS_DAS_RM_NBLK ─> 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        | 371 +++++++++++++++++++++++++++-------------
>>   fs/xfs/libxfs/xfs_attr.h        | 127 +++++++++++++-
>>   fs/xfs/libxfs/xfs_attr_remote.c | 110 +++++++-----
>>   fs/xfs/libxfs/xfs_attr_remote.h |   4 +
>>   fs/xfs/xfs_trace.h              |   1 -
>>   5 files changed, 445 insertions(+), 168 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7213589..0751231 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -44,7 +44,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>    * Internal routines when attribute list is one block.
>>    */
>>   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_addname(struct xfs_delattr_context *dac);
>>   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);
>>   
>> @@ -52,12 +52,13 @@ 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.
>>    */
>>   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_addname(struct xfs_delattr_context *dac);
>>   STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>>   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);
>>   
>>   void
>>   xfs_delattr_context_init(
>> @@ -227,8 +228,11 @@ xfs_attr_is_shortform(
>>   
>>   /*
>>    * Attempts to set an attr in shortform, or converts short form to leaf form if
>> - * there is not enough room.  If the attr is set, the transaction is committed
>> - * and set to NULL.
>> + * there is not enough room.  This function is meant to operate as a helper
>> + * routine to the delayed attribute functions.  It returns -EAGAIN to indicate
>> + * that the calling function should roll the transaction, and then proceed to
>> + * add the attr in leaf form.  This subroutine does not expect to be recalled
>> + * again like the other delayed attr routines do.
>>    */
>>   STATIC int
>>   xfs_attr_set_shortform(
>> @@ -236,16 +240,16 @@ xfs_attr_set_shortform(
>>   	struct xfs_buf		**leaf_bp)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	int			error, error2 = 0;
>> +	int			error = 0;
>>   
>>   	/*
>>   	 * 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) {
>> -		error2 = xfs_trans_commit(args->trans);
>> -		args->trans = NULL;
>> -		return error ? error : error2;
>> +		return error;
>>   	}
>>   	/*
>>   	 * It won't fit in the shortform, transform to a leaf block.  GROT:
>> @@ -258,20 +262,13 @@ xfs_attr_set_shortform(
>>   	/*
>>   	 * 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.
>> +	 * with the write verifier.
>>   	 */
>>   	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;
>> -	}
>> -
>> -	return 0;
>> +	return -EAGAIN;
>>   }
>>   
>> +STATIC
>>   int xfs_attr_defer_finish(
>>   	struct xfs_delattr_context      *dac)
>>   {
>> @@ -291,60 +288,128 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error = 0;
>> +	struct xfs_buf			*leaf_bp = NULL;
>> +	int				error = 0;
>> +	struct xfs_delattr_context	dac;
>> +
>> +	xfs_delattr_context_init(&dac, args);
>> +
>> +	do {
>> +		error = xfs_attr_set_iter(&dac, &leaf_bp);
>> +		if (error != -EAGAIN)
>> +			break;
>> +
>> +		error = xfs_attr_defer_finish(&dac);
>> +		if (error)
>> +			break;
>> +
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			break;
>> +
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (true);
>> +
>> +	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(
> 
> Could this be a static function above xfs_attr_set()?  Or is this
> something that will need to be exported in a later series?
Later it will be called by the log replay routines, but I suppose it 
could be static for now.

> 
>> +	struct xfs_delattr_context	*dac,
>> +	struct xfs_buf			**leaf_bp)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	/* State machine switch */
>> +	switch (dac->dela_state) {
>> +	case XFS_DAS_FLIP_LFLAG:
>> +	case XFS_DAS_FOUND_LBLK:
>> +		goto das_leaf;
>> +	case XFS_DAS_FOUND_NBLK:
>> +	case XFS_DAS_FLIP_NFLAG:
>> +	case XFS_DAS_ALLOC_NODE:
>> +		goto das_node;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * 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.
>> +	 * again. No need to set state as we will be in leaf form when we come
>> +	 * back
>>   	 */
>>   	if (xfs_attr_is_shortform(dp)) {
>>   
>>   		/*
>> -		 * If the attr was successfully set in shortform, the
>> -		 * transaction is committed and set to NULL.  Otherwise, is it
>> -		 * converted from shortform to leaf, and the transaction is
>> -		 * retained.
>> +		 * If the attr was successfully set in shortform, no need to
>> +		 * continue.  Otherwise, is it converted from shortform to leaf
>> +		 * and -EAGAIN is returned.
>>   		 */
>> -		error = xfs_attr_set_shortform(args, &leaf_bp);
>> -		if (error || !args->trans)
>> -			return error;
>> -	}
>> +		error = xfs_attr_set_shortform(args, leaf_bp);
>> +		if (error == -EAGAIN)
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>>   
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -		error = xfs_attr_leaf_addname(args);
>> -		if (error != -ENOSPC)
>> -			return error;
>> +		return error;
>> +	}
>>   
>> -		/*
>> -		 * Promote the attribute list to the Btree format.
>> -		 */
>> -		error = xfs_attr3_leaf_to_node(args);
>> -		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
> 
> "cycle"
ok, will fix
> 
>> +	 * the leaf.
>> +	 */
>> +	if (*leaf_bp != NULL) {
>> +		xfs_trans_bhold_release(args->trans, *leaf_bp);
>> +		*leaf_bp = NULL;
>> +	}
>>   
>> -		/*
>> -		 * Commit that transaction so that the node_addname()
>> -		 * call can manage its own transactions.
>> -		 */
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		switch (error) {
>> +		case -ENOSPC:
>> +			/*
>> +			 * Promote the attribute list to the Btree format.
>> +			 */
>> +			error = xfs_attr3_leaf_to_node(args);
>> +			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)
>> +			/*
>> +			 * Commit that transaction so that the node_addname()
>> +			 * call can manage its own transactions.
>> +			 */
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			return -EAGAIN;
>> +		case 0:
>> +			dac->dela_state = XFS_DAS_FOUND_LBLK;
>> +			return -EAGAIN;
>> +		default:
>>   			return error;
>> +		}
>> +das_leaf:
>> +		error = xfs_attr_leaf_addname(dac);
>> +		if (error == -ENOSPC)
>> +			/* We will be in node form when we return */
> 
> Er, how does this happen?  Is this comment merely referencing the node
> conversion that just happened 20 lines above?  Or does something else do
> the conversion too?
Ok, basically this comment is here in place of what used to be a state 
set.  There used to be a line here:

			dac->dela_state =  XFS_DAS_LEAF_TO_NODE

which jumped back down to the das_node tag below.  The reason we can get 
away with out needing a state is because  when we jump out and jump back 
in, the if(xfs_bmap_one_block()) will fail, and drop us back down to 
where the das_node tag is anyway.  Hope that makes sense?

Maybe the comment should say:
			/* No need to set state.  We will be in node form when we are recalled */

?

Some of the states from v8 we can get away from by leveraging things 
like this, though I have pondered if that reduces readability?

> 
>> +			return -EAGAIN;
>>   
>> +		return error;
>>   	}
>> -
>> -	error = xfs_attr_node_addname(args);
>> +das_node:
>> +	error = xfs_attr_node_addname(dac);
>>   	return error;
>>   }
>>   
>> @@ -711,28 +776,30 @@ 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)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	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;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_buf			*bp = NULL;
>> +	int				error, forkoff;
>> +	struct xfs_inode		*dp = args->dp;
>>   
>> -	/*
>> -	 * 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 (dac->dela_state) {
>> +	case XFS_DAS_FLIP_LFLAG:
>> +		goto das_flip_flag;
>> +	case XFS_DAS_RM_LBLK:
>> +		goto das_rm_lblk;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -740,12 +807,34 @@ xfs_attr_leaf_addname(
>>   	 * after we create the attribute so that we don't overflow the
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>> -	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> +
>> +	/* Open coded xfs_attr_rmtval_set without trans handling */
>> +	if ((dac->flags & XFS_DAC_LEAF_ADDNAME_INIT) == 0) {
>> +		dac->flags |= XFS_DAC_LEAF_ADDNAME_INIT;
>> +		if (args->rmtblkno > 0) {
>> +			error = xfs_attr_rmtval_set_init(dac);
>> +			if (error)
>> +				return error;
>> +		}
>> +	}
>> +
>> +	/*
>> +	 * Roll through the "value", allocating blocks on disk as
>> +	 * required.
>> +	 */
>> +	while (dac->blkcnt > 0) {
>> +		error = xfs_attr_rmtval_set_blk(dac);
>>   		if (error)
>>   			return error;
>> +
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>> +		return -EAGAIN;
>>   	}
>>   
>> +	error = xfs_attr_rmtval_set_value(args);
>> +	if (error)
>> +		return error;
>> +
>>   	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
>> @@ -765,29 +854,33 @@ xfs_attr_leaf_addname(
>>   	 * In a separate transaction, set the incomplete flag on the "old" attr
>>   	 * and clear the incomplete flag on the "new" attr.
>>   	 */
>> -
>>   	error = xfs_attr3_leaf_flipflags(args);
>>   	if (error)
>>   		return error;
>>   	/*
>>   	 * Commit the flag value change and start the next trans in series.
>>   	 */
>> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -	if (error)
>> -		return error;
>> -
>> +	dac->dela_state = XFS_DAS_FLIP_LFLAG;
>> +	return -EAGAIN;
>> +das_flip_flag:
>>   	/*
>>   	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>>   	 * (if it exists).
>>   	 */
>>   	xfs_attr_restore_rmt_blk(args);
>>   
>> +	error = xfs_attr_rmtval_invalidate(args);
>> +	if (error)
>> +		return error;
>> +das_rm_lblk:
>>   	if (args->rmtblkno) {
>> -		error = xfs_attr_rmtval_invalidate(args);
>> -		if (error)
>> -			return error;
>> +		error = __xfs_attr_rmtval_remove(dac);
>> +
>> +		if (error == -EAGAIN) {
>> +			dac->dela_state = XFS_DAS_RM_LBLK;
>> +			return -EAGAIN;
>> +		}
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
> 
> This whole bit could condense to:
> 
> 		error = __xfs_attr_rmtval_remove(dac);
> 		if (error == -EAGAIN)
> 			dac->dela_state = XFS_DAS_RM_LBLK;
> 		if (error)
> 			return error;
Ok, will update

> 
> 
>>   	}
>> @@ -957,16 +1050,23 @@ xfs_attr_node_hasname(
>>    *
>>    * "Remote" attribute values confuse the issue and atomic rename operations
>>    * add a whole extra layer of confusion on top of that.
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + *returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_addname(
>> -	struct xfs_da_args	*args)
>> +	struct xfs_delattr_context	*dac)
>>   {
>> -	struct xfs_da_state	*state;
>> -	struct xfs_da_state_blk	*blk;
>> -	struct xfs_inode	*dp;
>> -	struct xfs_mount	*mp;
>> -	int			retval, error;
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_da_state		*state = NULL;
>> +	struct xfs_da_state_blk		*blk;
>> +	struct xfs_inode		*dp;
>> +	struct xfs_mount		*mp;
>> +	int				retval = 0;
>> +	int				error = 0;
>>   
>>   	trace_xfs_attr_node_addname(args);
>>   
>> @@ -975,7 +1075,21 @@ xfs_attr_node_addname(
>>   	 */
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -restart:
>> +
>> +	/* State machine switch */
>> +	switch (dac->dela_state) {
>> +	case XFS_DAS_FLIP_NFLAG:
>> +		goto das_flip_flag;
>> +	case XFS_DAS_FOUND_NBLK:
>> +		goto das_found_nblk;
>> +	case XFS_DAS_ALLOC_NODE:
>> +		goto das_alloc_node;
>> +	case XFS_DAS_RM_NBLK:
>> +		goto das_rm_nblk;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>> @@ -1021,19 +1135,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;
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			return -EAGAIN;
>>   		}
>>   
>>   		/*
>> @@ -1045,9 +1153,7 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_split(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>>   	} else {
>>   		/*
>>   		 * Addition succeeded, update Btree hashvals.
>> @@ -1062,13 +1168,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;
>> +	dac->dela_state = XFS_DAS_FOUND_NBLK;
>> +	return -EAGAIN;
>> +das_found_nblk:
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -1077,7 +1179,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(dac);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>> +		 */
>> +das_alloc_node:
>> +		while (dac->blkcnt > 0) {
>> +			error = xfs_attr_rmtval_set_blk(dac);
>> +			if (error)
>> +				return error;
>> +
>> +			dac->flags |= XFS_DAC_DEFER_FINISH;
>> +			dac->dela_state = XFS_DAS_ALLOC_NODE;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -1107,22 +1229,28 @@ xfs_attr_node_addname(
>>   	/*
>>   	 * 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;
>> -
>> +	dac->dela_state = XFS_DAS_FLIP_NFLAG;
>> +	return -EAGAIN;
>> +das_flip_flag:
>>   	/*
>>   	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>>   	 * (if it exists).
>>   	 */
>>   	xfs_attr_restore_rmt_blk(args);
>>   
>> +	error = xfs_attr_rmtval_invalidate(args);
>> +	if (error)
>> +		return error;
>> +
>> +das_rm_nblk:
>>   	if (args->rmtblkno) {
>> -		error = xfs_attr_rmtval_invalidate(args);
>> -		if (error)
>> -			return error;
>> +		error = __xfs_attr_rmtval_remove(dac);
>> +
>> +		if (error == -EAGAIN) {
>> +			dac->dela_state = XFS_DAS_RM_NBLK;
>> +			return -EAGAIN;
>> +		}
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -1155,9 +1283,8 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_join(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> +
>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 0430c79..5cbefa90 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -106,6 +106,118 @@ struct xfs_attr_list_context {
>>    *	                                      v         │
>>    *	                                     done <─────┘
>>    *
>> + *
>> + * Below is a state machine diagram for attr set operations.
>> + *
>> + *  xfs_attr_set_iter()
>> + *             │
>> + *             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_attr_leaf_addname()
>> + *   │		                      │
>> + *   │		                      v
>> + *   │		                   was this
>> + *   │		                   a rename? ──n─┐
>> + *   │		                      │          │
>> + *   │		                      y          │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                flip incomplete  │
>> + *   │		                    flag         │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		              XFS_DAS_FLIP_LFLAG │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                    remove       │
>> + *   │		XFS_DAS_RM_LBLK ─> old name      │
>> + *   │		         ^            │          │
>> + *   │		         │            v          │
>> + *   │		         └──────y── more to      │
>> + *   │		                    remove       │
>> + *   │		                      │          │
>> + *   │		                      n          │
>> + *   │		                      │          │
>> + *   │		                      v          │
>> + *   │		                     done <──────┘
>> + *   └──> 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       │
>> + *	         XFS_DAS_RM_NBLK ─> old name      │
>> + *	                  ^            │          │
>> + *	                  │            v          │
>> + *	                  └──────y── more to      │
>> + *	                             remove       │
>> + *	                               │          │
>> + *	                               n          │
>> + *	                               │          │
>> + *	                               v          │
>> + *	                              done <──────┘
> 
> Ok, I traced through all this and I /think/ the state machine
> accurately reflects the code paths before all the surgery started.
> Whoever knew that implementing a key-value store was so complex?

I don't think any of us foresaw it becoming what it has back when we 
first started.  Comparatively, parent pointers seems less complex.  :-) 
In any case, it certainly seems unique!

Thanks for the reviews!!

Allison

> 
> --D
> 
>> + *
>>    */
>>   
>>   /*
>> @@ -120,6 +232,13 @@ struct xfs_attr_list_context {
>>   enum xfs_delattr_state {
>>   				      /* Zero is uninitalized */
>>   	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
>> +	XFS_DAS_FOUND_LBLK,	      /* We found leaf blk for attr */
>> +	XFS_DAS_FOUND_NBLK,	      /* We found node blk for attr */
>> +	XFS_DAS_FLIP_LFLAG,	      /* Flipped leaf INCOMPLETE attr flag */
>> +	XFS_DAS_RM_LBLK,	      /* A rename is removing leaf blocks */
>> +	XFS_DAS_ALLOC_NODE,	      /* We are allocating node blocks */
>> +	XFS_DAS_FLIP_NFLAG,	      /* Flipped node INCOMPLETE attr flag */
>> +	XFS_DAS_RM_NBLK,	      /* A rename is removing node blocks */
>>   };
>>   
>>   /*
>> @@ -127,6 +246,7 @@ enum xfs_delattr_state {
>>    */
>>   #define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>>   #define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
>> +#define XFS_DAC_LEAF_ADDNAME_INIT	0x04 /* xfs_attr_leaf_addname init*/
>>   
>>   /*
>>    * Context used for keeping track of delayed attribute operations
>> @@ -134,6 +254,11 @@ enum xfs_delattr_state {
>>   struct xfs_delattr_context {
>>   	struct xfs_da_args      *da_args;
>>   
>> +	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	int			blkcnt;
>> +
>>   	/* Used in xfs_attr_node_removename to roll through removing blocks */
>>   	struct xfs_da_state     *da_state;
>>   	struct xfs_da_state_blk *blk;
>> @@ -158,10 +283,10 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
>>   int xfs_attr_get(struct xfs_da_args *args);
>>   int xfs_attr_set(struct xfs_da_args *args);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> +int xfs_attr_set_iter(struct xfs_delattr_context *dac, struct xfs_buf **leaf_bp);
>>   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_delattr_context *dac);
>> -int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>>   void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>>   			      struct xfs_da_args *args);
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index f2d46c7..7a342f1 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,70 @@ 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_delattr_context	*dac)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_bmbt_irec		*map = &dac->map;
>> +	int error;
>> +
>> +	dac->lblkno = 0;
>> +	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;
>> +
>> +	dac->blkcnt = args->rmtblkcnt;
>> +	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_delattr_context	*dac)
>> +{
>> +	struct xfs_da_args		*args = dac->da_args;
>> +	struct xfs_inode		*dp = args->dp;
>> +	struct xfs_bmbt_irec		*map = &dac->map;
>> +	int nmap;
>> +	int error;
>> +
>> +	nmap = 1;
>> +	error = xfs_bmapi_write(args->trans, dp,
>> +		  (xfs_fileoff_t)dac->lblkno,
>> +		  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 */
>> +	dac->lblkno += map->br_blockcount;
>> +	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.
>>    */
>> @@ -671,48 +735,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)
>> -{
>> -	struct xfs_delattr_context	dac;
>> -	xfs_dablk_t			lblkno;
>> -	int				blkcnt;
>> -	int				error = 0;
>> -	int				retval = 0;
>> -
>> -	trace_xfs_attr_rmtval_remove(args);
>> -	xfs_delattr_context_init(&dac, args);
>> -
>> -	/*
>> -	 * Keep de-allocating extents until the remote-value region is gone.
>> -	 */
>> -	lblkno = args->rmtblkno;
>> -	blkcnt = args->rmtblkcnt;
>> -	do {
>> -		retval = __xfs_attr_rmtval_remove(&dac);
>> -		if (retval && retval != EAGAIN)
>> -			return retval;
>> -
>> -		error = xfs_attr_defer_finish(&dac);
>> -		if (error)
>> -			break;
>> -
>> -		/*
>> -		 * Close out trans and start the next one in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> -	} while (retval == -EAGAIN);
>> -
>> -	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/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 351da00..51a1c91 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_remove(struct xfs_delattr_context *dac);
>> +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_delattr_context *dac);
>> +int xfs_attr_rmtval_set_init(struct xfs_delattr_context *dac);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
>> index a4323a6..26dc8bf 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -1784,7 +1784,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] 76+ messages in thread

* Re: [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-05-05  0:26     ` Allison Collins
@ 2020-05-05  1:44       ` Darrick J. Wong
  2020-05-05 17:35         ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Darrick J. Wong @ 2020-05-05  1:44 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, May 04, 2020 at 05:26:52PM -0700, Allison Collins wrote:
> 
> 
> On 5/4/20 12:33 PM, Darrick J. Wong wrote:
> > On Thu, Apr 30, 2020 at 03:50:14PM -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.  A new XFS_DAC_DEFER_FINISH flag is used to finish the
> > > transaction where ever the existing code used to.
> > > 
> > > Calls to xfs_attr_rmtval_remove are replaced with the delay ready
> > > version __xfs_attr_rmtval_remove. We will rename
> > > __xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
> > > done.
> > > 
> > > xfs_attr_rmtval_remove itself is still in use by the set routines (used
> > > during a rename).  For reasons of perserving existing function, we
> > > modify xfs_attr_rmtval_remove to call xfs_defer_finish when the flag is
> > > set.  Similar to how xfs_attr_remove_args does here.  Once we transition
> > > the set routines to be delay ready, xfs_attr_rmtval_remove is no longer
> > > used and will be removed.
> > > 
> > > 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_attr_node_removename()
> > >                                                   │
> > >                                                   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        | 159 ++++++++++++++++++++++++++++++----------
> > >   fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
> > >   fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
> > >   fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
> > >   fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
> > >   fs/xfs/xfs_attr_inactive.c      |   2 +-
> > >   6 files changed, 215 insertions(+), 54 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index c8cae68..7213589 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -53,12 +53,21 @@ STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
> > >    */
> > >   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> > > -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > > +STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
> > >   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);
> > > +void
> > > +xfs_delattr_context_init(
> > > +	struct xfs_delattr_context	*dac,
> > > +	struct xfs_da_args		*args)
> > > +{
> > > +	memset(dac, 0, sizeof(struct xfs_delattr_context));
> > > +	dac->da_args = args;
> > 
> > Couldn't this could be open coded as:
> > 
> > struct xfs_delattr_context	dac = {
> > 	.da_args		= args,
> > };
> > 
> > in the callers?  One less helper function, and it means that the stack
> > contents will always be fully initialized.
> I believe Dave had suggested the initializer back when I had dac a member of
> args instead of the other way around.  I dont know that he was too
> particular about exactly what the initializer was though.  Is this generally
> the standard for initializers?

One of them, yes. :)

I've started to prefer that form simply because we don't have to
remember that some struct is uninitialized between its definition and
some later initializer function call.  There are (many) places where
we have to unpack other things before we can initialize a struct, but
for the simpler cases I like to reduce the brainpower needed to
understand code, lest I turn into Mr. D P Gumby.

> > 
> > > +}
> > > +
> > >   int
> > >   xfs_inode_hasattr(
> > >   	struct xfs_inode	*ip)
> > > @@ -263,6 +272,18 @@ xfs_attr_set_shortform(
> > >   	return 0;
> > >   }
> > > +int xfs_attr_defer_finish(
> > 
> > static inline int
> > xfs_attr_defer_finish(
> > 
> > > +	struct xfs_delattr_context      *dac)
> > > +{
> > > +	struct xfs_da_args              *args = dac->da_args;
> > > +
> > > +	if (!(dac->flags & XFS_DAC_DEFER_FINISH))
> > > +		return 0;
> > > +
> > > +	dac->flags &= ~XFS_DAC_DEFER_FINISH;
> > > +	return xfs_defer_finish(&args->trans);
> > 
> > I also wonder if you want to hoist the trans_roll_inode to here too?
> > 
> > Actually, what if this instead became:
> > 
> > static inline bool
> > xfs_attr_roll_again(
> > 	struct xfs_delattr_context	*dac,
> > 	int				*error)
> > {
> > 	if (*error != -EAGAIN)
> > 		return false;
> > 
> > 	if (dac->flags & XFS_DAC_DEFER_FINISH)) {
> > 		dac->flags &= ~XFS_DAC_DEFER_FINISH;
> > 		*error = xfs_defer_finish(&args->trans);
> > 		if (*error)
> > 			return false;
> > 	}
> > 
> > 	*error = xfs_trans_roll_inode(&dac->da_args->trans, dac->da_args->dp);
> > 	return *error == 0;
> > }
> > 
> Sure, that should be fine
> 
> > > +}
> > > +
> > >   /*
> > >    * Set the attribute specified in @args.
> > >    */
> > > @@ -363,23 +384,57 @@ xfs_has_attr(
> > >    */
> > >   int
> > >   xfs_attr_remove_args(
> > > -	struct xfs_da_args      *args)
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error = 0;
> > > +	struct			xfs_delattr_context dac;
> > > +
> > > +	xfs_delattr_context_init(&dac, args);
> > > +
> > > +	do {
> > > +		error = xfs_attr_remove_iter(&dac);
> > > +		if (error != -EAGAIN)
> > > +			break;
> > > +
> > > +		error = xfs_attr_defer_finish(&dac);
> > > +		if (error)
> > > +			break;
> > > +
> > > +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		if (error)
> > > +			break;
> > > +	} while (true);
> > 
> > and then this whole function becomes:
> > 
> > int
> > xfs_attr_remove_args(
> > 	struct xfs_da_args		*args)
> > {
> > 	struct xfs_delattr_context	dac = {
> > 		.da_args		= args,
> > 	};
> > 
> > 	do {
> > 		error = xfs_attr_remove_iter(&dac);
> > 	} while (xfs_attr_roll_again(&dac, &error));
> > 
> > 	return error;
> > }
> Alrighty then
> 
> > 
> > > +
> > > +	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_delattr_context *dac)
> > >   {
> > > +	struct xfs_da_args	*args = dac->da_args;
> > >   	struct xfs_inode	*dp = args->dp;
> > > -	int			error;
> > > +
> > > +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> > > +		goto node;
> > >   	if (!xfs_inode_hasattr(dp)) {
> > > -		error = -ENOATTR;
> > > +		return -ENOATTR;
> > >   	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > >   		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> > > -		error = xfs_attr_shortform_remove(args);
> > > +		return xfs_attr_shortform_remove(args);
> > >   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > -		error = xfs_attr_leaf_removename(args);
> > > -	} else {
> > > -		error = xfs_attr_node_removename(args);
> > > +		return xfs_attr_leaf_removename(args);
> > >   	}
> > > -
> > > -	return error;
> > > +node:
> > > +	return  xfs_attr_node_removename(dac);
> > >   }
> > >   /*
> > > @@ -1177,15 +1232,17 @@ xfs_attr_leaf_mark_incomplete(
> > >   /*
> > >    * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
> > > - * the blocks are valid.  Any remote blocks will be marked incomplete.
> > > + * the blocks are valid.  Any remote blocks will be marked incomplete and
> > > + * invalidated.
> > >    */
> > >   STATIC
> > >   int xfs_attr_node_removename_setup(
> > > -	struct xfs_da_args	*args,
> > > -	struct xfs_da_state	**state)
> > > +	struct xfs_delattr_context	*dac,
> > > +	struct xfs_da_state		**state)
> > >   {
> > > -	int			error;
> > > -	struct xfs_da_state_blk	*blk;
> > > +	struct xfs_da_args		*args = dac->da_args;
> > > +	int				error;
> > > +	struct xfs_da_state_blk		*blk;
> > >   	error = xfs_attr_node_hasname(args, state);
> > >   	if (error != -EEXIST)
> > > @@ -1195,6 +1252,13 @@ int xfs_attr_node_removename_setup(
> > >   	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
> > > +	 */
> > > +	dac->blk = blk;
> > > +	dac->da_state = *state;
> > > +
> > >   	if (args->rmtblkno > 0) {
> > >   		error = xfs_attr_leaf_mark_incomplete(args, *state);
> > >   		if (error)
> > > @@ -1210,12 +1274,15 @@ int xfs_attr_node_removename_setup(
> > >   STATIC int
> > >   xfs_attr_node_removename_rmt (
> > > -	struct xfs_da_args	*args,
> > > -	struct xfs_da_state	*state)
> > > +	struct xfs_delattr_context	*dac,
> > > +	struct xfs_da_state		*state)
> > >   {
> > > -	int			error = 0;
> > > +	int				error = 0;
> > > -	error = xfs_attr_rmtval_remove(args);
> > > +	/*
> > > +	 * May return -EAGAIN to request that the caller recall this function
> > > +	 */
> > > +	error = __xfs_attr_rmtval_remove(dac);
> > >   	if (error)
> > >   		return error;
> > > @@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
> > >    * 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(
> > > -	struct xfs_da_args	*args)
> > > +	struct xfs_delattr_context	*dac)
> > >   {
> > > -	struct xfs_da_state	*state;
> > > -	struct xfs_da_state_blk	*blk;
> > > -	int			retval, error;
> > > -	struct xfs_inode	*dp = args->dp;
> > > +	struct xfs_da_args		*args = dac->da_args;
> > > +	struct xfs_da_state		*state;
> > > +	struct xfs_da_state_blk		*blk;
> > > +	int				retval, error;
> > > +	struct xfs_inode		*dp = args->dp;
> > >   	trace_xfs_attr_node_removename(args);
> > > +	state = dac->da_state;
> > > +	blk = dac->blk;
> > > -	error = xfs_attr_node_removename_setup(args, &state);
> > > -	if (error)
> > > -		goto out;
> > > +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> > > +		goto das_rm_shrink;
> > > +
> > > +	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
> > > +		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
> > > +		error = xfs_attr_node_removename_setup(dac, &state);
> > 
> > Shouldn't XFS_DAC_NODE_RMVNAME_INIT be set by
> > xfs_attr_node_removename_setup?
> I suppose it could be.  Initially this was a state not a flag, so that's why
> we see it here in this scope.
> 
> There may be reason to keep it there though.  These -EAGAIN functions are
> admittadly sort of jumpy, so when trying to trace them though, haveing the
> flag in the top level like that makes it clear that when we come back
> through on another iteration, we dont init twice.  Really, it's more to do
> with managing function re-entry than anything else going on in the init
> function.  I think Brian and I have been trying our best to keep code flow
> craziness in the same scope rather than letting them get burried in
> subfunctions.  Though I suppose it wouldnt be too hard to find if folks
> prefer the flag be in the subfunction?

Hm, ok, leave it there then. :)

> 
> 
> > 
> > > +		if (error)
> > > +			goto out;
> > > +	}
> > >   	/*
> > >   	 * If there is an out-of-line value, de-allocate the blocks.
> > > @@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
> > >   	 * overflow the maximum size of a transaction and/or hit a deadlock.
> > >   	 */
> > >   	if (args->rmtblkno > 0) {
> > > -		error = xfs_attr_node_removename_rmt(args, state);
> > > -		if (error)
> > > +		/*
> > > +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
> > > +		 */
> > > +		error = xfs_attr_node_removename_rmt(dac, state);
> > > +		if (error == -EAGAIN)
> > > +			return error;
> > > +		else if (error)
> > >   			goto out;
> > >   	}
> > > @@ -1274,17 +1360,14 @@ 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;
> > > +
> > > +		dac->flags |= XFS_DAC_DEFER_FINISH;
> > > +		dac->dela_state = XFS_DAS_RM_SHRINK;
> > > +		return -EAGAIN;
> > >   	}
> > > +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 66575b8..0430c79 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -74,6 +74,75 @@ struct xfs_attr_list_context {
> > >   };
> > > +/*
> > > + * ========================================================================
> > > + * Structure used to pass context around among the delayed routines.
> > > + * ========================================================================
> > > + */
> > > +
> > > +/*
> > > + * 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_attr_node_removename()
> > > + *	                                      │
> > > + *	                                      v
> > > + *	                                   need to
> > > + *	                                shrink tree? ─n─┐
> > > + *	                                      │         │
> > > + *	                                      y         │
> > > + *	                                      │         │
> > > + *	                                      v         │
> > > + *	                              XFS_DAS_RM_SHRINK │
> > > + *	                                      │         │
> > > + *	                                      v         │
> > > + *	                                     done <─────┘
> > > + *
> > > + */
> > > +
> > > +/*
> > > + * 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 {
> > > +				      /* Zero is uninitalized */
> > > +	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
> > > +};
> > > +
> > > +/*
> > > + * Defines for xfs_delattr_context.flags
> > > + */
> > > +#define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
> > > +#define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
> > > +
> > > +/*
> > > + * Context used for keeping track of delayed attribute operations
> > > + */
> > > +struct xfs_delattr_context {
> > > +	struct xfs_da_args      *da_args;
> > > +
> > > +	/* Used in xfs_attr_node_removename to roll through removing blocks */
> > > +	struct xfs_da_state     *da_state;
> > > +	struct xfs_da_state_blk *blk;
> > > +
> > > +	/* Used to keep track of current state of delayed operation */
> > > +	unsigned int            flags;
> > > +	enum xfs_delattr_state  dela_state;
> > > +};
> > > +
> > >   /*========================================================================
> > >    * Function prototypes for the kernel.
> > >    *========================================================================*/
> > > @@ -91,6 +160,10 @@ int xfs_attr_set(struct xfs_da_args *args);
> > >   int xfs_attr_set_args(struct xfs_da_args *args);
> > >   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_delattr_context *dac);
> > > +int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
> > >   bool xfs_attr_namecheck(const void *name, size_t length);
> > > +void xfs_delattr_context_init(struct xfs_delattr_context *dac,
> > > +			      struct xfs_da_args *args);
> > >   #endif	/* __XFS_ATTR_H__ */
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > index f55402b..2e36c8b 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > @@ -19,8 +19,8 @@
> > >   #include "xfs_bmap_btree.h"
> > >   #include "xfs_bmap.h"
> > >   #include "xfs_attr_sf.h"
> > > -#include "xfs_attr_remote.h"
> > >   #include "xfs_attr.h"
> > > +#include "xfs_attr_remote.h"
> > >   #include "xfs_attr_leaf.h"
> > >   #include "xfs_error.h"
> > >   #include "xfs_trace.h"
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> > > index f770159..f2d46c7 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> > > @@ -676,14 +676,16 @@ xfs_attr_rmtval_invalidate(
> > >    */
> > >   int
> > >   xfs_attr_rmtval_remove(
> > > -	struct xfs_da_args      *args)
> > > +	struct xfs_da_args		*args)
> > >   {
> > > -	xfs_dablk_t		lblkno;
> > > -	int			blkcnt;
> > > -	int			error = 0;
> > > -	int			retval = 0;
> > > +	struct xfs_delattr_context	dac;
> > > +	xfs_dablk_t			lblkno;
> > > +	int				blkcnt;
> > > +	int				error = 0;
> > > +	int				retval = 0;
> > >   	trace_xfs_attr_rmtval_remove(args);
> > > +	xfs_delattr_context_init(&dac, args);
> > >   	/*
> > >   	 * Keep de-allocating extents until the remote-value region is gone.
> > > @@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
> > >   	lblkno = args->rmtblkno;
> > >   	blkcnt = args->rmtblkcnt;
> > >   	do {
> > > -		retval = __xfs_attr_rmtval_remove(args);
> > > +		retval = __xfs_attr_rmtval_remove(&dac);
> > >   		if (retval && retval != EAGAIN)
> > >   			return retval;
> > > +		error = xfs_attr_defer_finish(&dac);
> > > +		if (error)
> > > +			break;
> > > +
> > >   		/*
> > >   		 * Close out trans and start the next one in the chain.
> > >   		 */
> > > @@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
> > >    */
> > >   int
> > >   __xfs_attr_rmtval_remove(
> > > -	struct xfs_da_args	*args)
> > > +	struct xfs_delattr_context	*dac)
> > >   {
> > > -	int			error, done;
> > > +	struct xfs_da_args		*args = dac->da_args;
> > > +	int				error, done;
> > >   	/*
> > >   	 * Unmap value blocks for this attr.
> > > @@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
> > >   	if (error)
> > >   		return error;
> > > -	error = xfs_defer_finish(&args->trans);
> > > -	if (error)
> > > -		return error;
> > > -
> > > -	if (!done)
> > > +	if (!done) {
> > > +		dac->flags &= ~XFS_DAC_DEFER_FINISH;
> > 
> > Why do we strip off DEFER_FINISH here?  Is it because we're making
> > xfs_attr_rmtval_remove invoke xfs_defer_finish unconditionally to clear
> > out any pending rmap items?
> Sorry, that should have been a flag set, not a strip.  Will fix!
> 
> > 
> > If you transformed the do-while loop in xfs_attr_rmtval_remove to use
> > xfs_attr_roll_again, then you could make this set DEFER_FINISH, which
> > would make me a lot less suspicious that we're dropping state here.
> > 
> > (It would also clean up a lot of the defer_finish -> trans_roll_inode
> > code that's scattering everywhere...)
> Yes, will do that.  Thanks for the review!

:D

--D

> > 
> > --D
> > 
> > >   		return -EAGAIN;
> > > +	}
> > >   	return error;
> > >   }
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> > > index ee3337b..351da00 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.h
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> > > @@ -14,5 +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_remove(struct xfs_da_args *args);
> > > +int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
> > >   #endif /* __XFS_ATTR_REMOTE_H__ */
> > > diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> > > index c42f90e..b2150fa 100644
> > > --- a/fs/xfs/xfs_attr_inactive.c
> > > +++ b/fs/xfs/xfs_attr_inactive.c
> > > @@ -15,10 +15,10 @@
> > >   #include "xfs_da_format.h"
> > >   #include "xfs_da_btree.h"
> > >   #include "xfs_inode.h"
> > > +#include "xfs_attr.h"
> > >   #include "xfs_attr_remote.h"
> > >   #include "xfs_trans.h"
> > >   #include "xfs_bmap.h"
> > > -#include "xfs_attr.h"
> > >   #include "xfs_attr_leaf.h"
> > >   #include "xfs_quota.h"
> > >   #include "xfs_dir2.h"
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-05-04 21:36     ` Allison Collins
@ 2020-05-05 12:03       ` Brian Foster
  2020-05-05 17:35         ` Allison Collins
  0 siblings, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-05 12:03 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, May 04, 2020 at 02:36:39PM -0700, Allison Collins wrote:
> 
> 
> On 5/4/20 6:27 AM, Brian Foster wrote:
> > On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
> > > xfs_attr_rmtval_remove
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
> > > ---
> > 
> > Looks like the commit log needs some rewording now that this is a
> > refactor patch. With that fixed:
> Ok, maybe just an extra line like "Refactor xfs_attr_rmtval_remove to add
> helper function __xfs_attr_rmtval_remove" ?
> 

I'd update the first sentence to say something like that instead of how
the function is similar to xfs_attr_rmtval_remove().

Brian

> > 
> > Reviewed-by: Brian Foster <bfoster@redhat.com>
> Alrighty, thank you!
> 
> Allison
> 
> > 
> > >   fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
> > >   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
> > >   2 files changed, 37 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> > > index 4d51969..02d1a44 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_remote.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> > > @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
> > >   	xfs_dablk_t		lblkno;
> > >   	int			blkcnt;
> > >   	int			error = 0;
> > > -	int			done = 0;
> > > +	int			retval = 0;
> > >   	trace_xfs_attr_rmtval_remove(args);
> > > @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
> > >   	 */
> > >   	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;
> > > +	do {
> > > +		retval = __xfs_attr_rmtval_remove(args);
> > > +		if (retval && retval != EAGAIN)
> > > +			return retval;
> > >   		/*
> > >   		 * Close out trans and start the next one in the chain.
> > > @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
> > >   		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > >   		if (error)
> > >   			return error;
> > > -	}
> > > +	} while (retval == -EAGAIN);
> > > +
> > >   	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_remove(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error, done;
> > > +
> > > +	/*
> > > +	 * Unmap value blocks for this attr.
> > > +	 */
> > > +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
> > > +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	error = xfs_defer_finish(&args->trans);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	if (!done)
> > > +		return -EAGAIN;
> > > +
> > > +	return error;
> > > +}
> > > diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> > > index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
> > >   #endif /* __XFS_ATTR_REMOTE_H__ */
> > > -- 
> > > 2.7.4
> > > 
> > 
> 


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

* Re: [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname
  2020-04-30 22:50 ` [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname Allison Collins
  2020-05-04 19:03   ` Darrick J. Wong
@ 2020-05-05 13:11   ` Brian Foster
  2020-05-05 17:35     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-05 13:11 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:11PM -0700, Allison Collins wrote:
> Quick patch to unnest the rename logic in the leaf code path.  This will
> help simplify delayed attr logic later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

With Darrick's cleanups:

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

>  fs/xfs/libxfs/xfs_attr.c | 108 +++++++++++++++++++++++------------------------
>  1 file changed, 53 insertions(+), 55 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index ab1c9fa..1810f90 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -694,73 +694,71 @@ xfs_attr_leaf_addname(
>  			return error;
>  	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>  		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			return error;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> +		if (args->rmtblkno > 0)
> +			error = xfs_attr3_leaf_clearflag(args);
>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		xfs_attr_restore_rmt_blk(args);
> +		return error;
> +	}
>  
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_invalidate(args);
> -			if (error)
> -				return error;
> +	/*
> +	 * If this is an atomic rename operation, we must "flip" the incomplete
> +	 * flags on the "new" and "old" attribute/value pairs so that one
> +	 * disappears and one appears atomically.  Then we must remove the "old"
> +	 * attribute/value pair.
> +	 *
> +	 * In a separate transaction, set the incomplete flag on the "old" attr
> +	 * and clear the incomplete flag on the "new" attr.
> +	 */
>  
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +	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;
>  
> -		/*
> -		 * Read in the block containing the "old" attr, then
> -		 * remove the "old" attr from that block (neat, huh!)
> -		 */
> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -					   &bp);
> +	/*
> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
> +	 * (if it exists).
> +	 */
> +	xfs_attr_restore_rmt_blk(args);
> +
> +	if (args->rmtblkno) {
> +		error = xfs_attr_rmtval_invalidate(args);
>  		if (error)
>  			return error;
>  
> -		xfs_attr3_leaf_remove(bp, args);
> -
> -		/*
> -		 * If the result is small enough, shrink it all into the inode.
> -		 */
> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> -			/* bp is gone due to xfs_da_shrink_inode */
> -			if (error)
> -				return error;
> -		}
> -
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			return error;
>  	}
> +
> +	/*
> +	 * Read in the block containing the "old" attr, then remove the "old"
> +	 * attr from that block (neat, huh!)
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> +				   &bp);
> +	if (error)
> +		return error;
> +
> +	xfs_attr3_leaf_remove(bp, args);
> +
> +	/*
> +	 * If the result is small enough, shrink it all into the inode.
> +	 */
> +	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 */
> +
>  	return error;
>  }
>  
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname
  2020-04-30 22:50 ` [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname Allison Collins
  2020-05-04 19:06   ` Darrick J. Wong
@ 2020-05-05 13:12   ` Brian Foster
  2020-05-05 17:35     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-05 13:12 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:12PM -0700, Allison Collins wrote:
> Quick patch to unnest the rename logic in the node code path.  This will
> help simplify delayed attr logic later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 131 +++++++++++++++++++++++------------------------
>  1 file changed, 64 insertions(+), 67 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 1810f90..9171895 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1030,83 +1030,80 @@ xfs_attr_node_addname(
>  			return error;
>  	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			goto out;
> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>  		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			goto out;
> +		if (args->rmtblkno > 0)
> +			error = xfs_attr3_leaf_clearflag(args);
> +		retval = error;

Can we just init retval to 0 and avoid this assignment? With that and
similar fixups to the previous patch:

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

Note that I'm also of the mind to break this down into smaller functions
depending on what later patches look like, but if there's more to
consider around that this seems like a good step in that direction.

Brian

> +		goto out;
> +	}
>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		xfs_attr_restore_rmt_blk(args);
> +	/*
> +	 * If this is an atomic rename operation, we must "flip" the incomplete
> +	 * flags on the "new" and "old" attribute/value pairs so that one
> +	 * disappears and one appears atomically.  Then we must remove the "old"
> +	 * attribute/value pair.
> +	 *
> +	 * In a separate transaction, set the incomplete flag on the "old" attr
> +	 * and clear the incomplete flag on the "new" attr.
> +	 */
> +	error = xfs_attr3_leaf_flipflags(args);
> +	if (error)
> +		goto out;
> +	/*
> +	 * Commit the flag value change and start the next trans in series
> +	 */
> +	error = xfs_trans_roll_inode(&args->trans, args->dp);
> +	if (error)
> +		goto out;
>  
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_invalidate(args);
> -			if (error)
> -				return error;
> +	/*
> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
> +	 * (if it exists).
> +	 */
> +	xfs_attr_restore_rmt_blk(args);
>  
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +	if (args->rmtblkno) {
> +		error = xfs_attr_rmtval_invalidate(args);
> +		if (error)
> +			return error;
>  
> -		/*
> -		 * Re-find the "old" attribute entry after any split ops.
> -		 * The INCOMPLETE flag means that we will find the "old"
> -		 * attr, not the "new" one.
> -		 */
> -		args->attr_filter |= XFS_ATTR_INCOMPLETE;
> -		state = xfs_da_state_alloc();
> -		state->args = args;
> -		state->mp = mp;
> -		state->inleaf = 0;
> -		error = xfs_da3_node_lookup_int(state, &retval);
> +		error = xfs_attr_rmtval_remove(args);
>  		if (error)
> -			goto out;
> +			return error;
> +	}
>  
> -		/*
> -		 * Remove the name and update the hashvals in the tree.
> -		 */
> -		blk = &state->path.blk[ state->path.active-1 ];
> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -		error = xfs_attr3_leaf_remove(blk->bp, args);
> -		xfs_da3_fixhashpath(state, &state->path);
> +	/*
> +	 * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
> +	 * flag means that we will find the "old" attr, not the "new" one.
> +	 */
> +	args->attr_filter |= XFS_ATTR_INCOMPLETE;
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = mp;
> +	state->inleaf = 0;
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error)
> +		goto out;
>  
> -		/*
> -		 * Check to see if the tree needs to be collapsed.
> -		 */
> -		if (retval && (state->path.active > 1)) {
> -			error = xfs_da3_join(state);
> -			if (error)
> -				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
> -		}
> +	/*
> +	 * Remove the name and update the hashvals in the tree.
> +	 */
> +	blk = &state->path.blk[state->path.active-1];
> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +	error = xfs_attr3_leaf_remove(blk->bp, args);
> +	xfs_da3_fixhashpath(state, &state->path);
>  
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +	/*
> +	 * Check to see if the tree needs to be collapsed.
> +	 */
> +	if (retval && (state->path.active > 1)) {
> +		error = xfs_da3_join(state);
> +		if (error)
> +			goto out;
> +		error = xfs_defer_finish(&args->trans);
>  		if (error)
>  			goto out;
>  	}
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  2020-04-30 22:50 ` [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname Allison Collins
  2020-05-04 19:10   ` Darrick J. Wong
@ 2020-05-05 13:12   ` Brian Foster
  2020-05-05 17:37     ` Allison Collins
  1 sibling, 1 reply; 76+ messages in thread
From: Brian Foster @ 2020-05-05 13:12 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:13PM -0700, Allison Collins wrote:
> Lift -ENOSPC handler from xfs_attr_leaf_addname.  This will help to
> reorganize transitions between the attr forms later.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

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

>  fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++--------------
>  1 file changed, 11 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9171895..c8cae68 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -299,6 +299,13 @@ xfs_attr_set_args(
>  			return error;
>  
>  		/*
> +		 * Promote the attribute list to the Btree format.
> +		 */
> +		error = xfs_attr3_leaf_to_node(args);
> +		if (error)
> +			return error;
> +
> +		/*
>  		 * Commit that transaction so that the node_addname()
>  		 * call can manage its own transactions.
>  		 */
> @@ -602,7 +609,7 @@ xfs_attr_leaf_try_add(
>  	struct xfs_da_args	*args,
>  	struct xfs_buf		*bp)
>  {
> -	int			retval, error;
> +	int			retval;
>  
>  	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
> @@ -634,20 +641,10 @@ xfs_attr_leaf_try_add(
>  	}
>  
>  	/*
> -	 * Add the attribute to the leaf block, transitioning to a Btree
> -	 * if required.
> +	 * Add the attribute to the leaf block
>  	 */
> -	retval = xfs_attr3_leaf_add(bp, args);
> -	if (retval == -ENOSPC) {
> -		/*
> -		 * 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;
> -	}
> -	return retval;
> +	return xfs_attr3_leaf_add(bp, args);
> +
>  out_brelse:
>  	xfs_trans_brelse(args->trans, bp);
>  	return retval;
> -- 
> 2.7.4
> 


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

* Re: [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-05-05  1:44       ` Darrick J. Wong
@ 2020-05-05 17:35         ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05 17:35 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 5/4/20 6:44 PM, Darrick J. Wong wrote:
> On Mon, May 04, 2020 at 05:26:52PM -0700, Allison Collins wrote:
>>
>>
>> On 5/4/20 12:33 PM, Darrick J. Wong wrote:
>>> On Thu, Apr 30, 2020 at 03:50:14PM -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.  A new XFS_DAC_DEFER_FINISH flag is used to finish the
>>>> transaction where ever the existing code used to.
>>>>
>>>> Calls to xfs_attr_rmtval_remove are replaced with the delay ready
>>>> version __xfs_attr_rmtval_remove. We will rename
>>>> __xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
>>>> done.
>>>>
>>>> xfs_attr_rmtval_remove itself is still in use by the set routines (used
>>>> during a rename).  For reasons of perserving existing function, we
>>>> modify xfs_attr_rmtval_remove to call xfs_defer_finish when the flag is
>>>> set.  Similar to how xfs_attr_remove_args does here.  Once we transition
>>>> the set routines to be delay ready, xfs_attr_rmtval_remove is no longer
>>>> used and will be removed.
>>>>
>>>> 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_attr_node_removename()
>>>>                                                    │
>>>>                                                    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        | 159 ++++++++++++++++++++++++++++++----------
>>>>    fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
>>>>    fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
>>>>    fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
>>>>    fs/xfs/xfs_attr_inactive.c      |   2 +-
>>>>    6 files changed, 215 insertions(+), 54 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index c8cae68..7213589 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -53,12 +53,21 @@ STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>>>     */
>>>>    STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>>> -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>>>> +STATIC int xfs_attr_node_removename(struct xfs_delattr_context *dac);
>>>>    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);
>>>> +void
>>>> +xfs_delattr_context_init(
>>>> +	struct xfs_delattr_context	*dac,
>>>> +	struct xfs_da_args		*args)
>>>> +{
>>>> +	memset(dac, 0, sizeof(struct xfs_delattr_context));
>>>> +	dac->da_args = args;
>>>
>>> Couldn't this could be open coded as:
>>>
>>> struct xfs_delattr_context	dac = {
>>> 	.da_args		= args,
>>> };
>>>
>>> in the callers?  One less helper function, and it means that the stack
>>> contents will always be fully initialized.
>> I believe Dave had suggested the initializer back when I had dac a member of
>> args instead of the other way around.  I dont know that he was too
>> particular about exactly what the initializer was though.  Is this generally
>> the standard for initializers?
> 
> One of them, yes. :)
> 
> I've started to prefer that form simply because we don't have to
> remember that some struct is uninitialized between its definition and
> some later initializer function call.  There are (many) places where
> we have to unpack other things before we can initialize a struct, but
> for the simpler cases I like to reduce the brainpower needed to
> understand code, lest I turn into Mr. D P Gumby.
Alrighty, will change that out.  Thanks!

Allison
> 
>>>
>>>> +}
>>>> +
>>>>    int
>>>>    xfs_inode_hasattr(
>>>>    	struct xfs_inode	*ip)
>>>> @@ -263,6 +272,18 @@ xfs_attr_set_shortform(
>>>>    	return 0;
>>>>    }
>>>> +int xfs_attr_defer_finish(
>>>
>>> static inline int
>>> xfs_attr_defer_finish(
>>>
>>>> +	struct xfs_delattr_context      *dac)
>>>> +{
>>>> +	struct xfs_da_args              *args = dac->da_args;
>>>> +
>>>> +	if (!(dac->flags & XFS_DAC_DEFER_FINISH))
>>>> +		return 0;
>>>> +
>>>> +	dac->flags &= ~XFS_DAC_DEFER_FINISH;
>>>> +	return xfs_defer_finish(&args->trans);
>>>
>>> I also wonder if you want to hoist the trans_roll_inode to here too?
>>>
>>> Actually, what if this instead became:
>>>
>>> static inline bool
>>> xfs_attr_roll_again(
>>> 	struct xfs_delattr_context	*dac,
>>> 	int				*error)
>>> {
>>> 	if (*error != -EAGAIN)
>>> 		return false;
>>>
>>> 	if (dac->flags & XFS_DAC_DEFER_FINISH)) {
>>> 		dac->flags &= ~XFS_DAC_DEFER_FINISH;
>>> 		*error = xfs_defer_finish(&args->trans);
>>> 		if (*error)
>>> 			return false;
>>> 	}
>>>
>>> 	*error = xfs_trans_roll_inode(&dac->da_args->trans, dac->da_args->dp);
>>> 	return *error == 0;
>>> }
>>>
>> Sure, that should be fine
>>
>>>> +}
>>>> +
>>>>    /*
>>>>     * Set the attribute specified in @args.
>>>>     */
>>>> @@ -363,23 +384,57 @@ xfs_has_attr(
>>>>     */
>>>>    int
>>>>    xfs_attr_remove_args(
>>>> -	struct xfs_da_args      *args)
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int			error = 0;
>>>> +	struct			xfs_delattr_context dac;
>>>> +
>>>> +	xfs_delattr_context_init(&dac, args);
>>>> +
>>>> +	do {
>>>> +		error = xfs_attr_remove_iter(&dac);
>>>> +		if (error != -EAGAIN)
>>>> +			break;
>>>> +
>>>> +		error = xfs_attr_defer_finish(&dac);
>>>> +		if (error)
>>>> +			break;
>>>> +
>>>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>> +		if (error)
>>>> +			break;
>>>> +	} while (true);
>>>
>>> and then this whole function becomes:
>>>
>>> int
>>> xfs_attr_remove_args(
>>> 	struct xfs_da_args		*args)
>>> {
>>> 	struct xfs_delattr_context	dac = {
>>> 		.da_args		= args,
>>> 	};
>>>
>>> 	do {
>>> 		error = xfs_attr_remove_iter(&dac);
>>> 	} while (xfs_attr_roll_again(&dac, &error));
>>>
>>> 	return error;
>>> }
>> Alrighty then
>>
>>>
>>>> +
>>>> +	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_delattr_context *dac)
>>>>    {
>>>> +	struct xfs_da_args	*args = dac->da_args;
>>>>    	struct xfs_inode	*dp = args->dp;
>>>> -	int			error;
>>>> +
>>>> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
>>>> +		goto node;
>>>>    	if (!xfs_inode_hasattr(dp)) {
>>>> -		error = -ENOATTR;
>>>> +		return -ENOATTR;
>>>>    	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>>    		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>>> -		error = xfs_attr_shortform_remove(args);
>>>> +		return xfs_attr_shortform_remove(args);
>>>>    	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>> -		error = xfs_attr_leaf_removename(args);
>>>> -	} else {
>>>> -		error = xfs_attr_node_removename(args);
>>>> +		return xfs_attr_leaf_removename(args);
>>>>    	}
>>>> -
>>>> -	return error;
>>>> +node:
>>>> +	return  xfs_attr_node_removename(dac);
>>>>    }
>>>>    /*
>>>> @@ -1177,15 +1232,17 @@ xfs_attr_leaf_mark_incomplete(
>>>>    /*
>>>>     * Initial setup for xfs_attr_node_removename.  Make sure the attr is there and
>>>> - * the blocks are valid.  Any remote blocks will be marked incomplete.
>>>> + * the blocks are valid.  Any remote blocks will be marked incomplete and
>>>> + * invalidated.
>>>>     */
>>>>    STATIC
>>>>    int xfs_attr_node_removename_setup(
>>>> -	struct xfs_da_args	*args,
>>>> -	struct xfs_da_state	**state)
>>>> +	struct xfs_delattr_context	*dac,
>>>> +	struct xfs_da_state		**state)
>>>>    {
>>>> -	int			error;
>>>> -	struct xfs_da_state_blk	*blk;
>>>> +	struct xfs_da_args		*args = dac->da_args;
>>>> +	int				error;
>>>> +	struct xfs_da_state_blk		*blk;
>>>>    	error = xfs_attr_node_hasname(args, state);
>>>>    	if (error != -EEXIST)
>>>> @@ -1195,6 +1252,13 @@ int xfs_attr_node_removename_setup(
>>>>    	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
>>>> +	 */
>>>> +	dac->blk = blk;
>>>> +	dac->da_state = *state;
>>>> +
>>>>    	if (args->rmtblkno > 0) {
>>>>    		error = xfs_attr_leaf_mark_incomplete(args, *state);
>>>>    		if (error)
>>>> @@ -1210,12 +1274,15 @@ int xfs_attr_node_removename_setup(
>>>>    STATIC int
>>>>    xfs_attr_node_removename_rmt (
>>>> -	struct xfs_da_args	*args,
>>>> -	struct xfs_da_state	*state)
>>>> +	struct xfs_delattr_context	*dac,
>>>> +	struct xfs_da_state		*state)
>>>>    {
>>>> -	int			error = 0;
>>>> +	int				error = 0;
>>>> -	error = xfs_attr_rmtval_remove(args);
>>>> +	/*
>>>> +	 * May return -EAGAIN to request that the caller recall this function
>>>> +	 */
>>>> +	error = __xfs_attr_rmtval_remove(dac);
>>>>    	if (error)
>>>>    		return error;
>>>> @@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
>>>>     * 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(
>>>> -	struct xfs_da_args	*args)
>>>> +	struct xfs_delattr_context	*dac)
>>>>    {
>>>> -	struct xfs_da_state	*state;
>>>> -	struct xfs_da_state_blk	*blk;
>>>> -	int			retval, error;
>>>> -	struct xfs_inode	*dp = args->dp;
>>>> +	struct xfs_da_args		*args = dac->da_args;
>>>> +	struct xfs_da_state		*state;
>>>> +	struct xfs_da_state_blk		*blk;
>>>> +	int				retval, error;
>>>> +	struct xfs_inode		*dp = args->dp;
>>>>    	trace_xfs_attr_node_removename(args);
>>>> +	state = dac->da_state;
>>>> +	blk = dac->blk;
>>>> -	error = xfs_attr_node_removename_setup(args, &state);
>>>> -	if (error)
>>>> -		goto out;
>>>> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
>>>> +		goto das_rm_shrink;
>>>> +
>>>> +	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
>>>> +		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
>>>> +		error = xfs_attr_node_removename_setup(dac, &state);
>>>
>>> Shouldn't XFS_DAC_NODE_RMVNAME_INIT be set by
>>> xfs_attr_node_removename_setup?
>> I suppose it could be.  Initially this was a state not a flag, so that's why
>> we see it here in this scope.
>>
>> There may be reason to keep it there though.  These -EAGAIN functions are
>> admittadly sort of jumpy, so when trying to trace them though, haveing the
>> flag in the top level like that makes it clear that when we come back
>> through on another iteration, we dont init twice.  Really, it's more to do
>> with managing function re-entry than anything else going on in the init
>> function.  I think Brian and I have been trying our best to keep code flow
>> craziness in the same scope rather than letting them get burried in
>> subfunctions.  Though I suppose it wouldnt be too hard to find if folks
>> prefer the flag be in the subfunction?
> 
> Hm, ok, leave it there then. :)
> 
>>
>>
>>>
>>>> +		if (error)
>>>> +			goto out;
>>>> +	}
>>>>    	/*
>>>>    	 * If there is an out-of-line value, de-allocate the blocks.
>>>> @@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
>>>>    	 * overflow the maximum size of a transaction and/or hit a deadlock.
>>>>    	 */
>>>>    	if (args->rmtblkno > 0) {
>>>> -		error = xfs_attr_node_removename_rmt(args, state);
>>>> -		if (error)
>>>> +		/*
>>>> +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
>>>> +		 */
>>>> +		error = xfs_attr_node_removename_rmt(dac, state);
>>>> +		if (error == -EAGAIN)
>>>> +			return error;
>>>> +		else if (error)
>>>>    			goto out;
>>>>    	}
>>>> @@ -1274,17 +1360,14 @@ 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;
>>>> +
>>>> +		dac->flags |= XFS_DAC_DEFER_FINISH;
>>>> +		dac->dela_state = XFS_DAS_RM_SHRINK;
>>>> +		return -EAGAIN;
>>>>    	}
>>>> +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 66575b8..0430c79 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>> @@ -74,6 +74,75 @@ struct xfs_attr_list_context {
>>>>    };
>>>> +/*
>>>> + * ========================================================================
>>>> + * Structure used to pass context around among the delayed routines.
>>>> + * ========================================================================
>>>> + */
>>>> +
>>>> +/*
>>>> + * 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_attr_node_removename()
>>>> + *	                                      │
>>>> + *	                                      v
>>>> + *	                                   need to
>>>> + *	                                shrink tree? ─n─┐
>>>> + *	                                      │         │
>>>> + *	                                      y         │
>>>> + *	                                      │         │
>>>> + *	                                      v         │
>>>> + *	                              XFS_DAS_RM_SHRINK │
>>>> + *	                                      │         │
>>>> + *	                                      v         │
>>>> + *	                                     done <─────┘
>>>> + *
>>>> + */
>>>> +
>>>> +/*
>>>> + * 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 {
>>>> +				      /* Zero is uninitalized */
>>>> +	XFS_DAS_RM_SHRINK	= 1,  /* We are shrinking the tree */
>>>> +};
>>>> +
>>>> +/*
>>>> + * Defines for xfs_delattr_context.flags
>>>> + */
>>>> +#define XFS_DAC_DEFER_FINISH		0x01 /* finish the transaction */
>>>> +#define XFS_DAC_NODE_RMVNAME_INIT	0x02 /* xfs_attr_node_removename init */
>>>> +
>>>> +/*
>>>> + * Context used for keeping track of delayed attribute operations
>>>> + */
>>>> +struct xfs_delattr_context {
>>>> +	struct xfs_da_args      *da_args;
>>>> +
>>>> +	/* Used in xfs_attr_node_removename to roll through removing blocks */
>>>> +	struct xfs_da_state     *da_state;
>>>> +	struct xfs_da_state_blk *blk;
>>>> +
>>>> +	/* Used to keep track of current state of delayed operation */
>>>> +	unsigned int            flags;
>>>> +	enum xfs_delattr_state  dela_state;
>>>> +};
>>>> +
>>>>    /*========================================================================
>>>>     * Function prototypes for the kernel.
>>>>     *========================================================================*/
>>>> @@ -91,6 +160,10 @@ int xfs_attr_set(struct xfs_da_args *args);
>>>>    int xfs_attr_set_args(struct xfs_da_args *args);
>>>>    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_delattr_context *dac);
>>>> +int xfs_attr_defer_finish(struct xfs_delattr_context *dac);
>>>>    bool xfs_attr_namecheck(const void *name, size_t length);
>>>> +void xfs_delattr_context_init(struct xfs_delattr_context *dac,
>>>> +			      struct xfs_da_args *args);
>>>>    #endif	/* __XFS_ATTR_H__ */
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> index f55402b..2e36c8b 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> @@ -19,8 +19,8 @@
>>>>    #include "xfs_bmap_btree.h"
>>>>    #include "xfs_bmap.h"
>>>>    #include "xfs_attr_sf.h"
>>>> -#include "xfs_attr_remote.h"
>>>>    #include "xfs_attr.h"
>>>> +#include "xfs_attr_remote.h"
>>>>    #include "xfs_attr_leaf.h"
>>>>    #include "xfs_error.h"
>>>>    #include "xfs_trace.h"
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> index f770159..f2d46c7 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> @@ -676,14 +676,16 @@ xfs_attr_rmtval_invalidate(
>>>>     */
>>>>    int
>>>>    xfs_attr_rmtval_remove(
>>>> -	struct xfs_da_args      *args)
>>>> +	struct xfs_da_args		*args)
>>>>    {
>>>> -	xfs_dablk_t		lblkno;
>>>> -	int			blkcnt;
>>>> -	int			error = 0;
>>>> -	int			retval = 0;
>>>> +	struct xfs_delattr_context	dac;
>>>> +	xfs_dablk_t			lblkno;
>>>> +	int				blkcnt;
>>>> +	int				error = 0;
>>>> +	int				retval = 0;
>>>>    	trace_xfs_attr_rmtval_remove(args);
>>>> +	xfs_delattr_context_init(&dac, args);
>>>>    	/*
>>>>    	 * Keep de-allocating extents until the remote-value region is gone.
>>>> @@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
>>>>    	lblkno = args->rmtblkno;
>>>>    	blkcnt = args->rmtblkcnt;
>>>>    	do {
>>>> -		retval = __xfs_attr_rmtval_remove(args);
>>>> +		retval = __xfs_attr_rmtval_remove(&dac);
>>>>    		if (retval && retval != EAGAIN)
>>>>    			return retval;
>>>> +		error = xfs_attr_defer_finish(&dac);
>>>> +		if (error)
>>>> +			break;
>>>> +
>>>>    		/*
>>>>    		 * Close out trans and start the next one in the chain.
>>>>    		 */
>>>> @@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
>>>>     */
>>>>    int
>>>>    __xfs_attr_rmtval_remove(
>>>> -	struct xfs_da_args	*args)
>>>> +	struct xfs_delattr_context	*dac)
>>>>    {
>>>> -	int			error, done;
>>>> +	struct xfs_da_args		*args = dac->da_args;
>>>> +	int				error, done;
>>>>    	/*
>>>>    	 * Unmap value blocks for this attr.
>>>> @@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
>>>>    	if (error)
>>>>    		return error;
>>>> -	error = xfs_defer_finish(&args->trans);
>>>> -	if (error)
>>>> -		return error;
>>>> -
>>>> -	if (!done)
>>>> +	if (!done) {
>>>> +		dac->flags &= ~XFS_DAC_DEFER_FINISH;
>>>
>>> Why do we strip off DEFER_FINISH here?  Is it because we're making
>>> xfs_attr_rmtval_remove invoke xfs_defer_finish unconditionally to clear
>>> out any pending rmap items?
>> Sorry, that should have been a flag set, not a strip.  Will fix!
>>
>>>
>>> If you transformed the do-while loop in xfs_attr_rmtval_remove to use
>>> xfs_attr_roll_again, then you could make this set DEFER_FINISH, which
>>> would make me a lot less suspicious that we're dropping state here.
>>>
>>> (It would also clean up a lot of the defer_finish -> trans_roll_inode
>>> code that's scattering everywhere...)
>> Yes, will do that.  Thanks for the review!
> 
> :D
> 
> --D
> 
>>>
>>> --D
>>>
>>>>    		return -EAGAIN;
>>>> +	}
>>>>    	return error;
>>>>    }
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>>>> index ee3337b..351da00 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>>>> @@ -14,5 +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_remove(struct xfs_da_args *args);
>>>> +int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>>>>    #endif /* __XFS_ATTR_REMOTE_H__ */
>>>> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
>>>> index c42f90e..b2150fa 100644
>>>> --- a/fs/xfs/xfs_attr_inactive.c
>>>> +++ b/fs/xfs/xfs_attr_inactive.c
>>>> @@ -15,10 +15,10 @@
>>>>    #include "xfs_da_format.h"
>>>>    #include "xfs_da_btree.h"
>>>>    #include "xfs_inode.h"
>>>> +#include "xfs_attr.h"
>>>>    #include "xfs_attr_remote.h"
>>>>    #include "xfs_trans.h"
>>>>    #include "xfs_bmap.h"
>>>> -#include "xfs_attr.h"
>>>>    #include "xfs_attr_leaf.h"
>>>>    #include "xfs_quota.h"
>>>>    #include "xfs_dir2.h"
>>>> -- 
>>>> 2.7.4
>>>>

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

* Re: [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove
  2020-05-05 12:03       ` Brian Foster
@ 2020-05-05 17:35         ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05 17:35 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/5/20 5:03 AM, Brian Foster wrote:
> On Mon, May 04, 2020 at 02:36:39PM -0700, Allison Collins wrote:
>>
>>
>> On 5/4/20 6:27 AM, Brian Foster wrote:
>>> On Thu, Apr 30, 2020 at 03:50:02PM -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.  This function will eventually replace
>>>> xfs_attr_rmtval_remove
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
>>>> ---
>>>
>>> Looks like the commit log needs some rewording now that this is a
>>> refactor patch. With that fixed:
>> Ok, maybe just an extra line like "Refactor xfs_attr_rmtval_remove to add
>> helper function __xfs_attr_rmtval_remove" ?
>>
> 
> I'd update the first sentence to say something like that instead of how
> the function is similar to xfs_attr_rmtval_remove().
> 
> Brian

Ok then, will update.

Allison

> 
>>>
>>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> Alrighty, thank you!
>>
>> Allison
>>
>>>
>>>>    fs/xfs/libxfs/xfs_attr_remote.c | 46 ++++++++++++++++++++++++++++++++---------
>>>>    fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>>>    2 files changed, 37 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> index 4d51969..02d1a44 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>>>> @@ -681,7 +681,7 @@ xfs_attr_rmtval_remove(
>>>>    	xfs_dablk_t		lblkno;
>>>>    	int			blkcnt;
>>>>    	int			error = 0;
>>>> -	int			done = 0;
>>>> +	int			retval = 0;
>>>>    	trace_xfs_attr_rmtval_remove(args);
>>>> @@ -693,14 +693,10 @@ xfs_attr_rmtval_remove(
>>>>    	 */
>>>>    	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;
>>>> +	do {
>>>> +		retval = __xfs_attr_rmtval_remove(args);
>>>> +		if (retval && retval != EAGAIN)
>>>> +			return retval;
>>>>    		/*
>>>>    		 * Close out trans and start the next one in the chain.
>>>> @@ -708,6 +704,36 @@ xfs_attr_rmtval_remove(
>>>>    		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>    		if (error)
>>>>    			return error;
>>>> -	}
>>>> +	} while (retval == -EAGAIN);
>>>> +
>>>>    	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_remove(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int			error, done;
>>>> +
>>>> +	/*
>>>> +	 * Unmap value blocks for this attr.
>>>> +	 */
>>>> +	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
>>>> +			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
>>>> +	if (error)
>>>> +		return error;
>>>> +
>>>> +	error = xfs_defer_finish(&args->trans);
>>>> +	if (error)
>>>> +		return error;
>>>> +
>>>> +	if (!done)
>>>> +		return -EAGAIN;
>>>> +
>>>> +	return error;
>>>> +}
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>>>> index eff5f95..ee3337b 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_remove(struct xfs_da_args *args);
>>>>    #endif /* __XFS_ATTR_REMOTE_H__ */
>>>> -- 
>>>> 2.7.4
>>>>
>>>
>>
> 

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

* Re: [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname
  2020-05-05 13:11   ` Brian Foster
@ 2020-05-05 17:35     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05 17:35 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/5/20 6:11 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:11PM -0700, Allison Collins wrote:
>> Quick patch to unnest the rename logic in the leaf code path.  This will
>> help simplify delayed attr logic later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> With Darrick's cleanups:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Great, thank you!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c | 108 +++++++++++++++++++++++------------------------
>>   1 file changed, 53 insertions(+), 55 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index ab1c9fa..1810f90 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -694,73 +694,71 @@ xfs_attr_leaf_addname(
>>   			return error;
>>   	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>>   		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			return error;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> +		if (args->rmtblkno > 0)
>> +			error = xfs_attr3_leaf_clearflag(args);
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		xfs_attr_restore_rmt_blk(args);
>> +		return error;
>> +	}
>>   
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_invalidate(args);
>> -			if (error)
>> -				return error;
>> +	/*
>> +	 * If this is an atomic rename operation, we must "flip" the incomplete
>> +	 * flags on the "new" and "old" attribute/value pairs so that one
>> +	 * disappears and one appears atomically.  Then we must remove the "old"
>> +	 * attribute/value pair.
>> +	 *
>> +	 * In a separate transaction, set the incomplete flag on the "old" attr
>> +	 * and clear the incomplete flag on the "new" attr.
>> +	 */
>>   
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +	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;
>>   
>> -		/*
>> -		 * Read in the block containing the "old" attr, then
>> -		 * remove the "old" attr from that block (neat, huh!)
>> -		 */
>> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -					   &bp);
>> +	/*
>> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>> +	 * (if it exists).
>> +	 */
>> +	xfs_attr_restore_rmt_blk(args);
>> +
>> +	if (args->rmtblkno) {
>> +		error = xfs_attr_rmtval_invalidate(args);
>>   		if (error)
>>   			return error;
>>   
>> -		xfs_attr3_leaf_remove(bp, args);
>> -
>> -		/*
>> -		 * If the result is small enough, shrink it all into the inode.
>> -		 */
>> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -			/* bp is gone due to xfs_da_shrink_inode */
>> -			if (error)
>> -				return error;
>> -		}
>> -
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			return error;
>>   	}
>> +
>> +	/*
>> +	 * Read in the block containing the "old" attr, then remove the "old"
>> +	 * attr from that block (neat, huh!)
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> +				   &bp);
>> +	if (error)
>> +		return error;
>> +
>> +	xfs_attr3_leaf_remove(bp, args);
>> +
>> +	/*
>> +	 * If the result is small enough, shrink it all into the inode.
>> +	 */
>> +	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 */
>> +
>>   	return error;
>>   }
>>   
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname
  2020-05-05 13:12   ` Brian Foster
@ 2020-05-05 17:35     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05 17:35 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/5/20 6:12 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:12PM -0700, Allison Collins wrote:
>> Quick patch to unnest the rename logic in the node code path.  This will
>> help simplify delayed attr logic later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 131 +++++++++++++++++++++++------------------------
>>   1 file changed, 64 insertions(+), 67 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 1810f90..9171895 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1030,83 +1030,80 @@ xfs_attr_node_addname(
>>   			return error;
>>   	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			goto out;
>> +	if ((args->op_flags & XFS_DA_OP_RENAME) == 0) {
>>   		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>> +		if (args->rmtblkno > 0)
>> +			error = xfs_attr3_leaf_clearflag(args);
>> +		retval = error;
> 
> Can we just init retval to 0 and avoid this assignment? With that and
> similar fixups to the previous patch:
> 
Sure, will do.

> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
> Note that I'm also of the mind to break this down into smaller functions
> depending on what later patches look like, but if there's more to
> consider around that this seems like a good step in that direction.
Sure, and that's fine too if we change our minds later.  I just figured 
I see what people thought of this first.  Thanks for the reviews!

Allison

> 
> Brian
> 
>> +		goto out;
>> +	}
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		xfs_attr_restore_rmt_blk(args);
>> +	/*
>> +	 * If this is an atomic rename operation, we must "flip" the incomplete
>> +	 * flags on the "new" and "old" attribute/value pairs so that one
>> +	 * disappears and one appears atomically.  Then we must remove the "old"
>> +	 * attribute/value pair.
>> +	 *
>> +	 * In a separate transaction, set the incomplete flag on the "old" attr
>> +	 * and clear the incomplete flag on the "new" attr.
>> +	 */
>> +	error = xfs_attr3_leaf_flipflags(args);
>> +	if (error)
>> +		goto out;
>> +	/*
>> +	 * Commit the flag value change and start the next trans in series
>> +	 */
>> +	error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +	if (error)
>> +		goto out;
>>   
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_invalidate(args);
>> -			if (error)
>> -				return error;
>> +	/*
>> +	 * Dismantle the "old" attribute/value pair by removing a "remote" value
>> +	 * (if it exists).
>> +	 */
>> +	xfs_attr_restore_rmt_blk(args);
>>   
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +	if (args->rmtblkno) {
>> +		error = xfs_attr_rmtval_invalidate(args);
>> +		if (error)
>> +			return error;
>>   
>> -		/*
>> -		 * Re-find the "old" attribute entry after any split ops.
>> -		 * The INCOMPLETE flag means that we will find the "old"
>> -		 * attr, not the "new" one.
>> -		 */
>> -		args->attr_filter |= XFS_ATTR_INCOMPLETE;
>> -		state = xfs_da_state_alloc();
>> -		state->args = args;
>> -		state->mp = mp;
>> -		state->inleaf = 0;
>> -		error = xfs_da3_node_lookup_int(state, &retval);
>> +		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>> +	}
>>   
>> -		/*
>> -		 * Remove the name and update the hashvals in the tree.
>> -		 */
>> -		blk = &state->path.blk[ state->path.active-1 ];
>> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -		error = xfs_attr3_leaf_remove(blk->bp, args);
>> -		xfs_da3_fixhashpath(state, &state->path);
>> +	/*
>> +	 * Re-find the "old" attribute entry after any split ops. The INCOMPLETE
>> +	 * flag means that we will find the "old" attr, not the "new" one.
>> +	 */
>> +	args->attr_filter |= XFS_ATTR_INCOMPLETE;
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = mp;
>> +	state->inleaf = 0;
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error)
>> +		goto out;
>>   
>> -		/*
>> -		 * Check to see if the tree needs to be collapsed.
>> -		 */
>> -		if (retval && (state->path.active > 1)) {
>> -			error = xfs_da3_join(state);
>> -			if (error)
>> -				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>> -		}
>> +	/*
>> +	 * Remove the name and update the hashvals in the tree.
>> +	 */
>> +	blk = &state->path.blk[state->path.active-1];
>> +	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +	error = xfs_attr3_leaf_remove(blk->bp, args);
>> +	xfs_da3_fixhashpath(state, &state->path);
>>   
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +	/*
>> +	 * Check to see if the tree needs to be collapsed.
>> +	 */
>> +	if (retval && (state->path.active > 1)) {
>> +		error = xfs_da3_join(state);
>> +		if (error)
>> +			goto out;
>> +		error = xfs_defer_finish(&args->trans);
>>   		if (error)
>>   			goto out;
>>   	}
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname
  2020-05-05 13:12   ` Brian Foster
@ 2020-05-05 17:37     ` Allison Collins
  0 siblings, 0 replies; 76+ messages in thread
From: Allison Collins @ 2020-05-05 17:37 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 5/5/20 6:12 AM, Brian Foster wrote:
> On Thu, Apr 30, 2020 at 03:50:13PM -0700, Allison Collins wrote:
>> Lift -ENOSPC handler from xfs_attr_leaf_addname.  This will help to
>> reorganize transitions between the attr forms later.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Thank you!
Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++--------------
>>   1 file changed, 11 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9171895..c8cae68 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -299,6 +299,13 @@ xfs_attr_set_args(
>>   			return error;
>>   
>>   		/*
>> +		 * Promote the attribute list to the Btree format.
>> +		 */
>> +		error = xfs_attr3_leaf_to_node(args);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>>   		 * Commit that transaction so that the node_addname()
>>   		 * call can manage its own transactions.
>>   		 */
>> @@ -602,7 +609,7 @@ xfs_attr_leaf_try_add(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_buf		*bp)
>>   {
>> -	int			retval, error;
>> +	int			retval;
>>   
>>   	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>> @@ -634,20 +641,10 @@ xfs_attr_leaf_try_add(
>>   	}
>>   
>>   	/*
>> -	 * Add the attribute to the leaf block, transitioning to a Btree
>> -	 * if required.
>> +	 * Add the attribute to the leaf block
>>   	 */
>> -	retval = xfs_attr3_leaf_add(bp, args);
>> -	if (retval == -ENOSPC) {
>> -		/*
>> -		 * 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;
>> -	}
>> -	return retval;
>> +	return xfs_attr3_leaf_add(bp, args);
>> +
>>   out_brelse:
>>   	xfs_trans_brelse(args->trans, bp);
>>   	return retval;
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v9 22/24] xfs: Add delay ready attr remove routines
  2020-04-30 22:50 ` [PATCH v9 22/24] xfs: Add delay ready attr remove routines Allison Collins
  2020-05-04 19:33   ` Darrick J. Wong
@ 2020-05-07 11:54   ` Brian Foster
  1 sibling, 0 replies; 76+ messages in thread
From: Brian Foster @ 2020-05-07 11:54 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Thu, Apr 30, 2020 at 03:50:14PM -0700, Allison Collins wrote:
...
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        | 159 ++++++++++++++++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
>  fs/xfs/libxfs/xfs_attr_remote.c |  31 ++++----
>  fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
>  fs/xfs/xfs_attr_inactive.c      |   2 +-
>  6 files changed, 215 insertions(+), 54 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index c8cae68..7213589 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -363,23 +384,57 @@ xfs_has_attr(
...
> +/*
> + * 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_delattr_context *dac)
>  {
> +	struct xfs_da_args	*args = dac->da_args;
>  	struct xfs_inode	*dp = args->dp;
> -	int			error;
> +
> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> +		goto node;

If we're in the above state, doesn't that mean we're in node format and
should fall through to the node function based on the logic below
anyways?

>  
>  	if (!xfs_inode_hasattr(dp)) {
> -		error = -ENOATTR;
> +		return -ENOATTR;
>  	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>  		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> -		error = xfs_attr_shortform_remove(args);
> +		return xfs_attr_shortform_remove(args);
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_removename(args);
> -	} else {
> -		error = xfs_attr_node_removename(args);
> +		return xfs_attr_leaf_removename(args);
>  	}
> -
> -	return error;
> +node:
> +	return  xfs_attr_node_removename(dac);
>  }
>  
>  /*
...
> @@ -1232,21 +1299,35 @@ xfs_attr_node_removename_rmt (
>   * 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(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	struct xfs_da_state	*state;
> -	struct xfs_da_state_blk	*blk;
> -	int			retval, error;
> -	struct xfs_inode	*dp = args->dp;
> +	struct xfs_da_args		*args = dac->da_args;
> +	struct xfs_da_state		*state;
> +	struct xfs_da_state_blk		*blk;
> +	int				retval, error;
> +	struct xfs_inode		*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = dac->da_state;
> +	blk = dac->blk;
>  
> -	error = xfs_attr_node_removename_setup(args, &state);
> -	if (error)
> -		goto out;
> +	if (dac->dela_state == XFS_DAS_RM_SHRINK)
> +		goto das_rm_shrink;
> +
> +	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
> +		dac->flags |= XFS_DAC_NODE_RMVNAME_INIT;
> +		error = xfs_attr_node_removename_setup(dac, &state);
> +		if (error)
> +			goto out;
> +	}

Now that we've factored out this state with the flag, I wonder if we
could factor out this logic and pull it all the way up to
xfs_attr_remove_args(). That would remove the init flag, we'd presumably
just have to duplicate the format checks to make sure the fork is in
node format.

I'd consider that a followup patch, btw. I know it's a bit circuitous to
add the flag only to then remove it, but I think there's value in making
simple, incremental changes. ;)

>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1254,8 +1335,13 @@ xfs_attr_node_removename(
>  	 * overflow the maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_node_removename_rmt(args, state);
> -		if (error)
> +		/*
> +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
> +		 */
> +		error = xfs_attr_node_removename_rmt(dac, state);
> +		if (error == -EAGAIN)
> +			return error;
> +		else if (error)
>  			goto out;
>  	}
>  
> @@ -1274,17 +1360,14 @@ 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;
> +
> +		dac->flags |= XFS_DAC_DEFER_FINISH;
> +		dac->dela_state = XFS_DAS_RM_SHRINK;
> +		return -EAGAIN;
>  	}
>  
> +das_rm_shrink:
> +

Alternatively to the state question in xfs_attr_remove_iter(), I wonder
if we could lift the bottom part of this function (that does the tree
collapse and potential node shrink) into the caller. AFAICT that would
isolate all of the xattr remove state tracking code to
xfs_attr_remove_iter(), which would be a pretty nice result IMO.

>  	/*
>  	 * If the result is small enough, push it all into the inode.
>  	 */
...
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index f770159..f2d46c7 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
...
> @@ -691,10 +693,14 @@ xfs_attr_rmtval_remove(
>  	lblkno = args->rmtblkno;
>  	blkcnt = args->rmtblkcnt;
>  	do {
> -		retval = __xfs_attr_rmtval_remove(args);
> +		retval = __xfs_attr_rmtval_remove(&dac);
>  		if (retval && retval != EAGAIN)
>  			return retval;
>  
> +		error = xfs_attr_defer_finish(&dac);
> +		if (error)
> +			break;
> +

This seems to come out of nowhere..?

Brian

>  		/*
>  		 * Close out trans and start the next one in the chain.
>  		 */
> @@ -713,9 +719,10 @@ xfs_attr_rmtval_remove(
>   */
>  int
>  __xfs_attr_rmtval_remove(
> -	struct xfs_da_args	*args)
> +	struct xfs_delattr_context	*dac)
>  {
> -	int			error, done;
> +	struct xfs_da_args		*args = dac->da_args;
> +	int				error, done;
>  
>  	/*
>  	 * Unmap value blocks for this attr.
> @@ -725,12 +732,10 @@ __xfs_attr_rmtval_remove(
>  	if (error)
>  		return error;
>  
> -	error = xfs_defer_finish(&args->trans);
> -	if (error)
> -		return error;
> -
> -	if (!done)
> +	if (!done) {
> +		dac->flags &= ~XFS_DAC_DEFER_FINISH;
>  		return -EAGAIN;
> +	}
>  
>  	return error;
>  }
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index ee3337b..351da00 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -14,5 +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_remove(struct xfs_da_args *args);
> +int __xfs_attr_rmtval_remove(struct xfs_delattr_context *dac);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> index c42f90e..b2150fa 100644
> --- a/fs/xfs/xfs_attr_inactive.c
> +++ b/fs/xfs/xfs_attr_inactive.c
> @@ -15,10 +15,10 @@
>  #include "xfs_da_format.h"
>  #include "xfs_da_btree.h"
>  #include "xfs_inode.h"
> +#include "xfs_attr.h"
>  #include "xfs_attr_remote.h"
>  #include "xfs_trans.h"
>  #include "xfs_bmap.h"
> -#include "xfs_attr.h"
>  #include "xfs_attr_leaf.h"
>  #include "xfs_quota.h"
>  #include "xfs_dir2.h"
> -- 
> 2.7.4
> 


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

end of thread, other threads:[~2020-05-07 11:54 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-30 22:49 [PATCH v9 00/24] xfs: Delay Ready Attributes Allison Collins
2020-04-30 22:49 ` [PATCH v9 01/24] xfs: Add xfs_has_attr and subroutines Allison Collins
2020-04-30 22:49 ` [PATCH v9 02/24] xfs: Check for -ENOATTR or -EEXIST Allison Collins
2020-04-30 22:49 ` [PATCH v9 03/24] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2020-04-30 22:49 ` [PATCH v9 04/24] xfs: Pull up trans handling in xfs_attr3_leaf_flipflags Allison Collins
2020-04-30 22:49 ` [PATCH v9 05/24] xfs: Split apart xfs_attr_leaf_addname Allison Collins
2020-05-04 17:33   ` Darrick J. Wong
2020-05-04 22:34     ` Allison Collins
2020-04-30 22:49 ` [PATCH v9 06/24] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
2020-04-30 22:49 ` [PATCH v9 07/24] xfs: Pull up trans roll from xfs_attr3_leaf_setflag Allison Collins
2020-04-30 22:50 ` [PATCH v9 08/24] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
2020-04-30 22:50 ` [PATCH v9 09/24] xfs: Pull up trans roll in xfs_attr3_leaf_clearflag Allison Collins
2020-04-30 22:50 ` [PATCH v9 10/24] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
2020-05-04 13:27   ` Brian Foster
2020-05-04 21:36     ` Allison Collins
2020-05-05 12:03       ` Brian Foster
2020-05-05 17:35         ` Allison Collins
2020-05-04 17:41   ` Darrick J. Wong
2020-05-04 22:53     ` Allison Collins
2020-05-04 22:57       ` Darrick J. Wong
2020-04-30 22:50 ` [PATCH v9 11/24] xfs: Pull up xfs_attr_rmtval_invalidate Allison Collins
2020-05-04 13:27   ` Brian Foster
2020-05-04 21:37     ` Allison Collins
2020-05-04 17:41   ` Darrick J. Wong
2020-05-04 22:55     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 12/24] xfs: Add helper function xfs_attr_node_shrink Allison Collins
2020-05-04 13:27   ` Brian Foster
2020-05-04 21:37     ` Allison Collins
2020-05-04 17:42   ` Darrick J. Wong
2020-05-04 22:55     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 13/24] xfs: Remove unneeded xfs_trans_roll_inode calls Allison Collins
2020-05-04 13:30   ` Brian Foster
2020-05-04 22:15     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 14/24] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform Allison Collins
2020-05-04 18:46   ` Darrick J. Wong
2020-05-05  0:29     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 15/24] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
2020-05-04 18:47   ` Darrick J. Wong
2020-04-30 22:50 ` [PATCH v9 16/24] xfs: Add remote block helper functions Allison Collins
2020-05-04 18:55   ` Darrick J. Wong
2020-05-04 23:01     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 17/24] xfs: Add helper function xfs_attr_node_removename_setup Allison Collins
2020-05-04 18:58   ` Darrick J. Wong
2020-05-04 23:02     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 18/24] xfs: Add helper function xfs_attr_node_removename_rmt Allison Collins
2020-05-04 19:00   ` Darrick J. Wong
2020-05-04 23:04     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 19/24] xfs: Simplify xfs_attr_leaf_addname Allison Collins
2020-05-04 19:03   ` Darrick J. Wong
2020-05-04 23:06     ` Allison Collins
2020-05-05 13:11   ` Brian Foster
2020-05-05 17:35     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 20/24] xfs: Simplify xfs_attr_node_addname Allison Collins
2020-05-04 19:06   ` Darrick J. Wong
2020-05-04 23:16     ` Allison Collins
2020-05-05 13:12   ` Brian Foster
2020-05-05 17:35     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 21/24] xfs: Lift -ENOSPC handler from xfs_attr_leaf_addname Allison Collins
2020-05-04 19:10   ` Darrick J. Wong
2020-05-04 23:17     ` Allison Collins
2020-05-05 13:12   ` Brian Foster
2020-05-05 17:37     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 22/24] xfs: Add delay ready attr remove routines Allison Collins
2020-05-04 19:33   ` Darrick J. Wong
2020-05-05  0:26     ` Allison Collins
2020-05-05  1:44       ` Darrick J. Wong
2020-05-05 17:35         ` Allison Collins
2020-05-07 11:54   ` Brian Foster
2020-04-30 22:50 ` [PATCH v9 23/24] xfs: Add delay ready attr set routines Allison Collins
2020-05-04 19:49   ` Darrick J. Wong
2020-05-05  1:31     ` Allison Collins
2020-05-04 22:36   ` Darrick J. Wong
2020-05-05  1:32     ` Allison Collins
2020-04-30 22:50 ` [PATCH v9 24/24] xfs: Rename __xfs_attr_rmtval_remove Allison Collins
2020-05-04 19:34   ` Darrick J. Wong
2020-05-05  0:27     ` Allison Collins

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