Message ID | 20190211125427.16577-6-hch@lst.de (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | [01/10] xfs: remove the io_type field from the writeback context and ioend | expand |
On Mon, Feb 11, 2019 at 01:54:22PM +0100, Christoph Hellwig wrote: > 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: Brian Foster <bfoster@redhat.com> > fs/xfs/libxfs/xfs_bmap.c | 104 +++++++++++++++++++++------------------ > fs/xfs/libxfs/xfs_bmap.h | 4 -- > 2 files changed, 56 insertions(+), 52 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index a9c9bd39d822..be2cb5800e02 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -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,66 @@ 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; > + if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) { > + error = -ENOSPC; > + goto out_finish; > + } > + > + ASSERT(!isnullstartblock(bma.got.br_startblock)); > + ASSERT(bma.got.br_startblock || XFS_IS_REALTIME_INODE(ip)); > + *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; > } > > diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h > index 4dc7d1a02b35..b5eca7a26949 100644 > --- a/fs/xfs/libxfs/xfs_bmap.h > +++ b/fs/xfs/libxfs/xfs_bmap.h > @@ -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" } > -- > 2.20.1 >
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index a9c9bd39d822..be2cb5800e02 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -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,66 @@ 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; + if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) { + error = -ENOSPC; + goto out_finish; + } + + ASSERT(!isnullstartblock(bma.got.br_startblock)); + ASSERT(bma.got.br_startblock || XFS_IS_REALTIME_INODE(ip)); + *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; } diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 4dc7d1a02b35..b5eca7a26949 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -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" }
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> --- fs/xfs/libxfs/xfs_bmap.c | 104 +++++++++++++++++++++------------------ fs/xfs/libxfs/xfs_bmap.h | 4 -- 2 files changed, 56 insertions(+), 52 deletions(-)