xfs
[Top] [All Lists]

[PATCH 2/5] xfs_repair: better checking of v5 metadata fields

To: david@xxxxxxxxxxxxx, darrick.wong@xxxxxxxxxx
Subject: [PATCH 2/5] xfs_repair: better checking of v5 metadata fields
From: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx>
Date: Tue, 26 May 2015 15:51:39 -0700
Cc: xfs@xxxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <20150526225126.26434.69010.stgit@xxxxxxxxxxxxxxxx>
References: <20150526225126.26434.69010.stgit@xxxxxxxxxxxxxxxx>
User-agent: StGit/0.17.1-dirty
Check the UUID, owner, and block number fields during repair, looking for
blocks that fail either the checksum or the data structure verifiers.  For
directories we can simply rebuild corrupt/broken index data, though for
anything else we have to toss out the broken object.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 repair/dir2.c   |    7 ++
 repair/phase6.c |  159 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 repair/scan.c   |   17 ++++++
 3 files changed, 177 insertions(+), 6 deletions(-)


diff --git a/repair/dir2.c b/repair/dir2.c
index c6d618d..644c214 100644
--- a/repair/dir2.c
+++ b/repair/dir2.c
@@ -198,6 +198,13 @@ _("bad dir magic number 0x%x in inode %" PRIu64 " bno = 
%u\n"),
                                        da_cursor->ino, bno);
                        goto error_out;
                }
+               /* corrupt node; rebuild the dir. */
+               if (bp->b_error == EFSBADCRC || bp->b_error == EFSCORRUPTED) {
+                       do_warn(
+_("corrupt tree block %u for directory inode %" PRIu64 "\n"),
+                               bno, da_cursor->ino);
+                       goto error_out;
+               }
                btree = xfs_da3_node_tree_p(node);
                if (nodehdr.count > mp->m_dir_node_ents)  {
                        libxfs_putbuf(bp);
diff --git a/repair/phase6.c b/repair/phase6.c
index c09b394..efefb2b 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -1981,6 +1981,41 @@ longform_dir2_check_leaf(
                libxfs_putbuf(bp);
                return 1;
        }
+
+       /* check v5 metadata */
+       if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
+               struct xfs_dir3_leaf_hdr *block3 = bp->b_addr;
+
+               /* verify owner */
+               if (be64_to_cpu(block3->info.owner) != ip->i_ino) {
+                       do_warn(
+       _("expected owner inode %" PRIu64 ", got %llu, directory block %" 
PRIu64 "\n"),
+                               ip->i_ino, be64_to_cpu(block3->info.owner),
+                               bp->b_bn);
+                       libxfs_putbuf(bp);
+                       return 1;
+               }
+               /* verify block number */
+               if (be64_to_cpu(block3->info.blkno) != bp->b_bn) {
+                       do_warn(
+       _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 
"\n"),
+                               bp->b_bn,
+                               be64_to_cpu(block3->info.blkno),
+                               ip->i_ino);
+                       libxfs_putbuf(bp);
+                       return 1;
+               }
+               /* verify uuid */
+               if (platform_uuid_compare(&block3->info.uuid,
+                                         &mp->m_sb.sb_uuid) != 0) {
+                       do_warn(
+       _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+                               ip->i_ino, bp->b_bn);
+                       libxfs_putbuf(bp);
+                       return 1;
+               }
+       }
+
        seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale);
        if (dir_hash_check(hashtab, ip, seeval)) {
                libxfs_putbuf(bp);
@@ -2055,12 +2090,9 @@ longform_dir2_check_node(
                xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
                ents = xfs_dir3_leaf_ents_p(leaf);
                if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
-                     leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) {
-                       if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
-                           leafhdr.magic == XFS_DA3_NODE_MAGIC) {
-                               libxfs_putbuf(bp);
-                               continue;
-                       }
+                     leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+                     leafhdr.magic == XFS_DA_NODE_MAGIC ||
+                     leafhdr.magic == XFS_DA3_NODE_MAGIC)) {
                        do_warn(
        _("unknown magic number %#x for block %u in directory inode %" PRIu64 
"\n"),
                                leafhdr.magic, da_bno, ip->i_ino);
@@ -2068,6 +2100,48 @@ longform_dir2_check_node(
                        return 1;
                }
 
+               /* check v5 metadata */
+               if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+                   leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+                       struct xfs_da3_blkinfo  *info = bp->b_addr;
+
+                       /* verify owner */
+                       if (be64_to_cpu(info->owner) != ip->i_ino) {
+                               do_warn(
+       _("expected owner inode %" PRIu64 ", got %llu, directory block %" 
PRIu64 "\n"),
+                                       ip->i_ino, be64_to_cpu(info->owner),
+                                       bp->b_bn);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+                       /* verify block number */
+                       if (be64_to_cpu(info->blkno) != bp->b_bn) {
+                               do_warn(
+       _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 
"\n"),
+                                       bp->b_bn,
+                                       be64_to_cpu(info->blkno),
+                                       ip->i_ino);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+                       /* verify uuid */
+                       if (platform_uuid_compare(&info->uuid,
+                                                 &mp->m_sb.sb_uuid) != 0) {
+                               do_warn(
+       _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+                                       ip->i_ino, bp->b_bn);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+               }
+
+               /* ignore nodes */
+               if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
+                   leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+                       libxfs_putbuf(bp);
+                       continue;
+               }
+
                /*
                 * If there's a validator error, we need to ensure that we got
                 * the right ops on the buffer for when we write it back out.
@@ -2121,6 +2195,40 @@ longform_dir2_check_node(
                        libxfs_putbuf(bp);
                        return 1;
                }
+
+               /* check v5 metadata */
+               if (freehdr.magic == XFS_DIR3_FREE_MAGIC) {
+                       struct xfs_dir3_free_hdr *h = bp->b_addr;
+
+                       /* verify owner */
+                       if (be64_to_cpu(h->hdr.owner) != ip->i_ino) {
+                               do_warn(
+       _("expected owner inode %" PRIu64 ", got %llu, directory block %" 
PRIu64 "\n"),
+                                       ip->i_ino, be64_to_cpu(h->hdr.owner),
+                                       bp->b_bn);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+                       /* verify block number */
+                       if (be64_to_cpu(h->hdr.blkno) != bp->b_bn) {
+                               do_warn(
+       _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 
"\n"),
+                                       bp->b_bn,
+                                       be64_to_cpu(h->hdr.blkno),
+                                       ip->i_ino);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+                       /* verify uuid */
+                       if (platform_uuid_compare(&h->hdr.uuid,
+                                                 &mp->m_sb.sb_uuid) != 0) {
+                               do_warn(
+       _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+                                       ip->i_ino, bp->b_bn);
+                               libxfs_putbuf(bp);
+                               return 1;
+                       }
+               }
                for (i = used = 0; i < freehdr.nvalid; i++) {
                        if (i + freehdr.firstdb >= freetab->nents ||
                                        freetab->ents[i + freehdr.firstdb].v !=
@@ -2212,6 +2320,7 @@ longform_dir2_entry_check(xfs_mount_t     *mp,
             da_bno = (xfs_dablk_t)next_da_bno) {
                const struct xfs_buf_ops *ops;
                int                      error;
+               struct xfs_dir2_data_hdr *d;
 
                next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
                if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) {
@@ -2260,6 +2369,44 @@ longform_dir2_entry_check(xfs_mount_t    *mp,
                        }
                        continue;
                }
+
+               /* check v5 metadata */
+               d = bplist[db]->b_addr;
+               if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC ||
+                   be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) {
+                       struct xfs_buf           *bp = bplist[db];
+                       struct xfs_dir3_data_hdr *block3 = bp->b_addr;
+
+                       /* verify owner */
+                       if (be64_to_cpu(block3->hdr.owner) != ino) {
+                               do_warn(
+       _("expected owner inode %" PRIu64 ", got %llu, directory block %" 
PRIu64 "\n"),
+                                       ino, be64_to_cpu(block3->hdr.owner),
+                                       bp->b_bn);
+                               fixit++;
+                               continue;
+                       }
+                       /* verify block number */
+                       if (be64_to_cpu(block3->hdr.blkno) != bp->b_bn) {
+                               do_warn(
+       _("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 
"\n"),
+                                       bp->b_bn,
+                                       be64_to_cpu(block3->hdr.blkno),
+                                       ino);
+                               fixit++;
+                               continue;
+                       }
+                       /* verify uuid */
+                       if (platform_uuid_compare(&block3->hdr.uuid,
+                                                 &mp->m_sb.sb_uuid) != 0) {
+                               do_warn(
+       _("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+                                       ino, bp->b_bn);
+                               fixit++;
+                               continue;
+                       }
+               }
+
                longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
                                irec, ino_offset, &bplist[db], hashtab,
                                &freetab, da_bno, isblock);
diff --git a/repair/scan.c b/repair/scan.c
index 12aa782..79fbf83 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -227,6 +227,23 @@ _("expected owner inode %" PRIu64 ", got %llu, bmbt block 
%" PRIu64 "\n"),
                                ino, be64_to_cpu(block->bb_u.l.bb_owner), bno);
                        return(1);
                }
+               /* verify block number */
+               if (be64_to_cpu(block->bb_u.l.bb_blkno) !=
+                   XFS_FSB_TO_DADDR(mp, bno)) {
+                       do_warn(
+_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
+                               XFS_FSB_TO_DADDR(mp, bno),
+                               be64_to_cpu(block->bb_u.l.bb_blkno), bno);
+                       return(1);
+               }
+               /* verify uuid */
+               if (platform_uuid_compare(&block->bb_u.l.bb_uuid,
+                                         &mp->m_sb.sb_uuid) != 0) {
+                       do_warn(
+_("wrong FS UUID, bmbt block %" PRIu64 "\n"),
+                               bno);
+                       return(1);
+               }
        }
 
        if (check_dups == 0)  {

<Prev in Thread] Current Thread [Next in Thread>