diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/xfs_attr_leaf.c | 9 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr_remote.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf_item.h | 18 | ||||
| -rw-r--r-- | fs/xfs/xfs_da_btree.c | 46 | ||||
| -rw-r--r-- | fs/xfs/xfs_da_btree.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2_block.c | 12 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2_data.c | 8 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2_leaf.c | 26 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2_node.c | 15 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2_priv.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_log_recover.c | 252 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_buf.c | 17 | 
13 files changed, 322 insertions, 89 deletions
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 287c8089b70..92cda03d1c0 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -271,8 +271,13 @@ xfs_attr3_leaf_read(  	xfs_daddr_t		mappedbno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,  				XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops); +	if (!err && tp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_ATTR_LEAF_BUF); +	return err;  }  /*======================================================================== @@ -1078,6 +1083,7 @@ xfs_attr3_leaf_to_node(  		goto out;  	/* copy leaf to new buffer, update identifiers */ +	xfs_trans_buf_set_type(args->trans, bp2, XFS_BLF_ATTR_LEAF_BUF);  	bp2->b_ops = bp1->b_ops;  	memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(mp));  	if (xfs_sb_version_hascrc(&mp->m_sb)) { @@ -1140,6 +1146,7 @@ xfs_attr3_leaf_create(  	if (error)  		return error;  	bp->b_ops = &xfs_attr3_leaf_buf_ops; +	xfs_trans_buf_set_type(args->trans, bp, XFS_BLF_ATTR_LEAF_BUF);  	leaf = bp->b_addr;  	memset(leaf, 0, XFS_LBSIZE(mp)); diff --git a/fs/xfs/xfs_attr_remote.h b/fs/xfs/xfs_attr_remote.h index 0ca8d9a1fa0..c7cca60a062 100644 --- a/fs/xfs/xfs_attr_remote.h +++ b/fs/xfs/xfs_attr_remote.h @@ -37,6 +37,8 @@ struct xfs_attr3_rmt_hdr {  	((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \  			sizeof(struct xfs_attr3_rmt_hdr) : 0)) +extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; +  int xfs_attr_rmtval_get(struct xfs_da_args *args);  int xfs_attr_rmtval_set(struct xfs_da_args *args);  int xfs_attr_rmtval_remove(struct xfs_da_args *args); diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 09cab4ed106..640adcfa414 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -50,6 +50,14 @@ extern kmem_zone_t	*xfs_buf_item_zone;  #define XFS_BLF_AGI_BUF		(1<<8)  #define XFS_BLF_DINO_BUF	(1<<9)  #define XFS_BLF_SYMLINK_BUF	(1<<10) +#define XFS_BLF_DIR_BLOCK_BUF	(1<<11) +#define XFS_BLF_DIR_DATA_BUF	(1<<12) +#define XFS_BLF_DIR_FREE_BUF	(1<<13) +#define XFS_BLF_DIR_LEAF1_BUF	(1<<14) +#define XFS_BLF_DIR_LEAFN_BUF	(1<<15) +#define XFS_BLF_DA_NODE_BUF	(1<<16) +#define XFS_BLF_ATTR_LEAF_BUF	(1<<17) +#define XFS_BLF_ATTR_RMT_BUF	(1<<18)  #define XFS_BLF_TYPE_MASK	\  		(XFS_BLF_UDQUOT_BUF | \ @@ -60,7 +68,15 @@ extern kmem_zone_t	*xfs_buf_item_zone;  		 XFS_BLF_AGFL_BUF | \  		 XFS_BLF_AGI_BUF | \  		 XFS_BLF_DINO_BUF | \ -		 XFS_BLF_SYMLINK_BUF) +		 XFS_BLF_SYMLINK_BUF | \ +		 XFS_BLF_DIR_BLOCK_BUF | \ +		 XFS_BLF_DIR_DATA_BUF | \ +		 XFS_BLF_DIR_FREE_BUF | \ +		 XFS_BLF_DIR_LEAF1_BUF | \ +		 XFS_BLF_DIR_LEAFN_BUF | \ +		 XFS_BLF_DA_NODE_BUF | \ +		 XFS_BLF_ATTR_LEAF_BUF | \ +		 XFS_BLF_ATTR_RMT_BUF)  #define	XFS_BLF_CHUNK		128  #define	XFS_BLF_SHIFT		7 diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 779ecdcdbe0..5aebd9bd44d 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -292,7 +292,6 @@ const struct xfs_buf_ops xfs_da3_node_buf_ops = {  	.verify_write = xfs_da3_node_write_verify,  }; -  int  xfs_da3_node_read(  	struct xfs_trans	*tp, @@ -302,8 +301,35 @@ xfs_da3_node_read(  	struct xfs_buf		**bpp,  	int			which_fork)  { -	return xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,  					which_fork, &xfs_da3_node_buf_ops); +	if (!err && tp) { +		struct xfs_da_blkinfo	*info = (*bpp)->b_addr; +		int			type; + +		switch (be16_to_cpu(info->magic)) { +		case XFS_DA3_NODE_MAGIC: +		case XFS_DA_NODE_MAGIC: +			type = XFS_BLF_DA_NODE_BUF; +			break; +		case XFS_ATTR_LEAF_MAGIC: +		case XFS_ATTR3_LEAF_MAGIC: +			type = XFS_BLF_ATTR_LEAF_BUF; +			break; +		case XFS_DIR2_LEAFN_MAGIC: +		case XFS_DIR3_LEAFN_MAGIC: +			type = XFS_BLF_DIR_LEAFN_BUF; +			break; +		default: +			type = 0; +			ASSERT(0); +			break; +		} +		xfs_trans_buf_set_type(tp, *bpp, type); +	} +	return err;  }  /*======================================================================== @@ -334,6 +360,8 @@ xfs_da3_node_create(  	error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork);  	if (error)  		return(error); +	bp->b_ops = &xfs_da3_node_buf_ops; +	xfs_trans_buf_set_type(tp, bp, XFS_BLF_DA_NODE_BUF);  	node = bp->b_addr;  	if (xfs_sb_version_hascrc(&mp->m_sb)) { @@ -352,7 +380,6 @@ xfs_da3_node_create(  	xfs_trans_log_buf(tp, bp,  		XFS_DA_LOGRANGE(node, &node->hdr, xfs_da3_node_hdr_size(node))); -	bp->b_ops = &xfs_da3_node_buf_ops;  	*bpp = bp;  	return(0);  } @@ -565,6 +592,12 @@ xfs_da3_root_split(  		btree = xfs_da3_node_tree_p(oldroot);  		size = (int)((char *)&btree[nodehdr.count] - (char *)oldroot);  		level = nodehdr.level; + +		/* +		 * we are about to copy oldroot to bp, so set up the type +		 * of bp while we know exactly what it will be. +		 */ +		xfs_trans_buf_set_type(tp, bp, XFS_BLF_DA_NODE_BUF);  	} else {  		struct xfs_dir3_icleaf_hdr leafhdr;  		struct xfs_dir2_leaf_entry *ents; @@ -577,6 +610,12 @@ xfs_da3_root_split(  		       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);  		size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);  		level = 0; + +		/* +		 * we are about to copy oldroot to bp, so set up the type +		 * of bp while we know exactly what it will be. +		 */ +		xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAFN_BUF);  	}  	/* @@ -1092,6 +1131,7 @@ xfs_da3_root_join(  	 */  	memcpy(root_blk->bp->b_addr, bp->b_addr, state->blocksize);  	root_blk->bp->b_ops = bp->b_ops; +	xfs_trans_buf_copy_type(root_blk->bp, bp);  	if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) {  		struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr;  		da3->blkno = cpu_to_be64(root_blk->bp->b_bn); diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 0e8182c5210..6fb3371c63c 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -301,6 +301,8 @@ int	xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp,  			 xfs_dablk_t bno, xfs_daddr_t mappedbno,  			 struct xfs_buf **bpp, int which_fork); +extern const struct xfs_buf_ops xfs_da3_node_buf_ops; +  /*   * Utility routines.   */ diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index d2e445f92ff..58816ecdbba 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -132,20 +132,26 @@ xfs_dir3_block_read(  	struct xfs_buf		**bpp)  {  	struct xfs_mount	*mp = dp->i_mount; +	int			err; -	return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, +	err = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,  				XFS_DATA_FORK, &xfs_dir3_block_buf_ops); +	if (!err && tp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_BLOCK_BUF); +	return err;  }  static void  xfs_dir3_block_init(  	struct xfs_mount	*mp, +	struct xfs_trans	*tp,  	struct xfs_buf		*bp,  	struct xfs_inode	*dp)  {  	struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;  	bp->b_ops = &xfs_dir3_block_buf_ops; +	xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_BLOCK_BUF);  	if (xfs_sb_version_hascrc(&mp->m_sb)) {  		memset(hdr3, 0, sizeof(*hdr3)); @@ -1080,7 +1086,7 @@ xfs_dir2_leaf_to_block(  	/*  	 * Start converting it to block form.  	 */ -	xfs_dir3_block_init(mp, dbp, dp); +	xfs_dir3_block_init(mp, tp, dbp, dp);  	needlog = 1;  	needscan = 0; @@ -1209,7 +1215,7 @@ xfs_dir2_sf_to_block(  		kmem_free(sfp);  		return error;  	} -	xfs_dir3_block_init(mp, bp, dp); +	xfs_dir3_block_init(mp, tp, bp, dp);  	hdr = bp->b_addr;  	/* diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index 78320df3743..5e0c711f9af 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c @@ -301,8 +301,13 @@ xfs_dir3_data_read(  	xfs_daddr_t		mapped_bno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,  				XFS_DATA_FORK, &xfs_dir3_data_buf_ops); +	if (!err && tp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_DATA_BUF); +	return err;  }  int @@ -571,6 +576,7 @@ xfs_dir3_data_init(  	if (error)  		return error;  	bp->b_ops = &xfs_dir3_data_buf_ops; +	xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_DATA_BUF);  	/*  	 * Initialize the header. diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 7352e41d2aa..84f4c9cfe95 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -279,7 +279,7 @@ xfs_dir3_leafn_write_verify(  	__write_verify(bp, XFS_DIR2_LEAFN_MAGIC);  } -static const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = { +const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {  	.verify_read = xfs_dir3_leaf1_read_verify,  	.verify_write = xfs_dir3_leaf1_write_verify,  }; @@ -297,8 +297,13 @@ xfs_dir3_leaf_read(  	xfs_daddr_t		mappedbno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,  				XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops); +	if (!err && tp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_LEAF1_BUF); +	return err;  }  int @@ -309,8 +314,13 @@ xfs_dir3_leafn_read(  	xfs_daddr_t		mappedbno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,  				XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops); +	if (!err && tp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_LEAFN_BUF); +	return err;  }  /* @@ -319,6 +329,7 @@ xfs_dir3_leafn_read(  static void  xfs_dir3_leaf_init(  	struct xfs_mount	*mp, +	struct xfs_trans	*tp,  	struct xfs_buf		*bp,  	xfs_ino_t		owner,  	__uint16_t		type) @@ -353,8 +364,11 @@ xfs_dir3_leaf_init(  		ltp = xfs_dir2_leaf_tail_p(mp, leaf);  		ltp->bestcount = 0;  		bp->b_ops = &xfs_dir3_leaf1_buf_ops; -	} else +		xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAF1_BUF); +	} else {  		bp->b_ops = &xfs_dir3_leafn_buf_ops; +		xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_LEAFN_BUF); +	}  }  int @@ -379,7 +393,7 @@ xfs_dir3_leaf_get_buf(  	if (error)  		return error; -	xfs_dir3_leaf_init(mp, bp, dp->i_ino, magic); +	xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic);  	xfs_dir3_leaf_log_header(tp, bp);  	if (magic == XFS_DIR2_LEAF1_MAGIC)  		xfs_dir3_leaf_log_tail(tp, bp); @@ -474,6 +488,7 @@ xfs_dir2_block_to_leaf(  	 * Fix up the block header, make it a data block.  	 */  	dbp->b_ops = &xfs_dir3_data_buf_ops; +	xfs_trans_buf_set_type(tp, dbp, XFS_BLF_DIR_DATA_BUF);  	if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))  		hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);  	else @@ -2182,6 +2197,7 @@ xfs_dir2_node_to_leaf(  		xfs_dir3_leaf_compact(args, &leafhdr, lbp);  	lbp->b_ops = &xfs_dir3_leaf1_buf_ops; +	xfs_trans_buf_set_type(tp, lbp, XFS_BLF_DIR_LEAF1_BUF);  	leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC)  					? XFS_DIR2_LEAF1_MAGIC  					: XFS_DIR3_LEAF1_MAGIC; diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 122449b33f5..1806a22d559 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -147,7 +147,7 @@ xfs_dir3_free_write_verify(  	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_FREE_CRC_OFF);  } -static const struct xfs_buf_ops xfs_dir3_free_buf_ops = { +const struct xfs_buf_ops xfs_dir3_free_buf_ops = {  	.verify_read = xfs_dir3_free_read_verify,  	.verify_write = xfs_dir3_free_write_verify,  }; @@ -161,8 +161,15 @@ __xfs_dir3_free_read(  	xfs_daddr_t		mappedbno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, +	int			err; + +	err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,  				XFS_DATA_FORK, &xfs_dir3_free_buf_ops); + +	/* try read returns without an error or *bpp if it lands in a hole */ +	if (!err && tp && *bpp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLF_DIR_FREE_BUF); +	return err;  }  int @@ -249,6 +256,7 @@ xfs_dir3_free_get_buf(  	if (error)  		return error; +	xfs_trans_buf_set_type(tp, bp, XFS_BLF_DIR_FREE_BUF);  	bp->b_ops = &xfs_dir3_free_buf_ops;  	/* @@ -396,6 +404,7 @@ xfs_dir2_leaf_to_node(  	else  		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);  	lbp->b_ops = &xfs_dir3_leafn_buf_ops; +	xfs_trans_buf_set_type(tp, lbp, XFS_BLF_DIR_LEAFN_BUF);  	xfs_dir3_leaf_log_header(tp, lbp);  	xfs_dir3_leaf_check(mp, lbp);  	return 0; @@ -811,6 +820,7 @@ xfs_dir2_leafn_lookup_for_entry(  							(char *)curbp->b_addr);  			state->extrablk.magic = XFS_DIR2_DATA_MAGIC;  			curbp->b_ops = &xfs_dir3_data_buf_ops; +			xfs_trans_buf_set_type(tp, curbp, XFS_BLF_DIR_DATA_BUF);  			if (cmp == XFS_CMP_EXACT)  				return XFS_ERROR(EEXIST);  		} @@ -825,6 +835,7 @@ xfs_dir2_leafn_lookup_for_entry(  			state->extrablk.blkno = curdb;  			state->extrablk.magic = XFS_DIR2_DATA_MAGIC;  			curbp->b_ops = &xfs_dir3_data_buf_ops; +			xfs_trans_buf_set_type(tp, curbp, XFS_BLF_DIR_DATA_BUF);  		} else {  			/* If the curbp is not the CI match block, drop it */  			if (state->extrablk.bp != curbp) diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h index 932565d6ef2..7cf573c88aa 100644 --- a/fs/xfs/xfs_dir2_priv.h +++ b/fs/xfs/xfs_dir2_priv.h @@ -49,6 +49,7 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,  #endif  extern const struct xfs_buf_ops xfs_dir3_data_buf_ops; +extern const struct xfs_buf_ops xfs_dir3_free_buf_ops;  extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);  extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp, @@ -77,6 +78,7 @@ extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,  		xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);  /* xfs_dir2_leaf.c */ +extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;  extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;  extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp, diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index d1292fd1112..00727bc4a9b 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -45,7 +45,14 @@  #include "xfs_cksum.h"  #include "xfs_trace.h"  #include "xfs_icache.h" + +/* Need all the magic numbers and buffer ops structures from these headers */  #include "xfs_symlink.h" +#include "xfs_da_btree.h" +#include "xfs_dir2_format.h" +#include "xfs_dir2_priv.h" +#include "xfs_attr_leaf.h" +#include "xfs_attr_remote.h"  STATIC int  xlog_find_zeroed( @@ -1860,81 +1867,30 @@ xlog_recover_do_inode_buffer(  }  /* - * Perform a 'normal' buffer recovery.  Each logged region of the - * buffer should be copied over the corresponding region in the - * given buffer.  The bitmap in the buf log format structure indicates - * where to place the logged data. + * Validate the recovered buffer is of the correct type and attach the + * appropriate buffer operations to them for writeback. Magic numbers are in a + * few places: + *	the first 16 bits of the buffer (inode buffer, dquot buffer), + *	the first 32 bits of the buffer (most blocks), + *	inside a struct xfs_da_blkinfo at the start of the buffer.   */ -STATIC void -xlog_recover_do_reg_buffer( +static void +xlog_recovery_validate_buf_type(  	struct xfs_mount	*mp, -	xlog_recover_item_t	*item,  	struct xfs_buf		*bp,  	xfs_buf_log_format_t	*buf_f)  { -	int			i; -	int			bit; -	int			nbits; -	int                     error; - -	trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f); - -	bit = 0; -	i = 1;  /* 0 is the buf format structure */ -	while (1) { -		bit = xfs_next_bit(buf_f->blf_data_map, -				   buf_f->blf_map_size, bit); -		if (bit == -1) -			break; -		nbits = xfs_contig_bits(buf_f->blf_data_map, -					buf_f->blf_map_size, bit); -		ASSERT(nbits > 0); -		ASSERT(item->ri_buf[i].i_addr != NULL); -		ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0); -		ASSERT(BBTOB(bp->b_io_length) >= -		       ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT)); - -		/* -		 * Do a sanity check if this is a dquot buffer. Just checking -		 * the first dquot in the buffer should do. XXXThis is -		 * probably a good thing to do for other buf types also. -		 */ -		error = 0; -		if (buf_f->blf_flags & -		   (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { -			if (item->ri_buf[i].i_addr == NULL) { -				xfs_alert(mp, -					"XFS: NULL dquot in %s.", __func__); -				goto next; -			} -			if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) { -				xfs_alert(mp, -					"XFS: dquot too small (%d) in %s.", -					item->ri_buf[i].i_len, __func__); -				goto next; -			} -			error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr, -					       -1, 0, XFS_QMOPT_DOWARN, -					       "dquot_buf_recover"); -			if (error) -				goto next; -		} - -		memcpy(xfs_buf_offset(bp, -			(uint)bit << XFS_BLF_SHIFT),	/* dest */ -			item->ri_buf[i].i_addr,		/* source */ -			nbits<<XFS_BLF_SHIFT);		/* length */ - next: -		i++; -		bit += nbits; -	} - -	/* Shouldn't be any more regions */ -	ASSERT(i == item->ri_total); +	struct xfs_da_blkinfo	*info = bp->b_addr; +	__uint32_t		magic32; +	__uint16_t		magic16; +	__uint16_t		magicda; +	magic32 = be32_to_cpu(*(__be32 *)bp->b_addr); +	magic16 = be16_to_cpu(*(__be16*)bp->b_addr); +	magicda = be16_to_cpu(info->magic);  	switch (buf_f->blf_flags & XFS_BLF_TYPE_MASK) {  	case XFS_BLF_BTREE_BUF: -		switch (be32_to_cpu(*(__be32 *)bp->b_addr)) { +		switch (magic32) {  		case XFS_ABTB_CRC_MAGIC:  		case XFS_ABTC_CRC_MAGIC:  		case XFS_ABTB_MAGIC: @@ -1956,7 +1912,7 @@ xlog_recover_do_reg_buffer(  		}  		break;  	case XFS_BLF_AGF_BUF: -		if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGF_MAGIC)) { +		if (magic32 != XFS_AGF_MAGIC) {  			xfs_warn(mp, "Bad AGF block magic!");  			ASSERT(0);  			break; @@ -1966,7 +1922,7 @@ xlog_recover_do_reg_buffer(  	case XFS_BLF_AGFL_BUF:  		if (!xfs_sb_version_hascrc(&mp->m_sb))  			break; -		if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGFL_MAGIC)) { +		if (magic32 != XFS_AGFL_MAGIC) {  			xfs_warn(mp, "Bad AGFL block magic!");  			ASSERT(0);  			break; @@ -1974,7 +1930,7 @@ xlog_recover_do_reg_buffer(  		bp->b_ops = &xfs_agfl_buf_ops;  		break;  	case XFS_BLF_AGI_BUF: -		if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_AGI_MAGIC)) { +		if (magic32 != XFS_AGI_MAGIC) {  			xfs_warn(mp, "Bad AGI block magic!");  			ASSERT(0);  			break; @@ -1984,7 +1940,7 @@ xlog_recover_do_reg_buffer(  	case XFS_BLF_UDQUOT_BUF:  	case XFS_BLF_PDQUOT_BUF:  	case XFS_BLF_GDQUOT_BUF: -		if (*(__be16 *)bp->b_addr != cpu_to_be16(XFS_DQUOT_MAGIC)) { +		if (magic16 != XFS_DQUOT_MAGIC) {  			xfs_warn(mp, "Bad DQUOT block magic!");  			ASSERT(0);  			break; @@ -1996,7 +1952,7 @@ xlog_recover_do_reg_buffer(  		 * we get here with inode allocation buffers, not buffers that  		 * track unlinked list changes.  		 */ -		if (*(__be16 *)bp->b_addr != cpu_to_be16(XFS_DINODE_MAGIC)) { +		if (magic16 != XFS_DINODE_MAGIC) {  			xfs_warn(mp, "Bad INODE block magic!");  			ASSERT(0);  			break; @@ -2004,19 +1960,169 @@ xlog_recover_do_reg_buffer(  		bp->b_ops = &xfs_inode_buf_ops;  		break;  	case XFS_BLF_SYMLINK_BUF: -		if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_SYMLINK_MAGIC)) { +		if (magic32 != XFS_SYMLINK_MAGIC) {  			xfs_warn(mp, "Bad symlink block magic!");  			ASSERT(0);  			break;  		}  		bp->b_ops = &xfs_symlink_buf_ops;  		break; +	case XFS_BLF_DIR_BLOCK_BUF: +		if (magic32 != XFS_DIR2_BLOCK_MAGIC && +		    magic32 != XFS_DIR3_BLOCK_MAGIC) { +			xfs_warn(mp, "Bad dir block magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_dir3_block_buf_ops; +		break; +	case XFS_BLF_DIR_DATA_BUF: +		if (magic32 != XFS_DIR2_DATA_MAGIC && +		    magic32 != XFS_DIR3_DATA_MAGIC) { +			xfs_warn(mp, "Bad dir data magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_dir3_data_buf_ops; +		break; +	case XFS_BLF_DIR_FREE_BUF: +		if (magic32 != XFS_DIR2_FREE_MAGIC && +		    magic32 != XFS_DIR3_FREE_MAGIC) { +			xfs_warn(mp, "Bad dir3 free magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_dir3_free_buf_ops; +		break; +	case XFS_BLF_DIR_LEAF1_BUF: +		if (magicda != XFS_DIR2_LEAF1_MAGIC && +		    magicda != XFS_DIR3_LEAF1_MAGIC) { +			xfs_warn(mp, "Bad dir leaf1 magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_dir3_leaf1_buf_ops; +		break; +	case XFS_BLF_DIR_LEAFN_BUF: +		if (magicda != XFS_DIR2_LEAFN_MAGIC && +		    magicda != XFS_DIR3_LEAFN_MAGIC) { +			xfs_warn(mp, "Bad dir leafn magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_dir3_leafn_buf_ops; +		break; +	case XFS_BLF_DA_NODE_BUF: +		if (magicda != XFS_DA_NODE_MAGIC && +		    magicda != XFS_DA3_NODE_MAGIC) { +			xfs_warn(mp, "Bad da node magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_da3_node_buf_ops; +		break; +	case XFS_BLF_ATTR_LEAF_BUF: +		if (magicda != XFS_ATTR_LEAF_MAGIC && +		    magicda != XFS_ATTR3_LEAF_MAGIC) { +			xfs_warn(mp, "Bad attr leaf magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_attr3_leaf_buf_ops; +		break; +	case XFS_BLF_ATTR_RMT_BUF: +		if (!xfs_sb_version_hascrc(&mp->m_sb)) +			break; +		if (magicda != XFS_ATTR3_RMT_MAGIC) { +			xfs_warn(mp, "Bad attr remote magic!"); +			ASSERT(0); +			break; +		} +		bp->b_ops = &xfs_attr3_rmt_buf_ops; +		break;  	default:  		break;  	}  }  /* + * Perform a 'normal' buffer recovery.  Each logged region of the + * buffer should be copied over the corresponding region in the + * given buffer.  The bitmap in the buf log format structure indicates + * where to place the logged data. + */ +STATIC void +xlog_recover_do_reg_buffer( +	struct xfs_mount	*mp, +	xlog_recover_item_t	*item, +	struct xfs_buf		*bp, +	xfs_buf_log_format_t	*buf_f) +{ +	int			i; +	int			bit; +	int			nbits; +	int                     error; + +	trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f); + +	bit = 0; +	i = 1;  /* 0 is the buf format structure */ +	while (1) { +		bit = xfs_next_bit(buf_f->blf_data_map, +				   buf_f->blf_map_size, bit); +		if (bit == -1) +			break; +		nbits = xfs_contig_bits(buf_f->blf_data_map, +					buf_f->blf_map_size, bit); +		ASSERT(nbits > 0); +		ASSERT(item->ri_buf[i].i_addr != NULL); +		ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0); +		ASSERT(BBTOB(bp->b_io_length) >= +		       ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT)); + +		/* +		 * Do a sanity check if this is a dquot buffer. Just checking +		 * the first dquot in the buffer should do. XXXThis is +		 * probably a good thing to do for other buf types also. +		 */ +		error = 0; +		if (buf_f->blf_flags & +		   (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { +			if (item->ri_buf[i].i_addr == NULL) { +				xfs_alert(mp, +					"XFS: NULL dquot in %s.", __func__); +				goto next; +			} +			if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) { +				xfs_alert(mp, +					"XFS: dquot too small (%d) in %s.", +					item->ri_buf[i].i_len, __func__); +				goto next; +			} +			error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr, +					       -1, 0, XFS_QMOPT_DOWARN, +					       "dquot_buf_recover"); +			if (error) +				goto next; +		} + +		memcpy(xfs_buf_offset(bp, +			(uint)bit << XFS_BLF_SHIFT),	/* dest */ +			item->ri_buf[i].i_addr,		/* source */ +			nbits<<XFS_BLF_SHIFT);		/* length */ + next: +		i++; +		bit += nbits; +	} + +	/* Shouldn't be any more regions */ +	ASSERT(i == item->ri_total); + +	xlog_recovery_validate_buf_type(mp, bp, buf_f); + +} + +/*   * Do some primitive error checking on ondisk dquot data structures.   */  int diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 1b04fe59c60..fa78a3f87c6 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -507,6 +507,8 @@ void		xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);  void		xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);  void		xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,  				       uint); +void		xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, +					struct xfs_buf *src_bp);  void		xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);  void		xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);  void		xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 8a0f6af5120..40871bf607f 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c @@ -768,6 +768,9 @@ xfs_trans_buf_set_type(  {  	struct xfs_buf_log_item	*bip = bp->b_fspriv; +	if (!tp) +		return; +  	ASSERT(bp->b_transp == tp);  	ASSERT(bip != NULL);  	ASSERT(atomic_read(&bip->bli_refcount) > 0); @@ -777,6 +780,20 @@ xfs_trans_buf_set_type(  	bip->__bli_format.blf_flags |= type;  } +void +xfs_trans_buf_copy_type( +	struct xfs_buf		*dst_bp, +	struct xfs_buf		*src_bp) +{ +	struct xfs_buf_log_item	*sbip = src_bp->b_fspriv; +	struct xfs_buf_log_item	*dbip = dst_bp->b_fspriv; +	uint			type; + +	type = sbip->__bli_format.blf_flags & XFS_BLF_TYPE_MASK; +	dbip->__bli_format.blf_flags &= ~XFS_BLF_TYPE_MASK; +	dbip->__bli_format.blf_flags |= type; +} +  /*   * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of   * dquots. However, unlike in inode buffer recovery, dquot buffers get  |