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: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
parent
c8b54673b3
commit
d8ae82e394
fs/xfs/libxfs
|
@ -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;
|
||||
}
|
||||
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)
|
||||
error = -EFSCORRUPTED;
|
||||
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" }
|
||||
|
|
Loading…
Reference in New Issue