xfs
[Top] [All Lists]

[PATCH] xfs_db: make check work for sparse inodes

To: david@xxxxxxxxxxxxx
Subject: [PATCH] xfs_db: make check work for sparse inodes
From: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx>
Date: Fri, 4 Dec 2015 12:26:06 -0800
Cc: xfs@xxxxxxxxxxx, bfoster@xxxxxxxxxx, sandeen@xxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
User-agent: Mutt/1.5.21 (2010-09-15)
Teach the inobt/finobt scanning functions how to deal with sparse
inode chunks well enough that we can pass the spot-check.  Should
fix the xfs/076 failures.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 db/check.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 75 insertions(+), 15 deletions(-)

diff --git a/db/check.c b/db/check.c
index 9c1541d..14c7de5 100644
--- a/db/check.c
+++ b/db/check.c
@@ -4319,6 +4319,30 @@ scanfunc_cnt(
                scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, 
TYP_CNTBT);
 }
 
+static bool
+ino_issparse(
+       struct xfs_inobt_rec    *rp,
+       int                     offset)
+{
+       if (!xfs_sb_version_hassparseinodes(&mp->m_sb))
+               return false;
+
+       return xfs_inobt_is_sparse_disk(rp, offset);
+}
+
+static int
+find_first_zero_bit(
+       unsigned long   mask)
+{
+       int             n;
+       int             b = 0;
+
+       for (n = 0; n < sizeof(mask) * NBBY && (mask & 1); n++, mask >>= 1)
+               b++;
+
+       return b;
+}
+
 static void
 scanfunc_ino(
        struct xfs_btree_block  *block,
@@ -4336,6 +4360,10 @@ scanfunc_ino(
        int                     off;
        xfs_inobt_ptr_t         *pp;
        xfs_inobt_rec_t         *rp;
+       bool                    sparse;
+       int                     inodes_per_chunk;
+       int                     freecount;
+       int                     startidx;
 
        if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC &&
            be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) {
@@ -4364,29 +4392,44 @@ scanfunc_ino(
                }
                rp = XFS_INOBT_REC_ADDR(mp, block, 1);
                for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
-                       agino = be32_to_cpu(rp[i].ir_startino);
+                       sparse = xfs_sb_version_hassparseinodes(&mp->m_sb);
+                       if (sparse) {
+                               unsigned long   holemask;
+
+                               inodes_per_chunk = rp[i].ir_u.sp.ir_count;
+                               freecount = rp[i].ir_u.sp.ir_freecount;
+                               holemask = 
be16_to_cpu(rp[i].ir_u.sp.ir_holemask);
+                               startidx = find_first_zero_bit(holemask) * 
XFS_INODES_PER_HOLEMASK_BIT;
+                       } else {
+                               inodes_per_chunk = XFS_INODES_PER_CHUNK;
+                               freecount = 
be32_to_cpu(rp[i].ir_u.f.ir_freecount);
+                               startidx = 0;
+                       }
+                       agino = be32_to_cpu(rp[i].ir_startino) + startidx;
                        off = XFS_INO_TO_OFFSET(mp, agino);
                        if (off == 0) {
-                               if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
+                               if (!sparse &&
+                                   (sbversion & XFS_SB_VERSION_ALIGNBIT) &&
                                    mp->m_sb.sb_inoalignmt &&
                                    (XFS_INO_TO_AGBNO(mp, agino) %
                                     mp->m_sb.sb_inoalignmt))
                                        sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
                                set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino),
                                        (xfs_extlen_t)MAX(1,
-                                               XFS_INODES_PER_CHUNK >>
+                                               inodes_per_chunk >>
                                                mp->m_sb.sb_inopblog),
                                        DBM_INODE, seqno, bno);
                        }
-                       icount += XFS_INODES_PER_CHUNK;
-                       agicount += XFS_INODES_PER_CHUNK;
-                       ifree += be32_to_cpu(rp[i].ir_u.f.ir_freecount);
-                       agifreecount += be32_to_cpu(rp[i].ir_u.f.ir_freecount);
+                       icount += inodes_per_chunk;
+                       agicount += inodes_per_chunk;
+                       ifree += freecount;
+                       agifreecount += freecount;
                        push_cur();
                        set_cur(&typtab[TYP_INODE],
                                XFS_AGB_TO_DADDR(mp, seqno,
                                                 XFS_AGINO_TO_AGBNO(mp, agino)),
-                               (int)XFS_FSB_TO_BB(mp, mp->m_ialloc_blks),
+                               (int)XFS_FSB_TO_BB(mp, inodes_per_chunk >>
+                                                  mp->m_sb.sb_inopblog),
                                DB_RING_IGN, NULL);
                        if (iocur_top->data == NULL) {
                                if (!sflag)
@@ -4399,20 +4442,22 @@ scanfunc_ino(
                                continue;
                        }
                        for (j = 0, nfree = 0; j < XFS_INODES_PER_CHUNK; j++) {
+                               if (ino_issparse(&rp[i], j))
+                                       continue;
                                isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], j);
                                if (isfree)
                                        nfree++;
-                               process_inode(agf, agino + j,
-                                       (xfs_dinode_t *)((char 
*)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)),
+                               process_inode(agf, agino - startidx + j,
+                                       (xfs_dinode_t *)((char 
*)iocur_top->data + ((off - startidx + j) << mp->m_sb.sb_inodelog)),
                                                isfree);
                        }
-                       if (nfree != be32_to_cpu(rp[i].ir_u.f.ir_freecount)) {
+                       if (nfree != freecount) {
                                if (!sflag)
                                        dbprintf(_("ir_freecount/free mismatch, 
"
                                                 "inode chunk %u/%u, freecount "
                                                 "%d nfree %d\n"),
                                                seqno, agino,
-                                               
be32_to_cpu(rp[i].ir_u.f.ir_freecount), nfree);
+                                               freecount, nfree);
                                error++;
                        }
                        pop_cur();
@@ -4447,6 +4492,9 @@ scanfunc_fino(
        int                     off;
        xfs_inobt_ptr_t         *pp;
        struct xfs_inobt_rec    *rp;
+       bool                    sparse;
+       int                     inodes_per_chunk;
+       int                     startidx;
 
        if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC &&
            be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) {
@@ -4475,17 +4523,29 @@ scanfunc_fino(
                }
                rp = XFS_INOBT_REC_ADDR(mp, block, 1);
                for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
-                       agino = be32_to_cpu(rp[i].ir_startino);
+                       sparse = xfs_sb_version_hassparseinodes(&mp->m_sb);
+                       if (sparse) {
+                               unsigned long   holemask;
+
+                               inodes_per_chunk = rp[i].ir_u.sp.ir_count;
+                               holemask = 
be16_to_cpu(rp[i].ir_u.sp.ir_holemask);
+                               startidx = find_first_zero_bit(holemask) * 
XFS_INODES_PER_HOLEMASK_BIT;
+                       } else {
+                               inodes_per_chunk = XFS_INODES_PER_CHUNK;
+                               startidx = 0;
+                       }
+                       agino = be32_to_cpu(rp[i].ir_startino) + startidx;
                        off = XFS_INO_TO_OFFSET(mp, agino);
                        if (off == 0) {
-                               if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
+                               if (!sparse &&
+                                   (sbversion & XFS_SB_VERSION_ALIGNBIT) &&
                                    mp->m_sb.sb_inoalignmt &&
                                    (XFS_INO_TO_AGBNO(mp, agino) %
                                     mp->m_sb.sb_inoalignmt))
                                        sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
                                check_set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, 
agino),
                                        (xfs_extlen_t)MAX(1,
-                                               XFS_INODES_PER_CHUNK >>
+                                               inodes_per_chunk >>
                                                mp->m_sb.sb_inopblog),
                                        DBM_INODE, DBM_INODE, seqno, bno);
                        }

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