void phase2( struct xfs_mount *mp, int scan_threads) { int j; ino_tree_node_t *ino_rec; /* now we can start using the buffer cache routines */ set_mp(mp); /* Check whether this fs has internal or external log */ if (mp->m_sb.sb_logstart == 0) { if (!x.logname) do_error(_("This filesystem has an external log. " "Specify log device with the -l option.\n")); do_log(_("Phase 2 - using external log on %s\n"), x.logname); } else do_log(_("Phase 2 - using internal log\n")); /* Zero log if applicable */ if (!no_modify) { do_log(_(" - zero log...\n")); zero_log(mp); } do_log(_(" - scan filesystem freespace and inode maps...\n")); bad_ino_btree = 0; set_progress_msg(PROG_FMT_SCAN_AG, (__uint64_t) glob_agcount); scan_ags(mp, scan_threads); print_final_rpt(); /* * make sure we know about the root inode chunk */ if ((ino_rec = find_inode_rec(0, mp->m_sb.sb_rootino)) == NULL) { ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2); do_warn(_("root inode chunk not found\n")); /* * mark the first 3 used, the rest are free */ ino_rec = set_inode_used_alloc(0, (xfs_agino_t) mp->m_sb.sb_rootino); set_inode_used(ino_rec, 1); set_inode_used(ino_rec, 2); for (j = 3; j < XFS_INODES_PER_CHUNK; j++) set_inode_free(ino_rec, j); /* * also mark blocks */ set_bmap_ext(0, XFS_INO_TO_AGBNO(mp, mp->m_sb.sb_rootino), mp->m_ialloc_blks, XR_E_INO); } else { do_log(_(" - found root inode chunk\n")); /* * blocks are marked, just make sure they're in use */ if (is_inode_free(ino_rec, 0)) { do_warn(_("root inode marked free, ")); set_inode_used(ino_rec, 0); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } if (is_inode_free(ino_rec, 1)) { do_warn(_("realtime bitmap inode marked free, ")); set_inode_used(ino_rec, 1); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } if (is_inode_free(ino_rec, 2)) { do_warn(_("realtime summary inode marked free, ")); set_inode_used(ino_rec, 2); if (!no_modify) do_warn(_("correcting\n")); else do_warn(_("would correct\n")); } } }
/* * we don't have to worry here about how chewing up free extents * may perturb things because inode tree building happens before * freespace tree building. */ static void init_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, __uint64_t *num_inos, __uint64_t *num_free_inos, int finobt) { __uint64_t ninos; __uint64_t nfinos; int rec_nfinos; int rec_ninos; ino_tree_node_t *ino_rec; int num_recs; int level; bt_stat_level_t *lptr; bt_stat_level_t *p_lptr; xfs_extlen_t blocks_allocated; int i; *num_inos = *num_free_inos = 0; ninos = nfinos = 0; lptr = &btree_curs->level[0]; btree_curs->init = 1; /* * build up statistics */ ino_rec = findfirst_inode_rec(agno); for (num_recs = 0; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) { rec_ninos = 0; rec_nfinos = 0; for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { ASSERT(is_inode_confirmed(ino_rec, i)); /* * sparse inodes are not factored into superblock (free) * inode counts */ if (is_inode_sparse(ino_rec, i)) continue; if (is_inode_free(ino_rec, i)) rec_nfinos++; rec_ninos++; } /* * finobt only considers records with free inodes */ if (finobt && !rec_nfinos) continue; nfinos += rec_nfinos; ninos += rec_ninos; num_recs++; } if (num_recs == 0) { /* * easy corner-case -- no inode records */ lptr->num_blocks = 1; lptr->modulo = 0; lptr->num_recs_pb = 0; lptr->num_recs_tot = 0; btree_curs->num_levels = 1; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1; setup_cursor(mp, agno, btree_curs); return; } blocks_allocated = lptr->num_blocks = howmany(num_recs, XR_INOBT_BLOCK_MAXRECS(mp, 0)); lptr->modulo = num_recs % lptr->num_blocks; lptr->num_recs_pb = num_recs / lptr->num_blocks; lptr->num_recs_tot = num_recs; level = 1; if (lptr->num_blocks > 1) { for (; btree_curs->level[level-1].num_blocks > 1 && level < XFS_BTREE_MAXLEVELS; level++) { lptr = &btree_curs->level[level]; p_lptr = &btree_curs->level[level - 1]; lptr->num_blocks = howmany(p_lptr->num_blocks, XR_INOBT_BLOCK_MAXRECS(mp, level)); lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; lptr->num_recs_pb = p_lptr->num_blocks / lptr->num_blocks; lptr->num_recs_tot = p_lptr->num_blocks; blocks_allocated += lptr->num_blocks; } } ASSERT(lptr->num_blocks == 1); btree_curs->num_levels = level; btree_curs->num_tot_blocks = btree_curs->num_free_blocks = blocks_allocated; setup_cursor(mp, agno, btree_curs); *num_inos = ninos; *num_free_inos = nfinos; return; }
void phase2(xfs_mount_t *mp, libxfs_init_t *args) { xfs_agnumber_t i; xfs_agblock_t b; int j; ino_tree_node_t *ino_rec; /* now we can start using the buffer cache routines */ set_mp(mp); /* Check whether this fs has internal or external log */ if (mp->m_sb.sb_logstart == 0) { if (!args->logname) { fprintf (stderr, "This filesystem has an external log. " "Specify log device with the -l option.\n"); exit (1); } fprintf (stderr, "Phase 2 - using external log on %s\n", args->logname); } else fprintf (stderr, "Phase 2 - using internal log\n"); /* Zero log if applicable */ if (!no_modify) { do_log(" - zero log...\n"); zero_log(mp, args); } do_log(" - scan filesystem freespace and inode maps...\n"); /* * account for space used by ag headers and log if internal */ set_bmap_log(mp); set_bmap_fs(mp); bad_ino_btree = 0; for (i = 0; i < mp->m_sb.sb_agcount; i++) { scan_ag(i); #ifdef XR_INODE_TRACE print_inode_list(i); #endif } /* * make sure we know about the root inode chunk */ if ((ino_rec = find_inode_rec(0, mp->m_sb.sb_rootino)) == NULL) { ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2); do_warn("root inode chunk not found\n"); /* * mark the first 3 used, the rest are free */ ino_rec = set_inode_used_alloc(0, (xfs_agino_t) mp->m_sb.sb_rootino); set_inode_used(ino_rec, 1); set_inode_used(ino_rec, 2); for (j = 3; j < XFS_INODES_PER_CHUNK; j++) set_inode_free(ino_rec, j); /* * also mark blocks */ for (b = 0; b < mp->m_ialloc_blks; b++) { set_agbno_state(mp, 0, b + XFS_INO_TO_AGBNO(mp, mp->m_sb.sb_rootino), XR_E_INO); } } else { do_log(" - found root inode chunk\n"); /* * blocks are marked, just make sure they're in use */ if (is_inode_free(ino_rec, 0)) { do_warn("root inode marked free, "); set_inode_used(ino_rec, 0); if (!no_modify) do_warn("correcting\n"); else do_warn("would correct\n"); } if (is_inode_free(ino_rec, 1)) { do_warn("realtime bitmap inode marked free, "); set_inode_used(ino_rec, 1); if (!no_modify) do_warn("correcting\n"); else do_warn("would correct\n"); } if (is_inode_free(ino_rec, 2)) { do_warn("realtime summary inode marked free, "); set_inode_used(ino_rec, 2); if (!no_modify) do_warn("correcting\n"); else do_warn("would correct\n"); } } }
/* * rebuilds an inode tree given a cursor. We're lazy here and call * the routine that builds the agi */ static void build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, __uint32_t magic, struct agi_stat *agi_stat, int finobt) { xfs_agnumber_t i; xfs_agblock_t j; xfs_agblock_t agbno; xfs_agino_t first_agino; struct xfs_btree_block *bt_hdr; xfs_inobt_rec_t *bt_rec; ino_tree_node_t *ino_rec; bt_stat_level_t *lptr; xfs_agino_t count = 0; xfs_agino_t freecount = 0; int inocnt; uint8_t finocnt; int k; int level = btree_curs->num_levels; int spmask; uint64_t sparse; uint16_t holemask; for (i = 0; i < level; i++) { lptr = &btree_curs->level[i]; agbno = get_next_blockaddr(agno, i, btree_curs); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); if (i == btree_curs->num_levels - 1) btree_curs->root = agbno; lptr->agbno = agbno; lptr->prev_agbno = NULLAGBLOCK; lptr->prev_buf_p = NULL; /* * initialize block header */ lptr->buf_p->b_ops = &xfs_inobt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); if (xfs_sb_version_hascrc(&mp->m_sb)) xfs_btree_init_block(mp, lptr->buf_p, magic, i, 0, agno, XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block(mp, lptr->buf_p, magic, i, 0, agno, 0); } /* * run along leaf, setting up records. as we have to switch * blocks, call the prop_ino_cursor routine to set up the new * pointers for the parent. that can recurse up to the root * if required. set the sibling pointers for leaf level here. */ if (finobt) ino_rec = findfirst_free_inode_rec(agno); else ino_rec = findfirst_inode_rec(agno); if (ino_rec != NULL) first_agino = ino_rec->ino_startnum; else first_agino = NULLAGINO; lptr = &btree_curs->level[0]; for (i = 0; i < lptr->num_blocks; i++) { /* * block initialization, lay in block header */ lptr->buf_p->b_ops = &xfs_inobt_buf_ops; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); memset(bt_hdr, 0, mp->m_sb.sb_blocksize); if (xfs_sb_version_hascrc(&mp->m_sb)) xfs_btree_init_block(mp, lptr->buf_p, magic, 0, 0, agno, XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block(mp, lptr->buf_p, magic, 0, 0, agno, 0); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb + (lptr->modulo > 0)); if (lptr->modulo > 0) lptr->modulo--; if (lptr->num_recs_pb > 0) prop_ino_cursor(mp, agno, btree_curs, ino_rec->ino_startnum, 0); bt_rec = (xfs_inobt_rec_t *) ((char *)bt_hdr + XFS_INOBT_BLOCK_LEN(mp)); for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(ino_rec != NULL); bt_rec[j].ir_startino = cpu_to_be32(ino_rec->ino_startnum); bt_rec[j].ir_free = cpu_to_be64(ino_rec->ir_free); inocnt = finocnt = 0; for (k = 0; k < sizeof(xfs_inofree_t)*NBBY; k++) { ASSERT(is_inode_confirmed(ino_rec, k)); if (is_inode_sparse(ino_rec, k)) continue; if (is_inode_free(ino_rec, k)) finocnt++; inocnt++; } /* * Set the freecount and check whether we need to update * the sparse format fields. Otherwise, skip to the next * record. */ inorec_set_freecount(mp, &bt_rec[j], finocnt); if (!xfs_sb_version_hassparseinodes(&mp->m_sb)) goto nextrec; /* * Convert the 64-bit in-core sparse inode state to the * 16-bit on-disk holemask. */ holemask = 0; spmask = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; sparse = ino_rec->ir_sparse; for (k = 0; k < XFS_INOBT_HOLEMASK_BITS; k++) { if (sparse & spmask) { ASSERT((sparse & spmask) == spmask); holemask |= (1 << k); } else ASSERT((sparse & spmask) == 0); sparse >>= XFS_INODES_PER_HOLEMASK_BIT; } bt_rec[j].ir_u.sp.ir_count = inocnt; bt_rec[j].ir_u.sp.ir_holemask = cpu_to_be16(holemask); nextrec: freecount += finocnt; count += inocnt; if (finobt) ino_rec = next_free_ino_rec(ino_rec); else ino_rec = next_ino_rec(ino_rec); } if (ino_rec != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_INO_TRACE fprintf(stderr, "writing inobt agbno %u\n", lptr->prev_agbno); #endif ASSERT(lptr->prev_agbno != NULLAGBLOCK); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_buf_p = lptr->buf_p; lptr->prev_agbno = lptr->agbno; lptr->agbno = get_next_blockaddr(agno, 0, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(lptr->agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), XFS_FSB_TO_BB(mp, 1)); } } if (agi_stat) { agi_stat->first_agino = first_agino; agi_stat->count = count; agi_stat->freecount = freecount; } }