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,
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) {
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) {
- if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
- mp->m_sb.sb_inoalignmt &&
- (XFS_INO_TO_AGBNO(mp, agino) %
- mp->m_sb.sb_inoalignmt))
+ 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
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);
}
- 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 "
+
+ /* 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 "
"%u/%u\n"),
- seqno,
- XFS_AGINO_TO_AGBNO(mp, agino));
- error++;
+ 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);
+ }
pop_cur();
- 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)) {
+
+ 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) {
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();
}
return;
}
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) {
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) {
- if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
- mp->m_sb.sb_inoalignmt &&
- (XFS_INO_TO_AGBNO(mp, agino) %
- mp->m_sb.sb_inoalignmt))
+ 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
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;
}