From: Allison Collins <allison.henderson@oracle.com>
To: Brian Foster <bfoster@redhat.com>
Cc: linux-xfs@vger.kernel.org, dchinner@redhat.com
Subject: Re: [PATCH v8 18/20] xfs: Add delay ready attr remove routines
Date: Thu, 16 Apr 2020 15:41:45 -0700 [thread overview]
Message-ID: <3fe45a6c-877a-c8b0-a17e-d6e1187f8d50@oracle.com> (raw)
In-Reply-To: <20200416105832.GA6945@bfoster>
On 4/16/20 3:58 AM, Brian Foster wrote:
> On Wed, Apr 15, 2020 at 08:17:07PM -0700, Allison Collins wrote:
>>
>>
>> On 4/15/20 4:46 AM, Brian Foster wrote:
>>> On Tue, Apr 14, 2020 at 02:35:43PM -0700, Allison Collins wrote:
>>>>
>>>>
>>>> On 4/13/20 5:30 AM, Brian Foster wrote:
>>>>> On Fri, Apr 03, 2020 at 03:12:27PM -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.
>>>>>>
>>>>>> Calls to xfs_attr_rmtval_remove are replaced with the delay ready
>>>>>> counter parts: xfs_attr_rmtval_invalidate (appearing in the setup
>>>>>> helper) and then __xfs_attr_rmtval_remove. We will rename
>>>>>> __xfs_attr_rmtval_remove back to xfs_attr_rmtval_remove when we are
>>>>>> done.
>>>>>>
>>>>>> This patch also adds a new struct xfs_delattr_context, which we will use
>>>>>> to keep track of the current state of an attribute operation. The new
>>>>>> xfs_delattr_state enum is used to track various operations that are in
>>>>>> progress so that we know not to repeat them, and resume where we left
>>>>>> off before EAGAIN was returned to cycle out the transaction. Other
>>>>>> members take the place of local variables that need to retain their
>>>>>> values across multiple function recalls.
>>>>>>
>>>>>> Below is a state machine diagram for attr remove operations. The
>>>>>> XFS_DAS_* states indicate places where the function would return
>>>>>> -EAGAIN, and then immediately resume from after being recalled by the
>>>>>> calling function. States marked as a "subroutine state" indicate that
>>>>>> they belong to a subroutine, and so the calling function needs to pass
>>>>>> them back to that subroutine to allow it to finish where it left off.
>>>>>> But they otherwise do not have a role in the calling function other than
>>>>>> just passing through.
>>>>>>
>>>>>> xfs_attr_remove_iter()
>>>>>> XFS_DAS_RM_SHRINK ─┐
>>>>>> (subroutine state) │
>>>>>> │
>>>>>> XFS_DAS_RMTVAL_REMOVE ─┤
>>>>>> (subroutine state) │
>>>>>> └─>xfs_attr_node_removename()
>>>>>> │
>>>>>> v
>>>>>> need to remove
>>>>>> ┌─n── rmt blocks?
>>>>>> │ │
>>>>>> │ y
>>>>>> │ │
>>>>>> │ v
>>>>>> │ ┌─>XFS_DAS_RMTVAL_REMOVE
>>>>>> │ │ │
>>>>>> │ │ v
>>>>>> │ └──y── more blks
>>>>>> │ to remove?
>>>>>> │ │
>>>>>> │ n
>>>>>> │ │
>>>>>> │ v
>>>>>> │ need to
>>>>>> └─────> shrink tree? ─n─┐
>>>>>> │ │
>>>>>> y │
>>>>>> │ │
>>>>>> v │
>>>>>> XFS_DAS_RM_SHRINK │
>>>>>> │ │
>>>>>> v │
>>>>>> done <─────┘
>>>>>>
>>>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>>>> ---
>>>>>
>>>>> All in all this is starting to look much more simple to me, at least in
>>>>> the remove path. ;P There's only a few states and the markers that are
>>>>> introduced are fairly straightforward, etc. Comments to follow..
>>>>>
>>>>>> fs/xfs/libxfs/xfs_attr.c | 168 ++++++++++++++++++++++++++++++++++++-----------
>>>>>> fs/xfs/libxfs/xfs_attr.h | 38 +++++++++++
>>>>>> 2 files changed, 168 insertions(+), 38 deletions(-)
>>>>>>
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>>>> index d735570..f700976 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>>>> @@ -45,7 +45,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>>>>> */
>>>>>> STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>>>>> STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>>>>> -STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>>>>> +STATIC int xfs_attr_leaf_removename(struct xfs_delattr_context *dac);
>>>>>> STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>>>>> /*
>>>>>> @@ -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);
>>>>>> +STATIC 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)
>>>>>> @@ -356,20 +365,66 @@ 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;
>>>>>> +
>>>>>> + if (dac.flags & XFS_DAC_DEFER_FINISH) {
>>>>>> + dac.flags &= ~XFS_DAC_DEFER_FINISH;
>>>>>> + error = xfs_defer_finish(&args->trans);
>>>>>> + if (error)
>>>>>> + break;
>>>>>> + }
>>>>>> +
>>>>>> + error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>> + if (error)
>>>>>> + break;
>>>>>> + } while (true);
>>>>>> +
>>>>>> + return error;
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * 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;
>>>>>> + /* State machine switch */
>>>>>> + switch (dac->dela_state) {
>>>>>> + case XFS_DAS_RM_SHRINK:
>>>>>> + case XFS_DAS_RMTVAL_REMOVE:
>>>>>> + return xfs_attr_node_removename(dac);
>>>>>> + default:
>>>>>> + break;
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Hmm.. so we're duplicating the call instead of using labels..?
>>>>
>>>> Yes, this was a suggestion made during v7. I suspect Dave may have been
>>>> wanting to simplify things by escaping the use of labels. At least in so
>>>> far as the remove path is concerned. Though he may not have realized this
>>>> would create a duplication call? I will cc him here; the conditions for
>>>> calling xfs_attr_node_removename are: the below if/else sequence exhausts
>>>> with no successes, and defaults into the else case (ie: the entry
>>>> condition), OR one of the above states is set (which is a re-entry
>>>> condition)
>>>>
>>>
>>> Ok.
>>>
>>>>
>>>> I'm
>>>>> wondering if this can be elegantly combined with the if/else branches
>>>>> below, particularly since node format is the only situation that seems
>>>>> to require a roll here.
>>>>>
>>>>>> if (!xfs_inode_hasattr(dp)) {
>>>>>> error = -ENOATTR;
>>>>>> } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>>>> ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>>>>> error = xfs_attr_shortform_remove(args);
>>>>>> } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>>>> - error = xfs_attr_leaf_removename(args);
>>>>>> + error = xfs_attr_leaf_removename(dac);
>>>>>> } else {
>>>>>> - error = xfs_attr_node_removename(args);
>>>>>> + error = xfs_attr_node_removename(dac);
>>>>>> }
>>>>>> return error;
>>>>
>>>> If we want to try and combine this into if/elses with no duplication, I
>>>> believe the simplest arrangement would look something like this:
>>>>
>>>>
>>>> int
>>>> xfs_attr_remove_iter(
>>>> struct xfs_delattr_context *dac)
>>>> {
>>>> struct xfs_da_args *args = dac->da_args;
>>>> struct xfs_inode *dp = args->dp;
>>>>
>>>> if (dac->dela_state != XFS_DAS_RM_SHRINK &&
>>>> dac->dela_state != XFS_DAS_RMTVAL_REMOVE) {
>>>> if (!xfs_inode_hasattr(dp)) {
>>>> return -ENOATTR;
>>>> } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>> ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>>> return xfs_attr_shortform_remove(args);
>>>> } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>> return xfs_attr_leaf_removename(dac);
>>>> }
>>>> }
>>>>
>>>> return xfs_attr_node_removename(dac);
>>>> }
>>>>
>>>> Let me know what folks think of that. I'm not always clear on where people
>>>> stand with aesthetics. (IE, is it better to have a duplicate call if it gets
>>>> rid of a label? Is the solution with the least amount of LOC always
>>>> preferable?) This area seems simple enough maybe we can get it ironed out
>>>> here with out another version.
>>>>
>>>> IMHO I think the above code sort of obfuscates that the code flow is really
>>>> just one if/else switch with one function that has the statemachine
>>>> behavior. But its not bad either if that's what people prefer. I'd like to
>>>> find something every can be sort of happy with. :-)
>>>>
>>>
>>> If you want my .02, some combination of the above is cleanest from an
>>> aesthetic pov:
>>>
>>> {
>>> ...
>>> if (RM_SHRINK || RMTVAL_REMOVE)
>>> goto node;
>>>
>>> if (!hasattr)
>>> return -ENOATTR;
>>> else if (local)
>>> return shortform_remove();
>>> else if (oneblock)
>>> return leaf_removename();
>>>
>>> node:
>>> return node_removename();
>>> }
>>>
>>> I find that easiest to read at a glance, but I don't feel terribly
>>> strongly about it I guess.
>>
>> I am entirely fine with that if everyone else is :-)
>>
>>>
>>>>>> @@ -794,11 +849,12 @@ xfs_attr_leaf_hasname(
>>>>>> */
>>>>>> STATIC int
>>>>>> xfs_attr_leaf_removename(
>>>>>> - struct xfs_da_args *args)
>>>>>> + struct xfs_delattr_context *dac)
>>>>>> {
>>>>>> - struct xfs_inode *dp;
>>>>>> - struct xfs_buf *bp;
>>>>>> - int error, forkoff;
>>>>>> + struct xfs_da_args *args = dac->da_args;
>>>>>> + struct xfs_inode *dp;
>>>>>> + struct xfs_buf *bp;
>>>>>> + int error, forkoff;
>>>>>> trace_xfs_attr_leaf_removename(args);
>>>>>> @@ -825,9 +881,8 @@ xfs_attr_leaf_removename(
>>>>>> /* bp is gone due to xfs_da_shrink_inode */
>>>>>> if (error)
>>>>>> return error;
>>>>>> - error = xfs_defer_finish(&args->trans);
>>>>>> - if (error)
>>>>>> - return error;
>>>>>> +
>>>>>> + dac->flags |= XFS_DAC_DEFER_FINISH;
>>>>>
>>>>> There's no -EAGAIN return here, is this an exit path for the remove?
>>>> I think so, maybe I can remove this and the other one you pointed out in
>>>> patch 12 along with the other unneeded transaction handling.
>>>>
>>>>>
>>>>>> }
>>>>>> return 0;
>>>>>> }
>>>>>> @@ -1128,12 +1183,13 @@ xfs_attr_node_addname(
>>>>>> */
>>>>>> STATIC int
>>>>>> xfs_attr_node_shrink(
>>>>>> - struct xfs_da_args *args,
>>>>>> - struct xfs_da_state *state)
>>>>>> + struct xfs_delattr_context *dac,
>>>>>> + struct xfs_da_state *state)
>>>>>> {
>>>>>> - struct xfs_inode *dp = args->dp;
>>>>>> - int error, forkoff;
>>>>>> - struct xfs_buf *bp;
>>>>>> + struct xfs_da_args *args = dac->da_args;
>>>>>> + 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.
>>>>>> @@ -1153,9 +1209,7 @@ xfs_attr_node_shrink(
>>>>>> if (error)
>>>>>> return error;
>>>>>> - error = xfs_defer_finish(&args->trans);
>>>>>> - if (error)
>>>>>> - return error;
>>>>>> + dac->flags |= XFS_DAC_DEFER_FINISH;
>>>>>
>>>>> Same question here.
>>>>>
>>>>>> } else
>>>>>> xfs_trans_brelse(args->trans, bp);
>>>>>> @@ -1194,13 +1248,15 @@ 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)
>>>>>> {
>>>>>> + struct xfs_da_args *args = dac->da_args;
>>>>>> int error;
>>>>>> struct xfs_da_state_blk *blk;
>>>>>> @@ -1212,10 +1268,21 @@ 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)
>>>>>> return error;
>>>>>> +
>>>>>> + error = xfs_attr_rmtval_invalidate(args);
>>>>>> + if (error)
>>>>>> + return error;
>>>>>
>>>>> Seems like this moves code, which should probably happen in a separate
>>>>> patch.
>>>> Ok, this pairs with the xfs_attr_rmtval_remove to __xfs_attr_rmtval_remove
>>>> below. Basically xfs_attr_rmtval_remove is the combination of
>>>> xfs_attr_rmtval_invalidate and __xfs_attr_rmtval_remove. So thats why we see
>>>> xfs_attr_rmtval_remove going away and xfs_attr_rmtval_invalidate +
>>>> __xfs_attr_rmtval_remove coming in.
>>>>
>>>> How about a patch that pulls xfs_attr_rmtval_invalidate out of
>>>> xfs_attr_rmtval_remove and into the calling functions? I think that might
>>>> be more clear.
>>>>
>>>
>>> Yes, separate patch please. I think that if the earlier refactoring
>>> parts of the series are split out properly (i.e., no dependencies on
>>> subsequent patches) and reviewed, perhaps we can start getting some of
>>> those patches merged while the latter bits are worked out.
>> Ok then, will do
>>
>>>
>>>>>
>>>>>> }
>>>>>> return 0;
>>>>>> @@ -1228,7 +1295,10 @@ xfs_attr_node_removename_rmt (
>>>>>> {
>>>>>> 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(args);
>>>>>> if (error)
>>>>>> return error;
>>>>>> @@ -1249,19 +1319,37 @@ 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_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;
>>>>>> +
>>>>>> + /* State machine switch */
>>>>>> + switch (dac->dela_state) {
>>>>>> + case XFS_DAS_RMTVAL_REMOVE:
>>>>>> + goto das_rmtval_remove;
>>>>>> + case XFS_DAS_RM_SHRINK:
>>>>>> + goto das_rm_shrink;
>>>>>> + default:
>>>>>> + break;
>>>>>> + }
>>>>>> - error = xfs_attr_node_removename_setup(args, &state);
>>>>>> + error = xfs_attr_node_removename_setup(dac, &state);
>>>>>> if (error)
>>>>>> goto out;
>>>>>> @@ -1270,10 +1358,16 @@ 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.
>>>>>> */
>>>>>> +
>>>>>> +das_rmtval_remove:
>>>>>> +
>>>>>
>>>>> I wonder if we need this label just to protect the setup. Perhaps if we
>>>>> had something like:
>>>>>
>>>>> /* set up the remove only once... */
>>>>> if (dela_state == 0)
>>>>> error = xfs_attr_node_removename_setup(...);
>>>>>
>>>>> ... we could reduce another state.
>>>>>
>>>>> We could also accomplish the same thing with an explicit state to
>>>>> indicate the setup already occurred or a new dac flag, though I'm not
>>>>> sure a flag is appropriate if it would only be used here.
>>>>>
>>>>> Brian
>>>>
>>>> Mmmm, dela_state == 0 will conflict a bit when we get into fully delayed
>>>> attrs. Basically when this is getting called from the delayed operations
>>>> path, it sets dela_state to a new XFS_DAS_INIT. Because we have to set up
>>>> args mid fight, we need the extra state to not do that twice.
>>>>
>>>
>>> Can we address that when the conflict is introduced?
>> Sure, i was just looking ahead, but focus should stay here
>>
>>>
>>>> But even without getting into that right away, what you're proposing only
>>>> gets rid of the label. It doesnt get rid of the state. We still have to
>>>> set the state to not be zero (or what ever the initial value is). So we
>>>> still need the unique value of XFS_DAS_RMTVAL_REMOVE
>>>>
>>>
>>> Yeah, I was partly thinking of the setup call being tied to a flag
>>> rather than a state. That way the logic is something like the typical:
>>>
>>> if (!setup)
>>> do_setup();
>>> ...
>>>
>>> ... and it's one less bit of code tied into the state machine. All in
>>> all, it's more that having a label right at the top of a function like
>>> that kind of looks like it's asking for some form of simplification.
>> Ok, this is similar to the discussion going on in the next patch. To be
>> clear, if we add a flag, we need to keep it in the delay_attr_context so
>> that it persists across re-calls. We dont want multiple functions shareing
>> the same setup flag, so really we're talking about a new flag scheme like
>> XFS_DAC_SETUP_* for any function that needs a set up flag? Is that what you
>> had in mind?
>>
>
> Yep, pretty much. It's not clear to me if we can reuse one general INIT
> flag across operations or need several such flags, but I'm not sure I
> understand why we couldn't reuse the existing dac->flags at least..
>
> Brian
Ok, I think I likely answered this in the discussion for the next patch.
I forgot I had already added a flag member to the delay attr context,
I will move forward with an init flag scheme. Thanks again for all the
reviewing!
Allison
>
>>>
>>>> Really what you would need here in order to do what you are describeing is
>>>> dela_state != XFS_DAS_RMTVAL_REMOVE. If I assume to simplify away to the
>>>> lease amount of LOC we get this:
>>>>
>>>>
>>>> STATIC int
>>>> xfs_attr_node_removename(
>>>> struct xfs_delattr_context *dac)
>>>> {
>>>> 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;
>>>>
>>>> if (dac->dela_state == XFS_DAS_RM_SHRINK) {
>>>> goto das_rm_shrink;
>>>> } else if (dac->dela_state != XFS_DAS_RMTVAL_REMOVE) {
>>>> error = xfs_attr_node_removename_setup(dac, &state);
>>>> if (error)
>>>> goto out;
>>>> }
>>>>
>>>> /*
>>>> * If there is an out-of-line value, de-allocate the blocks.
>>>> * This is done before we remove the attribute so that we don't
>>>> * overflow the maximum size of a transaction and/or hit a deadlock.
>>>> */
>>>>
>>>> if (args->rmtblkno > 0) {
>>>> error = xfs_attr_node_removename_rmt(args, state);
>>>> if (error) {
>>>> if (error == -EAGAIN)
>>>> dac->dela_state = XFS_DAS_RMTVAL_REMOVE;
>>>> return error;
>>>> }
>>>> }
>>>>
>>>> .....
>>>>
>>>>
>>>> Let me know what folks think of this. Again, I think I like the switches
>>>> and the labels just because it makes it more clear where the jump points
>>>> are, even if its more LOC. But again, this isnt bad either if this is more
>>>> preferable to folks. If there's another arrangment that is preferable, let
>>>> me know, it's not difficult to run it through the test cases to make sure
>>>> it's functional. It may be a faster way to hash out what people want to
>>>> see.
>>>>
>>>
>>> I prefer to see the state management stuff as boilerplate as possible.
>>> The above pattern of creating separate reentry calls to the same
>>> functions is not nearly as clear to me, particularly in this instance
>>> where we have multiple branches of reentry logic (as opposed to the
>>> earlier example of only one).
>>>
>>> IOW, I agree that the jumps are preferable and more intuitive. I'm just
>>> trying to be reductive by considering what could be factored out vs.
>>> trying to fundamentally rework the approach or aggressively reduce LOC
>>> or anything like that. IMO, simplicity of the code is usually top
>>> priority.
>>>
>>> Brian
>>
>> Ok, lets firm up what we want this setup flag to look like, and then we can
>> simplify the current label and goto scheme :-)
>>
>> Thank you!!
>> Allison
>>
>>
>>>
>>>> Thank you again for all the reviewing!!!
>>>>
>>>> Allison
>>>>
>>>>>
>>>>>> if (args->rmtblkno > 0) {
>>>>>> error = xfs_attr_node_removename_rmt(args, state);
>>>>>> - if (error)
>>>>>> - goto out;
>>>>>> + if (error) {
>>>>>> + if (error == -EAGAIN)
>>>>>> + dac->dela_state = XFS_DAS_RMTVAL_REMOVE;
>>>>>> + return error;
>>>>>> + }
>>>>>> }
>>>>>> /*
>>>>>> @@ -1291,22 +1385,20 @@ 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:
>>>>>> + dac->dela_state = XFS_DAS_RM_SHRINK;
>>>>>> +
>>>>>> /*
>>>>>> * If the result is small enough, push it all into the inode.
>>>>>> */
>>>>>> if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>>>>>> - error = xfs_attr_node_shrink(args, state);
>>>>>> + error = xfs_attr_node_shrink(dac, state);
>>>>>> error = 0;
>>>>>> out:
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>>>> index 66575b8..0e8ae1a 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>>>> @@ -74,6 +74,43 @@ struct xfs_attr_list_context {
>>>>>> };
>>>>>> +/*
>>>>>> + * ========================================================================
>>>>>> + * Structure used to pass context around among the delayed routines.
>>>>>> + * ========================================================================
>>>>>> + */
>>>>>> +
>>>>>> +/*
>>>>>> + * 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 */
>>>>>> + XFS_DAS_RMTVAL_REMOVE, /* We are removing remote value blocks */
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * Defines for xfs_delattr_context.flags
>>>>>> + */
>>>>>> +#define XFS_DAC_DEFER_FINISH 0x1 /* indicates to finish the transaction */
>>>>>> +
>>>>>> +/*
>>>>>> + * Context used for keeping track of delayed attribute operations
>>>>>> + */
>>>>>> +struct xfs_delattr_context {
>>>>>> + struct xfs_da_args *da_args;
>>>>>> + struct xfs_da_state *da_state;
>>>>>> + struct xfs_da_state_blk *blk;
>>>>>> + unsigned int flags;
>>>>>> + enum xfs_delattr_state dela_state;
>>>>>> +};
>>>>>> +
>>>>>> /*========================================================================
>>>>>> * Function prototypes for the kernel.
>>>>>> *========================================================================*/
>>>>>> @@ -91,6 +128,7 @@ 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);
>>>>>> bool xfs_attr_namecheck(const void *name, size_t length);
>>>>>> #endif /* __XFS_ATTR_H__ */
>>>>>> --
>>>>>> 2.7.4
>>>>>>
>>>>>
>>>>
>>>
>>
>
next prev parent reply other threads:[~2020-04-16 22:43 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-03 22:12 [PATCH v8 00/20] xfs: Delay Ready Attributes Allison Collins
2020-04-03 22:12 ` [PATCH v8 01/20] xfs: Add xfs_has_attr and subroutines Allison Collins
2020-04-06 14:31 ` Brian Foster
2020-04-06 22:09 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 02/20] xfs: Check for -ENOATTR or -EEXIST Allison Collins
2020-04-06 14:31 ` Brian Foster
2020-04-06 23:14 ` Allison Collins
2020-04-15 6:43 ` Chandan Rajendra
2020-04-03 22:12 ` [PATCH v8 03/20] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2020-04-03 22:12 ` [PATCH v8 04/20] xfs: Pull up trans handling in xfs_attr3_leaf_flipflags Allison Collins
2020-04-03 22:12 ` [PATCH v8 05/20] xfs: Split apart xfs_attr_leaf_addname Allison Collins
2020-04-03 22:12 ` [PATCH v8 06/20] xfs: Refactor xfs_attr_try_sf_addname Allison Collins
2020-04-03 22:12 ` [PATCH v8 07/20] xfs: Pull up trans roll from xfs_attr3_leaf_setflag Allison Collins
2020-04-03 22:12 ` [PATCH v8 08/20] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
2020-04-03 22:12 ` [PATCH v8 09/20] xfs: Pull up trans roll in xfs_attr3_leaf_clearflag Allison Collins
2020-04-03 22:12 ` [PATCH v8 10/20] xfs: Add helper function __xfs_attr_rmtval_remove Allison Collins
2020-04-07 14:16 ` Brian Foster
2020-04-07 22:19 ` Allison Collins
2020-04-29 23:05 ` Darrick J. Wong
2020-04-29 23:09 ` Darrick J. Wong
2020-04-03 22:12 ` [PATCH v8 11/20] xfs: Add helper function xfs_attr_node_shrink Allison Collins
2020-04-07 14:17 ` Brian Foster
2020-04-07 21:52 ` Allison Collins
2020-04-15 10:16 ` Chandan Rajendra
2020-04-15 22:13 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 12/20] xfs: Removed unneeded xfs_trans_roll_inode calls Allison Collins
2020-04-07 14:17 ` Brian Foster
2020-04-07 21:53 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 13/20] xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform Allison Collins
2020-04-07 15:23 ` Brian Foster
2020-04-07 21:53 ` Allison Collins
2020-04-10 16:55 ` Allison Collins
2020-04-11 12:57 ` Brian Foster
2020-04-20 5:30 ` Chandan Rajendra
2020-04-20 22:45 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 14/20] xfs: Add helper function xfs_attr_leaf_mark_incomplete Allison Collins
2020-04-07 15:23 ` Brian Foster
2020-04-07 21:53 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 15/20] xfs: Add remote block helper functions Allison Collins
2020-04-08 12:09 ` Brian Foster
2020-04-08 16:32 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 16/20] xfs: Add helper function xfs_attr_node_removename_setup Allison Collins
2020-04-08 12:09 ` Brian Foster
2020-04-08 16:32 ` Allison Collins
2020-04-20 6:25 ` Chandan Rajendra
2020-04-20 22:46 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 17/20] xfs: Add helper function xfs_attr_node_removename_rmt Allison Collins
2020-04-08 12:10 ` Brian Foster
2020-04-08 16:32 ` Allison Collins
2020-04-20 6:38 ` Chandan Rajendra
2020-04-20 22:46 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 18/20] xfs: Add delay ready attr remove routines Allison Collins
2020-04-13 12:30 ` Brian Foster
2020-04-14 21:35 ` Allison Collins
2020-04-15 11:46 ` Brian Foster
2020-04-16 3:17 ` Allison Collins
2020-04-16 10:58 ` Brian Foster
2020-04-16 22:41 ` Allison Collins [this message]
2020-04-20 9:06 ` Chandan Rajendra
2020-04-20 23:26 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 19/20] xfs: Add delay ready attr set routines Allison Collins
2020-04-13 13:40 ` Brian Foster
2020-04-15 22:08 ` Allison Collins
2020-04-16 11:01 ` Brian Foster
2020-04-16 22:54 ` Allison Collins
2020-04-17 10:36 ` Brian Foster
2020-04-20 11:45 ` Chandan Rajendra
2020-04-20 16:20 ` Brian Foster
2020-04-20 23:26 ` Allison Collins
2020-04-03 22:12 ` [PATCH v8 20/20] xfs: Rename __xfs_attr_rmtval_remove 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=3fe45a6c-877a-c8b0-a17e-d6e1187f8d50@oracle.com \
--to=allison.henderson@oracle.com \
--cc=bfoster@redhat.com \
--cc=dchinner@redhat.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;
as well as URLs for NNTP newsgroup(s).