xfs: Conditionally upgrade existing inodes to use large extent counters
This commit enables upgrading existing inodes to use large extent counters provided that underlying filesystem's superblock has large extent counter feature enabled. Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Chandan Babu R <chandan.babu@oracle.com>
This commit is contained in:
parent
83a21c1844
commit
4f86bb4b66
@ -776,6 +776,9 @@ xfs_attr_set(
|
||||
if (args->value || xfs_inode_hasattr(dp)) {
|
||||
error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
|
||||
XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(args->trans, dp,
|
||||
XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
}
|
||||
|
@ -4524,14 +4524,16 @@ 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,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
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) {
|
||||
/*
|
||||
|
@ -934,6 +934,17 @@ enum xfs_dinode_fmt {
|
||||
#define XFS_MAX_EXTCNT_DATA_FORK_SMALL ((xfs_extnum_t)((1ULL << 31) - 1))
|
||||
#define XFS_MAX_EXTCNT_ATTR_FORK_SMALL ((xfs_extnum_t)((1ULL << 15) - 1))
|
||||
|
||||
/*
|
||||
* When we upgrade an inode to the large extent counts, the maximum value by
|
||||
* which the extent count can increase is bound by the change in size of the
|
||||
* on-disk field. No upgrade operation should ever be adding more than a few
|
||||
* tens of extents, so if we get a really large value it is a sign of a code bug
|
||||
* or corruption.
|
||||
*/
|
||||
#define XFS_MAX_EXTCNT_UPGRADE_NR \
|
||||
min(XFS_MAX_EXTCNT_ATTR_FORK_LARGE - XFS_MAX_EXTCNT_ATTR_FORK_SMALL, \
|
||||
XFS_MAX_EXTCNT_DATA_FORK_LARGE - XFS_MAX_EXTCNT_DATA_FORK_SMALL)
|
||||
|
||||
/*
|
||||
* Inode minimum and maximum sizes.
|
||||
*/
|
||||
|
@ -756,3 +756,27 @@ xfs_iext_count_may_overflow(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upgrade this inode's extent counter fields to be able to handle a potential
|
||||
* increase in the extent count by nr_to_add. Normally this is the same
|
||||
* quantity that caused xfs_iext_count_may_overflow() to return -EFBIG.
|
||||
*/
|
||||
int
|
||||
xfs_iext_count_upgrade(
|
||||
struct xfs_trans *tp,
|
||||
struct xfs_inode *ip,
|
||||
uint nr_to_add)
|
||||
{
|
||||
ASSERT(nr_to_add <= XFS_MAX_EXTCNT_UPGRADE_NR);
|
||||
|
||||
if (!xfs_has_large_extent_counts(ip->i_mount) ||
|
||||
xfs_inode_has_large_extent_counts(ip) ||
|
||||
XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
|
||||
return -EFBIG;
|
||||
|
||||
ip->i_diflags2 |= XFS_DIFLAG2_NREXT64;
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -275,6 +275,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_iext_count_upgrade(struct xfs_trans *tp, struct xfs_inode *ip,
|
||||
uint 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)
|
||||
|
@ -506,6 +506,8 @@ xfs_bui_item_recover(
|
||||
iext_delta = XFS_IEXT_PUNCH_HOLE_CNT;
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, whichfork, iext_delta);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip, iext_delta);
|
||||
if (error)
|
||||
goto err_cancel;
|
||||
|
||||
|
@ -859,6 +859,9 @@ xfs_alloc_file_space(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
@ -914,6 +917,8 @@ xfs_unmap_extent(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_PUNCH_HOLE_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip, XFS_IEXT_PUNCH_HOLE_CNT);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
@ -1195,6 +1200,8 @@ xfs_insert_file_space(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_PUNCH_HOLE_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip, XFS_IEXT_PUNCH_HOLE_CNT);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
@ -1423,6 +1430,9 @@ xfs_swap_extent_rmap(
|
||||
error = xfs_iext_count_may_overflow(ip,
|
||||
XFS_DATA_FORK,
|
||||
XFS_IEXT_SWAP_RMAP_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_SWAP_RMAP_CNT);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
@ -1431,6 +1441,9 @@ xfs_swap_extent_rmap(
|
||||
error = xfs_iext_count_may_overflow(tip,
|
||||
XFS_DATA_FORK,
|
||||
XFS_IEXT_SWAP_RMAP_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_SWAP_RMAP_CNT);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
@ -322,6 +322,9 @@ xfs_dquot_disk_alloc(
|
||||
|
||||
error = xfs_iext_count_may_overflow(quotip, XFS_DATA_FORK,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, quotip,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error)
|
||||
goto err_cancel;
|
||||
|
||||
|
@ -251,6 +251,8 @@ xfs_iomap_write_direct(
|
||||
return error;
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, nr_exts);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip, nr_exts);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
@ -555,6 +557,9 @@ xfs_iomap_write_unwritten(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_WRITE_UNWRITTEN_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_WRITE_UNWRITTEN_CNT);
|
||||
if (error)
|
||||
goto error_on_bmapi_transaction;
|
||||
|
||||
|
@ -620,6 +620,9 @@ xfs_reflink_end_cow_extent(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_REFLINK_END_COW_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_REFLINK_END_COW_CNT);
|
||||
if (error)
|
||||
goto out_cancel;
|
||||
|
||||
@ -1121,6 +1124,8 @@ xfs_reflink_remap_extent(
|
||||
++iext_delta;
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, iext_delta);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip, iext_delta);
|
||||
if (error)
|
||||
goto out_cancel;
|
||||
|
||||
|
@ -806,6 +806,9 @@ xfs_growfs_rt_alloc(
|
||||
|
||||
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error == -EFBIG)
|
||||
error = xfs_iext_count_upgrade(tp, ip,
|
||||
XFS_IEXT_ADD_NOSPLIT_CNT);
|
||||
if (error)
|
||||
goto out_trans_cancel;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user