aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-09-18 16:40:53 -0400
committerAlex Elder <aelder@sgi.com>2011-10-11 22:15:05 -0400
commit27a3f8f2de758205765f277b3428bbf3d15da973 (patch)
treedf658a3a539358117e53026cbd6e4d4f98af7989 /fs/xfs/xfs_bmap.c
parentc0dc7828af6952643219292be29e482ef74cb261 (diff)
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>
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r--fs/xfs/xfs_bmap.c226
1 files changed, 105 insertions, 121 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 595cc6311937..d9de5ae1fd5c 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -204,19 +204,6 @@ xfs_bmap_search_extents(
204 xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ 204 xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */
205 205
206/* 206/*
207 * Check the last inode extent to determine whether this allocation will result
208 * in blocks being allocated at the end of the file. When we allocate new data
209 * blocks at the end of the file which do not start at the previous data block,
210 * we will try to align the new blocks at stripe unit boundaries.
211 */
212STATIC int /* error */
213xfs_bmap_isaeof(
214 xfs_inode_t *ip, /* incore inode pointer */
215 xfs_fileoff_t off, /* file offset in fsblocks */
216 int whichfork, /* data or attribute fork */
217 char *aeof); /* return value */
218
219/*
220 * Compute the worst-case number of indirect blocks that will be used 207 * Compute the worst-case number of indirect blocks that will be used
221 * for ip's delayed extent of length "len". 208 * for ip's delayed extent of length "len".
222 */ 209 */
@@ -3924,42 +3911,122 @@ xfs_bmap_last_before(
3924 return 0; 3911 return 0;
3925} 3912}
3926 3913
3914STATIC int
3915xfs_bmap_last_extent(
3916 struct xfs_trans *tp,
3917 struct xfs_inode *ip,
3918 int whichfork,
3919 struct xfs_bmbt_irec *rec,
3920 int *is_empty)
3921{
3922 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
3923 int error;
3924 int nextents;
3925
3926 if (!(ifp->if_flags & XFS_IFEXTENTS)) {
3927 error = xfs_iread_extents(tp, ip, whichfork);
3928 if (error)
3929 return error;
3930 }
3931
3932 nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t);
3933 if (nextents == 0) {
3934 *is_empty = 1;
3935 return 0;
3936 }
3937
3938 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, nextents - 1), rec);
3939 *is_empty = 0;
3940 return 0;
3941}
3942
3943/*
3944 * Check the last inode extent to determine whether this allocation will result
3945 * in blocks being allocated at the end of the file. When we allocate new data
3946 * blocks at the end of the file which do not start at the previous data block,
3947 * we will try to align the new blocks at stripe unit boundaries.
3948 *
3949 * Returns 0 in *aeof if the file (fork) is empty as any new write will be at,
3950 * or past the EOF.
3951 */
3952STATIC int
3953xfs_bmap_isaeof(
3954 struct xfs_inode *ip,
3955 xfs_fileoff_t off,
3956 int whichfork,
3957 char *aeof)
3958{
3959 struct xfs_bmbt_irec rec;
3960 int is_empty;
3961 int error;
3962
3963 *aeof = 0;
3964 error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
3965 if (error || is_empty)
3966 return error;
3967
3968 /*
3969 * Check if we are allocation or past the last extent, or at least into
3970 * the last delayed allocated extent.
3971 */
3972 *aeof = off >= rec.br_startoff + rec.br_blockcount ||
3973 (off >= rec.br_startoff && isnullstartblock(rec.br_startblock));
3974 return 0;
3975}
3976
3977/*
3978 * Check if the endoff is outside the last extent. If so the caller will grow
3979 * the allocation to a stripe unit boundary. All offsets are considered outside
3980 * the end of file for an empty fork, so 1 is returned in *eof in that case.
3981 */
3982int
3983xfs_bmap_eof(
3984 struct xfs_inode *ip,
3985 xfs_fileoff_t endoff,
3986 int whichfork,
3987 int *eof)
3988{
3989 struct xfs_bmbt_irec rec;
3990 int error;
3991
3992 error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof);
3993 if (error || *eof)
3994 return error;
3995
3996 *eof = endoff >= rec.br_startoff + rec.br_blockcount;
3997 return 0;
3998}
3999
3927/* 4000/*
3928 * Returns the file-relative block number of the first block past eof in 4001 * Returns the file-relative block number of the first block past eof in
3929 * the file. This is not based on i_size, it is based on the extent records. 4002 * the file. This is not based on i_size, it is based on the extent records.
3930 * Returns 0 for local files, as they do not have extent records. 4003 * Returns 0 for local files, as they do not have extent records.
3931 */ 4004 */
3932int /* error */ 4005int
3933xfs_bmap_last_offset( 4006xfs_bmap_last_offset(
3934 xfs_trans_t *tp, /* transaction pointer */ 4007 struct xfs_trans *tp,
3935 xfs_inode_t *ip, /* incore inode */ 4008 struct xfs_inode *ip,
3936 xfs_fileoff_t *last_block, /* last block */ 4009 xfs_fileoff_t *last_block,
3937 int whichfork) /* data or attr fork */ 4010 int whichfork)
3938{ 4011{
3939 xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ 4012 struct xfs_bmbt_irec rec;
3940 int error; /* error return value */ 4013 int is_empty;
3941 xfs_ifork_t *ifp; /* inode fork pointer */ 4014 int error;
3942 xfs_extnum_t nextents; /* number of extent entries */ 4015
4016 *last_block = 0;
4017
4018 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL)
4019 return 0;
3943 4020
3944 if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && 4021 if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
3945 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && 4022 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS)
3946 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
3947 return XFS_ERROR(EIO); 4023 return XFS_ERROR(EIO);
3948 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { 4024
3949 *last_block = 0; 4025 error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty);
3950 return 0; 4026 if (error || is_empty)
3951 }
3952 ifp = XFS_IFORK_PTR(ip, whichfork);
3953 if (!(ifp->if_flags & XFS_IFEXTENTS) &&
3954 (error = xfs_iread_extents(tp, ip, whichfork)))
3955 return error; 4027 return error;
3956 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); 4028
3957 if (!nextents) { 4029 *last_block = rec.br_startoff + rec.br_blockcount;
3958 *last_block = 0;
3959 return 0;
3960 }
3961 ep = xfs_iext_get_ext(ifp, nextents - 1);
3962 *last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep);
3963 return 0; 4030 return 0;
3964} 4031}
3965 4032
@@ -5687,89 +5754,6 @@ xfs_getbmap(
5687 return error; 5754 return error;
5688} 5755}
5689 5756
5690/*
5691 * Check the last inode extent to determine whether this allocation will result
5692 * in blocks being allocated at the end of the file. When we allocate new data
5693 * blocks at the end of the file which do not start at the previous data block,
5694 * we will try to align the new blocks at stripe unit boundaries.
5695 */
5696STATIC int /* error */
5697xfs_bmap_isaeof(
5698 xfs_inode_t *ip, /* incore inode pointer */
5699 xfs_fileoff_t off, /* file offset in fsblocks */
5700 int whichfork, /* data or attribute fork */
5701 char *aeof) /* return value */
5702{
5703 int error; /* error return value */
5704 xfs_ifork_t *ifp; /* inode fork pointer */
5705 xfs_bmbt_rec_host_t *lastrec; /* extent record pointer */
5706 xfs_extnum_t nextents; /* number of file extents */
5707 xfs_bmbt_irec_t s; /* expanded extent record */
5708
5709 ASSERT(whichfork == XFS_DATA_FORK);
5710 ifp = XFS_IFORK_PTR(ip, whichfork);
5711 if (!(ifp->if_flags & XFS_IFEXTENTS) &&
5712 (error = xfs_iread_extents(NULL, ip, whichfork)))
5713 return error;
5714 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
5715 if (nextents == 0) {
5716 *aeof = 1;
5717 return 0;
5718 }
5719 /*
5720 * Go to the last extent
5721 */
5722 lastrec = xfs_iext_get_ext(ifp, nextents - 1);
5723 xfs_bmbt_get_all(lastrec, &s);
5724 /*
5725 * Check we are allocating in the last extent (for delayed allocations)
5726 * or past the last extent for non-delayed allocations.
5727 */
5728 *aeof = (off >= s.br_startoff &&
5729 off < s.br_startoff + s.br_blockcount &&
5730 isnullstartblock(s.br_startblock)) ||
5731 off >= s.br_startoff + s.br_blockcount;
5732 return 0;
5733}
5734
5735/*
5736 * Check if the endoff is outside the last extent. If so the caller will grow
5737 * the allocation to a stripe unit boundary.
5738 */
5739int /* error */
5740xfs_bmap_eof(
5741 xfs_inode_t *ip, /* incore inode pointer */
5742 xfs_fileoff_t endoff, /* file offset in fsblocks */
5743 int whichfork, /* data or attribute fork */
5744 int *eof) /* result value */
5745{
5746 xfs_fsblock_t blockcount; /* extent block count */
5747 int error; /* error return value */
5748 xfs_ifork_t *ifp; /* inode fork pointer */
5749 xfs_bmbt_rec_host_t *lastrec; /* extent record pointer */
5750 xfs_extnum_t nextents; /* number of file extents */
5751 xfs_fileoff_t startoff; /* extent starting file offset */
5752
5753 ASSERT(whichfork == XFS_DATA_FORK);
5754 ifp = XFS_IFORK_PTR(ip, whichfork);
5755 if (!(ifp->if_flags & XFS_IFEXTENTS) &&
5756 (error = xfs_iread_extents(NULL, ip, whichfork)))
5757 return error;
5758 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
5759 if (nextents == 0) {
5760 *eof = 1;
5761 return 0;
5762 }
5763 /*
5764 * Go to the last extent
5765 */
5766 lastrec = xfs_iext_get_ext(ifp, nextents - 1);
5767 startoff = xfs_bmbt_get_startoff(lastrec);
5768 blockcount = xfs_bmbt_get_blockcount(lastrec);
5769 *eof = endoff >= startoff + blockcount;
5770 return 0;
5771}
5772
5773#ifdef DEBUG 5757#ifdef DEBUG
5774STATIC struct xfs_buf * 5758STATIC struct xfs_buf *
5775xfs_bmap_get_bp( 5759xfs_bmap_get_bp(