]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: complain about copy-on-write leftovers
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 25 Oct 2016 22:14:35 +0000 (15:14 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 26 Oct 2016 23:41:07 +0000 (16:41 -0700)
Complain about leftover CoW allocations that are hanging off the
refcount btree.  These are cleaned out at mount time, but we could be
louder about flagging down evidence of trouble.

Since these extents aren't "owned" by anything, we'll free them up by
reconstructing the free space btrees.

v2: When we're processing rmap records, we inadvertently forgot to
handle the CoW owner, so the leftover CoW staging blocks got marked as
file data.  These blocks will just get freed later, so mark them
"CoW".  When we process the refcountbt, complain about leftovers if
the type is unknown or "CoW".

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

index 82bc27ec0e2b33d89346263cc9761c17c678a21f..8e618a2355c9180cd11a8ec4916c1bb5d88c88f5 100644 (file)
@@ -45,7 +45,7 @@ typedef enum {
        DBM_LOG,        DBM_MISSING,    DBM_QUOTA,      DBM_RTBITMAP,
        DBM_RTDATA,     DBM_RTFREE,     DBM_RTSUM,      DBM_SB,
        DBM_SYMLINK,    DBM_BTFINO,     DBM_BTRMAP,     DBM_BTREFC,
-       DBM_RLDATA,
+       DBM_RLDATA,     DBM_COWDATA,
        DBM_NDBM
 } dbm_t;
 
@@ -4731,9 +4731,22 @@ scanfunc_refcnt(
                rp = XFS_REFCOUNT_REC_ADDR(block, 1);
                lastblock = 0;
                for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
-                       set_dbmap(seqno, be32_to_cpu(rp[i].rc_startblock),
-                               be32_to_cpu(rp[i].rc_blockcount), DBM_RLDATA,
-                               seqno, bno);
+                       if (be32_to_cpu(rp[i].rc_refcount) == 1) {
+                               dbprintf(_(
+               "leftover CoW extent (%u/%u) len %u\n"),
+                                       seqno,
+                                       be32_to_cpu(rp[i].rc_startblock),
+                                       be32_to_cpu(rp[i].rc_blockcount));
+                               set_dbmap(seqno,
+                                       be32_to_cpu(rp[i].rc_startblock),
+                                       be32_to_cpu(rp[i].rc_blockcount),
+                                       DBM_COWDATA, seqno, bno);
+                       } else {
+                               set_dbmap(seqno,
+                                       be32_to_cpu(rp[i].rc_startblock),
+                                       be32_to_cpu(rp[i].rc_blockcount),
+                                       DBM_RLDATA, seqno, bno);
+                       }
                        if (be32_to_cpu(rp[i].rc_startblock) < lastblock) {
                                dbprintf(_(
                "out-of-order refcnt btree record %d (%u %u) block %u/%u\n"),
index bcd2f4b7193fb744fe122628a239b70e3088c113..c23a3a3c67c415a846cfe4ae2502e0ace2524cf5 100644 (file)
@@ -107,7 +107,8 @@ typedef struct rt_extent_tree_node  {
 #define XR_E_INO1      10      /* used by inodes (marked by rmap btree) */
 #define XR_E_FS_MAP1   11      /* used by fs space/inode maps (rmap btree) */
 #define XR_E_REFC      12      /* used by fs ag reference count btree */
-#define XR_E_BAD_STATE 13
+#define XR_E_COW       13      /* leftover cow extent */
+#define XR_E_BAD_STATE 14
 
 /* separate state bit, OR'ed into high (4th) bit of ex_state field */
 
index 1c60784f4de497c440fb1a28734f4a5e7c89cc6a..800a88a52ac8b2dbea078c1e95cdd7a82469c9fe 100644 (file)
@@ -813,6 +813,9 @@ process_rmap_rec(
                case XFS_RMAP_OWN_REFC:
                        set_bmap_ext(agno, b, blen, XR_E_REFC);
                        break;
+               case XFS_RMAP_OWN_COW:
+                       set_bmap_ext(agno, b, blen, XR_E_COW);
+                       break;
                case XFS_RMAP_OWN_NULL:
                        /* still unknown */
                        break;
@@ -1288,16 +1291,27 @@ _("%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
 
                rp = XFS_REFCOUNT_REC_ADDR(block, 1);
                for (i = 0; i < numrecs; i++) {
-                       xfs_agblock_t           b, end;
+                       xfs_agblock_t           b, agb, end;
                        xfs_extlen_t            len;
                        xfs_nlink_t             nr;
 
-                       b = be32_to_cpu(rp[i].rc_startblock);
+                       b = agb = be32_to_cpu(rp[i].rc_startblock);
                        len = be32_to_cpu(rp[i].rc_blockcount);
                        nr = be32_to_cpu(rp[i].rc_refcount);
-                       end = b + len;
+                       if (b >= XFS_REFC_COW_START && nr != 1)
+                               do_warn(
+_("leftover CoW extent has incorrect refcount in record %u of %s btree block %u/%u\n"),
+                                       i, name, agno, bno);
+                       if (nr == 1) {
+                               if (agb < XFS_REFC_COW_START)
+                                       do_warn(
+_("leftover CoW extent has invalid startblock in record %u of %s btree block %u/%u\n"),
+                                               i, name, agno, bno);
+                               agb -= XFS_REFC_COW_START;
+                       }
+                       end = agb + len;
 
-                       if (!verify_agbno(mp, agno, b)) {
+                       if (!verify_agbno(mp, agno, agb)) {
                                do_warn(
        _("invalid start block %u in record %u of %s btree block %u/%u\n"),
                                        b, i, name, agno, bno);
@@ -1310,7 +1324,28 @@ _("%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                                continue;
                        }
 
-                       if (nr < 2 || nr > MAXREFCOUNT) {
+                       if (nr == 1) {
+                               xfs_agblock_t   c;
+                               xfs_extlen_t    cnr;
+
+                               for (c = agb; c < end; c += cnr) {
+                                       state = get_bmap_ext(agno, c, end, &cnr);
+                                       switch (state) {
+                                       case XR_E_UNKNOWN:
+                                       case XR_E_COW:
+                                               do_warn(
+_("leftover CoW extent (%u/%u) len %u\n"),
+                                               agno, c, cnr);
+                                               set_bmap_ext(agno, c, cnr, XR_E_FREE);
+                                               break;
+                                       default:
+                                               do_warn(
+_("extent (%u/%u) len %u claimed, state is %d\n"),
+                                               agno, c, cnr, state);
+                                               break;
+                                       }
+                               }
+                       } else if (nr < 2 || nr > MAXREFCOUNT) {
                                do_warn(
        _("invalid reference count %u in record %u of %s btree block %u/%u\n"),
                                        nr, i, name, agno, bno);