This commit upgrades inodes to use 64-bit extent counters when they are read from disk. Inodes are upgraded only when the filesystem instance has XFS_SB_FEAT_INCOMPAT_NREXT64 incompat flag set. Signed-off-by: Chandan Babu R <chandan.babu@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_attr.c | 3 ++- fs/xfs/libxfs/xfs_bmap.c | 5 ++--- fs/xfs/libxfs/xfs_inode_fork.c | 37 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_inode_fork.h | 2 ++ fs/xfs/xfs_bmap_item.c | 3 ++- fs/xfs/xfs_bmap_util.c | 10 ++++----- fs/xfs/xfs_dquot.c | 2 +- fs/xfs/xfs_iomap.c | 5 +++-- fs/xfs/xfs_reflink.c | 5 +++-- fs/xfs/xfs_rtalloc.c | 2 +- 10 files changed, 58 insertions(+), 16 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 23523b802539..03a358930d74 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -774,7 +774,8 @@ xfs_attr_set( return error; if (args->value || xfs_inode_hasattr(dp)) { - error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK, + error = xfs_trans_inode_ensure_nextents(&args->trans, dp, + XFS_ATTR_FORK, XFS_IEXT_ATTR_MANIP_CNT(rmt_blks)); if (error) goto out_trans_cancel; diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index be7f8ebe3cd5..3a3c99ef7f13 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -4523,14 +4523,13 @@ xfs_bmapi_convert_delalloc( return error; xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, 0); - error = xfs_iext_count_may_overflow(ip, whichfork, + error = xfs_trans_inode_ensure_nextents(&tp, ip, whichfork, XFS_IEXT_ADD_NOSPLIT_CNT); if (error) goto out_trans_cancel; - xfs_trans_ijoin(tp, ip, 0); - if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) || bma.got.br_startoff > offset_fsb) { /* diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index a3a3b54f9c55..d1d065abeac3 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -757,3 +757,40 @@ xfs_iext_count_may_overflow( return 0; } + +/* + * Ensure that the inode has the ability to add the specified number of + * extents. Caller must hold ILOCK_EXCL and have joined the inode to + * the transaction. Upon return, the inode will still be in this state + * upon return and the transaction will be clean. + */ +int +xfs_trans_inode_ensure_nextents( + struct xfs_trans **tpp, + struct xfs_inode *ip, + int whichfork, + int nr_to_add) +{ + int error; + + error = xfs_iext_count_may_overflow(ip, whichfork, nr_to_add); + if (!error) + return 0; + + /* + * Try to upgrade if the extent count fields aren't large + * enough. + */ + if (!xfs_has_nrext64(ip->i_mount) || + (ip->i_diflags2 & XFS_DIFLAG2_NREXT64)) + return error; + + ip->i_diflags2 |= XFS_DIFLAG2_NREXT64; + xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); + + error = xfs_trans_roll(tpp); + if (error) + return error; + + return xfs_iext_count_may_overflow(ip, whichfork, nr_to_add); +} diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index 8e6221e32660..65265ca51b0d 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h @@ -286,6 +286,8 @@ int xfs_ifork_verify_local_data(struct xfs_inode *ip); int xfs_ifork_verify_local_attr(struct xfs_inode *ip); int xfs_iext_count_may_overflow(struct xfs_inode *ip, int whichfork, int nr_to_add); +int xfs_trans_inode_ensure_nextents(struct xfs_trans **tpp, + struct xfs_inode *ip, int whichfork, int nr_to_add); /* returns true if the fork has extents but they are not read in yet. */ static inline bool xfs_need_iread_extents(struct xfs_ifork *ifp) diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c index e1f4d7d5a011..27bc16a2b09b 100644 --- a/fs/xfs/xfs_bmap_item.c +++ b/fs/xfs/xfs_bmap_item.c @@ -505,7 +505,8 @@ xfs_bui_item_recover( else iext_delta = XFS_IEXT_PUNCH_HOLE_CNT; - error = xfs_iext_count_may_overflow(ip, whichfork, iext_delta); + error = xfs_trans_inode_ensure_nextents(&tp, ip, whichfork, + iext_delta); if (error) goto err_cancel; diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index eb2e387ba528..8d86d8d5ad88 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -855,7 +855,7 @@ xfs_alloc_file_space( if (error) break; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_ADD_NOSPLIT_CNT); if (error) goto error; @@ -910,7 +910,7 @@ xfs_unmap_extent( if (error) return error; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_PUNCH_HOLE_CNT); if (error) goto out_trans_cancel; @@ -1191,7 +1191,7 @@ xfs_insert_file_space( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_PUNCH_HOLE_CNT); if (error) goto out_trans_cancel; @@ -1418,7 +1418,7 @@ xfs_swap_extent_rmap( trace_xfs_swap_extent_rmap_remap_piece(tip, &uirec); if (xfs_bmap_is_real_extent(&uirec)) { - error = xfs_iext_count_may_overflow(ip, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_SWAP_RMAP_CNT); if (error) @@ -1426,7 +1426,7 @@ xfs_swap_extent_rmap( } if (xfs_bmap_is_real_extent(&irec)) { - error = xfs_iext_count_may_overflow(tip, + error = xfs_trans_inode_ensure_nextents(&tp, tip, XFS_DATA_FORK, XFS_IEXT_SWAP_RMAP_CNT); if (error) diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 5afedcbc78c7..193a2e66efc7 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -320,7 +320,7 @@ xfs_dquot_disk_alloc( goto err_cancel; } - error = xfs_iext_count_may_overflow(quotip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, quotip, XFS_DATA_FORK, XFS_IEXT_ADD_NOSPLIT_CNT); if (error) goto err_cancel; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index e552ce541ec2..4078d5324090 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -250,7 +250,8 @@ xfs_iomap_write_direct( if (error) return error; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, nr_exts); + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, + nr_exts); if (error) goto out_trans_cancel; @@ -553,7 +554,7 @@ xfs_iomap_write_unwritten( if (error) return error; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_WRITE_UNWRITTEN_CNT); if (error) goto error_on_bmapi_transaction; diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index db70060e7bf6..9d4fd2b160ff 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -615,7 +615,7 @@ xfs_reflink_end_cow_extent( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_REFLINK_END_COW_CNT); if (error) goto out_cancel; @@ -1117,7 +1117,8 @@ xfs_reflink_remap_extent( if (dmap_written) ++iext_delta; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, iext_delta); + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, + iext_delta); if (error) goto out_cancel; diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 379ef99722c5..4d24977d6a47 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -806,7 +806,7 @@ xfs_growfs_rt_alloc( xfs_trans_ijoin(tp, ip, 0); unlock_inode = true; - error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, + error = xfs_trans_inode_ensure_nextents(&tp, ip, XFS_DATA_FORK, XFS_IEXT_ADD_NOSPLIT_CNT); if (error) goto out_trans_cancel; -- 2.30.2