Re: [PATCH 10/63] xfs: create refcount update intent log items

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Sep 28, 2016 at 12:20:18PM -0400, Brian Foster wrote:
> On Tue, Sep 27, 2016 at 07:54:33PM -0700, Darrick J. Wong wrote:
> > Create refcount update intent/done log items to record redo
> > information in the log.  Because we need to roll transactions between
> > updating the bmbt mapping and updating the reverse mapping, we also
> > have to track the status of the metadata updates that will be recorded
> > in the post-roll transactions, just in case we crash before committing
> > the final transaction.  This mechanism enables log recovery to finish
> > what was already started.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> > ---
> >  fs/xfs/Makefile                |    1 
> >  fs/xfs/libxfs/xfs_log_format.h |   59 ++++++
> >  fs/xfs/xfs_refcount_item.c     |  406 ++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/xfs_refcount_item.h     |  102 ++++++++++
> >  fs/xfs/xfs_super.c             |   18 ++
> >  5 files changed, 584 insertions(+), 2 deletions(-)
> >  create mode 100644 fs/xfs/xfs_refcount_item.c
> >  create mode 100644 fs/xfs/xfs_refcount_item.h
> > 
> > 
> ...
> > diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c
> > new file mode 100644
> > index 0000000..ac52b02
> > --- /dev/null
> > +++ b/fs/xfs/xfs_refcount_item.c
> > @@ -0,0 +1,406 @@
> ...
> > +/*
> > + * This is called to fill in the vector of log iovecs for the
> > + * given cud log item. We use only 1 iovec, and we point that
> > + * at the cud_log_format structure embedded in the cud item.
> > + * It is at this point that we assert that all of the extent
> > + * slots in the cud item have been filled.
> > + */
> > +STATIC void
> > +xfs_cud_item_format(
> > +	struct xfs_log_item	*lip,
> > +	struct xfs_log_vec	*lv)
> > +{
> > +	struct xfs_cud_log_item	*cudp = CUD_ITEM(lip);
> > +	struct xfs_log_iovec	*vecp = NULL;
> > +
> > +	cudp->cud_format.cud_type = XFS_LI_CUD;
> > +	cudp->cud_format.cud_size = 1;
> > +
> > +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUD_FORMAT, &cudp->cud_format,
> > +			sizeof(struct xfs_rud_log_format));
> 
> They're the same size, but:	      xfs_cud_log_format

Yikes, good catch!

--D

> 
> Brian
> 
> > +}
> > +
> > +/*
> > + * Pinning has no meaning for an cud item, so just return.
> > + */
> > +STATIC void
> > +xfs_cud_item_pin(
> > +	struct xfs_log_item	*lip)
> > +{
> > +}
> > +
> > +/*
> > + * Since pinning has no meaning for an cud item, unpinning does
> > + * not either.
> > + */
> > +STATIC void
> > +xfs_cud_item_unpin(
> > +	struct xfs_log_item	*lip,
> > +	int			remove)
> > +{
> > +}
> > +
> > +/*
> > + * There isn't much you can do to push on an cud item.  It is simply stuck
> > + * waiting for the log to be flushed to disk.
> > + */
> > +STATIC uint
> > +xfs_cud_item_push(
> > +	struct xfs_log_item	*lip,
> > +	struct list_head	*buffer_list)
> > +{
> > +	return XFS_ITEM_PINNED;
> > +}
> > +
> > +/*
> > + * The CUD is either committed or aborted if the transaction is cancelled. If
> > + * the transaction is cancelled, drop our reference to the CUI and free the
> > + * CUD.
> > + */
> > +STATIC void
> > +xfs_cud_item_unlock(
> > +	struct xfs_log_item	*lip)
> > +{
> > +	struct xfs_cud_log_item	*cudp = CUD_ITEM(lip);
> > +
> > +	if (lip->li_flags & XFS_LI_ABORTED) {
> > +		xfs_cui_release(cudp->cud_cuip);
> > +		kmem_zone_free(xfs_cud_zone, cudp);
> > +	}
> > +}
> > +
> > +/*
> > + * When the cud item is committed to disk, all we need to do is delete our
> > + * reference to our partner cui item and then free ourselves. Since we're
> > + * freeing ourselves we must return -1 to keep the transaction code from
> > + * further referencing this item.
> > + */
> > +STATIC xfs_lsn_t
> > +xfs_cud_item_committed(
> > +	struct xfs_log_item	*lip,
> > +	xfs_lsn_t		lsn)
> > +{
> > +	struct xfs_cud_log_item	*cudp = CUD_ITEM(lip);
> > +
> > +	/*
> > +	 * Drop the CUI reference regardless of whether the CUD has been
> > +	 * aborted. Once the CUD transaction is constructed, it is the sole
> > +	 * responsibility of the CUD to release the CUI (even if the CUI is
> > +	 * aborted due to log I/O error).
> > +	 */
> > +	xfs_cui_release(cudp->cud_cuip);
> > +	kmem_zone_free(xfs_cud_zone, cudp);
> > +
> > +	return (xfs_lsn_t)-1;
> > +}
> > +
> > +/*
> > + * The CUD dependency tracking op doesn't do squat.  It can't because
> > + * it doesn't know where the free extent is coming from.  The dependency
> > + * tracking has to be handled by the "enclosing" metadata object.  For
> > + * example, for inodes, the inode is locked throughout the extent freeing
> > + * so the dependency should be recorded there.
> > + */
> > +STATIC void
> > +xfs_cud_item_committing(
> > +	struct xfs_log_item	*lip,
> > +	xfs_lsn_t		lsn)
> > +{
> > +}
> > +
> > +/*
> > + * This is the ops vector shared by all cud log items.
> > + */
> > +static const struct xfs_item_ops xfs_cud_item_ops = {
> > +	.iop_size	= xfs_cud_item_size,
> > +	.iop_format	= xfs_cud_item_format,
> > +	.iop_pin	= xfs_cud_item_pin,
> > +	.iop_unpin	= xfs_cud_item_unpin,
> > +	.iop_unlock	= xfs_cud_item_unlock,
> > +	.iop_committed	= xfs_cud_item_committed,
> > +	.iop_push	= xfs_cud_item_push,
> > +	.iop_committing = xfs_cud_item_committing,
> > +};
> > +
> > +/*
> > + * Allocate and initialize an cud item with the given number of extents.
> > + */
> > +struct xfs_cud_log_item *
> > +xfs_cud_init(
> > +	struct xfs_mount		*mp,
> > +	struct xfs_cui_log_item		*cuip)
> > +
> > +{
> > +	struct xfs_cud_log_item	*cudp;
> > +
> > +	cudp = kmem_zone_zalloc(xfs_cud_zone, KM_SLEEP);
> > +	xfs_log_item_init(mp, &cudp->cud_item, XFS_LI_CUD, &xfs_cud_item_ops);
> > +	cudp->cud_cuip = cuip;
> > +	cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id;
> > +
> > +	return cudp;
> > +}
> > diff --git a/fs/xfs/xfs_refcount_item.h b/fs/xfs/xfs_refcount_item.h
> > new file mode 100644
> > index 0000000..7b8f56b
> > --- /dev/null
> > +++ b/fs/xfs/xfs_refcount_item.h
> > @@ -0,0 +1,102 @@
> > +/*
> > + * Copyright (C) 2016 Oracle.  All Rights Reserved.
> > + *
> > + * Author: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version 2
> > + * of the License, or (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it would be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write the Free Software Foundation,
> > + * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
> > + */
> > +#ifndef	__XFS_REFCOUNT_ITEM_H__
> > +#define	__XFS_REFCOUNT_ITEM_H__
> > +
> > +/*
> > + * There are (currently) two pairs of refcount btree redo item types:
> > + * increase and decrease.  The log items for these are CUI (refcount
> > + * update intent) and CUD (refcount update done).  The redo item type
> > + * is encoded in the flags field of each xfs_map_extent.
> > + *
> > + * *I items should be recorded in the *first* of a series of rolled
> > + * transactions, and the *D items should be recorded in the same
> > + * transaction that records the associated refcountbt updates.
> > + *
> > + * Should the system crash after the commit of the first transaction
> > + * but before the commit of the final transaction in a series, log
> > + * recovery will use the redo information recorded by the intent items
> > + * to replay the refcountbt metadata updates.
> > + */
> > +
> > +/* kernel only CUI/CUD definitions */
> > +
> > +struct xfs_mount;
> > +struct kmem_zone;
> > +
> > +/*
> > + * Max number of extents in fast allocation path.
> > + */
> > +#define	XFS_CUI_MAX_FAST_EXTENTS	16
> > +
> > +/*
> > + * Define CUI flag bits. Manipulated by set/clear/test_bit operators.
> > + */
> > +#define	XFS_CUI_RECOVERED		1
> > +
> > +/*
> > + * This is the "refcount update intent" log item.  It is used to log
> > + * the fact that some reverse mappings need to change.  It is used in
> > + * conjunction with the "refcount update done" log item described
> > + * below.
> > + *
> > + * These log items follow the same rules as struct xfs_efi_log_item;
> > + * see the comments about that structure (in xfs_extfree_item.h) for
> > + * more details.
> > + */
> > +struct xfs_cui_log_item {
> > +	struct xfs_log_item		cui_item;
> > +	atomic_t			cui_refcount;
> > +	atomic_t			cui_next_extent;
> > +	unsigned long			cui_flags;	/* misc flags */
> > +	struct xfs_cui_log_format	cui_format;
> > +};
> > +
> > +static inline size_t
> > +xfs_cui_log_item_sizeof(
> > +	unsigned int		nr)
> > +{
> > +	return offsetof(struct xfs_cui_log_item, cui_format) +
> > +			xfs_cui_log_format_sizeof(nr);
> > +}
> > +
> > +/*
> > + * This is the "refcount update done" log item.  It is used to log the
> > + * fact that some refcountbt updates mentioned in an earlier cui item
> > + * have been performed.
> > + */
> > +struct xfs_cud_log_item {
> > +	struct xfs_log_item		cud_item;
> > +	struct xfs_cui_log_item		*cud_cuip;
> > +	struct xfs_cud_log_format	cud_format;
> > +};
> > +
> > +extern struct kmem_zone	*xfs_cui_zone;
> > +extern struct kmem_zone	*xfs_cud_zone;
> > +
> > +struct xfs_cui_log_item *xfs_cui_init(struct xfs_mount *, uint);
> > +struct xfs_cud_log_item *xfs_cud_init(struct xfs_mount *,
> > +		struct xfs_cui_log_item *);
> > +int xfs_cui_copy_format(struct xfs_log_iovec *buf,
> > +		struct xfs_cui_log_format *dst_cui_fmt);
> > +void xfs_cui_item_free(struct xfs_cui_log_item *);
> > +void xfs_cui_release(struct xfs_cui_log_item *);
> > +
> > +#endif	/* __XFS_REFCOUNT_ITEM_H__ */
> > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> > index 2d092f9..abe69c6 100644
> > --- a/fs/xfs/xfs_super.c
> > +++ b/fs/xfs/xfs_super.c
> > @@ -47,6 +47,7 @@
> >  #include "xfs_sysfs.h"
> >  #include "xfs_ondisk.h"
> >  #include "xfs_rmap_item.h"
> > +#include "xfs_refcount_item.h"
> >  
> >  #include <linux/namei.h>
> >  #include <linux/init.h>
> > @@ -1788,8 +1789,23 @@ xfs_init_zones(void)
> >  	if (!xfs_rui_zone)
> >  		goto out_destroy_rud_zone;
> >  
> > +	xfs_cud_zone = kmem_zone_init(sizeof(struct xfs_cud_log_item),
> > +			"xfs_cud_item");
> > +	if (!xfs_cud_zone)
> > +		goto out_destroy_rui_zone;
> > +
> > +	xfs_cui_zone = kmem_zone_init(
> > +			xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS),
> > +			"xfs_cui_item");
> > +	if (!xfs_cui_zone)
> > +		goto out_destroy_cud_zone;
> > +
> >  	return 0;
> >  
> > + out_destroy_cud_zone:
> > +	kmem_zone_destroy(xfs_cud_zone);
> > + out_destroy_rui_zone:
> > +	kmem_zone_destroy(xfs_rui_zone);
> >   out_destroy_rud_zone:
> >  	kmem_zone_destroy(xfs_rud_zone);
> >   out_destroy_icreate_zone:
> > @@ -1832,6 +1848,8 @@ xfs_destroy_zones(void)
> >  	 * destroy caches.
> >  	 */
> >  	rcu_barrier();
> > +	kmem_zone_destroy(xfs_cui_zone);
> > +	kmem_zone_destroy(xfs_cud_zone);
> >  	kmem_zone_destroy(xfs_rui_zone);
> >  	kmem_zone_destroy(xfs_rud_zone);
> >  	kmem_zone_destroy(xfs_icreate_zone);
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> > the body of a message to majordomo@xxxxxxxxxxxxxxx
> > 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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux