@@ -787,6 +787,17 @@ xfs_refc_valid(
return rc->rc_startblock != NULLAGBLOCK;
}
+static inline xfs_nlink_t
+xfs_refc_merge_refcount(
+ const struct xfs_refcount_irec *irec,
+ enum xfs_refc_adjust_op adjust)
+{
+ /* Once a record hits MAXREFCOUNT, it is pinned there forever */
+ if (irec->rc_refcount == MAXREFCOUNT)
+ return MAXREFCOUNT;
+ return irec->rc_refcount + adjust;
+}
+
static inline bool
xfs_refc_want_merge_center(
const struct xfs_refcount_irec *left,
@@ -798,6 +809,7 @@ xfs_refc_want_merge_center(
unsigned long long *ulenp)
{
unsigned long long ulen = left->rc_blockcount;
+ xfs_nlink_t new_refcount;
/*
* To merge with a center record, both shoulder records must be
@@ -813,9 +825,10 @@ xfs_refc_want_merge_center(
return false;
/* The shoulder record refcounts must match the new refcount. */
- if (left->rc_refcount != cleft->rc_refcount + adjust)
+ new_refcount = xfs_refc_merge_refcount(cleft, adjust);
+ if (left->rc_refcount != new_refcount)
return false;
- if (right->rc_refcount != cleft->rc_refcount + adjust)
+ if (right->rc_refcount != new_refcount)
return false;
/*
@@ -838,6 +851,7 @@ xfs_refc_want_merge_left(
enum xfs_refc_adjust_op adjust)
{
unsigned long long ulen = left->rc_blockcount;
+ xfs_nlink_t new_refcount;
/*
* For a left merge, the left shoulder record must be adjacent to the
@@ -848,7 +862,8 @@ xfs_refc_want_merge_left(
return false;
/* Left shoulder record refcount must match the new refcount. */
- if (left->rc_refcount != cleft->rc_refcount + adjust)
+ new_refcount = xfs_refc_merge_refcount(cleft, adjust);
+ if (left->rc_refcount != new_refcount)
return false;
/*
@@ -870,6 +885,7 @@ xfs_refc_want_merge_right(
enum xfs_refc_adjust_op adjust)
{
unsigned long long ulen = right->rc_blockcount;
+ xfs_nlink_t new_refcount;
/*
* For a right merge, the right shoulder record must be adjacent to the
@@ -880,7 +896,8 @@ xfs_refc_want_merge_right(
return false;
/* Right shoulder record refcount must match the new refcount. */
- if (right->rc_refcount != cright->rc_refcount + adjust)
+ new_refcount = xfs_refc_merge_refcount(cright, adjust);
+ if (right->rc_refcount != new_refcount)
return false;
/*