summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-09-18 22:40:48 +0200
committerAlex Elder <aelder@sgi.com>2011-10-12 04:15:04 +0200
commit4403280aa5c00c6074f2dc23e1cfc11f2bfb0032 (patch)
tree322f188e78d6faf1cae53cb56ed7918d49702366 /fs/xfs/xfs_bmap.c
parentxfs: factor delalloc reservations out of xfs_bmapi (diff)
downloadlinux-4403280aa5c00c6074f2dc23e1cfc11f2bfb0032.tar.xz
linux-4403280aa5c00c6074f2dc23e1cfc11f2bfb0032.zip
xfs: introduce xfs_bmapi_delay()
Delalloc reservations are much simpler than allocations, so give them a separate bmapi-level interface. Using the previously added xfs_bmapi_reserve_delalloc we get a function that is only minimally more complicated than xfs_bmapi_read, which is far from the complexity in xfs_bmapi. Also remove the XFS_BMAPI_DELAY code after switching over the only user to xfs_bmapi_delay. 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.c115
1 files changed, 89 insertions, 26 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index cd01783a89d7..6f3276974555 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4238,7 +4238,7 @@ xfs_bmap_validate_ret(
ASSERT(i == 0 ||
mval[i - 1].br_startoff + mval[i - 1].br_blockcount ==
mval[i].br_startoff);
- if ((flags & XFS_BMAPI_WRITE) && !(flags & XFS_BMAPI_DELAY))
+ if (flags & XFS_BMAPI_WRITE)
ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK &&
mval[i].br_startblock != HOLESTARTBLOCK);
ASSERT(mval[i].br_state == XFS_EXT_NORM ||
@@ -4556,6 +4556,90 @@ out_unreserve_quota:
}
/*
+ * Map file blocks to filesystem blocks, adding delayed allocations as needed.
+ */
+int
+xfs_bmapi_delay(
+ struct xfs_inode *ip, /* incore inode */
+ xfs_fileoff_t bno, /* starting file offs. mapped */
+ xfs_filblks_t len, /* length to map in file */
+ struct xfs_bmbt_irec *mval, /* output: map values */
+ int *nmap, /* i/o: mval size/count */
+ int flags) /* XFS_BMAPI_... */
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ struct xfs_bmbt_irec got; /* current file extent record */
+ struct xfs_bmbt_irec prev; /* previous file extent record */
+ xfs_fileoff_t obno; /* old block number (offset) */
+ xfs_fileoff_t end; /* end of mapped file region */
+ xfs_extnum_t lastx; /* last useful extent number */
+ int eof; /* we've hit the end of extents */
+ int n = 0; /* current extent index */
+ int error = 0;
+
+ ASSERT(*nmap >= 1);
+ ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
+ ASSERT(!(flags & ~XFS_BMAPI_ENTIRE));
+
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
+ mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmapi_delay", XFS_ERRLEVEL_LOW, mp);
+ return XFS_ERROR(EFSCORRUPTED);
+ }
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return XFS_ERROR(EIO);
+
+ XFS_STATS_INC(xs_blk_mapw);
+
+ if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+ error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+ if (error)
+ return error;
+ }
+
+ xfs_bmap_search_extents(ip, bno, XFS_DATA_FORK, &eof, &lastx, &got, &prev);
+ end = bno + len;
+ obno = bno;
+
+ while (bno < end && n < *nmap) {
+ if (eof || got.br_startoff > bno) {
+ error = xfs_bmapi_reserve_delalloc(ip, bno, len, &got,
+ &prev, &lastx, eof);
+ if (error) {
+ if (n == 0) {
+ *nmap = 0;
+ return error;
+ }
+ break;
+ }
+ }
+
+ /* set up the extent map to return. */
+ xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
+ xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
+
+ /* If we're done, stop now. */
+ if (bno >= end || n >= *nmap)
+ break;
+
+ /* Else go on to the next record. */
+ prev = got;
+ if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
+ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
+ else
+ eof = 1;
+ }
+
+ *nmap = n;
+ return 0;
+}
+
+
+/*
* Map file blocks to filesystem blocks.
* File range is given by the bno/len pair.
* Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set)
@@ -4663,7 +4747,6 @@ xfs_bmapi(
*/
if ((flags & XFS_BMAPI_IGSTATE) && wr) /* if writing unwritten space */
wr = 0; /* no allocations are allowed */
- ASSERT(wr || !(flags & XFS_BMAPI_DELAY));
logflags = 0;
nallocs = 0;
cur = NULL;
@@ -4698,8 +4781,7 @@ xfs_bmapi(
if (eof && !wr)
got.br_startoff = end;
inhole = eof || got.br_startoff > bno;
- wasdelay = wr && !inhole && !(flags & XFS_BMAPI_DELAY) &&
- isnullstartblock(got.br_startblock);
+ wasdelay = wr && !inhole && isnullstartblock(got.br_startblock);
/*
* First, deal with the hole before the allocated space
* that we found, if any.
@@ -4727,20 +4809,7 @@ xfs_bmapi(
aoff = bno;
}
minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1;
- if (flags & XFS_BMAPI_DELAY) {
- error = xfs_bmapi_reserve_delalloc(ip, bno, len, &got,
- &prev, &lastx, eof);
- if (error) {
- if (n == 0) {
- *nmap = 0;
- ASSERT(cur == NULL);
- return error;
- }
- break;
- }
-
- goto trim_extent;
- } else {
+ {
/*
* If first time, allocate and fill in
* once-only bma fields.
@@ -4851,14 +4920,8 @@ xfs_bmapi(
ASSERT(got.br_startoff <= aoff);
ASSERT(got.br_startoff + got.br_blockcount >=
aoff + alen);
-#ifdef DEBUG
- if (flags & XFS_BMAPI_DELAY) {
- ASSERT(isnullstartblock(got.br_startblock));
- ASSERT(startblockval(got.br_startblock) > 0);
- }
ASSERT(got.br_state == XFS_EXT_NORM ||
got.br_state == XFS_EXT_UNWRITTEN);
-#endif
/*
* Fall down into the found allocated space case.
*/
@@ -4877,7 +4940,7 @@ xfs_bmapi(
n++;
continue;
}
-trim_extent:
+
/* Deal with the allocated space we found. */
xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
@@ -4887,7 +4950,7 @@ trim_extent:
*/
if (wr &&
((mval->br_state == XFS_EXT_UNWRITTEN &&
- ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) ||
+ ((flags & XFS_BMAPI_PREALLOC) == 0)) ||
(mval->br_state == XFS_EXT_NORM &&
((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT)) ==
(XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT))))) {