[PATCH v2 2/7] xfs: add support FALLOC_FL_COLLAPSE_RANGE for fallocate

2013-09-02 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  |  174 
 fs/xfs/xfs_bmap.h  |3 +
 fs/xfs/xfs_bmap_util.c |   96 ++
 fs/xfs/xfs_bmap_util.h |2 +
 fs/xfs/xfs_file.c  |   20 --
 fs/xfs/xfs_fs.h|6 ++
 6 files changed, 296 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 92b8309..c12358e 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5356,3 +5356,177 @@ error0:
}
return error;
 }
+
+/*
+ * Update extents by shifting them downwards into a hole.
+ * At max count number of extents will be shifted and *current_ext
+ * is the extent number which is currently being shifted.
+ * This function will return error if the hole is not present
+ * while shifting extents. On success, 0 is returned.
+ */
+int
+xfs_bmap_shift_extents(
+   struct xfs_trans*tp,
+   struct xfs_inode*ip,
+   int *done,
+   xfs_fileoff_t   start_fsb,
+   xfs_fileoff_t   shift,
+   xfs_extnum_t*current_ext,
+   xfs_fsblock_t   *firstblock,
+   struct xfs_bmap_free*flist,
+   int count)
+{
+   struct xfs_btree_cur*cur;
+   struct xfs_bmbt_rec_host*gotp;
+   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 state;
+   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);
+
+   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) {
+   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++ < count &&
+  *current_ext <  XFS_IFORK_NEXTENTS(ip, whichfork)) {
+   state = 0;
+
+   gotp = xfs_iext_get_ext(ifp, *current_ext);
+   startoff = xfs_bmbt_get_startoff(gotp);
+   startoff -= shift;
+
+   /*
+* Before shifting extent into hole, make sure that the hole
+* is large enough to accomodate the shift.
+*/
+   if (*current_ext) {
+   state |= BMAP_LEFT_VALID;
+   xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
+   *current_ext - 1), );
+
+   if (isnullstartblock(left.br_startblock))
+   state |= BMAP_LEFT_DELAY;
+
+   if (startoff < left.br_startoff + left.br_blockcount)
+   error = XFS_ERROR(EFSCORRUPTED);
+
+   } else if (startoff > xfs_bmbt_get_startoff(gotp))
+   /* Hole is at the start but not large enough */
+   error = XFS_ERROR(EFSCORRUPTED);
+
+   if (error)
+   goto del_cursor;
+
+   /* 

[PATCH v2 2/7] xfs: add support FALLOC_FL_COLLAPSE_RANGE for fallocate

2013-09-02 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  |  174 
 fs/xfs/xfs_bmap.h  |3 +
 fs/xfs/xfs_bmap_util.c |   96 ++
 fs/xfs/xfs_bmap_util.h |2 +
 fs/xfs/xfs_file.c  |   20 --
 fs/xfs/xfs_fs.h|6 ++
 6 files changed, 296 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 92b8309..c12358e 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -5356,3 +5356,177 @@ error0:
}
return error;
 }
+
+/*
+ * Update extents by shifting them downwards into a hole.
+ * At max count number of extents will be shifted and *current_ext
+ * is the extent number which is currently being shifted.
+ * This function will return error if the hole is not present
+ * while shifting extents. On success, 0 is returned.
+ */
+int
+xfs_bmap_shift_extents(
+   struct xfs_trans*tp,
+   struct xfs_inode*ip,
+   int *done,
+   xfs_fileoff_t   start_fsb,
+   xfs_fileoff_t   shift,
+   xfs_extnum_t*current_ext,
+   xfs_fsblock_t   *firstblock,
+   struct xfs_bmap_free*flist,
+   int count)
+{
+   struct xfs_btree_cur*cur;
+   struct xfs_bmbt_rec_host*gotp;
+   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 state;
+   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);
+
+   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) {
+   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++  count 
+  *current_ext   XFS_IFORK_NEXTENTS(ip, whichfork)) {
+   state = 0;
+
+   gotp = xfs_iext_get_ext(ifp, *current_ext);
+   startoff = xfs_bmbt_get_startoff(gotp);
+   startoff -= shift;
+
+   /*
+* Before shifting extent into hole, make sure that the hole
+* is large enough to accomodate the shift.
+*/
+   if (*current_ext) {
+   state |= BMAP_LEFT_VALID;
+   xfs_bmbt_get_all(xfs_iext_get_ext(ifp,
+   *current_ext - 1), left);
+
+   if (isnullstartblock(left.br_startblock))
+   state |= BMAP_LEFT_DELAY;
+
+   if (startoff  left.br_startoff + left.br_blockcount)
+   error = XFS_ERROR(EFSCORRUPTED);
+
+   } else if (startoff  xfs_bmbt_get_startoff(gotp))
+   /* Hole is at the start but not large enough */
+   error = XFS_ERROR(EFSCORRUPTED);
+
+   if (error)
+