[PATCH 44/51] xfs_repair: handle multiple owners of data blocks

Darrick J. Wong
2015-10-07T05:10:07Z

If reflink is enabled, don't freak out if there are multiple owners of
a given block; that's just a sign that each of those owners are
reflink files.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
repair/dinode.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
repair/scan.c | 40 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/repair/dinode.c b/repair/dinode.c
index 2c0a421..5b7c31f 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -722,6 +722,9 @@ _("Fatal error: inode %" PRIu64 " - blkmap_set_ext(): %s\n"
* checking each entry without setting the
* block bitmap
*/
+ if (type == XR_INO_DATA &&
+ xfs_sb_version_hasreflink(&mp->m_sb))
+ goto skip_dup;
if (search_dup_extent(agno, agbno, ebno)) {
do_warn(
_("%s fork in ino %" PRIu64 " claims dup extent, "
@@ -731,6 +734,7 @@ _("%s fork in ino %" PRIu64 " claims dup extent, "
irec.br_blockcount);
goto done;
}
+skip_dup:
*tot += irec.br_blockcount;
continue;
}
@@ -770,6 +774,9 @@ _("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"),
case XR_E_INUSE:
case XR_E_MULT:
set_bmap_ext(agno, agbno, blen, XR_E_MULT);
+ if (type == XR_INO_DATA &&
+ xfs_sb_version_hasreflink(&mp->m_sb))
+ break;
do_warn(
_("%s fork in %s inode %" PRIu64 " claims used block %" PRIu64 "\n"),
forkname, ftype, ino, b);
@@ -2458,6 +2465,52 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
}
}

+ /*
+ * check that we only have valid flags2 set, and those that are set make
+ * sense.
+ */
+ if (dino->di_version >= 3) {
+ uint16_t flags = be16_to_cpu(dino->di_flags);
+ uint64_t flags2 = be64_to_cpu(dino->di_flags2);
+
+ if (flags2 & ~XFS_DIFLAG2_ANY) {
+ if (!uncertain) {
+ do_warn(
+ _("Bad flags2 set in inode %" PRIu64 "\n"),
+ lino);
+ }
+ flags2 &= XFS_DIFLAG2_ANY;
+ }
+
+ if ((flags2 & XFS_DIFLAG2_REFLINK) &&
+ (flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT))) {
+ if (!uncertain) {
+ do_warn(
+ _("Cannot have a reflinked realtime inode %" PRIu64 "\n"),
+ lino);
+ }
+ goto clear_bad_out;
+ }
+
+ if ((flags2 & XFS_DIFLAG2_REFLINK) &&
+ !xfs_sb_version_hasreflink(&mp->m_sb)) {
+ if (!uncertain) {
+ do_warn(
+ _("inode %" PRIu64 " is marked reflinked but file system does not support reflink\n"),
+ lino);
+ }
+ goto clear_bad_out;
+ }
+ if (!verify_mode && flags2 != be64_to_cpu(dino->di_flags2)) {
+ if (!no_modify) {
+ do_warn(_("fixing bad flags2.\n"));
+ dino->di_flags2 = cpu_to_be64(flags2);
+ *dirty = 1;
+ } else
+ do_warn(_("would fix bad flags2.\n"));
+ }
+ }
+
if (verify_mode)
return retval;

diff --git a/repair/scan.c b/repair/scan.c
index 4be02a6..54b9b68 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -783,7 +783,29 @@ ino_issparse(

return xfs_inobt_is_sparse_disk(rp, offset);
}
-
+
+static bool
+rmap_in_order(
+ xfs_agblock_t b,
+ xfs_agblock_t lastblock,
+ int64_t owner,
+ int64_t lastowner,
+ int64_t offset,
+ int64_t lastoffset)
+{
+ if (b > lastblock)
+ return true;
+ else if (b < lastblock)
+ return false;
+
+ if (owner > lastowner)
+ return true;
+ else if (owner < lastowner)
+ return false;
+
+ return offset > lastoffset;
+}
+
static void
scan_rmapbt(
struct xfs_btree_block *block,
@@ -910,7 +932,12 @@ advance:
} else {
bool bad;

- bad = b <= lastblock;
+ if (xfs_sb_version_hasreflink(&mp->m_sb))
+ bad = !rmap_in_order(b, lastblock,
+ owner, lastowner,
+ offset, lastoffset);
+ else
+ bad = b <= lastblock;
if (bad)
do_warn(
_("out-of-order rmap btree record %d (%u %"PRId64" %"PRIx64" %u) block %u/%u\n"),
@@ -997,6 +1024,15 @@ _("in use block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"),
* be caught later.
*/
break;
+ case XR_E_INUSE1:
+ /*
+ * multiple inode owners are ok with
+ * reflink enabled
+ */
+ if (xfs_sb_version_hasreflink(&mp->m_sb) &&
+ !XFS_RMAP_NON_INODE_OWNER(owner))
+ break;
+ /* fall through */
default:
do_warn(
_("unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%" PRIx64 "\n"),