Commit d8ae82e3 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Darrick J. Wong

xfs: split XFS_BMAPI_DELALLOC handling from xfs_bmapi_write

Delalloc conversion has traditionally been part of our function to
allocate blocks on disk (first xfs_bmapi, then xfs_bmapi_write), but
delalloc conversion is a little special as we really do not want
to allocate blocks over holes, for which we don't have reservations.

Split the delalloc conversions into a separate helper to keep the
code simple and structured.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent c8b54673
......@@ -4327,22 +4327,6 @@ xfs_bmapi_write(
bma.datatype = 0;
bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);
/*
* The delalloc flag means the caller wants to allocate the entire
* delalloc extent backing bno where bno may not necessarily match the
* startoff. Now that we've looked up the extent, reset the range to
* map based on the extent in the file. If we're in a hole, this may be
* an error so don't adjust anything.
*/
if ((flags & XFS_BMAPI_DELALLOC) &&
!eof && bno >= bma.got.br_startoff) {
bno = bma.got.br_startoff;
len = bma.got.br_blockcount;
#ifdef DEBUG
orig_bno = bno;
orig_len = len;
#endif
}
n = 0;
end = bno + len;
obno = bno;
......@@ -4359,26 +4343,7 @@ xfs_bmapi_write(
ASSERT(!((flags & XFS_BMAPI_CONVERT) &&
(flags & XFS_BMAPI_COWFORK)));
if (flags & XFS_BMAPI_DELALLOC) {
/*
* For the COW fork we can reasonably get a
* request for converting an extent that races
* with other threads already having converted
* part of it, as there converting COW to
* regular blocks is not protected using the
* IOLOCK.
*/
ASSERT(flags & XFS_BMAPI_COWFORK);
if (!(flags & XFS_BMAPI_COWFORK)) {
error = -EIO;
goto error0;
}
if (eof || bno >= end)
break;
} else {
need_alloc = true;
}
} else if (isnullstartblock(bma.got.br_startblock)) {
wasdelay = true;
}
......@@ -4487,23 +4452,68 @@ xfs_bmapi_convert_delalloc(
int whichfork,
struct xfs_bmbt_irec *imap)
{
int flags = XFS_BMAPI_DELALLOC;
int nimaps = 1;
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
struct xfs_bmalloca bma = { NULL };
int error;
int total = XFS_EXTENTADD_SPACE_RES(ip->i_mount,
XFS_DATA_FORK);
if (whichfork == XFS_COW_FORK)
flags |= XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC;
if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) ||
bma.got.br_startoff > offset_fsb) {
/*
* No extent found in the range we are trying to convert. This
* should only happen for the COW fork, where another thread
* might have moved the extent to the data fork in the meantime.
*/
WARN_ON_ONCE(whichfork != XFS_COW_FORK);
return -EAGAIN;
}
/*
* The delalloc flag means to allocate the entire extent; pass a dummy
* length of 1.
* If we find a real extent here we raced with another thread converting
* the extent. Just return the real extent at this offset.
*/
error = xfs_bmapi_write(tp, ip, offset_fsb, 1, flags, total, imap,
&nimaps);
if (!error && !nimaps)
if (!isnullstartblock(bma.got.br_startblock)) {
*imap = bma.got;
return 0;
}
bma.tp = tp;
bma.ip = ip;
bma.wasdel = true;
bma.offset = bma.got.br_startoff;
bma.length = max_t(xfs_filblks_t, bma.got.br_blockcount, MAXEXTLEN);
bma.total = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);
if (whichfork == XFS_COW_FORK)
bma.flags = XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC;
if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev))
bma.prev.br_startoff = NULLFILEOFF;
error = xfs_bmapi_allocate(&bma);
if (error)
goto out_finish;
error = -ENOSPC;
if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK))
goto out_finish;
error = -EFSCORRUPTED;
if (WARN_ON_ONCE(!bma.got.br_startblock && !XFS_IS_REALTIME_INODE(ip)))
goto out_finish;
ASSERT(!isnullstartblock(bma.got.br_startblock));
*imap = bma.got;
if (whichfork == XFS_COW_FORK) {
error = xfs_refcount_alloc_cow_extent(tp, bma.blkno,
bma.length);
if (error)
goto out_finish;
}
error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &bma.logflags,
whichfork);
out_finish:
xfs_bmapi_finish(&bma, whichfork, error);
return error;
}
......
......@@ -95,9 +95,6 @@ struct xfs_extent_free_item
/* Map something in the CoW fork. */
#define XFS_BMAPI_COWFORK 0x200
/* Only convert delalloc space, don't allocate entirely new extents */
#define XFS_BMAPI_DELALLOC 0x400
/* Only convert unwritten extents, don't allocate new blocks */
#define XFS_BMAPI_CONVERT_ONLY 0x800
......@@ -117,7 +114,6 @@ struct xfs_extent_free_item
{ XFS_BMAPI_ZERO, "ZERO" }, \
{ XFS_BMAPI_REMAP, "REMAP" }, \
{ XFS_BMAPI_COWFORK, "COWFORK" }, \
{ XFS_BMAPI_DELALLOC, "DELALLOC" }, \
{ XFS_BMAPI_CONVERT_ONLY, "CONVERT_ONLY" }, \
{ XFS_BMAPI_NODISCARD, "NODISCARD" }, \
{ XFS_BMAPI_NORMAP, "NORMAP" }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment