public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Allison Collins <allison.henderson@oracle.com>
To: Brian Foster <bfoster@redhat.com>,
	"Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH v12 1/8] xfs: Add delay ready attr remove routines
Date: Fri, 4 Sep 2020 16:03:59 -0700	[thread overview]
Message-ID: <de7920d9-abbb-fd8e-44f0-fb05a5d71bcf@oracle.com> (raw)
In-Reply-To: <20200902122258.GA285409@bfoster>



On 9/2/20 5:22 AM, Brian Foster wrote:
> On Tue, Sep 01, 2020 at 11:31:34AM -0700, Darrick J. Wong wrote:
>> On Tue, Sep 01, 2020 at 02:07:41PM -0400, Brian Foster wrote:
>>> On Tue, Sep 01, 2020 at 10:20:21AM -0700, Darrick J. Wong wrote:
>>>> On Tue, Sep 01, 2020 at 01:00:20PM -0400, Brian Foster wrote:
>>>>> On Wed, Aug 26, 2020 at 05:35:11PM -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
>>>>>
>>>>> Nit:				preserving
ok, will fix
>>>>>
>>>>>> 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.  See xfs_attr.h for a more
>>>>>> detailed diagram of the states.
>>>>>>
>>>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>>>> ---
>>>>>>   fs/xfs/libxfs/xfs_attr.c        | 162 ++++++++++++++++++++++++++++++----------
>>>>>>   fs/xfs/libxfs/xfs_attr.h        |  73 ++++++++++++++++++
>>>>>>   fs/xfs/libxfs/xfs_attr_leaf.c   |   2 +-
>>>>>>   fs/xfs/libxfs/xfs_attr_remote.c |  39 +++++-----
>>>>>>   fs/xfs/libxfs/xfs_attr_remote.h |   2 +-
>>>>>>   fs/xfs/xfs_attr_inactive.c      |   2 +-
>>>>>>   6 files changed, 220 insertions(+), 60 deletions(-)
>>>>>>
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>>>> index 2e055c0..ea50fc3 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>>> ...
>>>>>> @@ -264,6 +264,33 @@ xfs_attr_set_shortform(
>>>>>>   }
>>>>>>   
>>>>>>   /*
>>>>>> + * Checks to see if a delayed attribute transaction should be rolled.  If so,
>>>>>> + * also checks for a defer finish.  Transaction is finished and rolled as
>>>>>> + * needed, and returns true of false if the delayed operation should continue.
>>>>>> + */
>>>>>> +int
>>>>>> +xfs_attr_trans_roll(
>>>>>> +	struct xfs_delattr_context	*dac)
>>>>>> +{
>>>>>> +	struct xfs_da_args              *args = dac->da_args;
>>>>>> +	int				error = 0;
>>>>>> +
>>>>>> +	if (dac->flags & XFS_DAC_DEFER_FINISH) {
>>>>>> +		/*
>>>>>> +		 * The caller wants us to finish all the deferred ops so that we
>>>>>> +		 * avoid pinning the log tail with a large number of deferred
>>>>>> +		 * ops.
>>>>>> +		 */
>>>>>> +		dac->flags &= ~XFS_DAC_DEFER_FINISH;
>>>>>> +		error = xfs_defer_finish(&args->trans);
>>>>>> +		if (error)
>>>>>> +			return error;
>>>>>> +	}
>>>>>> +
>>>>>> +	return xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>
>>>>> I'm not sure there's a need to roll the transaction again if the
>>>>> defer path above executes. xfs_defer_finish() completes the dfops and
>>>>> always returns a clean transaction.
>>>>
>>>> I'm not sure we even really need a DEFER_FINISH flag if (a) xfs_defer.c
>>>> gets patched to finish all the other defer items before coming back to
>>>> the next step of the delattr state machine and (b) Allison removes the
>>>> _iter functions in favor of using the defer op mechanism even when we're
>>>> not pushing the state changes through the log.
>>>>
>>>
>>> What do you mean by using the dfops mechanism without pushing state
>>> changes through the log? My understanding was that dfops would be
>>> involved with the new intent based attr ops and the state management
>>> handles the original ops until we no longer have to support them..
>>
>> I think you were probably still out when Dave and Allison and I had the
>> brain fart^Wstorm that nothing in the defer ops code actually requires
>> you to log anything, which means that you can use it to manage a long
>> running operation that spans multiple transaction rolls! :)
>>
> 
> Ok..
> 
>> ->create_intent and ->create_done are supposed to create log items and
>> attach them to the transaction, but the defer finish loop will still
>> call ->finish_item even if they return NULL pointers.  If the
>> finish_item call steps around the null pointers and calls whatever upper
>> level functions are needed to make progress, that works fine.  There's
>> no log recovery, obviously.
>>
>> In other words, we can (ab)use defer ops for attr set/remove even in the
>> non-logged case, which eliminates the need for the separate control
>> loop.
>>
> 
> Right, that all makes sense. I'm still missing how this impacts the
> lower level functional code driven by the control loop...
> 
>> FWIW, I've implemented that strategy as a proof of concept for extent
>> swapping:
>>
>> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/commit/?h=atomic-file-updates&id=a85883c36e2f3eff50db50fcf58a71d4f13d1f64__;!!GqivPVa7Brio!MQTOxwgVl5y_iE_BCpboDzsjWozVuUj8T-EEE1ICVu3TVeAwAWaWedD-cxFowrJwBzGi$
>>
>> Wherein you get atomic swapext if you have the log items enabled, and
>> if not, you get the old "rmap swapext" that doesn't have log tracking.
>>
> 
> Interesting, thanks. The whole dfops reuse idea sounds neat to me in
> that we can presumably condense the new/old implementations even further
> than originally expected, but I think this side steps the concern
> related to my initial comment around refactoring. AFAICT this model
> doesn't necessarily dictate what the underlying code looks like. In the
> example above, it looks like the swapext code reenters into a
> xfs_swapext_finish_one() function that trivially understands how to pick
> up where it left off. This is a fortunate implementation detail of the
> swapext operation (along with the whole notion of the
> xfs_op_has_more_work() pattern, which as we've already touched on can be
> difficult for things like xattr set, etc.).
> 
> By contrast, the xattr code is currently a ball of wire that rolls
> transactions at various points up and down its implementation (generally
> speaking). The primary intent of all this refactoring work is to isolate
> the transaction rolling to a single mechanism so we have the ability to
> use something like dfops in the first place. I don't see how the
> insertion of unlogged dfops in the design really changes much in that
> regard. Is there more to the previous discussion that I'm missing?
> 
> ISTM that we're potentially talking about different aspects of the
> implementation. If so, we either need to continue to refactor the xattr
> code to untangle the existing mess so it can be driven by a single entry
> point (just like the swapext example), or that retrofitting the existing
> implementation into the dfops mechanism means something more involved
> like creating new dfops op types per sub-component of a particular xattr
> op and queueing/running those individually. Though TBH, the latter
> sounds like it is getting a bit into crazy infrastructure territory. ;P
> Thoughts?
> 
> Brian

Yeah, I'll try some experimenting to see what that ends up looking like. 
  I've looked at the swap extent code from the link above, and I think I 
understand now what Darrick is describing with the reuse/abuse the 
defops mechanics.  We modify the *_create_intent routine to return null 
to skip recoding it to the log. I THINK this should still work beucase 
the state machine context is carried around in the xfs_attr_item, not 
the xfs_attri_log_item.  So we maybe might be able to make it work with 
out too much crazy.



> 
>>>> (I'm working on (a) still, will have something in a few days...)
>>>>
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>>    * Set the attribute specified in @args.
>>>>>>    */
>>>>>>   int
>>>>> ...
>>>>>> @@ -1218,21 +1288,35 @@ xfs_attr_node_remove_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.
>>>>>> @@ -1240,8 +1324,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_remove_rmt(args, state);
>>>>>> -		if (error)
>>>>>> +		/*
>>>>>> +		 * May return -EAGAIN. Remove blocks until args->rmtblkno == 0
>>>>>> +		 */
>>>>>> +		error = xfs_attr_node_remove_rmt(dac, state);
>>>>>> +		if (error == -EAGAIN)
>>>>>> +			return error;
>>>>>> +		else if (error)
>>>>>>   			goto out;
>>>>>>   	}
>>>>>>   
>>>>>> @@ -1260,17 +1349,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.
>>>>>>   	 */
>>>>>
>>>>> ISTR that Dave or Darrick previously suggested that we should try to
>>>>> isolate the state transition code as much as possible to a single
>>>>> location. That basically means we should look at any place a particular
>>>>> state check travels through multiple functions and see if we can
>>>>> refactor things to flatten the state processing code. I tend to agree
>>>>> that is the ideal approach given how difficult it can be to track state
>>>>> changes through multiple functions.
>>>>
>>>> Yes. :)
>>>>
>>>>> In light of that (and as an example), I think the whole
>>>>> xfs_attr_node_removename() path should be refactored so it looks
>>>>> something like the following (with obvious error
>>>>> handling/comment/aesthetic cleanups etc.):
>>>>>
>>>>> xfs_attr_node_removename_iter()
>>>>> {
>>>>> 	...
>>>>>
>>>>> 	if ((dac->flags & XFS_DAC_NODE_RMVNAME_INIT) == 0) {
>>>>> 		<do init stuff>
>>>>> 	}
>>>>>
>>>>> 	switch (dac->dela_state) {
>>>>> 	case 0:
>>>>
>>>> I kinda wish "0" had its own name, but I don't also want to start
>>>> another round of naming bikeshed. :)
>>>>
>>>>> 		/*
>>>>> 		 * repeatedly remove remote blocks, remove the entry and
>>>>> 		 * join. returns -EAGAIN or 0 for completion of the step.
>>>>> 		 */
>>>>> 		error = xfs_attr_node_remove_step(dac, state);
>>>>> 		if (error)
>>>>> 			break;
>>>>>
>>>>> 		/* check whether to shrink or return success */
>>>>> 		if (!error && xfs_bmap_one_block(...)) {
>>>>> 			dac->dela_state = XFS_DAS_RM_SHRINK;
>>>>> 			error = -EAGAIN;
>>>>> 		}
>>>>> 		break;
>>>>> 	case XFS_DAS_RM_SHRINK:
>>>>> 		/* shrink the fork, no reentry, no next step */
>>>>> 		error = xfs_attr_node_shrink_step(args, state);	
>>>>> 		break;
>>>>
>>>> <nod> The ASCII art diagrams help assuage my nerves about the fact that
>>>> we branch based on dela_state but not all the branches actually show us
>>>> moving to the next state.
>>>>
>>>> I've gotten the distinct sense, though, that throwing the new state all
>>>> the way back up to _iter() to set it is probably a lot more fuss than
>>>> it's worth for the attr set case, though...
>>>>
>>>
>>> That's quite possible. :P
Sure, I will see if I can get something similar to this worked out, at 
least for the remove path.  But yes, the set path would be a bit more of 
a challenge.

Thanks all!

Allison

>>>
>>>>> 	default:
>>>>> 		ASSERT(0);
>>>>> 		return -EINVAL;
>>>>> 	}
>>>>>
>>>>> 	if (error == -EAGAIN)
>>>>> 		return error;
>>>>>
>>>>> 	<do cleanup stuff>
>>>>> 	...
>>>>> 	return error;
>>>>> }
>>>>>
>>>>> The idea here is that we have one _iter() function that does all the
>>>>> state management for a particular operation and has minimal other logic.
>>>>> That way we can see the states that repeat, transition, etc. all in one
>>>>> place. The _step() functions implement the functional components of each
>>>>> state and do no state management whatsoever beyond return -EAGAIN to
>>>>> request reentry or return 0 for completion. In the case of the latter,
>>>>> the _iter() function decides whether to transition to another state
>>>>> (returning -EAGAIN itself) or complete the operation. If a _step()
>>>>> function ever needs to set or check ->dela_state, then that is clear
>>>>> indication it must be broken up into multiple _step() functions.
>>>>
>>>> ...because I've frequently had the same thought that the state machine
>>>> handling ought to be in the same place.  But then I start reading
>>>> through the xattr code to figure out how that would be done, and get
>>>> trapped by the fact that some of the decisions about the next state have
>>>> to happen pretty deep in the xattr code-- stuff like allocating an
>>>> extent for a remote value, where depending on whether or not we got enough
>>>> blocks to satisfy the space requirements, either we can move on to the
>>>> next state and return EAGAIN, or we have to save the current state and
>>>> EAGAIN to try to get more blocks.
>>>>
>>>
>>> I haven't walked through the set code in a while, but this sort of
>>> sounds like more of the same (heavy refactoring followed by insertion of
>>> state management).
>>>
>>>> Maybe it would help a little if the setting of DEFER_FINISH and changing
>>>> of dela_state could be put into a little helper with a tracepoint so
>>>> that future us can ftrace the state machine to make sure it's working
>>>> correctly?
>>>>
>>>
>>> I like the idea, but not sure it helps with following the code as much
>>> as runtime analysis.
>>
>> <nod>
>>
>>>>> I think this implements the separation of state and functionality model
>>>>> we're after without introduction of crazy state processing frameworks,
>>>>
>>>> "crazy state processing frameworks"... like xfs_defer.c? :)
>>>>
>>>
>>> Re: my question above, I'm curious about reusing dfops as a mechanism
>>> for both modes if somebody can elaborate on the idea or point me at a
>>> reference where it was previously discussed..? I could have lost track
>>> or missed a discussion while I was out...
>>
>> (See above...)
>>
>>>>> etc., but I admit I've so far only thought about it wrt the remove case
>>>>> (which is more simple than the set case). Also note that as usual, any
>>>>> associated refactoring of the functional components should come as
>>>>> preliminary patches such that this patch only introduces state bits.
>>>>> Thoughts?
>>>>
>>>> (I thought/hoped we'd done all the refactoring in the 23-patch megalith
>>>> that I tossed into 5.9... :))
>>>>
>>>
>>> Heh. I'm glad to see that snowball got tossed. ;)
>>
>> :)
>>
>> --D
>>
>>> Brian
>>>
>>>> --D
>>>>
>>>>> Brian
>>>>>
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>>>> index 3e97a93..9573949 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_trans_roll(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 8623c81..4ed7b31 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 3f80ced..7f81b48 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>>>>>> @@ -676,10 +676,14 @@ xfs_attr_rmtval_invalidate(
>>>>>>    */
>>>>>>   int
>>>>>>   xfs_attr_rmtval_remove(
>>>>>> -	struct xfs_da_args      *args)
>>>>>> +	struct xfs_da_args		*args)
>>>>>>   {
>>>>>> -	int			error;
>>>>>> -	int			retval;
>>>>>> +	xfs_dablk_t			lblkno;
>>>>>> +	int				blkcnt;
>>>>>> +	int				error;
>>>>>> +	struct xfs_delattr_context	dac  = {
>>>>>> +		.da_args	= args,
>>>>>> +	};
>>>>>>   
>>>>>>   	trace_xfs_attr_rmtval_remove(args);
>>>>>>   
>>>>>> @@ -687,19 +691,17 @@ xfs_attr_rmtval_remove(
>>>>>>   	 * Keep de-allocating extents until the remote-value region is gone.
>>>>>>   	 */
>>>>>>   	do {
>>>>>> -		retval = __xfs_attr_rmtval_remove(args);
>>>>>> -		if (retval && retval != -EAGAIN)
>>>>>> -			return retval;
>>>>>> +		error = __xfs_attr_rmtval_remove(&dac);
>>>>>> +		if (error != -EAGAIN)
>>>>>> +			break;
>>>>>>   
>>>>>> -		/*
>>>>>> -		 * Close out trans and start the next one in the chain.
>>>>>> -		 */
>>>>>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>> +		error = xfs_attr_trans_roll(&dac);
>>>>>>   		if (error)
>>>>>>   			return error;
>>>>>> -	} while (retval == -EAGAIN);
>>>>>>   
>>>>>> -	return 0;
>>>>>> +	} while (true);
>>>>>> +
>>>>>> +	return error;
>>>>>>   }
>>>>>>   
>>>>>>   /*
>>>>>> @@ -709,9 +711,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.
>>>>>> @@ -721,12 +724,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 9eee615..002fd30 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 bfad669..aaa7e66 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
>>>>>>
>>>>>
>>>>
>>>
>>
> 

  reply	other threads:[~2020-09-04 23:04 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-27  0:35 [PATCH v12 0/8] xfs: Delayed Attributes Allison Collins
2020-08-27  0:35 ` [PATCH v12 1/8] xfs: Add delay ready attr remove routines Allison Collins
2020-09-01 17:00   ` Brian Foster
2020-09-01 17:20     ` Darrick J. Wong
2020-09-01 18:07       ` Brian Foster
2020-09-01 18:31         ` Darrick J. Wong
2020-09-02 12:22           ` Brian Foster
2020-09-04 23:03             ` Allison Collins [this message]
2020-09-08 14:43               ` Brian Foster
2020-08-27  0:35 ` [PATCH v12 2/8] xfs: Add delay ready attr set routines Allison Collins
2020-08-27  0:35 ` [PATCH v12 3/8] xfs: Rename __xfs_attr_rmtval_remove Allison Collins
2020-08-27  0:35 ` [PATCH v12 4/8] xfs: Set up infastructure for deferred attribute operations Allison Collins
2020-08-28 21:27   ` Darrick J. Wong
2020-09-02  0:46     ` Allison Collins
2020-09-02  2:33       ` Allison Collins
2020-08-27  0:35 ` [PATCH v12 5/8] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
2020-08-27  0:35 ` [PATCH v12 6/8] xfs: Add feature bit XFS_SB_FEAT_INCOMPAT_LOG_DELATTR Allison Collins
2020-08-27  0:35 ` [PATCH v12 7/8] xfs: Enable delayed attributes Allison Collins
2020-08-27  0:35 ` [PATCH v12 8/8] xfs_io: Add delayed attributes error tag Allison Collins
2020-08-28 16:02   ` Darrick J. Wong
2020-08-28 18:00     ` Allison Collins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=de7920d9-abbb-fd8e-44f0-fb05a5d71bcf@oracle.com \
    --to=allison.henderson@oracle.com \
    --cc=bfoster@redhat.com \
    --cc=darrick.wong@oracle.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox