]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: handle multiple owners of data blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 25 Oct 2016 22:14:34 +0000 (15:14 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 26 Oct 2016 19:43:53 +0000 (12:43 -0700)
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.

v2: owner and offset are unsigned types, so use those for inorder
comparison.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
repair/dinode.c
repair/scan.c

index 16e0a0637fd732c549fa15ba0f0dfc3cb8df3bb7..259f133cb48ade8b1c28a0cbad2663739a21821d 100644 (file)
@@ -722,7 +722,9 @@ _("Fatal error: inode %" PRIu64 " - blkmap_set_ext(): %s\n"
                         * checking each entry without setting the
                         * block bitmap
                         */
-                       if (search_dup_extent(agno, agbno, ebno)) {
+                       if (!(type == XR_INO_DATA &&
+                           xfs_sb_version_hasreflink(&mp->m_sb)) &&
+                           search_dup_extent(agno, agbno, ebno)) {
                                do_warn(
 _("%s fork in ino %" PRIu64 " claims dup extent, "
   "off - %" PRIu64 ", start - %" PRIu64 ", cnt %" PRIu64 "\n"),
@@ -770,6 +772,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);
@@ -2475,6 +2480,65 @@ _("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) &&
+                   !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 (flags2 & XFS_DIFLAG2_REFLINK) {
+                       /* must be a file */
+                       if (di_mode && !S_ISREG(di_mode)) {
+                               if (!uncertain) {
+                                       do_warn(
+       _("reflink flag set on non-file inode %" PRIu64 "\n"),
+                                               lino);
+                               }
+                               goto clear_bad_out;
+                       }
+               }
+
+               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 (!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;
 
index c27f969dc2314709a9df1da4abd37c4c6263e0ac..d3a1a82f61d5e4fc6bc0dc416bca8a5dabd3440c 100644 (file)
@@ -872,6 +872,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"),
@@ -888,6 +897,28 @@ struct rmap_priv {
        xfs_agblock_t           nr_blocks;
 };
 
+static bool
+rmap_in_order(
+       xfs_agblock_t   b,
+       xfs_agblock_t   lastblock,
+       uint64_t        owner,
+       uint64_t        lastowner,
+       uint64_t        offset,
+       uint64_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,
@@ -908,6 +939,8 @@ scan_rmapbt(
        int                     numrecs;
        int                     state;
        xfs_agblock_t           lastblock = 0;
+       uint64_t                lastowner = 0;
+       uint64_t                lastoffset = 0;
        struct xfs_rmap_key     *kp;
        struct xfs_rmap_irec    key = {0};
 
@@ -1038,10 +1071,17 @@ _("%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                        if (i == 0) {
 advance:
                                lastblock = b;
+                               lastowner = owner;
+                               lastoffset = offset;
                        } 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"),