diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-09-18 16:40:53 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2011-10-11 22:15:05 -0400 |
commit | 27a3f8f2de758205765f277b3428bbf3d15da973 (patch) | |
tree | df658a3a539358117e53026cbd6e4d4f98af7989 /fs/xfs/xfs_bmap.c | |
parent | c0dc7828af6952643219292be29e482ef74cb261 (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.c | 226 |
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 | */ | ||
212 | STATIC int /* error */ | ||
213 | xfs_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 | ||
3914 | STATIC int | ||
3915 | xfs_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 | */ | ||
3952 | STATIC int | ||
3953 | xfs_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 | */ | ||
3982 | int | ||
3983 | xfs_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 | */ |
3932 | int /* error */ | 4005 | int |
3933 | xfs_bmap_last_offset( | 4006 | xfs_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 | */ | ||
5696 | STATIC int /* error */ | ||
5697 | xfs_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 | */ | ||
5739 | int /* error */ | ||
5740 | xfs_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 |
5774 | STATIC struct xfs_buf * | 5758 | STATIC struct xfs_buf * |
5775 | xfs_bmap_get_bp( | 5759 | xfs_bmap_get_bp( |