Re: [PATCH RESEND 2/10] xfs: Add support FALLOC_FL_COLLAPSE_RANGE for fallocate

2014-02-11 Thread Namjae Jeon
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

2014-02-11 Thread Namjae Jeon
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

2014-02-10 Thread 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.
.

> + 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

2014-02-10 Thread Dave Chinner
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

2014-02-01 Thread Namjae Jeon
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

2014-02-01 Thread Namjae Jeon
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