Skip to content

Commit 4f86bb4

Browse files
author
Chandan Babu R
committed
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>
1 parent 83a21c1 commit 4f86bb4

11 files changed

Lines changed: 75 additions & 2 deletions

fs/xfs/libxfs/xfs_attr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@ xfs_attr_set(
776776
if (args->value || xfs_inode_hasattr(dp)) {
777777
error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
778778
XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
779+
if (error == -EFBIG)
780+
error = xfs_iext_count_upgrade(args->trans, dp,
781+
XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
779782
if (error)
780783
goto out_trans_cancel;
781784
}

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4524,14 +4524,16 @@ xfs_bmapi_convert_delalloc(
45244524
return error;
45254525

45264526
xfs_ilock(ip, XFS_ILOCK_EXCL);
4527+
xfs_trans_ijoin(tp, ip, 0);
45274528

45284529
error = xfs_iext_count_may_overflow(ip, whichfork,
45294530
XFS_IEXT_ADD_NOSPLIT_CNT);
4531+
if (error == -EFBIG)
4532+
error = xfs_iext_count_upgrade(tp, ip,
4533+
XFS_IEXT_ADD_NOSPLIT_CNT);
45304534
if (error)
45314535
goto out_trans_cancel;
45324536

4533-
xfs_trans_ijoin(tp, ip, 0);
4534-
45354537
if (!xfs_iext_lookup_extent(ip, ifp, offset_fsb, &bma.icur, &bma.got) ||
45364538
bma.got.br_startoff > offset_fsb) {
45374539
/*

fs/xfs/libxfs/xfs_format.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,17 @@ enum xfs_dinode_fmt {
934934
#define XFS_MAX_EXTCNT_DATA_FORK_SMALL ((xfs_extnum_t)((1ULL << 31) - 1))
935935
#define XFS_MAX_EXTCNT_ATTR_FORK_SMALL ((xfs_extnum_t)((1ULL << 15) - 1))
936936

937+
/*
938+
* When we upgrade an inode to the large extent counts, the maximum value by
939+
* which the extent count can increase is bound by the change in size of the
940+
* on-disk field. No upgrade operation should ever be adding more than a few
941+
* tens of extents, so if we get a really large value it is a sign of a code bug
942+
* or corruption.
943+
*/
944+
#define XFS_MAX_EXTCNT_UPGRADE_NR \
945+
min(XFS_MAX_EXTCNT_ATTR_FORK_LARGE - XFS_MAX_EXTCNT_ATTR_FORK_SMALL, \
946+
XFS_MAX_EXTCNT_DATA_FORK_LARGE - XFS_MAX_EXTCNT_DATA_FORK_SMALL)
947+
937948
/*
938949
* Inode minimum and maximum sizes.
939950
*/

fs/xfs/libxfs/xfs_inode_fork.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,3 +756,27 @@ xfs_iext_count_may_overflow(
756756

757757
return 0;
758758
}
759+
760+
/*
761+
* Upgrade this inode's extent counter fields to be able to handle a potential
762+
* increase in the extent count by nr_to_add. Normally this is the same
763+
* quantity that caused xfs_iext_count_may_overflow() to return -EFBIG.
764+
*/
765+
int
766+
xfs_iext_count_upgrade(
767+
struct xfs_trans *tp,
768+
struct xfs_inode *ip,
769+
uint nr_to_add)
770+
{
771+
ASSERT(nr_to_add <= XFS_MAX_EXTCNT_UPGRADE_NR);
772+
773+
if (!xfs_has_large_extent_counts(ip->i_mount) ||
774+
xfs_inode_has_large_extent_counts(ip) ||
775+
XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
776+
return -EFBIG;
777+
778+
ip->i_diflags2 |= XFS_DIFLAG2_NREXT64;
779+
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
780+
781+
return 0;
782+
}

fs/xfs/libxfs/xfs_inode_fork.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ int xfs_ifork_verify_local_data(struct xfs_inode *ip);
275275
int xfs_ifork_verify_local_attr(struct xfs_inode *ip);
276276
int xfs_iext_count_may_overflow(struct xfs_inode *ip, int whichfork,
277277
int nr_to_add);
278+
int xfs_iext_count_upgrade(struct xfs_trans *tp, struct xfs_inode *ip,
279+
uint nr_to_add);
278280

279281
/* returns true if the fork has extents but they are not read in yet. */
280282
static inline bool xfs_need_iread_extents(struct xfs_ifork *ifp)

fs/xfs/xfs_bmap_item.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,8 @@ xfs_bui_item_recover(
506506
iext_delta = XFS_IEXT_PUNCH_HOLE_CNT;
507507

508508
error = xfs_iext_count_may_overflow(ip, whichfork, iext_delta);
509+
if (error == -EFBIG)
510+
error = xfs_iext_count_upgrade(tp, ip, iext_delta);
509511
if (error)
510512
goto err_cancel;
511513

fs/xfs/xfs_bmap_util.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,9 @@ xfs_alloc_file_space(
859859

860860
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
861861
XFS_IEXT_ADD_NOSPLIT_CNT);
862+
if (error == -EFBIG)
863+
error = xfs_iext_count_upgrade(tp, ip,
864+
XFS_IEXT_ADD_NOSPLIT_CNT);
862865
if (error)
863866
goto error;
864867

@@ -914,6 +917,8 @@ xfs_unmap_extent(
914917

915918
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
916919
XFS_IEXT_PUNCH_HOLE_CNT);
920+
if (error == -EFBIG)
921+
error = xfs_iext_count_upgrade(tp, ip, XFS_IEXT_PUNCH_HOLE_CNT);
917922
if (error)
918923
goto out_trans_cancel;
919924

@@ -1195,6 +1200,8 @@ xfs_insert_file_space(
11951200

11961201
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
11971202
XFS_IEXT_PUNCH_HOLE_CNT);
1203+
if (error == -EFBIG)
1204+
error = xfs_iext_count_upgrade(tp, ip, XFS_IEXT_PUNCH_HOLE_CNT);
11981205
if (error)
11991206
goto out_trans_cancel;
12001207

@@ -1423,6 +1430,9 @@ xfs_swap_extent_rmap(
14231430
error = xfs_iext_count_may_overflow(ip,
14241431
XFS_DATA_FORK,
14251432
XFS_IEXT_SWAP_RMAP_CNT);
1433+
if (error == -EFBIG)
1434+
error = xfs_iext_count_upgrade(tp, ip,
1435+
XFS_IEXT_SWAP_RMAP_CNT);
14261436
if (error)
14271437
goto out;
14281438
}
@@ -1431,6 +1441,9 @@ xfs_swap_extent_rmap(
14311441
error = xfs_iext_count_may_overflow(tip,
14321442
XFS_DATA_FORK,
14331443
XFS_IEXT_SWAP_RMAP_CNT);
1444+
if (error == -EFBIG)
1445+
error = xfs_iext_count_upgrade(tp, ip,
1446+
XFS_IEXT_SWAP_RMAP_CNT);
14341447
if (error)
14351448
goto out;
14361449
}

fs/xfs/xfs_dquot.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ xfs_dquot_disk_alloc(
322322

323323
error = xfs_iext_count_may_overflow(quotip, XFS_DATA_FORK,
324324
XFS_IEXT_ADD_NOSPLIT_CNT);
325+
if (error == -EFBIG)
326+
error = xfs_iext_count_upgrade(tp, quotip,
327+
XFS_IEXT_ADD_NOSPLIT_CNT);
325328
if (error)
326329
goto err_cancel;
327330

fs/xfs/xfs_iomap.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ xfs_iomap_write_direct(
251251
return error;
252252

253253
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, nr_exts);
254+
if (error == -EFBIG)
255+
error = xfs_iext_count_upgrade(tp, ip, nr_exts);
254256
if (error)
255257
goto out_trans_cancel;
256258

@@ -555,6 +557,9 @@ xfs_iomap_write_unwritten(
555557

556558
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
557559
XFS_IEXT_WRITE_UNWRITTEN_CNT);
560+
if (error == -EFBIG)
561+
error = xfs_iext_count_upgrade(tp, ip,
562+
XFS_IEXT_WRITE_UNWRITTEN_CNT);
558563
if (error)
559564
goto error_on_bmapi_transaction;
560565

fs/xfs/xfs_reflink.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,9 @@ xfs_reflink_end_cow_extent(
620620

621621
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
622622
XFS_IEXT_REFLINK_END_COW_CNT);
623+
if (error == -EFBIG)
624+
error = xfs_iext_count_upgrade(tp, ip,
625+
XFS_IEXT_REFLINK_END_COW_CNT);
623626
if (error)
624627
goto out_cancel;
625628

@@ -1121,6 +1124,8 @@ xfs_reflink_remap_extent(
11211124
++iext_delta;
11221125

11231126
error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK, iext_delta);
1127+
if (error == -EFBIG)
1128+
error = xfs_iext_count_upgrade(tp, ip, iext_delta);
11241129
if (error)
11251130
goto out_cancel;
11261131

0 commit comments

Comments
 (0)