diff options
Diffstat (limited to 'fs/xfs/libxfs')
| -rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 30 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_alloc.h | 8 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr.c | 6 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.c | 3 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_remote.c | 2 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 65 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.h | 13 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_btree.c | 21 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_btree.h | 39 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_da_btree.c | 4 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2.c | 6 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2_block.c | 3 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2_data.c | 3 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2_leaf.c | 3 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2_node.c | 3 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_format.h | 18 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_fs.h | 10 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 10 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_sb.c | 10 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_symlink_remote.c | 7 | 
20 files changed, 203 insertions, 61 deletions
| diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index ffad7f20342f..3479294c1d58 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -482,7 +482,9 @@ xfs_agfl_verify(  		    be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)  			return false;  	} -	return true; + +	return xfs_log_check_lsn(mp, +				 be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn));  }  static void @@ -651,8 +653,8 @@ xfs_alloc_ag_vextent(  				 -((long)(args->len)));  	} -	XFS_STATS_INC(xs_allocx); -	XFS_STATS_ADD(xs_allocb, args->len); +	XFS_STATS_INC(args->mp, xs_allocx); +	XFS_STATS_ADD(args->mp, xs_allocb, args->len);  	return error;  } @@ -1808,8 +1810,8 @@ xfs_free_ag_extent(  	if (!isfl)  		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); -	XFS_STATS_INC(xs_freex); -	XFS_STATS_ADD(xs_freeb, len); +	XFS_STATS_INC(mp, xs_freex); +	XFS_STATS_ADD(mp, xs_freeb, len);  	trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright); @@ -2259,9 +2261,13 @@ xfs_agf_verify(   {  	struct xfs_agf	*agf = XFS_BUF_TO_AGF(bp); -	if (xfs_sb_version_hascrc(&mp->m_sb) && -	    !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))  			return false; +		if (!xfs_log_check_lsn(mp, +				be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn))) +			return false; +	}  	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&  	      XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && @@ -2503,7 +2509,7 @@ xfs_alloc_vextent(  		 * Try near allocation first, then anywhere-in-ag after  		 * the first a.g. fails.  		 */ -		if ((args->userdata  == XFS_ALLOC_INITIAL_USER_DATA) && +		if ((args->userdata & XFS_ALLOC_INITIAL_USER_DATA) &&  		    (mp->m_flags & XFS_MOUNT_32BITINODES)) {  			args->fsbno = XFS_AGB_TO_FSB(mp,  					((mp->m_agfrotor / rotorstep) % @@ -2634,6 +2640,14 @@ xfs_alloc_vextent(  		XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno),  			args->len);  #endif + +		/* Zero the extent if we were asked to do so */ +		if (args->userdata & XFS_ALLOC_USERDATA_ZERO) { +			error = xfs_zero_extent(args->ip, args->fsbno, args->len); +			if (error) +				goto error0; +		} +  	}  	xfs_perag_put(args->pag);  	return 0; diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h index ca1c8168373a..0ecde4d5cac8 100644 --- a/fs/xfs/libxfs/xfs_alloc.h +++ b/fs/xfs/libxfs/xfs_alloc.h @@ -101,6 +101,7 @@ typedef struct xfs_alloc_arg {  	struct xfs_mount *mp;		/* file system mount point */  	struct xfs_buf	*agbp;		/* buffer for a.g. freelist header */  	struct xfs_perag *pag;		/* per-ag struct for this agno */ +	struct xfs_inode *ip;		/* for userdata zeroing method */  	xfs_fsblock_t	fsbno;		/* file system block number */  	xfs_agnumber_t	agno;		/* allocation group number */  	xfs_agblock_t	agbno;		/* allocation group-relative block # */ @@ -120,15 +121,16 @@ typedef struct xfs_alloc_arg {  	char		wasdel;		/* set if allocation was prev delayed */  	char		wasfromfl;	/* set if allocation is from freelist */  	char		isfl;		/* set if is freelist blocks - !acctg */ -	char		userdata;	/* set if this is user data */ +	char		userdata;	/* mask defining userdata treatment */  	xfs_fsblock_t	firstblock;	/* io first block allocated */  } xfs_alloc_arg_t;  /*   * Defines for userdata   */ -#define XFS_ALLOC_USERDATA		1	/* allocation is for user data*/ -#define XFS_ALLOC_INITIAL_USER_DATA	2	/* special case start of file */ +#define XFS_ALLOC_USERDATA		(1 << 0)/* allocation is for user data*/ +#define XFS_ALLOC_INITIAL_USER_DATA	(1 << 1)/* special case start of file */ +#define XFS_ALLOC_USERDATA_ZERO		(1 << 2)/* zero extent on allocation */  xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp,  		struct xfs_perag *pag, xfs_extlen_t need); diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index ff065578969f..f949818fa1c7 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -125,7 +125,7 @@ xfs_attr_get(  	uint			lock_mode;  	int			error; -	XFS_STATS_INC(xs_attr_get); +	XFS_STATS_INC(ip->i_mount, xs_attr_get);  	if (XFS_FORCED_SHUTDOWN(ip->i_mount))  		return -EIO; @@ -209,7 +209,7 @@ xfs_attr_set(  	int			rsvd = (flags & ATTR_ROOT) != 0;  	int			error, err2, committed, local; -	XFS_STATS_INC(xs_attr_set); +	XFS_STATS_INC(mp, xs_attr_set);  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))  		return -EIO; @@ -412,7 +412,7 @@ xfs_attr_remove(  	xfs_fsblock_t		firstblock;  	int			error; -	XFS_STATS_INC(xs_attr_remove); +	XFS_STATS_INC(mp, xs_attr_remove);  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))  		return -EIO; diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 33df52d97ec7..aa187f7ba2dd 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -41,6 +41,7 @@  #include "xfs_buf_item.h"  #include "xfs_cksum.h"  #include "xfs_dir2.h" +#include "xfs_log.h"  /* @@ -266,6 +267,8 @@ xfs_attr3_leaf_verify(  			return false;  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) +			return false;  	} else {  		if (ichdr.magic != XFS_ATTR_LEAF_MAGIC)  			return false; diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c index f38f9bd81557..5ab95ffa4ae9 100644 --- a/fs/xfs/libxfs/xfs_attr_remote.c +++ b/fs/xfs/libxfs/xfs_attr_remote.c @@ -107,7 +107,7 @@ xfs_attr3_rmt_verify(  	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))  		return false;  	if (be32_to_cpu(rmt->rm_offset) + -				be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX) +				be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)  		return false;  	if (rmt->rm_owner == 0)  		return false; diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 8e2010d53b07..119c2422aac7 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -948,14 +948,16 @@ xfs_bmap_local_to_extents(  	bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);  	/* -	 * Initialise the block and copy the data +	 * Initialize the block, copy the data and log the remote buffer.  	 * -	 * Note: init_fn must set the buffer log item type correctly! +	 * The callout is responsible for logging because the remote format +	 * might differ from the local format and thus we don't know how much to +	 * log here. Note that init_fn must also set the buffer log item type +	 * correctly.  	 */  	init_fn(tp, bp, ip, ifp); -	/* account for the change in fork size and log everything */ -	xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); +	/* account for the change in fork size */  	xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);  	xfs_bmap_local_to_extents_empty(ip, whichfork);  	flags |= XFS_ILOG_CORE; @@ -1435,7 +1437,7 @@ xfs_bmap_search_extents(  	xfs_ifork_t	*ifp;		/* inode fork pointer */  	xfs_bmbt_rec_host_t  *ep;            /* extent record pointer */ -	XFS_STATS_INC(xs_look_exlist); +	XFS_STATS_INC(ip->i_mount, xs_look_exlist);  	ifp = XFS_IFORK_PTR(ip, fork);  	ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp); @@ -1732,7 +1734,7 @@ xfs_bmap_add_extent_delay_real(  	ASSERT(!bma->cur ||  	       (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); -	XFS_STATS_INC(xs_add_exlist); +	XFS_STATS_INC(mp, xs_add_exlist);  #define	LEFT		r[0]  #define	RIGHT		r[1] @@ -2286,7 +2288,7 @@ xfs_bmap_add_extent_unwritten_real(  	ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));  	ASSERT(!isnullstartblock(new->br_startblock)); -	XFS_STATS_INC(xs_add_exlist); +	XFS_STATS_INC(mp, xs_add_exlist);  #define	LEFT		r[0]  #define	RIGHT		r[1] @@ -2946,7 +2948,7 @@ xfs_bmap_add_extent_hole_real(  	ASSERT(!bma->cur ||  	       !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); -	XFS_STATS_INC(xs_add_exlist); +	XFS_STATS_INC(mp, xs_add_exlist);  	state = 0;  	if (whichfork == XFS_ATTR_FORK) @@ -3800,8 +3802,13 @@ xfs_bmap_btalloc(  	args.wasdel = ap->wasdel;  	args.isfl = 0;  	args.userdata = ap->userdata; -	if ((error = xfs_alloc_vextent(&args))) +	if (ap->userdata & XFS_ALLOC_USERDATA_ZERO) +		args.ip = ap->ip; + +	error = xfs_alloc_vextent(&args); +	if (error)  		return error; +  	if (tryagain && args.fsbno == NULLFSBLOCK) {  		/*  		 * Exact allocation failed. Now try with alignment @@ -4036,7 +4043,7 @@ xfs_bmapi_read(  	if (XFS_FORCED_SHUTDOWN(mp))  		return -EIO; -	XFS_STATS_INC(xs_blk_mapr); +	XFS_STATS_INC(mp, xs_blk_mapr);  	ifp = XFS_IFORK_PTR(ip, whichfork); @@ -4221,7 +4228,7 @@ xfs_bmapi_delay(  	if (XFS_FORCED_SHUTDOWN(mp))  		return -EIO; -	XFS_STATS_INC(xs_blk_mapw); +	XFS_STATS_INC(mp, xs_blk_mapw);  	if (!(ifp->if_flags & XFS_IFEXTENTS)) {  		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); @@ -4300,11 +4307,14 @@ xfs_bmapi_allocate(  	/*  	 * Indicate if this is the first user data in the file, or just any -	 * user data. +	 * user data. And if it is userdata, indicate whether it needs to +	 * be initialised to zero during allocation.  	 */  	if (!(bma->flags & XFS_BMAPI_METADATA)) {  		bma->userdata = (bma->offset == 0) ?  			XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; +		if (bma->flags & XFS_BMAPI_ZERO) +			bma->userdata |= XFS_ALLOC_USERDATA_ZERO;  	}  	bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1; @@ -4419,6 +4429,17 @@ xfs_bmapi_convert_unwritten(  	mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)  				? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; +	/* +	 * Before insertion into the bmbt, zero the range being converted +	 * if required. +	 */ +	if (flags & XFS_BMAPI_ZERO) { +		error = xfs_zero_extent(bma->ip, mval->br_startblock, +					mval->br_blockcount); +		if (error) +			return error; +	} +  	error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx,  			&bma->cur, mval, bma->firstblock, bma->flist,  			&tmp_logflags); @@ -4512,6 +4533,18 @@ xfs_bmapi_write(  	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); +	/* zeroing is for currently only for data extents, not metadata */ +	ASSERT((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)) != +			(XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)); +	/* +	 * we can allocate unwritten extents or pre-zero allocated blocks, +	 * but it makes no sense to do both at once. This would result in +	 * zeroing the unwritten extent twice, but it still being an +	 * unwritten extent.... +	 */ +	ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) != +			(XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)); +  	if (unlikely(XFS_TEST_ERROR(  	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&  	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), @@ -4525,7 +4558,7 @@ xfs_bmapi_write(  	ifp = XFS_IFORK_PTR(ip, whichfork); -	XFS_STATS_INC(xs_blk_mapw); +	XFS_STATS_INC(mp, xs_blk_mapw);  	if (*firstblock == NULLFSBLOCK) {  		if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) @@ -4718,12 +4751,12 @@ xfs_bmap_del_extent(  	xfs_filblks_t		temp2;	/* for indirect length calculations */  	int			state = 0; -	XFS_STATS_INC(xs_del_exlist); +	mp = ip->i_mount; +	XFS_STATS_INC(mp, xs_del_exlist);  	if (whichfork == XFS_ATTR_FORK)  		state |= BMAP_ATTRFORK; -	mp = ip->i_mount;  	ifp = XFS_IFORK_PTR(ip, whichfork);  	ASSERT((*idx >= 0) && (*idx < ifp->if_bytes /  		(uint)sizeof(xfs_bmbt_rec_t))); @@ -5070,7 +5103,7 @@ xfs_bunmapi(  		*done = 1;  		return 0;  	} -	XFS_STATS_INC(xs_blk_unmap); +	XFS_STATS_INC(mp, xs_blk_unmap);  	isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);  	start = bno;  	bno = start + len - 1; diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 6aaa0c1c7200..a160f8a5a3fc 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -52,9 +52,9 @@ struct xfs_bmalloca {  	xfs_extlen_t		minleft; /* amount must be left after alloc */  	bool			eof;	/* set if allocating past last extent */  	bool			wasdel;	/* replacing a delayed allocation */ -	bool			userdata;/* set if is user data */  	bool			aeof;	/* allocated space at eof */  	bool			conv;	/* overwriting unwritten extents */ +	char			userdata;/* userdata mask */  	int			flags;  }; @@ -109,6 +109,14 @@ typedef	struct xfs_bmap_free   */  #define XFS_BMAPI_CONVERT	0x040 +/* + * allocate zeroed extents - this requires all newly allocated user data extents + * to be initialised to zero. It will be ignored if XFS_BMAPI_METADATA is set. + * Use in conjunction with XFS_BMAPI_CONVERT to convert unwritten extents found + * during the allocation range to zeroed written extents. + */ +#define XFS_BMAPI_ZERO		0x080 +  #define XFS_BMAPI_FLAGS \  	{ XFS_BMAPI_ENTIRE,	"ENTIRE" }, \  	{ XFS_BMAPI_METADATA,	"METADATA" }, \ @@ -116,7 +124,8 @@ typedef	struct xfs_bmap_free  	{ XFS_BMAPI_PREALLOC,	"PREALLOC" }, \  	{ XFS_BMAPI_IGSTATE,	"IGSTATE" }, \  	{ XFS_BMAPI_CONTIG,	"CONTIG" }, \ -	{ XFS_BMAPI_CONVERT,	"CONVERT" } +	{ XFS_BMAPI_CONVERT,	"CONVERT" }, \ +	{ XFS_BMAPI_ZERO,	"ZERO" }  static inline int xfs_bmapi_aflag(int w) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index f7d7ee7a2607..af1bbee5586e 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -32,6 +32,7 @@  #include "xfs_trace.h"  #include "xfs_cksum.h"  #include "xfs_alloc.h" +#include "xfs_log.h"  /*   * Cursor allocation zone. @@ -222,7 +223,7 @@ xfs_btree_check_ptr(   * long-form btree header.   *   * Prior to calculting the CRC, pull the LSN out of the buffer log item and put - * it into the buffer so recovery knows what the last modifcation was that made + * it into the buffer so recovery knows what the last modification was that made   * it to disk.   */  void @@ -243,8 +244,14 @@ bool  xfs_btree_lblock_verify_crc(  	struct xfs_buf		*bp)  { -	if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) +	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp); +	struct xfs_mount	*mp = bp->b_target->bt_mount; + +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn))) +			return false;  		return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); +	}  	return true;  } @@ -254,7 +261,7 @@ xfs_btree_lblock_verify_crc(   * short-form btree header.   *   * Prior to calculting the CRC, pull the LSN out of the buffer log item and put - * it into the buffer so recovery knows what the last modifcation was that made + * it into the buffer so recovery knows what the last modification was that made   * it to disk.   */  void @@ -275,8 +282,14 @@ bool  xfs_btree_sblock_verify_crc(  	struct xfs_buf		*bp)  { -	if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) +	struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp); +	struct xfs_mount	*mp = bp->b_target->bt_mount; + +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn))) +			return false;  		return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); +	}  	return true;  } diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index 8f18bab73ea5..992dec0638f3 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -84,31 +84,38 @@ union xfs_btree_rec {  /*   * Generic stats interface   */ -#define __XFS_BTREE_STATS_INC(type, stat) \ -	XFS_STATS_INC(xs_ ## type ## _2_ ## stat) -#define XFS_BTREE_STATS_INC(cur, stat)  \ +#define __XFS_BTREE_STATS_INC(mp, type, stat) \ +	XFS_STATS_INC(mp, xs_ ## type ## _2_ ## stat) +#define XFS_BTREE_STATS_INC(cur, stat)	\  do {    \ +	struct xfs_mount *__mp = cur->bc_mp; \  	switch (cur->bc_btnum) {  \ -	case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break;	\ -	case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break;	\ -	case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break;	\ -	case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break;	\ -	case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break;	\ +	case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(__mp, abtb, stat); break; \ +	case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(__mp, abtc, stat); break; \ +	case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(__mp, bmbt, stat); break; \ +	case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(__mp, ibt, stat); break; \ +	case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(__mp, fibt, stat); break; \  	case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;	\  	}       \  } while (0) -#define __XFS_BTREE_STATS_ADD(type, stat, val) \ -	XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val) +#define __XFS_BTREE_STATS_ADD(mp, type, stat, val) \ +	XFS_STATS_ADD(mp, xs_ ## type ## _2_ ## stat, val)  #define XFS_BTREE_STATS_ADD(cur, stat, val)  \  do {    \ +	struct xfs_mount *__mp = cur->bc_mp; \  	switch (cur->bc_btnum) {  \ -	case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \ -	case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ -	case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ -	case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ -	case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \ -	case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;	\ +	case XFS_BTNUM_BNO:	\ +		__XFS_BTREE_STATS_ADD(__mp, abtb, stat, val); break; \ +	case XFS_BTNUM_CNT:	\ +		__XFS_BTREE_STATS_ADD(__mp, abtc, stat, val); break; \ +	case XFS_BTNUM_BMAP:	\ +		__XFS_BTREE_STATS_ADD(__mp, bmbt, stat, val); break; \ +	case XFS_BTNUM_INO:	\ +		__XFS_BTREE_STATS_ADD(__mp, ibt, stat, val); break; \ +	case XFS_BTNUM_FINO:	\ +		__XFS_BTREE_STATS_ADD(__mp, fibt, stat, val); break; \ +	case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \  	}       \  } while (0) diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index be43248a5822..e89a0f8f827c 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -39,6 +39,7 @@  #include "xfs_trace.h"  #include "xfs_cksum.h"  #include "xfs_buf_item.h" +#include "xfs_log.h"  /*   * xfs_da_btree.c @@ -150,6 +151,8 @@ xfs_da3_node_verify(  			return false;  		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) +			return false;  	} else {  		if (ichdr.magic != XFS_DA_NODE_MAGIC)  			return false; @@ -322,6 +325,7 @@ xfs_da3_node_create(  	if (xfs_sb_version_hascrc(&mp->m_sb)) {  		struct xfs_da3_node_hdr *hdr3 = bp->b_addr; +		memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));  		ichdr.magic = XFS_DA3_NODE_MAGIC;  		hdr3->info.blkno = cpu_to_be64(bp->b_bn);  		hdr3->info.owner = cpu_to_be64(args->dp->i_ino); diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c index 9de401d297e5..2fb53a5c0a74 100644 --- a/fs/xfs/libxfs/xfs_dir2.c +++ b/fs/xfs/libxfs/xfs_dir2.c @@ -271,7 +271,7 @@ xfs_dir_createname(  		rval = xfs_dir_ino_validate(tp->t_mountp, inum);  		if (rval)  			return rval; -		XFS_STATS_INC(xs_dir_create); +		XFS_STATS_INC(dp->i_mount, xs_dir_create);  	}  	args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); @@ -365,7 +365,7 @@ xfs_dir_lookup(  	int		lock_mode;  	ASSERT(S_ISDIR(dp->i_d.di_mode)); -	XFS_STATS_INC(xs_dir_lookup); +	XFS_STATS_INC(dp->i_mount, xs_dir_lookup);  	/*  	 * We need to use KM_NOFS here so that lockdep will not throw false @@ -444,7 +444,7 @@ xfs_dir_removename(  	int		v;		/* type-checking value */  	ASSERT(S_ISDIR(dp->i_d.di_mode)); -	XFS_STATS_INC(xs_dir_remove); +	XFS_STATS_INC(dp->i_mount, xs_dir_remove);  	args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);  	if (!args) diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c index 4778d1dd511a..9c10e2b8cfcb 100644 --- a/fs/xfs/libxfs/xfs_dir2_block.c +++ b/fs/xfs/libxfs/xfs_dir2_block.c @@ -34,6 +34,7 @@  #include "xfs_error.h"  #include "xfs_trace.h"  #include "xfs_cksum.h" +#include "xfs_log.h"  /*   * Local function prototypes. @@ -71,6 +72,8 @@ xfs_dir3_block_verify(  			return false;  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) +			return false;  	} else {  		if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))  			return false; diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c index 824131e71bc5..af71a84f343c 100644 --- a/fs/xfs/libxfs/xfs_dir2_data.c +++ b/fs/xfs/libxfs/xfs_dir2_data.c @@ -31,6 +31,7 @@  #include "xfs_trans.h"  #include "xfs_buf_item.h"  #include "xfs_cksum.h" +#include "xfs_log.h"  /*   * Check the consistency of the data block. @@ -224,6 +225,8 @@ xfs_dir3_data_verify(  			return false;  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) +			return false;  	} else {  		if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC))  			return false; diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c index f300240ebb8d..3923e1f94697 100644 --- a/fs/xfs/libxfs/xfs_dir2_leaf.c +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c @@ -33,6 +33,7 @@  #include "xfs_trans.h"  #include "xfs_buf_item.h"  #include "xfs_cksum.h" +#include "xfs_log.h"  /*   * Local function declarations. @@ -164,6 +165,8 @@ xfs_dir3_leaf_verify(  			return false;  		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(leaf3->info.lsn))) +			return false;  	} else {  		if (leaf->hdr.info.magic != cpu_to_be16(magic))  			return false; diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index cc28e924545b..70b0cb2fd556 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c @@ -33,6 +33,7 @@  #include "xfs_trans.h"  #include "xfs_buf_item.h"  #include "xfs_cksum.h" +#include "xfs_log.h"  /*   * Function declarations. @@ -97,6 +98,8 @@ xfs_dir3_free_verify(  			return false;  		if (be64_to_cpu(hdr3->blkno) != bp->b_bn)  			return false; +		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) +			return false;  	} else {  		if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC))  			return false; diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 9590a069e556..8774498ce0ff 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -60,6 +60,14 @@ struct xfs_ifork;  #define	XFS_SB_VERSION_MOREBITSBIT	0x8000  /* + * The size of a single extended attribute on disk is limited by + * the size of index values within the attribute entries themselves. + * These are be16 fields, so we can only support attribute data + * sizes up to 2^16 bytes in length. + */ +#define XFS_XATTR_SIZE_MAX (1 << 16) + +/*   * Supported feature bit list is just all bits in the versionnum field because   * we've used them all up and understand them all. Except, of course, for the   * shared superblock bit, which nobody knows what it does and so is unsupported. @@ -1483,13 +1491,17 @@ struct xfs_acl {   */  #define XFS_ACL_MAX_ENTRIES(mp)	\  	(xfs_sb_version_hascrc(&mp->m_sb) \ -		?  (XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \ +		?  (XFS_XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \  						sizeof(struct xfs_acl_entry) \  		: 25) -#define XFS_ACL_MAX_SIZE(mp) \ +#define XFS_ACL_SIZE(cnt) \  	(sizeof(struct xfs_acl) + \ -		sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp))) +		sizeof(struct xfs_acl_entry) * cnt) + +#define XFS_ACL_MAX_SIZE(mp) \ +	XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp))) +  /* On-disk XFS extended attribute names */  #define SGI_ACL_FILE		"SGI_ACL_FILE" diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 89689c6a43e2..b2b73a998d42 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -490,6 +490,16 @@ typedef struct xfs_swapext  #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH		0x2	/* don't flush log nor data */  /* + * ioctl limits + */ +#ifdef XATTR_LIST_MAX +#  define XFS_XATTR_LIST_MAX XATTR_LIST_MAX +#else +#  define XFS_XATTR_LIST_MAX 65536 +#endif + + +/*   * ioctl commands that are used by Linux filesystems   */  #define XFS_IOC_GETXFLAGS	FS_IOC_GETFLAGS diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 54deb2d12ac6..70c1db99f6a7 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -38,6 +38,7 @@  #include "xfs_icreate_item.h"  #include "xfs_icache.h"  #include "xfs_trace.h" +#include "xfs_log.h"  /* @@ -2500,9 +2501,14 @@ xfs_agi_verify(  	struct xfs_mount *mp = bp->b_target->bt_mount;  	struct xfs_agi	*agi = XFS_BUF_TO_AGI(bp); -	if (xfs_sb_version_hascrc(&mp->m_sb) && -	    !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) +			return false; +		if (!xfs_log_check_lsn(mp, +				be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn)))  			return false; +	} +  	/*  	 * Validate the magic number of the agi block.  	 */ diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 47425140f343..a0b071d881a0 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -35,6 +35,7 @@  #include "xfs_bmap_btree.h"  #include "xfs_alloc_btree.h"  #include "xfs_ialloc_btree.h" +#include "xfs_log.h"  /*   * Physical superblock buffer manipulations. Shared with libxfs in userspace. @@ -163,6 +164,15 @@ xfs_mount_validate_sb(  "Filesystem can not be safely mounted by this kernel.");  			return -EINVAL;  		} +	} else if (xfs_sb_version_hascrc(sbp)) { +		/* +		 * We can't read verify the sb LSN because the read verifier is +		 * called before the log is allocated and processed. We know the +		 * log is set up before write verifier (!check_version) calls, +		 * so just check it here. +		 */ +		if (!xfs_log_check_lsn(mp, sbp->sb_lsn)) +			return -EFSCORRUPTED;  	}  	if (xfs_sb_version_has_pquotino(sbp)) { diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c index 8f8af05b3f13..cb6fd20a4d3d 100644 --- a/fs/xfs/libxfs/xfs_symlink_remote.c +++ b/fs/xfs/libxfs/xfs_symlink_remote.c @@ -31,6 +31,7 @@  #include "xfs_cksum.h"  #include "xfs_trans.h"  #include "xfs_buf_item.h" +#include "xfs_log.h"  /* @@ -60,6 +61,7 @@ xfs_symlink_hdr_set(  	if (!xfs_sb_version_hascrc(&mp->m_sb))  		return 0; +	memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));  	dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);  	dsl->sl_offset = cpu_to_be32(offset);  	dsl->sl_bytes = cpu_to_be32(size); @@ -116,6 +118,8 @@ xfs_symlink_verify(  		return false;  	if (dsl->sl_owner == 0)  		return false; +	if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn))) +		return false;  	return true;  } @@ -183,6 +187,7 @@ xfs_symlink_local_to_remote(  	if (!xfs_sb_version_hascrc(&mp->m_sb)) {  		bp->b_ops = NULL;  		memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); +		xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);  		return;  	} @@ -198,4 +203,6 @@ xfs_symlink_local_to_remote(  	buf = bp->b_addr;  	buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);  	memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); +	xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + +					ifp->if_bytes - 1);  } | 
