diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_bmap_btree.c')
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap_btree.c | 123 | 
1 files changed, 102 insertions, 21 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index bf3f1b36fdd2..71f2d50f7823 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -15,6 +15,7 @@  #include "xfs_trans.h"  #include "xfs_alloc.h"  #include "xfs_btree.h" +#include "xfs_btree_staging.h"  #include "xfs_bmap_btree.h"  #include "xfs_bmap.h"  #include "xfs_error.h" @@ -272,7 +273,7 @@ xfs_bmbt_free_block(  	xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);  	error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo, -			XFS_AG_RESV_NONE); +			XFS_AG_RESV_NONE, false);  	if (error)  		return error; @@ -288,10 +289,7 @@ xfs_bmbt_get_minrecs(  	int			level)  {  	if (level == cur->bc_nlevels - 1) { -		struct xfs_ifork	*ifp; - -		ifp = xfs_ifork_ptr(cur->bc_ino.ip, -				    cur->bc_ino.whichfork); +		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);  		return xfs_bmbt_maxrecs(cur->bc_mp,  					ifp->if_broot_bytes, level == 0) / 2; @@ -306,10 +304,7 @@ xfs_bmbt_get_maxrecs(  	int			level)  {  	if (level == cur->bc_nlevels - 1) { -		struct xfs_ifork	*ifp; - -		ifp = xfs_ifork_ptr(cur->bc_ino.ip, -				    cur->bc_ino.whichfork); +		struct xfs_ifork	*ifp = xfs_btree_ifork_ptr(cur);  		return xfs_bmbt_maxrecs(cur->bc_mp,  					ifp->if_broot_bytes, level == 0); @@ -543,23 +538,19 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {  	.keys_contiguous	= xfs_bmbt_keys_contiguous,  }; -/* - * Allocate a new bmap btree cursor. - */ -struct xfs_btree_cur *				/* new bmap btree cursor */ -xfs_bmbt_init_cursor( -	struct xfs_mount	*mp,		/* file system mount point */ -	struct xfs_trans	*tp,		/* transaction pointer */ -	struct xfs_inode	*ip,		/* inode owning the btree */ -	int			whichfork)	/* data or attr fork */ +static struct xfs_btree_cur * +xfs_bmbt_init_common( +	struct xfs_mount	*mp, +	struct xfs_trans	*tp, +	struct xfs_inode	*ip, +	int			whichfork)  { -	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, whichfork);  	struct xfs_btree_cur	*cur; +  	ASSERT(whichfork != XFS_COW_FORK);  	cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_BMAP,  			mp->m_bm_maxlevels[whichfork], xfs_bmbt_cur_cache); -	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2);  	cur->bc_ops = &xfs_bmbt_ops; @@ -567,10 +558,30 @@ xfs_bmbt_init_cursor(  	if (xfs_has_crc(mp))  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; -	cur->bc_ino.forksize = xfs_inode_fork_size(ip, whichfork);  	cur->bc_ino.ip = ip;  	cur->bc_ino.allocated = 0;  	cur->bc_ino.flags = 0; + +	return cur; +} + +/* + * Allocate a new bmap btree cursor. + */ +struct xfs_btree_cur * +xfs_bmbt_init_cursor( +	struct xfs_mount	*mp, +	struct xfs_trans	*tp, +	struct xfs_inode	*ip, +	int			whichfork) +{ +	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, whichfork); +	struct xfs_btree_cur	*cur; + +	cur = xfs_bmbt_init_common(mp, tp, ip, whichfork); + +	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; +	cur->bc_ino.forksize = xfs_inode_fork_size(ip, whichfork);  	cur->bc_ino.whichfork = whichfork;  	return cur; @@ -588,6 +599,76 @@ xfs_bmbt_block_maxrecs(  }  /* + * Allocate a new bmap btree cursor for reloading an inode block mapping data + * structure.  Note that callers can use the staged cursor to reload extents + * format inode forks if they rebuild the iext tree and commit the staged + * cursor immediately. + */ +struct xfs_btree_cur * +xfs_bmbt_stage_cursor( +	struct xfs_mount	*mp, +	struct xfs_inode	*ip, +	struct xbtree_ifakeroot	*ifake) +{ +	struct xfs_btree_cur	*cur; +	struct xfs_btree_ops	*ops; + +	/* data fork always has larger maxheight */ +	cur = xfs_bmbt_init_common(mp, NULL, ip, XFS_DATA_FORK); +	cur->bc_nlevels = ifake->if_levels; +	cur->bc_ino.forksize = ifake->if_fork_size; + +	/* Don't let anyone think we're attached to the real fork yet. */ +	cur->bc_ino.whichfork = -1; +	xfs_btree_stage_ifakeroot(cur, ifake, &ops); +	ops->update_cursor = NULL; +	return cur; +} + +/* + * Swap in the new inode fork root.  Once we pass this point the newly rebuilt + * mappings are in place and we have to kill off any old btree blocks. + */ +void +xfs_bmbt_commit_staged_btree( +	struct xfs_btree_cur	*cur, +	struct xfs_trans	*tp, +	int			whichfork) +{ +	struct xbtree_ifakeroot	*ifake = cur->bc_ino.ifake; +	struct xfs_ifork	*ifp; +	static const short	brootflag[2] = {XFS_ILOG_DBROOT, XFS_ILOG_ABROOT}; +	static const short	extflag[2] = {XFS_ILOG_DEXT, XFS_ILOG_AEXT}; +	int			flags = XFS_ILOG_CORE; + +	ASSERT(cur->bc_flags & XFS_BTREE_STAGING); +	ASSERT(whichfork != XFS_COW_FORK); + +	/* +	 * Free any resources hanging off the real fork, then shallow-copy the +	 * staging fork's contents into the real fork to transfer everything +	 * we just built. +	 */ +	ifp = xfs_ifork_ptr(cur->bc_ino.ip, whichfork); +	xfs_idestroy_fork(ifp); +	memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork)); + +	switch (ifp->if_format) { +	case XFS_DINODE_FMT_EXTENTS: +		flags |= extflag[whichfork]; +		break; +	case XFS_DINODE_FMT_BTREE: +		flags |= brootflag[whichfork]; +		break; +	default: +		ASSERT(0); +		break; +	} +	xfs_trans_log_inode(tp, cur->bc_ino.ip, flags); +	xfs_btree_commit_ifakeroot(cur, tp, whichfork, &xfs_bmbt_ops); +} + +/*   * Calculate number of records in a bmap btree block.   */  int  |