All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brian Foster <bfoster@redhat.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH v2 2/6] xfs: defer agfl block frees when dfops is available
Date: Wed, 9 May 2018 11:41:32 -0400	[thread overview]
Message-ID: <20180509154132.GA66101@bfoster.bfoster> (raw)
In-Reply-To: <20180509143453.GG11261@magnolia>

On Wed, May 09, 2018 at 07:34:53AM -0700, Darrick J. Wong wrote:
> On Wed, May 09, 2018 at 07:18:59AM -0400, Brian Foster wrote:
> > On Tue, May 08, 2018 at 11:04:02AM -0700, Darrick J. Wong wrote:
> > > On Tue, May 08, 2018 at 08:31:40AM -0400, Brian Foster wrote:
> > > > On Mon, May 07, 2018 at 06:10:32PM -0700, Darrick J. Wong wrote:
> > > > > On Wed, Apr 18, 2018 at 09:31:15AM -0400, Brian Foster wrote:
> > > > ...
> > > > > > 
> > > > > > Signed-off-by: Brian Foster <bfoster@redhat.com>
> > > > > > ---
> > > > > >  fs/xfs/libxfs/xfs_alloc.c  | 51 ++++++++++++++++++++++++++++++---
> > > > > >  fs/xfs/libxfs/xfs_defer.h  |  1 +
> > > > > >  fs/xfs/xfs_trace.h         |  2 ++
> > > > > >  fs/xfs/xfs_trans.c         | 11 ++++++--
> > > > > >  fs/xfs/xfs_trans.h         |  1 +
> > > > > >  fs/xfs/xfs_trans_extfree.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++
> > > > > >  6 files changed, 129 insertions(+), 7 deletions(-)
> > > > > > 
> > > > ...
> > > > > > diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> > > > > > index 9d542dfe0052..834388c2c9de 100644
> > > > > > --- a/fs/xfs/xfs_trans.h
> > > > > > +++ b/fs/xfs/xfs_trans.h
> > > > > > @@ -111,6 +111,7 @@ typedef struct xfs_trans {
> > > > > >  	struct xlog_ticket	*t_ticket;	/* log mgr ticket */
> > > > > >  	struct xfs_mount	*t_mountp;	/* ptr to fs mount struct */
> > > > > >  	struct xfs_dquot_acct   *t_dqinfo;	/* acctg info for dquots */
> > > > > > +	struct xfs_defer_ops	*t_agfl_dfops;	/* optional agfl fixup dfops */
> > > > > 
> > > > > This more or less looks fine to me, with ^^^^ this one (incoherent) quibble:
> > > > > 
> > > > 
> > > > I wouldn't call it incoherent...
> > > > 
> > > > > A thread can only have one transaction and one dfops in play at a time,
> > > > > so could we just call this t_dfops and allow anyone to access it who
> > > > > wants to add their own deferred operations?  Then we can stop passing
> > > > > both tp and dfops all over the stack.  Can you think of a situation
> > > > > where we would want access to t_dfops for deferred agfl frees but not
> > > > > for any other deferred ops?
> > > > > 
> > > > 
> > > > ... because that is precisely the secondary goal of this approach. :)
> > > > Dave suggested this approach in a previous version and the last post
> > > > actually used ->t_dfops rather than ->t_agfl_dfops and included some
> > > > associated dfops parameter elimination cleanup I did along the way.
> > > > 
> > > > Christoph objected to the partial refactoring, however, so I'm trying to
> > > > do this in two parts where the first is primarily focused on fixing the
> > > > problems resolved by deferred agfl frees. The challenge is that I don't
> > > > want to manually plumb dfops through new codepaths to control deferred
> > > > agfl frees only to immediately turn around and clean that code out, and
> > > > I certainly don't want to refactor all of our dfops code just to enable
> > > > deferred agfl frees because it creates an unnecessary dependency for
> > > > backports. As a result, I've stripped out as much refactoring as
> > > > possible to try and make it clear that this is a bug fix series that
> > > > happens to create a new xfs_trans field that will open wider cleanups in
> > > > a follow on series.
> > > > 
> > > > IOW, I have a series in progress where patch 1 renames ->t_agfl_dfops
> > > > back to ->t_dfops to essentially open it for general use and then starts
> > > > to incorporate the broader cleanups like removing dfops from callstacks,
> > > > alloc/bmap data structures, etc.
> > > 
> > > Seems reasonable.  I've occasionally thought that passing around (tp,
> > > dfops, firstblock) is kinda bulky and silly.
> > > 
> > > > BTW, something I'm curious of your (and Dave, Christoph?) opinion on...
> > > > another thing that was dropped (permanently) from the previous series
> > > > was an update to xfs_defer_init() to do the ->t_dfops = &dfops
> > > > assignment that is otherwise open-coded throughout here. While I don't
> > > > have a strong preference on that for this series, the more broader
> > > > cleanup I do the less I like the open-coded approach because it creates
> > > > a tx setup requirement that's easy to miss (case in point: a function
> > > > signature change is an easy way to verify all dfops have been associated
> > > > with transactions). Instead, I'd prefer code that looks something like
> > > > the following as the end result of the follow-on cleanup series:
> > > > 
> > > > 	struct xfs_trans	*tp;
> > > > 	struct xfs_defer_ops	dfops;
> > > > 
> > > > 	xfs_trans_alloc(... &tp);
> > > > 	xfs_defer_init(&dfops, &first_block, tp);
> > > > 
> > > > 	...
> > > > 
> > > > 	xfs_defer_finish(&tp);
> > > > 	xfs_trans_commit(tp);
> > > > 	...
> > > > 
> > > > Note that once we require association of dfops with tp, we don't have to
> > > > pass dfops around to anywhere the tp isn't already needed, including
> > > > xfs_defer_finish(). This also opens the possibility of doing things like
> > > > replacing on-stack dfops with something that's just embedded in
> > > > xfs_trans itself (optionally pushing down the init/finish calls into the
> > > > trans infrastructure), but that would require changing how dfops are
> > > > transferred to rolled transactions and whatnot. I haven't really got far
> > > > enough to give that proper consideration, but that may be a possible 3rd
> > > > step cleanup if there's value.
> > > 
> > > Not sure.  There are places where it seems to make sense to be able to
> > > _defer_finish but still have a transaction around to continue making
> > > changes afterwards.  Or at least, the attr and quota code seems to do
> > > that. :P
> > > 
> > 
> > Right.. I do think xfs_defer_finish() should continue to exist even if
> > we were to eventually do something like embed a dfops in the tp and
> > allow a transaction commit to do the dfops completion. Something like
> > that would just essentially clean out some of the simple trans_alloc()
> > -> do_stuff() -> xfs_defer_finish() -> xfs_trans_commit() boilerplate
> > code. Code that does looping xfs_defer_finish() calls and whatnot should
> > continue to look the same.
> > 
> > But I don't think that has much of a bearing on tweaking
> > xfs_defer_init() vs. tp->t_dfops = &dfops..?
> 
> It doesn't; I had gone off into the weeds thinking about the _finish
> cases.  I guess we're talking about splitting the dfops usages into
> scenario (a) where the transaction owns the dfops and _finishes it as
> part of _trans_commit; and (b) the existing situation where the calling
> function owns the dfops and has to take care of _init and _finish
> explicitly.  I think that would work and it seems like a reasonable
> cleanup since there are a lot of places where the code does _finish and
> _commit and that's it.
> 

Ok.

> > > Also, there's one funny case where we can have a dfops but no
> > > transaction, which is xlog_recover_process_intents ->
> > > xlog_finish_defer_ops.  We create a dfops to collect new intents created
> > > as part of replaying unfinished intents that were in the dirty log, but
> > > since the intent recovery functions create and commit their own
> > > transactions, we don't create the transaction that goes with the dfops
> > > until we're done replaying old intents and ready to finish the new
> > > intents.
> > 
> > I should have pointed out that the tp parameter is intended to be
> > optional. So xfs_defer_init() simply does the tp->t_dfops = &dfops
> > assignment if tp != NULL. If tp == NULL, the associated dfops could
> > certainly already be associated with some transaction and be reused
> > (which appears to be the use case down in some of the xfs_da_args code
> > IIRC), or not at all. So the recovery code you refer to could simply go
> > unchanged or be an exception where we do open-code the ->t_dfops
> > assignment.
> > 
> > The part I'm curious about here is really just whether it's worth
> > tweaking xfs_defer_init() so we don't have to add an additional
> > tp->t_dfops = &dfops assignment (almost) everywhere we already call
> > xfs_defer_init(). I suppose I could try that change after the fact so
> > it's easier to factor in or out...
> 
> Hm, I think I like this idea where the transaction can set up an
> internal dfops and manage it for you unless you call _defer_init to
> signal that you're going to manage the dfops yourself and want to
> override the internal dfops.  Would that fit well with all this?  I
> think it would...
> 

I think it could..

> (And now that I think about it, no, you can't really have nested dfops
> because _defer_[bi]join means that you want the specified buffer/inode
> relogged and held across transaction rolls, which doesn't happen if a
> nested dfops rolls the transaction.)
> 

... but in the simplest form it may just depend on the context. Some
transactions may be able to use the in-tx model, others may have to
exclusively use something local or otherwise reference the embedded
dfops directly.

Anyways, I haven't really thought far enough ahead to consider changing
how dfops might be allocated/used directly in a transaction. I wanted to
leave that as a last step once the low hanging fruit is cleaned up and
the transaction reference is used consistently.

Brian

> --D
> 
> > 
> > Brian
> > 
> > > 
> > > --D
> > > 
> > > 
> > > > Anyways, I'd really like to avoid having to switch back and forth
> > > > between the xfs_defer_init() tweak and open-coded assignment if
> > > > possible. Any thoughts/preferences on either approach?
> > > > Brian
> > > > 
> > > > > Separate cleanup, of course, and sorry if this has already been asked.
> > > > > 
> > > > > Other than that this looks ok enough to test,
> > > > > Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> > > > > 
> > > > > --D
> > > > > 
> > > > > 
> > > > > >  	unsigned int		t_flags;	/* misc flags */
> > > > > >  	int64_t			t_icount_delta;	/* superblock icount change */
> > > > > >  	int64_t			t_ifree_delta;	/* superblock ifree change */
> > > > > > diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c
> > > > > > index ab438647592a..f5620796ae25 100644
> > > > > > --- a/fs/xfs/xfs_trans_extfree.c
> > > > > > +++ b/fs/xfs/xfs_trans_extfree.c
> > > > > > @@ -231,9 +231,79 @@ static const struct xfs_defer_op_type xfs_extent_free_defer_type = {
> > > > > >  	.cancel_item	= xfs_extent_free_cancel_item,
> > > > > >  };
> > > > > >  
> > > > > > +/*
> > > > > > + * AGFL blocks are accounted differently in the reserve pools and are not
> > > > > > + * inserted into the busy extent list.
> > > > > > + */
> > > > > > +STATIC int
> > > > > > +xfs_agfl_free_finish_item(
> > > > > > +	struct xfs_trans		*tp,
> > > > > > +	struct xfs_defer_ops		*dop,
> > > > > > +	struct list_head		*item,
> > > > > > +	void				*done_item,
> > > > > > +	void				**state)
> > > > > > +{
> > > > > > +	struct xfs_mount		*mp = tp->t_mountp;
> > > > > > +	struct xfs_efd_log_item		*efdp = done_item;
> > > > > > +	struct xfs_extent_free_item	*free;
> > > > > > +	struct xfs_extent		*extp;
> > > > > > +	struct xfs_buf			*agbp;
> > > > > > +	int				error;
> > > > > > +	xfs_agnumber_t			agno;
> > > > > > +	xfs_agblock_t			agbno;
> > > > > > +	uint				next_extent;
> > > > > > +
> > > > > > +	free = container_of(item, struct xfs_extent_free_item, xefi_list);
> > > > > > +	ASSERT(free->xefi_blockcount == 1);
> > > > > > +	agno = XFS_FSB_TO_AGNO(mp, free->xefi_startblock);
> > > > > > +	agbno = XFS_FSB_TO_AGBNO(mp, free->xefi_startblock);
> > > > > > +
> > > > > > +	trace_xfs_agfl_free_deferred(mp, agno, 0, agbno, free->xefi_blockcount);
> > > > > > +
> > > > > > +	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> > > > > > +	if (!error)
> > > > > > +		error = xfs_free_agfl_block(tp, agno, agbno, agbp,
> > > > > > +					    &free->xefi_oinfo);
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Mark the transaction dirty, even on error. This ensures the
> > > > > > +	 * transaction is aborted, which:
> > > > > > +	 *
> > > > > > +	 * 1.) releases the EFI and frees the EFD
> > > > > > +	 * 2.) shuts down the filesystem
> > > > > > +	 */
> > > > > > +	tp->t_flags |= XFS_TRANS_DIRTY;
> > > > > > +	efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY;
> > > > > > +
> > > > > > +	next_extent = efdp->efd_next_extent;
> > > > > > +	ASSERT(next_extent < efdp->efd_format.efd_nextents);
> > > > > > +	extp = &(efdp->efd_format.efd_extents[next_extent]);
> > > > > > +	extp->ext_start = free->xefi_startblock;
> > > > > > +	extp->ext_len = free->xefi_blockcount;
> > > > > > +	efdp->efd_next_extent++;
> > > > > > +
> > > > > > +	kmem_free(free);
> > > > > > +	return error;
> > > > > > +}
> > > > > > +
> > > > > > +
> > > > > > +/* sub-type with special handling for AGFL deferred frees */
> > > > > > +static const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
> > > > > > +	.type		= XFS_DEFER_OPS_TYPE_AGFL_FREE,
> > > > > > +	.max_items	= XFS_EFI_MAX_FAST_EXTENTS,
> > > > > > +	.diff_items	= xfs_extent_free_diff_items,
> > > > > > +	.create_intent	= xfs_extent_free_create_intent,
> > > > > > +	.abort_intent	= xfs_extent_free_abort_intent,
> > > > > > +	.log_item	= xfs_extent_free_log_item,
> > > > > > +	.create_done	= xfs_extent_free_create_done,
> > > > > > +	.finish_item	= xfs_agfl_free_finish_item,
> > > > > > +	.cancel_item	= xfs_extent_free_cancel_item,
> > > > > > +};
> > > > > > +
> > > > > >  /* Register the deferred op type. */
> > > > > >  void
> > > > > >  xfs_extent_free_init_defer_op(void)
> > > > > >  {
> > > > > >  	xfs_defer_init_op_type(&xfs_extent_free_defer_type);
> > > > > > +	xfs_defer_init_op_type(&xfs_agfl_free_defer_type);
> > > > > >  }
> > > > > > -- 
> > > > > > 2.13.6
> > > > > > 
> > > > > > --
> > > > > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > > > > > the body of a message to majordomo@vger.kernel.org
> > > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > > --
> > > > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > > > > the body of a message to majordomo@vger.kernel.org
> > > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > > --
> > > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > > > the body of a message to majordomo@vger.kernel.org
> > > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > > the body of a message to majordomo@vger.kernel.org
> > > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2018-05-09 15:41 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-18 13:31 [PATCH v2 0/6] xfs: defer agfl block frees Brian Foster
2018-04-18 13:31 ` [PATCH v2 1/6] xfs: create agfl block free helper function Brian Foster
2018-05-08  0:35   ` Darrick J. Wong
2018-04-18 13:31 ` [PATCH v2 2/6] xfs: defer agfl block frees when dfops is available Brian Foster
2018-05-08  1:10   ` Darrick J. Wong
2018-05-08 12:31     ` Brian Foster
2018-05-08 18:04       ` Darrick J. Wong
2018-05-09 11:18         ` Brian Foster
2018-05-09 14:34           ` Darrick J. Wong
2018-05-09 15:41             ` Brian Foster [this message]
2018-05-09 15:56               ` Darrick J. Wong
2018-05-09 16:04   ` Darrick J. Wong
2018-05-09 16:31     ` Brian Foster
2018-04-18 13:31 ` [PATCH v2 3/6] xfs: defer agfl block frees from deferred ops processing context Brian Foster
2018-05-08  1:11   ` Darrick J. Wong
2018-04-18 13:31 ` [PATCH v2 4/6] xfs: defer agfl frees from inode inactivation Brian Foster
2018-04-18 13:31 ` [PATCH v2 5/6] xfs: defer frees from common inode allocation paths Brian Foster
2018-04-18 13:31 ` [PATCH v2 6/6] xfs: defer agfl frees from directory op transactions Brian Foster
2018-05-08  1:12   ` Darrick J. Wong
2018-05-08 12:33     ` Brian Foster
2018-05-08 14:53       ` Darrick J. Wong

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=20180509154132.GA66101@bfoster.bfoster \
    --to=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 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.