xfs: introduce xfs_bmap_last_extent
Add a common helper for finding the last extent in a file. Largely based on a patch from Dave Chinner. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
		
					parent
					
						
							
								c0dc7828af
							
						
					
				
			
			
				commit
				
					
						27a3f8f2de
					
				
			
		
					 1 changed files with 105 additions and 121 deletions
				
			
		|  | @ -203,19 +203,6 @@ xfs_bmap_search_extents( | |||
| 	xfs_bmbt_irec_t	*gotp,		/* out: extent entry found */ | ||||
| 	xfs_bmbt_irec_t	*prevp);	/* out: previous extent entry found */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Check the last inode extent to determine whether this allocation will result | ||||
|  * in blocks being allocated at the end of the file. When we allocate new data | ||||
|  * blocks at the end of the file which do not start at the previous data block, | ||||
|  * we will try to align the new blocks at stripe unit boundaries. | ||||
|  */ | ||||
| STATIC int				/* error */ | ||||
| xfs_bmap_isaeof( | ||||
| 	xfs_inode_t	*ip,		/* incore inode pointer */ | ||||
| 	xfs_fileoff_t   off,		/* file offset in fsblocks */ | ||||
| 	int             whichfork,	/* data or attribute fork */ | ||||
| 	char		*aeof);		/* return value */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Compute the worst-case number of indirect blocks that will be used | ||||
|  * for ip's delayed extent of length "len". | ||||
|  | @ -3924,42 +3911,122 @@ xfs_bmap_last_before( | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| STATIC int | ||||
| xfs_bmap_last_extent( | ||||
| 	struct xfs_trans	*tp, | ||||
| 	struct xfs_inode	*ip, | ||||
| 	int			whichfork, | ||||
| 	struct xfs_bmbt_irec	*rec, | ||||
| 	int			*is_empty) | ||||
| { | ||||
| 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork); | ||||
| 	int			error; | ||||
| 	int			nextents; | ||||
| 
 | ||||
| 	if (!(ifp->if_flags & XFS_IFEXTENTS)) { | ||||
| 		error = xfs_iread_extents(tp, ip, whichfork); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 	} | ||||
| 
 | ||||
| 	nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); | ||||
| 	if (nextents == 0) { | ||||
| 		*is_empty = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	xfs_bmbt_get_all(xfs_iext_get_ext(ifp, nextents - 1), rec); | ||||
| 	*is_empty = 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check the last inode extent to determine whether this allocation will result | ||||
|  * in blocks being allocated at the end of the file. When we allocate new data | ||||
|  * blocks at the end of the file which do not start at the previous data block, | ||||
|  * we will try to align the new blocks at stripe unit boundaries. | ||||
|  * | ||||
|  * Returns 0 in *aeof if the file (fork) is empty as any new write will be at, | ||||
|  * or past the EOF. | ||||
|  */ | ||||
| STATIC int | ||||
| xfs_bmap_isaeof( | ||||
| 	struct xfs_inode	*ip, | ||||
| 	xfs_fileoff_t		off, | ||||
| 	int			whichfork, | ||||
| 	char			*aeof) | ||||
| { | ||||
| 	struct xfs_bmbt_irec	rec; | ||||
| 	int			is_empty; | ||||
| 	int			error; | ||||
| 
 | ||||
| 	*aeof = 0; | ||||
| 	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); | ||||
| 	if (error || is_empty) | ||||
| 		return error; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check if we are allocation or past the last extent, or at least into | ||||
| 	 * the last delayed allocated extent. | ||||
| 	 */ | ||||
| 	*aeof = off >= rec.br_startoff + rec.br_blockcount || | ||||
| 		(off >= rec.br_startoff && isnullstartblock(rec.br_startblock)); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check if the endoff is outside the last extent. If so the caller will grow | ||||
|  * the allocation to a stripe unit boundary.  All offsets are considered outside | ||||
|  * the end of file for an empty fork, so 1 is returned in *eof in that case. | ||||
|  */ | ||||
| int | ||||
| xfs_bmap_eof( | ||||
| 	struct xfs_inode	*ip, | ||||
| 	xfs_fileoff_t		endoff, | ||||
| 	int			whichfork, | ||||
| 	int			*eof) | ||||
| { | ||||
| 	struct xfs_bmbt_irec	rec; | ||||
| 	int			error; | ||||
| 
 | ||||
| 	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof); | ||||
| 	if (error || *eof) | ||||
| 		return error; | ||||
| 
 | ||||
| 	*eof = endoff >= rec.br_startoff + rec.br_blockcount; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Returns the file-relative block number of the first block past eof in | ||||
|  * the file.  This is not based on i_size, it is based on the extent records. | ||||
|  * Returns 0 for local files, as they do not have extent records. | ||||
|  */ | ||||
| int						/* error */ | ||||
| int | ||||
| xfs_bmap_last_offset( | ||||
| 	xfs_trans_t	*tp,			/* transaction pointer */ | ||||
| 	xfs_inode_t	*ip,			/* incore inode */ | ||||
| 	xfs_fileoff_t	*last_block,		/* last block */ | ||||
| 	int		whichfork)		/* data or attr fork */ | ||||
| 	struct xfs_trans	*tp, | ||||
| 	struct xfs_inode	*ip, | ||||
| 	xfs_fileoff_t		*last_block, | ||||
| 	int			whichfork) | ||||
| { | ||||
| 	xfs_bmbt_rec_host_t *ep;		/* pointer to last extent */ | ||||
| 	int		error;			/* error return value */ | ||||
| 	xfs_ifork_t	*ifp;			/* inode fork pointer */ | ||||
| 	xfs_extnum_t	nextents;		/* number of extent entries */ | ||||
| 	struct xfs_bmbt_irec	rec; | ||||
| 	int			is_empty; | ||||
| 	int			error; | ||||
| 
 | ||||
| 	*last_block = 0; | ||||
| 
 | ||||
| 	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && | ||||
| 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && | ||||
| 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) | ||||
| 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) | ||||
| 	       return XFS_ERROR(EIO); | ||||
| 	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { | ||||
| 		*last_block = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	ifp = XFS_IFORK_PTR(ip, whichfork); | ||||
| 	if (!(ifp->if_flags & XFS_IFEXTENTS) && | ||||
| 	    (error = xfs_iread_extents(tp, ip, whichfork))) | ||||
| 
 | ||||
| 	error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); | ||||
| 	if (error || is_empty) | ||||
| 		return error; | ||||
| 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | ||||
| 	if (!nextents) { | ||||
| 		*last_block = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	ep = xfs_iext_get_ext(ifp, nextents - 1); | ||||
| 	*last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep); | ||||
| 
 | ||||
| 	*last_block = rec.br_startoff + rec.br_blockcount; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -5687,89 +5754,6 @@ xfs_getbmap( | |||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check the last inode extent to determine whether this allocation will result | ||||
|  * in blocks being allocated at the end of the file. When we allocate new data | ||||
|  * blocks at the end of the file which do not start at the previous data block, | ||||
|  * we will try to align the new blocks at stripe unit boundaries. | ||||
|  */ | ||||
| STATIC int				/* error */ | ||||
| xfs_bmap_isaeof( | ||||
| 	xfs_inode_t	*ip,		/* incore inode pointer */ | ||||
| 	xfs_fileoff_t   off,		/* file offset in fsblocks */ | ||||
| 	int             whichfork,	/* data or attribute fork */ | ||||
| 	char		*aeof)		/* return value */ | ||||
| { | ||||
| 	int		error;		/* error return value */ | ||||
| 	xfs_ifork_t	*ifp;		/* inode fork pointer */ | ||||
| 	xfs_bmbt_rec_host_t *lastrec;	/* extent record pointer */ | ||||
| 	xfs_extnum_t	nextents;	/* number of file extents */ | ||||
| 	xfs_bmbt_irec_t	s;		/* expanded extent record */ | ||||
| 
 | ||||
| 	ASSERT(whichfork == XFS_DATA_FORK); | ||||
| 	ifp = XFS_IFORK_PTR(ip, whichfork); | ||||
| 	if (!(ifp->if_flags & XFS_IFEXTENTS) && | ||||
| 	    (error = xfs_iread_extents(NULL, ip, whichfork))) | ||||
| 		return error; | ||||
| 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | ||||
| 	if (nextents == 0) { | ||||
| 		*aeof = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * Go to the last extent | ||||
| 	 */ | ||||
| 	lastrec = xfs_iext_get_ext(ifp, nextents - 1); | ||||
| 	xfs_bmbt_get_all(lastrec, &s); | ||||
| 	/*
 | ||||
| 	 * Check we are allocating in the last extent (for delayed allocations) | ||||
| 	 * or past the last extent for non-delayed allocations. | ||||
| 	 */ | ||||
| 	*aeof = (off >= s.br_startoff && | ||||
| 		 off < s.br_startoff + s.br_blockcount && | ||||
| 		 isnullstartblock(s.br_startblock)) || | ||||
| 		off >= s.br_startoff + s.br_blockcount; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check if the endoff is outside the last extent. If so the caller will grow | ||||
|  * the allocation to a stripe unit boundary. | ||||
|  */ | ||||
| int					/* error */ | ||||
| xfs_bmap_eof( | ||||
| 	xfs_inode_t	*ip,		/* incore inode pointer */ | ||||
| 	xfs_fileoff_t	endoff,		/* file offset in fsblocks */ | ||||
| 	int		whichfork,	/* data or attribute fork */ | ||||
| 	int		*eof)		/* result value */ | ||||
| { | ||||
| 	xfs_fsblock_t	blockcount;	/* extent block count */ | ||||
| 	int		error;		/* error return value */ | ||||
| 	xfs_ifork_t	*ifp;		/* inode fork pointer */ | ||||
| 	xfs_bmbt_rec_host_t *lastrec;	/* extent record pointer */ | ||||
| 	xfs_extnum_t	nextents;	/* number of file extents */ | ||||
| 	xfs_fileoff_t	startoff;	/* extent starting file offset */ | ||||
| 
 | ||||
| 	ASSERT(whichfork == XFS_DATA_FORK); | ||||
| 	ifp = XFS_IFORK_PTR(ip, whichfork); | ||||
| 	if (!(ifp->if_flags & XFS_IFEXTENTS) && | ||||
| 	    (error = xfs_iread_extents(NULL, ip, whichfork))) | ||||
| 		return error; | ||||
| 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | ||||
| 	if (nextents == 0) { | ||||
| 		*eof = 1; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * Go to the last extent | ||||
| 	 */ | ||||
| 	lastrec = xfs_iext_get_ext(ifp, nextents - 1); | ||||
| 	startoff = xfs_bmbt_get_startoff(lastrec); | ||||
| 	blockcount = xfs_bmbt_get_blockcount(lastrec); | ||||
| 	*eof = endoff >= startoff + blockcount; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef DEBUG | ||||
| STATIC struct xfs_buf * | ||||
| xfs_bmap_get_bp( | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Christoph Hellwig
				Christoph Hellwig