Re: [PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
Hi Dave. 2014-02-11 8:32 GMT+09:00, Dave Chinner : > On Sun, Feb 02, 2014 at 02:44:11PM +0900, Namjae Jeon wrote: >> From: Namjae Jeon >> >> Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. >> >> Signed-off-by: Namjae Jeon >> Signed-off-by: Ashish Sangwan > > A more detailed description would be nice for the change logs. > . Okay, I will update it on next version. > >> +while (nexts++ < num_exts && >> + *current_ext < XFS_IFORK_NEXTENTS(ip, whichfork)) { >> + >> +gotp = xfs_iext_get_ext(ifp, *current_ext); >> +xfs_bmbt_get_all(gotp, ); >> +startoff = got.br_startoff - offset_shift_fsb; >> + >> +/* >> + * Before shifting extent into hole, make sure that the hole >> + * is large enough to accomodate the shift. >> + */ >> +if (*current_ext) { >> +xfs_bmbt_get_all(xfs_iext_get_ext(ifp, >> +*current_ext - 1), ); >> + >> +if (startoff < left.br_startoff + left.br_blockcount) >> +error = XFS_ERROR(EINVAL); >> + >> +} else if (startoff > xfs_bmbt_get_startoff(gotp)) { >> +/* Hole is at the start but not large enough */ >> +error = XFS_ERROR(EINVAL); >> +} > > This second branch seems wrong to me: > > startoff = got.br_startoff - offset_shift_fsb; > and > got.br_startoff = xfs_bmbt_get_startoff(gotp)). > > I'm not 100% sure what you are trying to check in this case - > perhaps some basic ascii art to describe the two cases is in order > here: > > leftholegot > +---+hhh+-+ > LS LE GSGE > HS HE > > The first is checking that GS - offset_shift_fsb is greater than LE. > i.e the shift doesn't overrun the hole betwenn LE and GS. > > leftholegot > +---+hhh+-+ > LS LE GSGE > HS HE > +---+hhh+-+ > LS LE GS' GE' > HS HE' > > The second I can't visualise from the code or comment When we shift first extent, *current_ext will be 0. So we need to check that offset_shift_fsb ( Number of blocks to be shifted ) should be less than starting offset of the first extent. So, code will be changed more clearly like this. + else if (offset_shift_fsb > got.br_startoff) { + /* Hole is at the start but not large enough */ + error = XFS_ERROR(EINVAL); + } And will update comment more clearly. > > >> + >> +if (error) >> +goto del_cursor; >> + >> +if (cur) { >> +error = xfs_bmbt_lookup_eq(cur, >> +got.br_startoff, >> +got.br_startblock, >> +got.br_blockcount, >> +); > > Whitespace comment - a more compact form is the typical XFS > convention if it will fit in 80 columns: Okay. I will fix it. > > error = xfs_bmbt_lookup_eq(cur, got.br_startoff, > got.br_startblock, > got.br_blockcount, ); > >> +if (error) >> +goto del_cursor; >> +XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); >> +} >> + >> +/* Check if we can merge 2 adjacent extents */ >> +if (*current_ext && >> +left.br_startoff + left.br_blockcount == startoff && >> +left.br_startblock + left.br_blockcount == >> +got.br_startblock && >> +left.br_state == got.br_state && >> +left.br_blockcount + got.br_blockcount <= MAXEXTLEN) { >> +blockcount = left.br_blockcount + >> +xfs_bmbt_get_blockcount(gotp); > > got.br_blockcount? Right. will fix it. > >> +xfs_iext_remove(ip, *current_ext, 1, 0); >> +if (cur) { >> +error = xfs_btree_delete(cur, ); >> +if (error) >> +goto del_cursor; >> +XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); >> +} >> +XFS_IFORK_NEXT_SET(ip, whichfork, >> +XFS_IFORK_NEXTENTS(ip, whichfork) - 1); >> +gotp = xfs_iext_get_ext(ifp, --*current_ext); >> +xfs_bmbt_get_all(gotp, ); >> + >> +/* Make cursor point to the extent we will update */ >> +if (cur) { >> +error =
Re: [PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
Hi Dave. 2014-02-11 8:32 GMT+09:00, Dave Chinner da...@fromorbit.com: On Sun, Feb 02, 2014 at 02:44:11PM +0900, Namjae Jeon wrote: From: Namjae Jeon namjae.j...@samsung.com Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. Signed-off-by: Namjae Jeon namjae.j...@samsung.com Signed-off-by: Ashish Sangwan a.sang...@samsung.com A more detailed description would be nice for the change logs. . Okay, I will update it on next version. +while (nexts++ num_exts + *current_ext XFS_IFORK_NEXTENTS(ip, whichfork)) { + +gotp = xfs_iext_get_ext(ifp, *current_ext); +xfs_bmbt_get_all(gotp, got); +startoff = got.br_startoff - offset_shift_fsb; + +/* + * Before shifting extent into hole, make sure that the hole + * is large enough to accomodate the shift. + */ +if (*current_ext) { +xfs_bmbt_get_all(xfs_iext_get_ext(ifp, +*current_ext - 1), left); + +if (startoff left.br_startoff + left.br_blockcount) +error = XFS_ERROR(EINVAL); + +} else if (startoff xfs_bmbt_get_startoff(gotp)) { +/* Hole is at the start but not large enough */ +error = XFS_ERROR(EINVAL); +} This second branch seems wrong to me: startoff = got.br_startoff - offset_shift_fsb; and got.br_startoff = xfs_bmbt_get_startoff(gotp)). I'm not 100% sure what you are trying to check in this case - perhaps some basic ascii art to describe the two cases is in order here: leftholegot +---+hhh+-+ LS LE GSGE HS HE The first is checking that GS - offset_shift_fsb is greater than LE. i.e the shift doesn't overrun the hole betwenn LE and GS. leftholegot +---+hhh+-+ LS LE GSGE HS HE +---+hhh+-+ LS LE GS' GE' HS HE' The second I can't visualise from the code or comment When we shift first extent, *current_ext will be 0. So we need to check that offset_shift_fsb ( Number of blocks to be shifted ) should be less than starting offset of the first extent. So, code will be changed more clearly like this. + else if (offset_shift_fsb got.br_startoff) { + /* Hole is at the start but not large enough */ + error = XFS_ERROR(EINVAL); + } And will update comment more clearly. + +if (error) +goto del_cursor; + +if (cur) { +error = xfs_bmbt_lookup_eq(cur, +got.br_startoff, +got.br_startblock, +got.br_blockcount, +i); Whitespace comment - a more compact form is the typical XFS convention if it will fit in 80 columns: Okay. I will fix it. error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, i); +if (error) +goto del_cursor; +XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); +} + +/* Check if we can merge 2 adjacent extents */ +if (*current_ext +left.br_startoff + left.br_blockcount == startoff +left.br_startblock + left.br_blockcount == +got.br_startblock +left.br_state == got.br_state +left.br_blockcount + got.br_blockcount = MAXEXTLEN) { +blockcount = left.br_blockcount + +xfs_bmbt_get_blockcount(gotp); got.br_blockcount? Right. will fix it. +xfs_iext_remove(ip, *current_ext, 1, 0); +if (cur) { +error = xfs_btree_delete(cur, i); +if (error) +goto del_cursor; +XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); +} +XFS_IFORK_NEXT_SET(ip, whichfork, +XFS_IFORK_NEXTENTS(ip, whichfork) - 1); +gotp = xfs_iext_get_ext(ifp, --*current_ext); +xfs_bmbt_get_all(gotp, got); + +/* Make cursor point to the extent we will update */ +if (cur) { +error = xfs_bmbt_lookup_eq(cur, +got.br_startoff, +
Re: [PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
On Sun, Feb 02, 2014 at 02:44:11PM +0900, Namjae Jeon wrote: > From: Namjae Jeon > > Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. > > Signed-off-by: Namjae Jeon > Signed-off-by: Ashish Sangwan A more detailed description would be nice for the change logs. . > + while (nexts++ < num_exts && > +*current_ext < XFS_IFORK_NEXTENTS(ip, whichfork)) { > + > + gotp = xfs_iext_get_ext(ifp, *current_ext); > + xfs_bmbt_get_all(gotp, ); > + startoff = got.br_startoff - offset_shift_fsb; > + > + /* > + * Before shifting extent into hole, make sure that the hole > + * is large enough to accomodate the shift. > + */ > + if (*current_ext) { > + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, > + *current_ext - 1), ); > + > + if (startoff < left.br_startoff + left.br_blockcount) > + error = XFS_ERROR(EINVAL); > + > + } else if (startoff > xfs_bmbt_get_startoff(gotp)) { > + /* Hole is at the start but not large enough */ > + error = XFS_ERROR(EINVAL); > + } This second branch seems wrong to me: startoff = got.br_startoff - offset_shift_fsb; and got.br_startoff = xfs_bmbt_get_startoff(gotp)). I'm not 100% sure what you are trying to check in this case - perhaps some basic ascii art to describe the two cases is in order here: leftholegot +---+hhh+-+ LS LE GSGE HS HE The first is checking that GS - offset_shift_fsb is greater than LE. i.e the shift doesn't overrun the hole betwenn LE and GS. leftholegot +---+hhh+-+ LS LE GSGE HS HE +---+hhh+-+ LS LE GS' GE' HS HE' The second I can't visualise from the code or comment > + > + if (error) > + goto del_cursor; > + > + if (cur) { > + error = xfs_bmbt_lookup_eq(cur, > + got.br_startoff, > + got.br_startblock, > + got.br_blockcount, > + ); Whitespace comment - a more compact form is the typical XFS convention if it will fit in 80 columns: error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, ); > + if (error) > + goto del_cursor; > + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); > + } > + > + /* Check if we can merge 2 adjacent extents */ > + if (*current_ext && > + left.br_startoff + left.br_blockcount == startoff && > + left.br_startblock + left.br_blockcount == > + got.br_startblock && > + left.br_state == got.br_state && > + left.br_blockcount + got.br_blockcount <= MAXEXTLEN) { > + blockcount = left.br_blockcount + > + xfs_bmbt_get_blockcount(gotp); got.br_blockcount? > + xfs_iext_remove(ip, *current_ext, 1, 0); > + if (cur) { > + error = xfs_btree_delete(cur, ); > + if (error) > + goto del_cursor; > + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); > + } > + XFS_IFORK_NEXT_SET(ip, whichfork, > + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); > + gotp = xfs_iext_get_ext(ifp, --*current_ext); > + xfs_bmbt_get_all(gotp, ); > + > + /* Make cursor point to the extent we will update */ > + if (cur) { > + error = xfs_bmbt_lookup_eq(cur, > + got.br_startoff, > + got.br_startblock, > + got.br_blockcount, > + ); whitespace. > + if (error) > + goto del_cursor; > + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); > + } > + > + xfs_bmbt_set_blockcount(gotp, blockcount); > + got.br_blockcount = blockcount; > + goto bmbt_update; > +
Re: [PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
On Sun, Feb 02, 2014 at 02:44:11PM +0900, Namjae Jeon wrote: From: Namjae Jeon namjae.j...@samsung.com Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. Signed-off-by: Namjae Jeon namjae.j...@samsung.com Signed-off-by: Ashish Sangwan a.sang...@samsung.com A more detailed description would be nice for the change logs. . + while (nexts++ num_exts +*current_ext XFS_IFORK_NEXTENTS(ip, whichfork)) { + + gotp = xfs_iext_get_ext(ifp, *current_ext); + xfs_bmbt_get_all(gotp, got); + startoff = got.br_startoff - offset_shift_fsb; + + /* + * Before shifting extent into hole, make sure that the hole + * is large enough to accomodate the shift. + */ + if (*current_ext) { + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, + *current_ext - 1), left); + + if (startoff left.br_startoff + left.br_blockcount) + error = XFS_ERROR(EINVAL); + + } else if (startoff xfs_bmbt_get_startoff(gotp)) { + /* Hole is at the start but not large enough */ + error = XFS_ERROR(EINVAL); + } This second branch seems wrong to me: startoff = got.br_startoff - offset_shift_fsb; and got.br_startoff = xfs_bmbt_get_startoff(gotp)). I'm not 100% sure what you are trying to check in this case - perhaps some basic ascii art to describe the two cases is in order here: leftholegot +---+hhh+-+ LS LE GSGE HS HE The first is checking that GS - offset_shift_fsb is greater than LE. i.e the shift doesn't overrun the hole betwenn LE and GS. leftholegot +---+hhh+-+ LS LE GSGE HS HE +---+hhh+-+ LS LE GS' GE' HS HE' The second I can't visualise from the code or comment + + if (error) + goto del_cursor; + + if (cur) { + error = xfs_bmbt_lookup_eq(cur, + got.br_startoff, + got.br_startblock, + got.br_blockcount, + i); Whitespace comment - a more compact form is the typical XFS convention if it will fit in 80 columns: error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, i); + if (error) + goto del_cursor; + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); + } + + /* Check if we can merge 2 adjacent extents */ + if (*current_ext + left.br_startoff + left.br_blockcount == startoff + left.br_startblock + left.br_blockcount == + got.br_startblock + left.br_state == got.br_state + left.br_blockcount + got.br_blockcount = MAXEXTLEN) { + blockcount = left.br_blockcount + + xfs_bmbt_get_blockcount(gotp); got.br_blockcount? + xfs_iext_remove(ip, *current_ext, 1, 0); + if (cur) { + error = xfs_btree_delete(cur, i); + if (error) + goto del_cursor; + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); + } + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + gotp = xfs_iext_get_ext(ifp, --*current_ext); + xfs_bmbt_get_all(gotp, got); + + /* Make cursor point to the extent we will update */ + if (cur) { + error = xfs_bmbt_lookup_eq(cur, + got.br_startoff, + got.br_startblock, + got.br_blockcount, + i); whitespace. + if (error) + goto del_cursor; + XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); + } + + xfs_bmbt_set_blockcount(gotp, blockcount); + got.br_blockcount = blockcount; + goto bmbt_update; + } +
[PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
From: Namjae Jeon Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. Signed-off-by: Namjae Jeon Signed-off-by: Ashish Sangwan --- fs/xfs/xfs_bmap.c | 195 fs/xfs/xfs_bmap.h |5 ++ fs/xfs/xfs_bmap_util.c | 99 fs/xfs/xfs_bmap_util.h |2 + fs/xfs/xfs_file.c | 19 - fs/xfs/xfs_trace.h |1 + 6 files changed, 319 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 3ef11b2..aba3fc9 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -5358,3 +5358,198 @@ error0: } return error; } + +/* + * Shift extent records to the left to cover a hole. + * + * The maximum number of extents to be shifted in a single operation + * is @num_exts, and @current_ext keeps track of the current extent + * index we have shifted. @offset_shift_fsb is the length by which each + * extent is shifted. If there is no hole to shift the extents + * into, this will be considered invalid operation and we abort immediately. + */ +int +xfs_bmap_shift_extents( + struct xfs_trans*tp, + struct xfs_inode*ip, + int *done, + xfs_fileoff_t start_fsb, + xfs_fileoff_t offset_shift_fsb, + xfs_extnum_t*current_ext, + xfs_fsblock_t *firstblock, + struct xfs_bmap_free*flist, + int num_exts) +{ + struct xfs_btree_cur*cur; + struct xfs_bmbt_rec_host*gotp; + struct xfs_bmbt_irecgot; + struct xfs_bmbt_irecleft; + struct xfs_mount*mp = ip->i_mount; + struct xfs_ifork*ifp; + xfs_extnum_tnexts = 0; + xfs_fileoff_t startoff; + int error = 0; + int i; + int whichfork = XFS_DATA_FORK; + int logflags; + xfs_filblks_t blockcount = 0; + + if (unlikely(XFS_TEST_ERROR( + (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && +XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), +mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { + XFS_ERROR_REPORT("xfs_bmap_shift_extents", +XFS_ERRLEVEL_LOW, mp); + return XFS_ERROR(EFSCORRUPTED); + } + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + ASSERT(current_ext != NULL); + + ifp = XFS_IFORK_PTR(ip, whichfork); + + if (!(ifp->if_flags & XFS_IFEXTENTS)) { + /* Read in all the extents */ + error = xfs_iread_extents(tp, ip, whichfork); + if (error) + return error; + } + + /* +* If *current_ext is 0, we would need to lookup the extent +* from where we would start shifting and store it in gotp. +*/ + if (!*current_ext) { + gotp = xfs_iext_bno_to_ext(ifp, start_fsb, current_ext); + /* +* gotp can be null in 2 cases: 1) if there are no extents +* or 2) start_fsb lies in a hole beyond which there are +* no extents. Either way, we are done. +*/ + if (!gotp) { + *done = 1; + return 0; + } + } + + /* We are going to change core inode */ + logflags = XFS_ILOG_CORE; + + if (ifp->if_flags & XFS_IFBROOT) { + cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = 0; + } else { + cur = NULL; + logflags |= XFS_ILOG_DEXT; + } + + while (nexts++ < num_exts && + *current_ext < XFS_IFORK_NEXTENTS(ip, whichfork)) { + + gotp = xfs_iext_get_ext(ifp, *current_ext); + xfs_bmbt_get_all(gotp, ); + startoff = got.br_startoff - offset_shift_fsb; + + /* +* Before shifting extent into hole, make sure that the hole +* is large enough to accomodate the shift. +*/ + if (*current_ext) { + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, + *current_ext - 1), ); + + if (startoff < left.br_startoff + left.br_blockcount) + error = XFS_ERROR(EINVAL); + + } else if (startoff > xfs_bmbt_get_startoff(gotp)) { + /* Hole is at the start but not large enough */ + error =
[PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate
From: Namjae Jeon namjae.j...@samsung.com Add support FALLOC_FL_COLLAPSE_RANGE for fallocate. Signed-off-by: Namjae Jeon namjae.j...@samsung.com Signed-off-by: Ashish Sangwan a.sang...@samsung.com --- fs/xfs/xfs_bmap.c | 195 fs/xfs/xfs_bmap.h |5 ++ fs/xfs/xfs_bmap_util.c | 99 fs/xfs/xfs_bmap_util.h |2 + fs/xfs/xfs_file.c | 19 - fs/xfs/xfs_trace.h |1 + 6 files changed, 319 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 3ef11b2..aba3fc9 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -5358,3 +5358,198 @@ error0: } return error; } + +/* + * Shift extent records to the left to cover a hole. + * + * The maximum number of extents to be shifted in a single operation + * is @num_exts, and @current_ext keeps track of the current extent + * index we have shifted. @offset_shift_fsb is the length by which each + * extent is shifted. If there is no hole to shift the extents + * into, this will be considered invalid operation and we abort immediately. + */ +int +xfs_bmap_shift_extents( + struct xfs_trans*tp, + struct xfs_inode*ip, + int *done, + xfs_fileoff_t start_fsb, + xfs_fileoff_t offset_shift_fsb, + xfs_extnum_t*current_ext, + xfs_fsblock_t *firstblock, + struct xfs_bmap_free*flist, + int num_exts) +{ + struct xfs_btree_cur*cur; + struct xfs_bmbt_rec_host*gotp; + struct xfs_bmbt_irecgot; + struct xfs_bmbt_irecleft; + struct xfs_mount*mp = ip-i_mount; + struct xfs_ifork*ifp; + xfs_extnum_tnexts = 0; + xfs_fileoff_t startoff; + int error = 0; + int i; + int whichfork = XFS_DATA_FORK; + int logflags; + xfs_filblks_t blockcount = 0; + + if (unlikely(XFS_TEST_ERROR( + (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS +XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), +mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { + XFS_ERROR_REPORT(xfs_bmap_shift_extents, +XFS_ERRLEVEL_LOW, mp); + return XFS_ERROR(EFSCORRUPTED); + } + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + ASSERT(current_ext != NULL); + + ifp = XFS_IFORK_PTR(ip, whichfork); + + if (!(ifp-if_flags XFS_IFEXTENTS)) { + /* Read in all the extents */ + error = xfs_iread_extents(tp, ip, whichfork); + if (error) + return error; + } + + /* +* If *current_ext is 0, we would need to lookup the extent +* from where we would start shifting and store it in gotp. +*/ + if (!*current_ext) { + gotp = xfs_iext_bno_to_ext(ifp, start_fsb, current_ext); + /* +* gotp can be null in 2 cases: 1) if there are no extents +* or 2) start_fsb lies in a hole beyond which there are +* no extents. Either way, we are done. +*/ + if (!gotp) { + *done = 1; + return 0; + } + } + + /* We are going to change core inode */ + logflags = XFS_ILOG_CORE; + + if (ifp-if_flags XFS_IFBROOT) { + cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); + cur-bc_private.b.firstblock = *firstblock; + cur-bc_private.b.flist = flist; + cur-bc_private.b.flags = 0; + } else { + cur = NULL; + logflags |= XFS_ILOG_DEXT; + } + + while (nexts++ num_exts + *current_ext XFS_IFORK_NEXTENTS(ip, whichfork)) { + + gotp = xfs_iext_get_ext(ifp, *current_ext); + xfs_bmbt_get_all(gotp, got); + startoff = got.br_startoff - offset_shift_fsb; + + /* +* Before shifting extent into hole, make sure that the hole +* is large enough to accomodate the shift. +*/ + if (*current_ext) { + xfs_bmbt_get_all(xfs_iext_get_ext(ifp, + *current_ext - 1), left); + + if (startoff left.br_startoff + left.br_blockcount) + error = XFS_ERROR(EINVAL); + + } else if (startoff xfs_bmbt_get_startoff(gotp)) { + /* Hole is at the start but not