diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 27 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 21 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 19 |
4 files changed, 39 insertions, 32 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 26518aa7b9ae..f45f05c45e15 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -1386,17 +1386,8 @@ xfs_bmap_last_before( return error; } - if (xfs_iext_lookup_extent(ip, ifp, *last_block - 1, &idx, &got)) { - if (got.br_startoff <= *last_block - 1) - return 0; - } - - if (xfs_iext_get_extent(ifp, idx - 1, &got)) { - *last_block = got.br_startoff + got.br_blockcount; - return 0; - } - - *last_block = 0; + if (!xfs_iext_lookup_extent_before(ip, ifp, last_block, &idx, &got)) + *last_block = 0; return 0; } @@ -5171,17 +5162,13 @@ __xfs_bunmapi( } XFS_STATS_INC(mp, xs_blk_unmap); isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); - end = start + len - 1; + end = start + len; - /* - * Check to see if the given block number is past the end of the - * file, back up to the last block if so... - */ - if (!xfs_iext_lookup_extent(ip, ifp, end, &lastx, &got)) { - ASSERT(lastx > 0); - xfs_iext_get_extent(ifp, --lastx, &got); - end = got.br_startoff + got.br_blockcount - 1; + if (!xfs_iext_lookup_extent_before(ip, ifp, &end, &lastx, &got)) { + *rlen = 0; + return 0; } + end--; logflags = 0; if (ifp->if_flags & XFS_IFBROOT) { diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 911ff791a896..bb63f38b97cc 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -1968,6 +1968,27 @@ xfs_iext_lookup_extent( } /* + * Returns the last extent before end, and if this extent doesn't cover + * end, update end to the end of the extent. + */ +bool +xfs_iext_lookup_extent_before( + struct xfs_inode *ip, + struct xfs_ifork *ifp, + xfs_fileoff_t *end, + xfs_extnum_t *idxp, + struct xfs_bmbt_irec *gotp) +{ + if (xfs_iext_lookup_extent(ip, ifp, *end - 1, idxp, gotp) && + gotp->br_startoff <= *end - 1) + return true; + if (!xfs_iext_get_extent(ifp, --*idxp, gotp)) + return false; + *end = gotp->br_startoff + gotp->br_blockcount; + return true; +} + +/* * Return true if there is an extent at index idx, and return the expanded * extent structure at idx in that case. Else return false. */ diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index e0c42ea9b8d0..113fd42ec36d 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h @@ -183,6 +183,10 @@ void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); bool xfs_iext_lookup_extent(struct xfs_inode *ip, struct xfs_ifork *ifp, xfs_fileoff_t bno, xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp); +bool xfs_iext_lookup_extent_before(struct xfs_inode *ip, + struct xfs_ifork *ifp, xfs_fileoff_t *end, + xfs_extnum_t *idxp, struct xfs_bmbt_irec *gotp); + bool xfs_iext_get_extent(struct xfs_ifork *ifp, xfs_extnum_t idx, struct xfs_bmbt_irec *gotp); void xfs_iext_update_extent(struct xfs_inode *ip, int state, diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 37e603bf1591..1205747e1409 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -733,18 +733,13 @@ xfs_reflink_end_cow( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - /* If there is a hole at end_fsb - 1 go to the previous extent */ - if (!xfs_iext_lookup_extent(ip, ifp, end_fsb - 1, &idx, &got) || - got.br_startoff > end_fsb) { - /* - * In case of racing, overlapping AIO writes no COW extents - * might be left by the time I/O completes for the loser of - * the race. In that case we are done. - */ - if (idx <= 0) - goto out_cancel; - xfs_iext_get_extent(ifp, --idx, &got); - } + /* + * In case of racing, overlapping AIO writes no COW extents might be + * left by the time I/O completes for the loser of the race. In that + * case we are done. + */ + if (!xfs_iext_lookup_extent_before(ip, ifp, &end_fsb, &idx, &got)) + goto out_cancel; /* Walk backwards until we're out of the I/O range... */ while (got.br_startoff + got.br_blockcount > offset_fsb) { |