[PATCH 16/22] xfs_repair: reject unwritten shared extents

Darrick J. Wong
2025-02-06T23:00:56Z

We don't allow sharing of unwritten extents, which means that repair
should reject an unwritten extent if someone else has already claimed
the space.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
repair/dinode.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/repair/dinode.c b/repair/dinode.c
index 3260df94511ed2..f49c735d34356b 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -311,7 +311,8 @@ _("bad state in rt extent map %" PRIu64 "\n"),
break;
case XR_E_INUSE:
case XR_E_MULT:
- if (xfs_has_rtreflink(mp))
+ if (xfs_has_rtreflink(mp) &&
+ irec->br_state == XFS_EXT_NORM)
break;
set_rtbmap(ext, XR_E_MULT);
break;
@@ -387,8 +388,14 @@ _("data fork in rt inode %" PRIu64 " found rt metadata extent %" PRIu64 " in rt
return 1;
case XR_E_INUSE:
case XR_E_MULT:
- if (xfs_has_rtreflink(mp))
- break;
+ if (xfs_has_rtreflink(mp)) {
+ if (irec->br_state == XFS_EXT_NORM)
+ break;
+ do_warn(
+_("data fork in rt inode %" PRIu64 " claims shared unwritten rt extent %" PRIu64 "\n"),
+ ino, b);
+ return 1;
+ }
do_warn(
_("data fork in rt inode %" PRIu64 " claims used rt extent %" PRIu64 "\n"),
ino, b);
@@ -472,6 +479,18 @@ _("inode %" PRIu64 " - bad rt extent overflows - start %" PRIu64 ", "
return bad;
}

+static inline bool
+is_reflink_type(
+ struct xfs_mount *mp,
+ int type)
+{
+ if (type == XR_INO_DATA && xfs_has_reflink(mp))
+ return true;
+ if (type == XR_INO_RTDATA && xfs_has_rtreflink(mp))
+ return true;
+ return false;
+}
+
/*
* return 1 if inode should be cleared, 0 otherwise
* if check_dups should be set to 1, that implies that
@@ -717,9 +736,14 @@ _("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"),

case XR_E_INUSE:
case XR_E_MULT:
- if (type == XR_INO_DATA &&
- xfs_has_reflink(mp))
- break;
+ if (is_reflink_type(mp, type)) {
+ if (irec.br_state == XFS_EXT_NORM)
+ break;
+ do_warn(
+_("%s fork in %s inode %" PRIu64 " claims shared unwritten block %" PRIu64 "\n"),
+ forkname, ftype, ino, b);
+ goto done;
+ }
do_warn(
_("%s fork in %s inode %" PRIu64 " claims used block %" PRIu64 "\n"),
forkname, ftype, ino, b);