Skip to content

Commit 8bc54d3

Browse files
author
Bill O'Donnell
committed
xfs: estimate post-merge refcounts correctly
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2161676 commit b25d198 Author: Darrick J. Wong <djwong@kernel.org> Date: Wed Nov 30 09:25:51 2022 -0800 xfs: estimate post-merge refcounts correctly Upon enabling fsdax + reflink for XFS, xfs/179 began to report refcount metadata corruptions after being run. Specifically, xfs_repair noticed single-block refcount records that could be combined but had not been. The root cause of this is improper MAXREFCOUNT edge case handling in xfs_refcount_merge_extents. When we're trying to find candidates for a refcount btree record merge, we compute the refcount attribute of the merged record, but we fail to account for the fact that once a record hits rc_refcount == MAXREFCOUNT, it is pinned that way forever. Hence the computed refcount is wrong, and we fail to merge the extents. Fix this by adjusting the merge predicates to compute the adjusted refcount correctly. Fixes: 3172725 ("xfs: adjust refcount of an extent of blocks in refcount btree") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Xiao Yang <yangx.jy@fujitsu.com> Signed-off-by: Bill O'Donnell <bodonnel@redhat.com>
1 parent 3d3e38e commit 8bc54d3

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,17 @@ xfs_refc_valid(
789789
return rc->rc_startblock != NULLAGBLOCK;
790790
}
791791

792+
static inline xfs_nlink_t
793+
xfs_refc_merge_refcount(
794+
const struct xfs_refcount_irec *irec,
795+
enum xfs_refc_adjust_op adjust)
796+
{
797+
/* Once a record hits MAXREFCOUNT, it is pinned there forever */
798+
if (irec->rc_refcount == MAXREFCOUNT)
799+
return MAXREFCOUNT;
800+
return irec->rc_refcount + adjust;
801+
}
802+
792803
static inline bool
793804
xfs_refc_want_merge_center(
794805
const struct xfs_refcount_irec *left,
@@ -800,6 +811,7 @@ xfs_refc_want_merge_center(
800811
unsigned long long *ulenp)
801812
{
802813
unsigned long long ulen = left->rc_blockcount;
814+
xfs_nlink_t new_refcount;
803815

804816
/*
805817
* To merge with a center record, both shoulder records must be
@@ -815,9 +827,10 @@ xfs_refc_want_merge_center(
815827
return false;
816828

817829
/* The shoulder record refcounts must match the new refcount. */
818-
if (left->rc_refcount != cleft->rc_refcount + adjust)
830+
new_refcount = xfs_refc_merge_refcount(cleft, adjust);
831+
if (left->rc_refcount != new_refcount)
819832
return false;
820-
if (right->rc_refcount != cleft->rc_refcount + adjust)
833+
if (right->rc_refcount != new_refcount)
821834
return false;
822835

823836
/*
@@ -840,6 +853,7 @@ xfs_refc_want_merge_left(
840853
enum xfs_refc_adjust_op adjust)
841854
{
842855
unsigned long long ulen = left->rc_blockcount;
856+
xfs_nlink_t new_refcount;
843857

844858
/*
845859
* For a left merge, the left shoulder record must be adjacent to the
@@ -850,7 +864,8 @@ xfs_refc_want_merge_left(
850864
return false;
851865

852866
/* Left shoulder record refcount must match the new refcount. */
853-
if (left->rc_refcount != cleft->rc_refcount + adjust)
867+
new_refcount = xfs_refc_merge_refcount(cleft, adjust);
868+
if (left->rc_refcount != new_refcount)
854869
return false;
855870

856871
/*
@@ -872,6 +887,7 @@ xfs_refc_want_merge_right(
872887
enum xfs_refc_adjust_op adjust)
873888
{
874889
unsigned long long ulen = right->rc_blockcount;
890+
xfs_nlink_t new_refcount;
875891

876892
/*
877893
* For a right merge, the right shoulder record must be adjacent to the
@@ -882,7 +898,8 @@ xfs_refc_want_merge_right(
882898
return false;
883899

884900
/* Right shoulder record refcount must match the new refcount. */
885-
if (right->rc_refcount != cright->rc_refcount + adjust)
901+
new_refcount = xfs_refc_merge_refcount(cright, adjust);
902+
if (right->rc_refcount != new_refcount)
886903
return false;
887904

888905
/*

0 commit comments

Comments
 (0)