Instead enhance xfs_reflink_find_cow_mapping to properly deal with the fact that we might not have a COW mapping at the offset, and just return false in this case. This avoids code duplication, makes xfs_reflink_find_cow_mapping more robust, and last but not least halves the number of extent map lookups needed in COW writeback operations. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/xfs/xfs_aops.c | 28 ++++++++++++++++------------ fs/xfs/xfs_reflink.c | 42 +++++++++++------------------------------- fs/xfs/xfs_reflink.h | 3 +-- 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index d8ce18b..1933803 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -379,10 +379,13 @@ xfs_map_blocks( end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); offset_fsb = XFS_B_TO_FSBT(mp, offset); - if (type == XFS_IO_COW) - error = xfs_reflink_find_cow_mapping(ip, offset, imap, - &need_alloc); - else { + if (type == XFS_IO_COW) { + if (!xfs_reflink_find_cow_mapping(ip, offset, imap, + &need_alloc)) { + WARN_ON_ONCE(1); + return -EIO; + } + } else { error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, imap, &nimaps, bmapi_flags); /* @@ -712,13 +715,14 @@ xfs_is_cow_io( struct xfs_inode *ip, xfs_off_t offset) { - bool is_cow; + struct xfs_bmbt_irec imap; + bool is_cow, need_alloc; if (!xfs_sb_version_hasreflink(&ip->i_mount->m_sb)) return false; xfs_ilock(ip, XFS_ILOCK_SHARED); - is_cow = xfs_reflink_is_cow_pending(ip, offset); + is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, &need_alloc); xfs_iunlock(ip, XFS_ILOCK_SHARED); return is_cow; @@ -1316,12 +1320,12 @@ __xfs_get_blocks( end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size); offset_fsb = XFS_B_TO_FSBT(mp, offset); - if (create && direct) - is_cow = xfs_reflink_is_cow_pending(ip, offset); - if (is_cow) - error = xfs_reflink_find_cow_mapping(ip, offset, &imap, - &need_alloc); - else { + if (create && direct) { + is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, + &need_alloc); + } + + if (!is_cow) { error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, &nimaps, XFS_BMAPI_ENTIRE); /* diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 6f87b1e..a1ba7f5 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -429,26 +429,31 @@ advloop: } /* - * Determine if there's a CoW reservation at a byte offset of an inode. + * Find the CoW reservation (and whether or not it needs block allocation) + * for a given byte offset of a file. */ bool -xfs_reflink_is_cow_pending( +xfs_reflink_find_cow_mapping( struct xfs_inode *ip, - xfs_off_t offset) + xfs_off_t offset, + struct xfs_bmbt_irec *imap, + bool *need_alloc) { + struct xfs_bmbt_irec irec; struct xfs_ifork *ifp; struct xfs_bmbt_rec_host *gotp; - struct xfs_bmbt_irec irec; xfs_fileoff_t bno; xfs_extnum_t idx; + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); + if (!xfs_is_reflink_inode(ip)) return false; + /* Find the extent in the CoW fork. */ ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); bno = XFS_B_TO_FSBT(ip->i_mount, offset); gotp = xfs_iext_bno_to_ext(ifp, bno, &idx); - if (!gotp) return false; @@ -456,31 +461,6 @@ xfs_reflink_is_cow_pending( if (bno >= irec.br_startoff + irec.br_blockcount || bno < irec.br_startoff) return false; - return true; -} - -/* - * Find the CoW reservation (and whether or not it needs block allocation) - * for a given byte offset of a file. - */ -int -xfs_reflink_find_cow_mapping( - struct xfs_inode *ip, - xfs_off_t offset, - struct xfs_bmbt_irec *imap, - bool *need_alloc) -{ - struct xfs_bmbt_irec irec; - struct xfs_ifork *ifp; - struct xfs_bmbt_rec_host *gotp; - xfs_fileoff_t bno; - xfs_extnum_t idx; - - /* Find the extent in the CoW fork. */ - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - bno = XFS_B_TO_FSBT(ip->i_mount, offset); - gotp = xfs_iext_bno_to_ext(ifp, bno, &idx); - xfs_bmbt_get_all(gotp, &irec); trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE, &irec); @@ -489,7 +469,7 @@ xfs_reflink_find_cow_mapping( *imap = irec; *need_alloc = !!(isnullstartblock(irec.br_startblock)); - return 0; + return true; } /* diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index 398e726..6519f19 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -30,8 +30,7 @@ extern int xfs_reflink_reserve_cow_range(struct xfs_inode *ip, xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb); extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, xfs_off_t pos, xfs_off_t len); -extern bool xfs_reflink_is_cow_pending(struct xfs_inode *ip, xfs_off_t offset); -extern int xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, +extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, struct xfs_bmbt_irec *imap, bool *need_alloc); extern int xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap); -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html