diff options
| author | Dave Chinner <dchinner@redhat.com> | 2012-11-12 22:54:13 +1100 | 
|---|---|---|
| committer | Ben Myers <bpm@sgi.com> | 2012-11-15 21:34:43 -0600 | 
| commit | 2025207ca6738a1217126ef14af9d104433f9824 (patch) | |
| tree | 522cac64d22f59063e16e7e2aec5a1688fa77a6b /fs/xfs/xfs_dir2_node.c | |
| parent | 82025d7f79148fe66a1594a0ebe4ab38152cf9e6 (diff) | |
| download | olio-linux-3.10-2025207ca6738a1217126ef14af9d104433f9824.tar.xz olio-linux-3.10-2025207ca6738a1217126ef14af9d104433f9824.zip  | |
xfs: factor dir2 free block reading
Also factor out the updating of the free block when removing entries
from leaf blocks, and add a verifier callback for reads.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Phil White <pwhite@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_dir2_node.c')
| -rw-r--r-- | fs/xfs/xfs_dir2_node.c | 218 | 
1 files changed, 140 insertions, 78 deletions
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 290c2b1016a..d7f899dfbff 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -55,6 +55,57 @@ static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,  static int xfs_dir2_node_addname_int(xfs_da_args_t *args,  				     xfs_da_state_blk_t *fblk); +static void +xfs_dir2_free_verify( +	struct xfs_buf		*bp) +{ +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_dir2_free_hdr *hdr = bp->b_addr; +	int			block_ok = 0; + +	block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC); +	if (!block_ok) { +		XFS_CORRUPTION_ERROR("xfs_dir2_free_verify magic", +				     XFS_ERRLEVEL_LOW, mp, hdr); +		xfs_buf_ioerror(bp, EFSCORRUPTED); +	} + +	bp->b_iodone = NULL; +	xfs_buf_ioend(bp, 0); +} + +static int +__xfs_dir2_free_read( +	struct xfs_trans	*tp, +	struct xfs_inode	*dp, +	xfs_dablk_t		fbno, +	xfs_daddr_t		mappedbno, +	struct xfs_buf		**bpp) +{ +	return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, +					XFS_DATA_FORK, xfs_dir2_free_verify); +} + +int +xfs_dir2_free_read( +	struct xfs_trans	*tp, +	struct xfs_inode	*dp, +	xfs_dablk_t		fbno, +	struct xfs_buf		**bpp) +{ +	return __xfs_dir2_free_read(tp, dp, fbno, -1, bpp); +} + +static int +xfs_dir2_free_try_read( +	struct xfs_trans	*tp, +	struct xfs_inode	*dp, +	xfs_dablk_t		fbno, +	struct xfs_buf		**bpp) +{ +	return __xfs_dir2_free_read(tp, dp, fbno, -2, bpp); +} +  /*   * Log entries from a freespace block.   */ @@ -394,12 +445,10 @@ xfs_dir2_leafn_lookup_for_addname(  				 */  				if (curbp)  					xfs_trans_brelse(tp, curbp); -				/* -				 * Read the free block. -				 */ -				error = xfs_da_read_buf(tp, dp, + +				error = xfs_dir2_free_read(tp, dp,  						xfs_dir2_db_to_da(mp, newfdb), -						-1, &curbp, XFS_DATA_FORK, NULL); +						&curbp);  				if (error)  					return error;  				free = curbp->b_addr; @@ -825,6 +874,77 @@ xfs_dir2_leafn_rebalance(  	}  } +static int +xfs_dir2_data_block_free( +	xfs_da_args_t		*args, +	struct xfs_dir2_data_hdr *hdr, +	struct xfs_dir2_free	*free, +	xfs_dir2_db_t		fdb, +	int			findex, +	struct xfs_buf		*fbp, +	int			longest) +{ +	struct xfs_trans	*tp = args->trans; +	int			logfree = 0; + +	if (!hdr) { +		/* One less used entry in the free table.  */ +		be32_add_cpu(&free->hdr.nused, -1); +		xfs_dir2_free_log_header(tp, fbp); + +		/* +		 * If this was the last entry in the table, we can trim the +		 * table size back.  There might be other entries at the end +		 * referring to non-existent data blocks, get those too. +		 */ +		if (findex == be32_to_cpu(free->hdr.nvalid) - 1) { +			int	i;		/* free entry index */ + +			for (i = findex - 1; i >= 0; i--) { +				if (free->bests[i] != cpu_to_be16(NULLDATAOFF)) +					break; +			} +			free->hdr.nvalid = cpu_to_be32(i + 1); +			logfree = 0; +		} else { +			/* Not the last entry, just punch it out.  */ +			free->bests[findex] = cpu_to_be16(NULLDATAOFF); +			logfree = 1; +		} +		/* +		 * If there are no useful entries left in the block, +		 * get rid of the block if we can. +		 */ +		if (!free->hdr.nused) { +			int error; + +			error = xfs_dir2_shrink_inode(args, fdb, fbp); +			if (error == 0) { +				fbp = NULL; +				logfree = 0; +			} else if (error != ENOSPC || args->total != 0) +				return error; +			/* +			 * It's possible to get ENOSPC if there is no +			 * space reservation.  In this case some one +			 * else will eventually get rid of this block. +			 */ +		} +	} else { +		/* +		 * Data block is not empty, just set the free entry to the new +		 * value. +		 */ +		free->bests[findex] = cpu_to_be16(longest); +		logfree = 1; +	} + +	/* Log the free entry that changed, unless we got rid of it.  */ +	if (logfree) +		xfs_dir2_free_log_bests(tp, fbp, findex, findex); +	return 0; +} +  /*   * Remove an entry from a node directory.   * This removes the leaf entry and the data entry, @@ -908,15 +1028,14 @@ xfs_dir2_leafn_remove(  		xfs_dir2_db_t	fdb;		/* freeblock block number */  		int		findex;		/* index in freeblock entries */  		xfs_dir2_free_t	*free;		/* freeblock structure */ -		int		logfree;	/* need to log free entry */  		/*  		 * Convert the data block number to a free block,  		 * read in the free block.  		 */  		fdb = xfs_dir2_db_to_fdb(mp, db); -		error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb), -					-1, &fbp, XFS_DATA_FORK, NULL); +		error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(mp, fdb), +					   &fbp);  		if (error)  			return error;  		free = fbp->b_addr; @@ -954,68 +1073,12 @@ xfs_dir2_leafn_remove(  		 * If we got rid of the data block, we can eliminate that entry  		 * in the free block.  		 */ -		if (hdr == NULL) { -			/* -			 * One less used entry in the free table. -			 */ -			be32_add_cpu(&free->hdr.nused, -1); -			xfs_dir2_free_log_header(tp, fbp); -			/* -			 * If this was the last entry in the table, we can -			 * trim the table size back.  There might be other -			 * entries at the end referring to non-existent -			 * data blocks, get those too. -			 */ -			if (findex == be32_to_cpu(free->hdr.nvalid) - 1) { -				int	i;		/* free entry index */ - -				for (i = findex - 1; -				     i >= 0 && -				     free->bests[i] == cpu_to_be16(NULLDATAOFF); -				     i--) -					continue; -				free->hdr.nvalid = cpu_to_be32(i + 1); -				logfree = 0; -			} -			/* -			 * Not the last entry, just punch it out. -			 */ -			else { -				free->bests[findex] = cpu_to_be16(NULLDATAOFF); -				logfree = 1; -			} -			/* -			 * If there are no useful entries left in the block, -			 * get rid of the block if we can. -			 */ -			if (!free->hdr.nused) { -				error = xfs_dir2_shrink_inode(args, fdb, fbp); -				if (error == 0) { -					fbp = NULL; -					logfree = 0; -				} else if (error != ENOSPC || args->total != 0) -					return error; -				/* -				 * It's possible to get ENOSPC if there is no -				 * space reservation.  In this case some one -				 * else will eventually get rid of this block. -				 */ -			} -		} -		/* -		 * Data block is not empty, just set the free entry to -		 * the new value. -		 */ -		else { -			free->bests[findex] = cpu_to_be16(longest); -			logfree = 1; -		} -		/* -		 * Log the free entry that changed, unless we got rid of it. -		 */ -		if (logfree) -			xfs_dir2_free_log_bests(tp, fbp, findex, findex); +		error = xfs_dir2_data_block_free(args, hdr, free, +						 fdb, findex, fbp, longest); +		if (error) +			return error;  	} +  	xfs_dir2_leafn_check(dp, bp);  	/*  	 * Return indication of whether this leaf block is empty enough @@ -1453,9 +1516,9 @@ xfs_dir2_node_addname_int(  			 * This should be really rare, so there's no reason  			 * to avoid it.  			 */ -			error = xfs_da_read_buf(tp, dp, -						xfs_dir2_db_to_da(mp, fbno), -2, -						&fbp, XFS_DATA_FORK, NULL); +			error = xfs_dir2_free_try_read(tp, dp, +						xfs_dir2_db_to_da(mp, fbno), +						&fbp);  			if (error)  				return error;  			if (!fbp) @@ -1518,8 +1581,9 @@ xfs_dir2_node_addname_int(  		 * that was just allocated.  		 */  		fbno = xfs_dir2_db_to_fdb(mp, dbno); -		error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno), -2, -					&fbp, XFS_DATA_FORK, NULL); +		error = xfs_dir2_free_try_read(tp, dp, +					       xfs_dir2_db_to_da(mp, fbno), +					       &fbp);  		if (error)  			return error; @@ -1915,17 +1979,15 @@ xfs_dir2_node_trim_free(  	/*  	 * Read the freespace block.  	 */ -	error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -2, &bp, -				XFS_DATA_FORK, NULL); +	error = xfs_dir2_free_try_read(tp, dp, fo, &bp);  	if (error)  		return error;  	/*  	 * There can be holes in freespace.  If fo is a hole, there's  	 * nothing to do.  	 */ -	if (bp == NULL) { +	if (!bp)  		return 0; -	}  	free = bp->b_addr;  	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));  	/*  |