summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_bmap.c107
1 files changed, 70 insertions, 37 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 311cbc1d64c5..c2e49fd18bfd 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4089,7 +4089,6 @@ xfs_bmap_read_extents(
xfs_extnum_t num_recs;
xfs_extnum_t start;
-
num_recs = xfs_btree_get_numrecs(block);
if (unlikely(i + num_recs > room)) {
ASSERT(i + num_recs <= room);
@@ -4746,6 +4745,69 @@ xfs_bmapi_allocate(
return 0;
}
+STATIC int
+xfs_bmapi_convert_unwritten(
+ struct xfs_bmalloca *bma,
+ struct xfs_bmbt_irec *mval,
+ xfs_filblks_t len,
+ xfs_extnum_t *lastx,
+ struct xfs_btree_cur **cur,
+ xfs_fsblock_t *firstblock,
+ struct xfs_bmap_free *flist,
+ int flags,
+ int *logflags)
+{
+ int whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+ XFS_ATTR_FORK : XFS_DATA_FORK;
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
+ int error;
+
+ *logflags = 0;
+
+ /* check if we need to do unwritten->real conversion */
+ if (mval->br_state == XFS_EXT_UNWRITTEN &&
+ (flags & XFS_BMAPI_PREALLOC))
+ return 0;
+
+ /* check if we need to do real->unwritten conversion */
+ if (mval->br_state == XFS_EXT_NORM &&
+ (flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) !=
+ (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT))
+ return 0;
+
+ /*
+ * Modify (by adding) the state flag, if writing.
+ */
+ ASSERT(mval->br_blockcount <= len);
+ if ((ifp->if_flags & XFS_IFBROOT) && !*cur) {
+ *cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp,
+ bma->ip, whichfork);
+ (*cur)->bc_private.b.firstblock = *firstblock;
+ (*cur)->bc_private.b.flist = flist;
+ }
+ mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
+ ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
+
+ error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, mval,
+ firstblock, flist, logflags, whichfork);
+ if (error)
+ return error;
+
+ /*
+ * Update our extent pointer, given that xfs_bmap_add_extent might
+ * have merged it into one of the neighbouring ones.
+ */
+ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
+
+ /*
+ * We may have combined previously unwritten space with written space,
+ * so generate another request.
+ */
+ if (mval->br_blockcount < len)
+ return EAGAIN;
+ return 0;
+}
+
/*
* Map file blocks to filesystem blocks.
* File range is given by the bno/len pair.
@@ -4932,45 +4994,16 @@ xfs_bmapi(
/* Deal with the allocated space we found. */
xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
- /*
- * Check if writing previously allocated but
- * unwritten extents.
- */
- if (wr &&
- ((mval->br_state == XFS_EXT_UNWRITTEN &&
- ((flags & XFS_BMAPI_PREALLOC) == 0)) ||
- (mval->br_state == XFS_EXT_NORM &&
- ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT)) ==
- (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT))))) {
- /*
- * Modify (by adding) the state flag, if writing.
- */
- ASSERT(mval->br_blockcount <= len);
- if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
- cur = xfs_bmbt_init_cursor(mp,
- tp, ip, whichfork);
- cur->bc_private.b.firstblock =
- *firstblock;
- cur->bc_private.b.flist = flist;
- }
- mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
- ? XFS_EXT_NORM
- : XFS_EXT_UNWRITTEN;
- error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, mval,
- firstblock, flist, &tmp_logflags,
- whichfork);
+ /* Execute unwritten extent conversion if necessary */
+ if (wr) {
+ error = xfs_bmapi_convert_unwritten(&bma, mval, len,
+ &lastx, &cur, firstblock, flist, flags,
+ &tmp_logflags);
logflags |= tmp_logflags;
+ if (error == EAGAIN)
+ continue;
if (error)
goto error0;
- ep = xfs_iext_get_ext(ifp, lastx);
- xfs_bmbt_get_all(ep, &got);
- /*
- * We may have combined previously unwritten
- * space with written space, so generate
- * another request.
- */
- if (mval->br_blockcount < len)
- continue;
}
/* update the extent map to return */