[PATCH v2 2/7] 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 | 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
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) +