diff mbox series

[RFC,v5,7/9] xfs: buffer relogging support prototype

Message ID 20200227134321.7238-8-bfoster@redhat.com (mailing list archive)
State Superseded, archived
Headers show
Series xfs: automatic relogging experiment | expand

Commit Message

Brian Foster Feb. 27, 2020, 1:43 p.m. UTC
Add a quick and dirty implementation of buffer relogging support.
There is currently no use case for buffer relogging. This is for
experimental use only and serves as an example to demonstrate the
ability to relog arbitrary items in the future, if necessary.

Add a hook to enable relogging a buffer in a transaction, update the
buffer log item handlers to support relogged BLIs and update the
relog handler to join the relogged buffer to the relog transaction.

Signed-off-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/xfs_buf_item.c  |  5 +++++
 fs/xfs/xfs_trans.h     |  1 +
 fs/xfs/xfs_trans_ail.c | 19 ++++++++++++++++---
 fs/xfs/xfs_trans_buf.c | 22 ++++++++++++++++++++++
 4 files changed, 44 insertions(+), 3 deletions(-)

Comments

Allison Henderson Feb. 27, 2020, 11:33 p.m. UTC | #1
On 2/27/20 6:43 AM, Brian Foster wrote:
> Add a quick and dirty implementation of buffer relogging support.
> There is currently no use case for buffer relogging. This is for
> experimental use only and serves as an example to demonstrate the
> ability to relog arbitrary items in the future, if necessary.
> 
> Add a hook to enable relogging a buffer in a transaction, update the
> buffer log item handlers to support relogged BLIs and update the
> relog handler to join the relogged buffer to the relog transaction.
> 
Alrighty, thanks for the example!  It sounds like it's meant more to be 
a demo than to really be applied though?

Allison

> Signed-off-by: Brian Foster <bfoster@redhat.com>
> ---
>   fs/xfs/xfs_buf_item.c  |  5 +++++
>   fs/xfs/xfs_trans.h     |  1 +
>   fs/xfs/xfs_trans_ail.c | 19 ++++++++++++++++---
>   fs/xfs/xfs_trans_buf.c | 22 ++++++++++++++++++++++
>   4 files changed, 44 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
> index 663810e6cd59..4ef2725fa8ce 100644
> --- a/fs/xfs/xfs_buf_item.c
> +++ b/fs/xfs/xfs_buf_item.c
> @@ -463,6 +463,7 @@ xfs_buf_item_unpin(
>   			list_del_init(&bp->b_li_list);
>   			bp->b_iodone = NULL;
>   		} else {
> +			xfs_trans_relog_item_cancel(lip, false);
>   			spin_lock(&ailp->ail_lock);
>   			xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR);
>   			xfs_buf_item_relse(bp);
> @@ -528,6 +529,9 @@ xfs_buf_item_push(
>   		return XFS_ITEM_LOCKED;
>   	}
>   
> +	if (test_bit(XFS_LI_RELOG, &lip->li_flags))
> +		return XFS_ITEM_RELOG;
> +
>   	ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
>   
>   	trace_xfs_buf_item_push(bip);
> @@ -956,6 +960,7 @@ STATIC void
>   xfs_buf_item_free(
>   	struct xfs_buf_log_item	*bip)
>   {
> +	ASSERT(!test_bit(XFS_LI_RELOG, &bip->bli_item.li_flags));
>   	xfs_buf_item_free_format(bip);
>   	kmem_free(bip->bli_item.li_lv_shadow);
>   	kmem_cache_free(xfs_buf_item_zone, bip);
> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> index 1637df32c64c..81cb42f552d9 100644
> --- a/fs/xfs/xfs_trans.h
> +++ b/fs/xfs/xfs_trans.h
> @@ -226,6 +226,7 @@ void		xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
>   void		xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
>   bool		xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
>   void		xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
> +bool		xfs_trans_relog_buf(struct xfs_trans *, struct xfs_buf *);
>   void		xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
>   void		xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
>   void		xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
> diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
> index 71a47faeaae8..103ab62e61be 100644
> --- a/fs/xfs/xfs_trans_ail.c
> +++ b/fs/xfs/xfs_trans_ail.c
> @@ -18,6 +18,7 @@
>   #include "xfs_error.h"
>   #include "xfs_log.h"
>   #include "xfs_log_priv.h"
> +#include "xfs_buf_item.h"
>   
>   #ifdef DEBUG
>   /*
> @@ -187,9 +188,21 @@ xfs_ail_relog(
>   			xfs_log_ticket_put(ailp->ail_relog_tic);
>   		spin_unlock(&ailp->ail_lock);
>   
> -		xfs_trans_add_item(tp, lip);
> -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> -		tp->t_flags |= XFS_TRANS_DIRTY;
> +		/*
> +		 * TODO: Ideally, relog transaction management would be pushed
> +		 * down into the ->iop_push() callbacks rather than playing
> +		 * games with ->li_trans and looking at log item types here.
> +		 */
> +		if (lip->li_type == XFS_LI_BUF) {
> +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> +			xfs_buf_hold(bli->bli_buf);
> +			xfs_trans_bjoin(tp, bli->bli_buf);
> +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> +		} else {
> +			xfs_trans_add_item(tp, lip);
> +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> +			tp->t_flags |= XFS_TRANS_DIRTY;
> +		}
>   		/* XXX: include ticket owner task fix */
>   		error = xfs_trans_roll(&tp);
>   		ASSERT(!error);
> diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
> index 08174ffa2118..e17715ac23fc 100644
> --- a/fs/xfs/xfs_trans_buf.c
> +++ b/fs/xfs/xfs_trans_buf.c
> @@ -787,3 +787,25 @@ xfs_trans_dquot_buf(
>   
>   	xfs_trans_buf_set_type(tp, bp, type);
>   }
> +
> +/*
> + * Enable automatic relogging on a buffer. This essentially pins a dirty buffer
> + * in-core until relogging is disabled. Note that the buffer must not already be
> + * queued for writeback.
> + */
> +bool
> +xfs_trans_relog_buf(
> +	struct xfs_trans	*tp,
> +	struct xfs_buf		*bp)
> +{
> +	struct xfs_buf_log_item	*bip = bp->b_log_item;
> +
> +	ASSERT(tp->t_flags & XFS_TRANS_RELOG);
> +	ASSERT(xfs_buf_islocked(bp));
> +
> +	if (bp->b_flags & _XBF_DELWRI_Q)
> +		return false;
> +
> +	xfs_trans_relog_item(&bip->bli_item);
> +	return true;
> +}
>
Brian Foster Feb. 28, 2020, 2:04 p.m. UTC | #2
On Thu, Feb 27, 2020 at 04:33:26PM -0700, Allison Collins wrote:
> On 2/27/20 6:43 AM, Brian Foster wrote:
> > Add a quick and dirty implementation of buffer relogging support.
> > There is currently no use case for buffer relogging. This is for
> > experimental use only and serves as an example to demonstrate the
> > ability to relog arbitrary items in the future, if necessary.
> > 
> > Add a hook to enable relogging a buffer in a transaction, update the
> > buffer log item handlers to support relogged BLIs and update the
> > relog handler to join the relogged buffer to the relog transaction.
> > 
> Alrighty, thanks for the example!  It sounds like it's meant more to be a
> demo than to really be applied though?
> 

Yeah, I just wanted to include something that demonstrates how this can
be used for something other than intents, because that concern was
raised on previous versions...

Brian

> Allison
> 
> > Signed-off-by: Brian Foster <bfoster@redhat.com>
> > ---
> >   fs/xfs/xfs_buf_item.c  |  5 +++++
> >   fs/xfs/xfs_trans.h     |  1 +
> >   fs/xfs/xfs_trans_ail.c | 19 ++++++++++++++++---
> >   fs/xfs/xfs_trans_buf.c | 22 ++++++++++++++++++++++
> >   4 files changed, 44 insertions(+), 3 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
> > index 663810e6cd59..4ef2725fa8ce 100644
> > --- a/fs/xfs/xfs_buf_item.c
> > +++ b/fs/xfs/xfs_buf_item.c
> > @@ -463,6 +463,7 @@ xfs_buf_item_unpin(
> >   			list_del_init(&bp->b_li_list);
> >   			bp->b_iodone = NULL;
> >   		} else {
> > +			xfs_trans_relog_item_cancel(lip, false);
> >   			spin_lock(&ailp->ail_lock);
> >   			xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR);
> >   			xfs_buf_item_relse(bp);
> > @@ -528,6 +529,9 @@ xfs_buf_item_push(
> >   		return XFS_ITEM_LOCKED;
> >   	}
> > +	if (test_bit(XFS_LI_RELOG, &lip->li_flags))
> > +		return XFS_ITEM_RELOG;
> > +
> >   	ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
> >   	trace_xfs_buf_item_push(bip);
> > @@ -956,6 +960,7 @@ STATIC void
> >   xfs_buf_item_free(
> >   	struct xfs_buf_log_item	*bip)
> >   {
> > +	ASSERT(!test_bit(XFS_LI_RELOG, &bip->bli_item.li_flags));
> >   	xfs_buf_item_free_format(bip);
> >   	kmem_free(bip->bli_item.li_lv_shadow);
> >   	kmem_cache_free(xfs_buf_item_zone, bip);
> > diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> > index 1637df32c64c..81cb42f552d9 100644
> > --- a/fs/xfs/xfs_trans.h
> > +++ b/fs/xfs/xfs_trans.h
> > @@ -226,6 +226,7 @@ void		xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
> >   void		xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
> >   bool		xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
> >   void		xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
> > +bool		xfs_trans_relog_buf(struct xfs_trans *, struct xfs_buf *);
> >   void		xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
> >   void		xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
> >   void		xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
> > diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
> > index 71a47faeaae8..103ab62e61be 100644
> > --- a/fs/xfs/xfs_trans_ail.c
> > +++ b/fs/xfs/xfs_trans_ail.c
> > @@ -18,6 +18,7 @@
> >   #include "xfs_error.h"
> >   #include "xfs_log.h"
> >   #include "xfs_log_priv.h"
> > +#include "xfs_buf_item.h"
> >   #ifdef DEBUG
> >   /*
> > @@ -187,9 +188,21 @@ xfs_ail_relog(
> >   			xfs_log_ticket_put(ailp->ail_relog_tic);
> >   		spin_unlock(&ailp->ail_lock);
> > -		xfs_trans_add_item(tp, lip);
> > -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > -		tp->t_flags |= XFS_TRANS_DIRTY;
> > +		/*
> > +		 * TODO: Ideally, relog transaction management would be pushed
> > +		 * down into the ->iop_push() callbacks rather than playing
> > +		 * games with ->li_trans and looking at log item types here.
> > +		 */
> > +		if (lip->li_type == XFS_LI_BUF) {
> > +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> > +			xfs_buf_hold(bli->bli_buf);
> > +			xfs_trans_bjoin(tp, bli->bli_buf);
> > +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> > +		} else {
> > +			xfs_trans_add_item(tp, lip);
> > +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > +			tp->t_flags |= XFS_TRANS_DIRTY;
> > +		}
> >   		/* XXX: include ticket owner task fix */
> >   		error = xfs_trans_roll(&tp);
> >   		ASSERT(!error);
> > diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
> > index 08174ffa2118..e17715ac23fc 100644
> > --- a/fs/xfs/xfs_trans_buf.c
> > +++ b/fs/xfs/xfs_trans_buf.c
> > @@ -787,3 +787,25 @@ xfs_trans_dquot_buf(
> >   	xfs_trans_buf_set_type(tp, bp, type);
> >   }
> > +
> > +/*
> > + * Enable automatic relogging on a buffer. This essentially pins a dirty buffer
> > + * in-core until relogging is disabled. Note that the buffer must not already be
> > + * queued for writeback.
> > + */
> > +bool
> > +xfs_trans_relog_buf(
> > +	struct xfs_trans	*tp,
> > +	struct xfs_buf		*bp)
> > +{
> > +	struct xfs_buf_log_item	*bip = bp->b_log_item;
> > +
> > +	ASSERT(tp->t_flags & XFS_TRANS_RELOG);
> > +	ASSERT(xfs_buf_islocked(bp));
> > +
> > +	if (bp->b_flags & _XBF_DELWRI_Q)
> > +		return false;
> > +
> > +	xfs_trans_relog_item(&bip->bli_item);
> > +	return true;
> > +}
> > 
>
Dave Chinner March 2, 2020, 7:47 a.m. UTC | #3
On Thu, Feb 27, 2020 at 08:43:19AM -0500, Brian Foster wrote:
> Add a quick and dirty implementation of buffer relogging support.
> There is currently no use case for buffer relogging. This is for
> experimental use only and serves as an example to demonstrate the
> ability to relog arbitrary items in the future, if necessary.
> 
> Add a hook to enable relogging a buffer in a transaction, update the
> buffer log item handlers to support relogged BLIs and update the
> relog handler to join the relogged buffer to the relog transaction.
> 
> Signed-off-by: Brian Foster <bfoster@redhat.com>
.....
>  /*
> @@ -187,9 +188,21 @@ xfs_ail_relog(
>  			xfs_log_ticket_put(ailp->ail_relog_tic);
>  		spin_unlock(&ailp->ail_lock);
>  
> -		xfs_trans_add_item(tp, lip);
> -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> -		tp->t_flags |= XFS_TRANS_DIRTY;
> +		/*
> +		 * TODO: Ideally, relog transaction management would be pushed
> +		 * down into the ->iop_push() callbacks rather than playing
> +		 * games with ->li_trans and looking at log item types here.
> +		 */
> +		if (lip->li_type == XFS_LI_BUF) {
> +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> +			xfs_buf_hold(bli->bli_buf);

What is this for? The bli already has a reference to the buffer.

> +			xfs_trans_bjoin(tp, bli->bli_buf);
> +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> +		} else {
> +			xfs_trans_add_item(tp, lip);
> +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> +			tp->t_flags |= XFS_TRANS_DIRTY;
> +		}

Really, this should be a xfs_item_ops callout. i.e.

		lip->li_ops->iop_relog(lip);

And then a) it doesn't matter really where we call it from, and b)
it becomes fully generic and we can implement the callout
as future functionality requires.

However, we have to make sure that the current transaction we are
running has the correct space usage accounted to it, so I think this
callout really does need to be done in a tight loop iterating and
accounting all the relog items into the transaction without outside
interference.

Cheers,

Dave.
Brian Foster March 2, 2020, 7 p.m. UTC | #4
On Mon, Mar 02, 2020 at 06:47:28PM +1100, Dave Chinner wrote:
> On Thu, Feb 27, 2020 at 08:43:19AM -0500, Brian Foster wrote:
> > Add a quick and dirty implementation of buffer relogging support.
> > There is currently no use case for buffer relogging. This is for
> > experimental use only and serves as an example to demonstrate the
> > ability to relog arbitrary items in the future, if necessary.
> > 
> > Add a hook to enable relogging a buffer in a transaction, update the
> > buffer log item handlers to support relogged BLIs and update the
> > relog handler to join the relogged buffer to the relog transaction.
> > 
> > Signed-off-by: Brian Foster <bfoster@redhat.com>
> .....
> >  /*
> > @@ -187,9 +188,21 @@ xfs_ail_relog(
> >  			xfs_log_ticket_put(ailp->ail_relog_tic);
> >  		spin_unlock(&ailp->ail_lock);
> >  
> > -		xfs_trans_add_item(tp, lip);
> > -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > -		tp->t_flags |= XFS_TRANS_DIRTY;
> > +		/*
> > +		 * TODO: Ideally, relog transaction management would be pushed
> > +		 * down into the ->iop_push() callbacks rather than playing
> > +		 * games with ->li_trans and looking at log item types here.
> > +		 */
> > +		if (lip->li_type == XFS_LI_BUF) {
> > +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> > +			xfs_buf_hold(bli->bli_buf);
> 
> What is this for? The bli already has a reference to the buffer.
> 

The buffer reference is for the transaction. It is analogous to the
reference acquired in xfs_buf_find() via xfs_trans_[get|read]_buf(), for
example.

> > +			xfs_trans_bjoin(tp, bli->bli_buf);
> > +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> > +		} else {
> > +			xfs_trans_add_item(tp, lip);
> > +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > +			tp->t_flags |= XFS_TRANS_DIRTY;
> > +		}
> 
> Really, this should be a xfs_item_ops callout. i.e.
> 
> 		lip->li_ops->iop_relog(lip);
> 

Yeah, I've already done pretty much this in my local tree. The callback
also takes the transaction because that's the code that knows how to add
a particular type of item to a transaction. I didn't require a callback
for the else case above where no special handling is required
(quotaoff), so the callback is optional, but I'm not opposed to
reworking things such that ->iop_relog() is always required if that is
preferred.

> And then a) it doesn't matter really where we call it from, and b)
> it becomes fully generic and we can implement the callout
> as future functionality requires.
> 

Yep.

Brian

> However, we have to make sure that the current transaction we are
> running has the correct space usage accounted to it, so I think this
> callout really does need to be done in a tight loop iterating and
> accounting all the relog items into the transaction without outside
> interference.
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
>
Dave Chinner March 3, 2020, 12:09 a.m. UTC | #5
On Mon, Mar 02, 2020 at 02:00:34PM -0500, Brian Foster wrote:
> On Mon, Mar 02, 2020 at 06:47:28PM +1100, Dave Chinner wrote:
> > On Thu, Feb 27, 2020 at 08:43:19AM -0500, Brian Foster wrote:
> > > Add a quick and dirty implementation of buffer relogging support.
> > > There is currently no use case for buffer relogging. This is for
> > > experimental use only and serves as an example to demonstrate the
> > > ability to relog arbitrary items in the future, if necessary.
> > > 
> > > Add a hook to enable relogging a buffer in a transaction, update the
> > > buffer log item handlers to support relogged BLIs and update the
> > > relog handler to join the relogged buffer to the relog transaction.
> > > 
> > > Signed-off-by: Brian Foster <bfoster@redhat.com>
> > .....
> > >  /*
> > > @@ -187,9 +188,21 @@ xfs_ail_relog(
> > >  			xfs_log_ticket_put(ailp->ail_relog_tic);
> > >  		spin_unlock(&ailp->ail_lock);
> > >  
> > > -		xfs_trans_add_item(tp, lip);
> > > -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > > -		tp->t_flags |= XFS_TRANS_DIRTY;
> > > +		/*
> > > +		 * TODO: Ideally, relog transaction management would be pushed
> > > +		 * down into the ->iop_push() callbacks rather than playing
> > > +		 * games with ->li_trans and looking at log item types here.
> > > +		 */
> > > +		if (lip->li_type == XFS_LI_BUF) {
> > > +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> > > +			xfs_buf_hold(bli->bli_buf);
> > 
> > What is this for? The bli already has a reference to the buffer.
> > 
> 
> The buffer reference is for the transaction. It is analogous to the
> reference acquired in xfs_buf_find() via xfs_trans_[get|read]_buf(), for
> example.

Ah. Comment please :P

> > > +			xfs_trans_bjoin(tp, bli->bli_buf);
> > > +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> > > +		} else {
> > > +			xfs_trans_add_item(tp, lip);
> > > +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > > +			tp->t_flags |= XFS_TRANS_DIRTY;
> > > +		}
> > 
> > Really, this should be a xfs_item_ops callout. i.e.
> > 
> > 		lip->li_ops->iop_relog(lip);
> > 
> 
> Yeah, I've already done pretty much this in my local tree. The callback
> also takes the transaction because that's the code that knows how to add
> a particular type of item to a transaction. I didn't require a callback
> for the else case above where no special handling is required
> (quotaoff), so the callback is optional, but I'm not opposed to
> reworking things such that ->iop_relog() is always required if that is
> preferred.

I think I'd prefer to keep things simple right now. Making it an
unconditional callout keeps this code simple, and if there's a
common implementation, add a generic function for it that the items
use.

Cheers,

Dave.
Brian Foster March 3, 2020, 2:14 p.m. UTC | #6
On Tue, Mar 03, 2020 at 11:09:09AM +1100, Dave Chinner wrote:
> On Mon, Mar 02, 2020 at 02:00:34PM -0500, Brian Foster wrote:
> > On Mon, Mar 02, 2020 at 06:47:28PM +1100, Dave Chinner wrote:
> > > On Thu, Feb 27, 2020 at 08:43:19AM -0500, Brian Foster wrote:
> > > > Add a quick and dirty implementation of buffer relogging support.
> > > > There is currently no use case for buffer relogging. This is for
> > > > experimental use only and serves as an example to demonstrate the
> > > > ability to relog arbitrary items in the future, if necessary.
> > > > 
> > > > Add a hook to enable relogging a buffer in a transaction, update the
> > > > buffer log item handlers to support relogged BLIs and update the
> > > > relog handler to join the relogged buffer to the relog transaction.
> > > > 
> > > > Signed-off-by: Brian Foster <bfoster@redhat.com>
> > > .....
> > > >  /*
> > > > @@ -187,9 +188,21 @@ xfs_ail_relog(
> > > >  			xfs_log_ticket_put(ailp->ail_relog_tic);
> > > >  		spin_unlock(&ailp->ail_lock);
> > > >  
> > > > -		xfs_trans_add_item(tp, lip);
> > > > -		set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > > > -		tp->t_flags |= XFS_TRANS_DIRTY;
> > > > +		/*
> > > > +		 * TODO: Ideally, relog transaction management would be pushed
> > > > +		 * down into the ->iop_push() callbacks rather than playing
> > > > +		 * games with ->li_trans and looking at log item types here.
> > > > +		 */
> > > > +		if (lip->li_type == XFS_LI_BUF) {
> > > > +			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
> > > > +			xfs_buf_hold(bli->bli_buf);
> > > 
> > > What is this for? The bli already has a reference to the buffer.
> > > 
> > 
> > The buffer reference is for the transaction. It is analogous to the
> > reference acquired in xfs_buf_find() via xfs_trans_[get|read]_buf(), for
> > example.
> 
> Ah. Comment please :P
> 

Sure.

> > > > +			xfs_trans_bjoin(tp, bli->bli_buf);
> > > > +			xfs_trans_dirty_buf(tp, bli->bli_buf);
> > > > +		} else {
> > > > +			xfs_trans_add_item(tp, lip);
> > > > +			set_bit(XFS_LI_DIRTY, &lip->li_flags);
> > > > +			tp->t_flags |= XFS_TRANS_DIRTY;
> > > > +		}
> > > 
> > > Really, this should be a xfs_item_ops callout. i.e.
> > > 
> > > 		lip->li_ops->iop_relog(lip);
> > > 
> > 
> > Yeah, I've already done pretty much this in my local tree. The callback
> > also takes the transaction because that's the code that knows how to add
> > a particular type of item to a transaction. I didn't require a callback
> > for the else case above where no special handling is required
> > (quotaoff), so the callback is optional, but I'm not opposed to
> > reworking things such that ->iop_relog() is always required if that is
> > preferred.
> 
> I think I'd prefer to keep things simple right now. Making it an
> unconditional callout keeps this code simple, and if there's a
> common implementation, add a generic function for it that the items
> use.
> 

Fine by me, will fix.

Brian

> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
>
diff mbox series

Patch

diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 663810e6cd59..4ef2725fa8ce 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -463,6 +463,7 @@  xfs_buf_item_unpin(
 			list_del_init(&bp->b_li_list);
 			bp->b_iodone = NULL;
 		} else {
+			xfs_trans_relog_item_cancel(lip, false);
 			spin_lock(&ailp->ail_lock);
 			xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR);
 			xfs_buf_item_relse(bp);
@@ -528,6 +529,9 @@  xfs_buf_item_push(
 		return XFS_ITEM_LOCKED;
 	}
 
+	if (test_bit(XFS_LI_RELOG, &lip->li_flags))
+		return XFS_ITEM_RELOG;
+
 	ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
 
 	trace_xfs_buf_item_push(bip);
@@ -956,6 +960,7 @@  STATIC void
 xfs_buf_item_free(
 	struct xfs_buf_log_item	*bip)
 {
+	ASSERT(!test_bit(XFS_LI_RELOG, &bip->bli_item.li_flags));
 	xfs_buf_item_free_format(bip);
 	kmem_free(bip->bli_item.li_lv_shadow);
 	kmem_cache_free(xfs_buf_item_zone, bip);
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 1637df32c64c..81cb42f552d9 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -226,6 +226,7 @@  void		xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void		xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
 bool		xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
 void		xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
+bool		xfs_trans_relog_buf(struct xfs_trans *, struct xfs_buf *);
 void		xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
 void		xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
 void		xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 71a47faeaae8..103ab62e61be 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -18,6 +18,7 @@ 
 #include "xfs_error.h"
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
+#include "xfs_buf_item.h"
 
 #ifdef DEBUG
 /*
@@ -187,9 +188,21 @@  xfs_ail_relog(
 			xfs_log_ticket_put(ailp->ail_relog_tic);
 		spin_unlock(&ailp->ail_lock);
 
-		xfs_trans_add_item(tp, lip);
-		set_bit(XFS_LI_DIRTY, &lip->li_flags);
-		tp->t_flags |= XFS_TRANS_DIRTY;
+		/*
+		 * TODO: Ideally, relog transaction management would be pushed
+		 * down into the ->iop_push() callbacks rather than playing
+		 * games with ->li_trans and looking at log item types here.
+		 */
+		if (lip->li_type == XFS_LI_BUF) {
+			struct xfs_buf_log_item	*bli = (struct xfs_buf_log_item *) lip;
+			xfs_buf_hold(bli->bli_buf);
+			xfs_trans_bjoin(tp, bli->bli_buf);
+			xfs_trans_dirty_buf(tp, bli->bli_buf);
+		} else {
+			xfs_trans_add_item(tp, lip);
+			set_bit(XFS_LI_DIRTY, &lip->li_flags);
+			tp->t_flags |= XFS_TRANS_DIRTY;
+		}
 		/* XXX: include ticket owner task fix */
 		error = xfs_trans_roll(&tp);
 		ASSERT(!error);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 08174ffa2118..e17715ac23fc 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -787,3 +787,25 @@  xfs_trans_dquot_buf(
 
 	xfs_trans_buf_set_type(tp, bp, type);
 }
+
+/*
+ * Enable automatic relogging on a buffer. This essentially pins a dirty buffer
+ * in-core until relogging is disabled. Note that the buffer must not already be
+ * queued for writeback.
+ */
+bool
+xfs_trans_relog_buf(
+	struct xfs_trans	*tp,
+	struct xfs_buf		*bp)
+{
+	struct xfs_buf_log_item	*bip = bp->b_log_item;
+
+	ASSERT(tp->t_flags & XFS_TRANS_RELOG);
+	ASSERT(xfs_buf_islocked(bp));
+
+	if (bp->b_flags & _XBF_DELWRI_Q)
+		return false;
+
+	xfs_trans_relog_item(&bip->bli_item);
+	return true;
+}