commit 09c93e56b5296a30507cde9c00433eb4ed2d395d Author: Brian Foster Date: Tue Jun 21 12:58:57 2016 +1000 xfs_db: Revert "xfs_db: make check work for sparse inodes" This reverts commit bb2f98b78f20f4abbfbbd442162d9f535c84888a which introduced support for multi-record inode chunks in xfs_db/xfs_check. However, it doesn't currently handle filesystems with multi-record inode chunks correctly. For example, do the following on a 64k page size arch such as ppc64: # mkfs.xfs -f -b size=64k # xfs_db -c check bad magic number 0 for inode 1152 bad magic number 0 for inode 1153 bad magic number 0 for inode 1154 bad magic number 0 for inode 1155 bad magic number 0 for inode 1156 bad magic number 0 for inode 1157 ... This boils down to a regression in the inode record processing code (scanfunc_ino()) in db/check.c. Specifically, the cblocks value can end up being zero after it is shifted by mp->m_sb.sb_inopblog (i.e., 64 >> 7 == 0 for an -isize=512 -bsize=64k fs). Fixing this problem is easier to do from scratch, so revert the oringial commit first. Signed-off-by: Brian Foster Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner diff --git a/db/check.c b/db/check.c index 0871ed7..750ecc1 100644 --- a/db/check.c +++ b/db/check.c @@ -4311,51 +4311,6 @@ 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_one_ino_bit( - __u16 mask, - int startino) -{ - int n; - int b; - - startino /= XFS_INODES_PER_HOLEMASK_BIT; - b = startino; - mask >>= startino; - for (n = startino; n < sizeof(mask) * NBBY && !(mask & 1); n++, mask >>= 1) - b++; - - return b * XFS_INODES_PER_HOLEMASK_BIT; -} - -static int -find_zero_ino_bit( - __u16 mask, - int startino) -{ - int n; - int b; - - startino /= XFS_INODES_PER_HOLEMASK_BIT; - b = startino; - mask >>= startino; - for (n = startino; n < sizeof(mask) * NBBY && (mask & 1); n++, mask >>= 1) - b++; - - return b * XFS_INODES_PER_HOLEMASK_BIT; -} - static void scanfunc_ino( struct xfs_btree_block *block, @@ -4373,13 +4328,6 @@ scanfunc_ino( int off; xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; - bool sparse, crc; - int inodes_per_chunk; - int freecount; - int startidx, endidx; - __u16 holemask; - xfs_agino_t rino; - xfs_extlen_t cblocks; if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC && be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) { @@ -4407,111 +4355,59 @@ scanfunc_ino( return; } rp = XFS_INOBT_REC_ADDR(mp, block, 1); - sparse = xfs_sb_version_hassparseinodes(&mp->m_sb); - crc = xfs_sb_version_hascrc(&mp->m_sb); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { - nfree = 0; - - /* First let's look at the inode chunk alignment */ agino = be32_to_cpu(rp[i].ir_startino); off = XFS_INO_TO_OFFSET(mp, agino); - if (off == 0 && - (sbversion & XFS_SB_VERSION_ALIGNBIT) && - mp->m_sb.sb_inoalignmt && - (XFS_INO_TO_AGBNO(mp, agino) % - mp->m_sb.sb_inoalignmt)) { - if (sparse || crc) { - dbprintf(_("incorrect record %u/%u " - "alignment in inobt block " - "%u/%u\n"), - seqno, agino, seqno, bno); - error++; - } else + if (off == 0) { + if ((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 >> + mp->m_sb.sb_inopblog), + DBM_INODE, seqno, bno); } - - /* Move on to examining the inode chunks */ - if (sparse) { - 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_zero_ino_bit(holemask, 0); - } else { - inodes_per_chunk = XFS_INODES_PER_CHUNK; - freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount); - holemask = 0; - startidx = 0; - } - - /* For each allocated chunk, look at each inode. */ - endidx = find_one_ino_bit(holemask, startidx); - do { - rino = agino + startidx; - cblocks = (endidx - startidx) >> - mp->m_sb.sb_inopblog; - - /* Check the sparse chunk alignment */ - if (sparse && - (XFS_INO_TO_AGBNO(mp, rino) % - mp->m_sb.sb_spino_align)) { - dbprintf(_("incorrect chunk %u/%u " - "alignment in inobt block " + 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); + 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), + DB_RING_IGN, NULL); + if (iocur_top->data == NULL) { + if (!sflag) + dbprintf(_("can't read inode block " "%u/%u\n"), - seqno, rino, seqno, bno); - error++; - } - - /* Check the block map */ - set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, rino), - cblocks, DBM_INODE, seqno, bno); - - push_cur(); - set_cur(&typtab[TYP_INODE], - XFS_AGB_TO_DADDR(mp, seqno, - XFS_AGINO_TO_AGBNO(mp, rino)), - (int)XFS_FSB_TO_BB(mp, cblocks), - DB_RING_IGN, NULL); - if (iocur_top->data == NULL) { - if (!sflag) - dbprintf(_("can't read inode block " - "%u/%u\n"), - seqno, - XFS_AGINO_TO_AGBNO(mp, agino)); - error++; - pop_cur(); - continue; - } - - /* Examine each inode in this chunk */ - for (j = startidx; j < endidx; 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 + ((j - startidx) << mp->m_sb.sb_inodelog)), - isfree); - } + seqno, + XFS_AGINO_TO_AGBNO(mp, agino)); + error++; pop_cur(); - - startidx = find_zero_ino_bit(holemask, endidx); - endidx = find_one_ino_bit(holemask, startidx); - } while (endidx < XFS_INODES_PER_CHUNK); - icount += inodes_per_chunk; - agicount += inodes_per_chunk; - ifree += freecount; - agifreecount += freecount; - - if (nfree != freecount) { + continue; + } + for (j = 0, nfree = 0; j < XFS_INODES_PER_CHUNK; j++) { + 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)), + isfree); + } + if (nfree != be32_to_cpu(rp[i].ir_u.f.ir_freecount)) { if (!sflag) dbprintf(_("ir_freecount/free mismatch, " "inode chunk %u/%u, freecount " "%d nfree %d\n"), seqno, agino, - freecount, nfree); + be32_to_cpu(rp[i].ir_u.f.ir_freecount), nfree); error++; } + pop_cur(); } return; } @@ -4543,11 +4439,6 @@ scanfunc_fino( int off; xfs_inobt_ptr_t *pp; struct xfs_inobt_rec *rp; - bool sparse, crc; - int startidx, endidx; - __u16 holemask; - xfs_agino_t rino; - xfs_extlen_t cblocks; if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC && be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) { @@ -4575,63 +4466,21 @@ scanfunc_fino( return; } rp = XFS_INOBT_REC_ADDR(mp, block, 1); - sparse = xfs_sb_version_hassparseinodes(&mp->m_sb); - crc = xfs_sb_version_hascrc(&mp->m_sb); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { - /* First let's look at the inode chunk alignment */ agino = be32_to_cpu(rp[i].ir_startino); off = XFS_INO_TO_OFFSET(mp, agino); - if (off == 0 && - (sbversion & XFS_SB_VERSION_ALIGNBIT) && - mp->m_sb.sb_inoalignmt && - (XFS_INO_TO_AGBNO(mp, agino) % - mp->m_sb.sb_inoalignmt)) { - if (sparse || crc) { - dbprintf(_("incorrect record %u/%u " - "alignment in finobt block " - "%u/%u\n"), - seqno, agino, seqno, bno); - error++; - } else + if (off == 0) { + if ((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 >> + mp->m_sb.sb_inopblog), + DBM_INODE, DBM_INODE, seqno, bno); } - - /* Move on to examining the inode chunks */ - if (sparse) { - holemask = be16_to_cpu(rp[i].ir_u.sp.ir_holemask); - startidx = find_zero_ino_bit(holemask, 0); - } else { - holemask = 0; - startidx = 0; - } - - /* For each allocated chunk... */ - endidx = find_one_ino_bit(holemask, startidx); - do { - rino = agino + startidx; - cblocks = (endidx - startidx) >> - mp->m_sb.sb_inopblog; - - /* Check the sparse chunk alignment */ - if (sparse && - (XFS_INO_TO_AGBNO(mp, rino) % - mp->m_sb.sb_spino_align)) { - dbprintf(_("incorrect chunk %u/%u " - "alignment in finobt block " - "%u/%u\n"), - seqno, rino, seqno, bno); - error++; - } - - /* Check the block map */ - check_set_dbmap(seqno, - XFS_AGINO_TO_AGBNO(mp, rino), - cblocks, DBM_INODE, DBM_INODE, - seqno, bno); - - startidx = find_zero_ino_bit(holemask, endidx); - endidx = find_one_ino_bit(holemask, startidx); - } while (endidx < XFS_INODES_PER_CHUNK); } return; }