static void xfs_agiblock_init( struct xfs_mount *mp, struct xfs_buf *bp, struct aghdr_init_data *id) { struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); int bucket; agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); agi->agi_seqno = cpu_to_be32(id->agno); agi->agi_length = cpu_to_be32(id->agsize); agi->agi_count = 0; agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp)); agi->agi_level = cpu_to_be32(1); agi->agi_freecount = 0; agi->agi_newino = cpu_to_be32(NULLAGINO); agi->agi_dirino = cpu_to_be32(NULLAGINO); if (xfs_sb_version_hascrc(&mp->m_sb)) uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); if (xfs_sb_version_hasfinobt(&mp->m_sb)) { agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); agi->agi_free_level = cpu_to_be32(1); } for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); }
/* * The free inode btree is a conditional feature. The behavior differs slightly * from that of the traditional inode btree in that the finobt tracks records * for inode chunks with at least one free inode. A record can be removed from * the tree during individual inode allocation. Therefore the finobt * reservation is unconditional for both the inode chunk allocation and * individual inode allocation (modify) cases. * * Behavior aside, the reservation for finobt modification is equivalent to the * traditional inobt: cover a full finobt shape change plus block allocation. */ STATIC uint xfs_calc_finobt_res( struct xfs_mount *mp) { if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return 0; return xfs_calc_inobt_res(mp); }
/* * XXX: yet more code that can be shared with mkfs, growfs. */ static void build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, bt_status_t *finobt_curs, struct agi_stat *agi_stat) { xfs_buf_t *agi_buf; xfs_agi_t *agi; int i; agi_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agi_buf->b_ops = &xfs_agi_buf_ops; agi = XFS_BUF_TO_AGI(agi_buf); memset(agi, 0, mp->m_sb.sb_sectsize); agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); agi->agi_seqno = cpu_to_be32(agno); if (agno < mp->m_sb.sb_agcount - 1) agi->agi_length = cpu_to_be32(mp->m_sb.sb_agblocks); else agi->agi_length = cpu_to_be32(mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); agi->agi_count = cpu_to_be32(agi_stat->count); agi->agi_root = cpu_to_be32(btree_curs->root); agi->agi_level = cpu_to_be32(btree_curs->num_levels); agi->agi_freecount = cpu_to_be32(agi_stat->freecount); agi->agi_newino = cpu_to_be32(agi_stat->first_agino); agi->agi_dirino = cpu_to_be32(NULLAGINO); for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO); if (xfs_sb_version_hascrc(&mp->m_sb)) platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); if (xfs_sb_version_hasfinobt(&mp->m_sb)) { agi->agi_free_root = cpu_to_be32(finobt_curs->root); agi->agi_free_level = cpu_to_be32(finobt_curs->num_levels); } libxfs_writebuf(agi_buf, 0); }
/* * The free inode btree is a conditional feature and the log reservation * requirements differ slightly from that of the traditional inode allocation * btree. The finobt tracks records for inode chunks with at least one free * inode. A record can be removed from the tree for an inode allocation * or free and thus the finobt reservation is unconditional across: * * - inode allocation * - inode free * - inode chunk allocation * * The 'modify' param indicates to include the record modification scenario. The * 'alloc' param indicates to include the reservation for free space btree * modifications on behalf of finobt modifications. This is required only for * transactions that do not already account for free space btree modifications. * * the free inode btree: max depth * block size * the allocation btrees: 2 trees * (max depth - 1) * block size * the free inode btree entry: block size */ STATIC uint xfs_calc_finobt_res( struct xfs_mount *mp, int alloc, int modify) { uint res; if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return 0; res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)); if (alloc) res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); if (modify) res += (uint)XFS_FSB_TO_B(mp, 1); return res; }
static char * version_string( xfs_sb_t *sbp) { static char s[1024]; if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1) strcpy(s, "V1"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2) strcpy(s, "V2"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3) strcpy(s, "V3"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) strcpy(s, "V4"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) strcpy(s, "V5"); /* * We assume the state of these features now, so macros don't exist for * them any more. */ if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) strcat(s, ",NLINK"); if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) strcat(s, ",SHARED"); if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT) strcat(s, ",DIRV2"); if (xfs_sb_version_hasattr(sbp)) strcat(s, ",ATTR"); if (xfs_sb_version_hasquota(sbp)) strcat(s, ",QUOTA"); if (xfs_sb_version_hasalign(sbp)) strcat(s, ",ALIGN"); if (xfs_sb_version_hasdalign(sbp)) strcat(s, ",DALIGN"); if (xfs_sb_version_haslogv2(sbp)) strcat(s, ",LOGV2"); if (xfs_sb_version_hasextflgbit(sbp)) strcat(s, ",EXTFLG"); if (xfs_sb_version_hassector(sbp)) strcat(s, ",SECTOR"); if (xfs_sb_version_hasasciici(sbp)) strcat(s, ",ASCII_CI"); if (xfs_sb_version_hasmorebits(sbp)) strcat(s, ",MOREBITS"); if (xfs_sb_version_hasattr2(sbp)) strcat(s, ",ATTR2"); if (xfs_sb_version_haslazysbcount(sbp)) strcat(s, ",LAZYSBCOUNT"); if (xfs_sb_version_hasprojid32bit(sbp)) strcat(s, ",PROJID32BIT"); if (xfs_sb_version_hascrc(sbp)) strcat(s, ",CRC"); if (xfs_sb_version_hasftype(sbp)) strcat(s, ",FTYPE"); if (xfs_sb_version_hasfinobt(sbp)) strcat(s, ",FINOBT"); if (xfs_sb_version_hassparseinodes(sbp)) strcat(s, ",SPARSE_INODES"); if (xfs_sb_version_hasmetauuid(sbp)) strcat(s, ",META_UUID"); return s; }
/* * Figure out how many blocks to reserve for an AG repair. We calculate the * worst case estimate for the number of blocks we'd need to rebuild one of * any type of per-AG btree. */ xfs_extlen_t xrep_calc_ag_resblks( struct xfs_scrub *sc) { struct xfs_mount *mp = sc->mp; struct xfs_scrub_metadata *sm = sc->sm; struct xfs_perag *pag; struct xfs_buf *bp; xfs_agino_t icount = NULLAGINO; xfs_extlen_t aglen = NULLAGBLOCK; xfs_extlen_t usedlen; xfs_extlen_t freelen; xfs_extlen_t bnobt_sz; xfs_extlen_t inobt_sz; xfs_extlen_t rmapbt_sz; xfs_extlen_t refcbt_sz; int error; if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) return 0; pag = xfs_perag_get(mp, sm->sm_agno); if (pag->pagi_init) { /* Use in-core icount if possible. */ icount = pag->pagi_count; } else { /* Try to get the actual counters from disk. */ error = xfs_ialloc_read_agi(mp, NULL, sm->sm_agno, &bp); if (!error) { icount = pag->pagi_count; xfs_buf_relse(bp); } } /* Now grab the block counters from the AGF. */ error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp); if (!error) { aglen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_length); freelen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_freeblks); usedlen = aglen - freelen; xfs_buf_relse(bp); } xfs_perag_put(pag); /* If the icount is impossible, make some worst-case assumptions. */ if (icount == NULLAGINO || !xfs_verify_agino(mp, sm->sm_agno, icount)) { xfs_agino_t first, last; xfs_agino_range(mp, sm->sm_agno, &first, &last); icount = last - first + 1; } /* If the block counts are impossible, make worst-case assumptions. */ if (aglen == NULLAGBLOCK || aglen != xfs_ag_block_count(mp, sm->sm_agno) || freelen >= aglen) { aglen = xfs_ag_block_count(mp, sm->sm_agno); freelen = aglen; usedlen = aglen; } trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen, freelen, usedlen); /* * Figure out how many blocks we'd need worst case to rebuild * each type of btree. Note that we can only rebuild the * bnobt/cntbt or inobt/finobt as pairs. */ bnobt_sz = 2 * xfs_allocbt_calc_size(mp, freelen); if (xfs_sb_version_hassparseinodes(&mp->m_sb)) inobt_sz = xfs_iallocbt_calc_size(mp, icount / XFS_INODES_PER_HOLEMASK_BIT); else inobt_sz = xfs_iallocbt_calc_size(mp, icount / XFS_INODES_PER_CHUNK); if (xfs_sb_version_hasfinobt(&mp->m_sb)) inobt_sz *= 2; if (xfs_sb_version_hasreflink(&mp->m_sb)) refcbt_sz = xfs_refcountbt_calc_size(mp, usedlen); else refcbt_sz = 0; if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { /* * Guess how many blocks we need to rebuild the rmapbt. * For non-reflink filesystems we can't have more records than * used blocks. However, with reflink it's possible to have * more than one rmap record per AG block. We don't know how * many rmaps there could be in the AG, so we start off with * what we hope is an generous over-estimation. */ if (xfs_sb_version_hasreflink(&mp->m_sb)) rmapbt_sz = xfs_rmapbt_calc_size(mp, (unsigned long long)aglen * 2); else rmapbt_sz = xfs_rmapbt_calc_size(mp, usedlen); } else { rmapbt_sz = 0; } trace_xrep_calc_ag_resblks_btsize(mp, sm->sm_agno, bnobt_sz, inobt_sz, rmapbt_sz, refcbt_sz); return max(max(bnobt_sz, inobt_sz), max(rmapbt_sz, refcbt_sz)); }
static void phase5_func( xfs_mount_t *mp, xfs_agnumber_t agno) { __uint64_t num_inos; __uint64_t num_free_inos; __uint64_t finobt_num_inos; __uint64_t finobt_num_free_inos; bt_status_t bno_btree_curs; bt_status_t bcnt_btree_curs; bt_status_t ino_btree_curs; bt_status_t fino_btree_curs; int extra_blocks = 0; uint num_freeblocks; xfs_extlen_t freeblks1; #ifdef DEBUG xfs_extlen_t freeblks2; #endif xfs_agblock_t num_extents; __uint32_t magic; struct agi_stat agi_stat = {0,}; if (verbose) do_log(_(" - agno = %d\n"), agno); { /* * build up incore bno and bcnt extent btrees */ num_extents = mk_incore_fstree(mp, agno); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); #endif if (num_extents == 0) { /* * XXX - what we probably should do here is pick an * inode for a regular file in the allocation group * that has space allocated and shoot it by traversing * the bmap list and putting all its extents on the * incore freespace trees, clearing the inode, * and clearing the in-use bit in the incore inode * tree. Then try mk_incore_fstree() again. */ do_error(_("unable to rebuild AG %u. " "Not enough free space in on-disk AG.\n"), agno); } /* * ok, now set up the btree cursors for the * on-disk btrees (includs pre-allocating all * required blocks for the trees themselves) */ init_ino_cursor(mp, agno, &ino_btree_curs, &num_inos, &num_free_inos, 0); if (xfs_sb_version_hasfinobt(&mp->m_sb)) init_ino_cursor(mp, agno, &fino_btree_curs, &finobt_num_inos, &finobt_num_free_inos, 1); sb_icount_ag[agno] += num_inos; sb_ifree_ag[agno] += num_free_inos; num_extents = count_bno_extents_blocks(agno, &num_freeblocks); /* * lose two blocks per AG -- the space tree roots * are counted as allocated since the space trees * always have roots */ sb_fdblocks_ag[agno] += num_freeblocks - 2; if (num_extents == 0) { /* * XXX - what we probably should do here is pick an * inode for a regular file in the allocation group * that has space allocated and shoot it by traversing * the bmap list and putting all its extents on the * incore freespace trees, clearing the inode, * and clearing the in-use bit in the incore inode * tree. Then try mk_incore_fstree() again. */ do_error( _("unable to rebuild AG %u. No free space.\n"), agno); } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", num_extents); #endif /* * track blocks that we might really lose */ extra_blocks = calculate_freespace_cursor(mp, agno, &num_extents, &bno_btree_curs); /* * freespace btrees live in the "free space" but * the filesystem treats AGFL blocks as allocated * since they aren't described by the freespace trees */ /* * see if we can fit all the extra blocks into the AGFL */ extra_blocks = (extra_blocks - XFS_AGFL_SIZE(mp) > 0) ? extra_blocks - XFS_AGFL_SIZE(mp) : 0; if (extra_blocks > 0) { do_warn(_("lost %d blocks in agno %d, sorry.\n"), extra_blocks, agno); sb_fdblocks_ag[agno] -= extra_blocks; } bcnt_btree_curs = bno_btree_curs; setup_cursor(mp, agno, &bno_btree_curs); setup_cursor(mp, agno, &bcnt_btree_curs); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of bno extents is %d\n", count_bno_extents(agno)); fprintf(stderr, "# of bcnt extents is %d\n", count_bcnt_extents(agno)); #endif /* * now rebuild the freespace trees */ freeblks1 = build_freespace_tree(mp, agno, &bno_btree_curs, XFS_ABTB_MAGIC); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "# of free blocks == %d\n", freeblks1); #endif write_cursor(&bno_btree_curs); #ifdef DEBUG freeblks2 = build_freespace_tree(mp, agno, &bcnt_btree_curs, XFS_ABTC_MAGIC); #else (void) build_freespace_tree(mp, agno, &bcnt_btree_curs, XFS_ABTC_MAGIC); #endif write_cursor(&bcnt_btree_curs); ASSERT(freeblks1 == freeblks2); /* * set up agf and agfl */ build_agf_agfl(mp, agno, &bno_btree_curs, &bcnt_btree_curs, freeblks1, extra_blocks); /* * build inode allocation tree. */ magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC : XFS_IBT_MAGIC; build_ino_tree(mp, agno, &ino_btree_curs, magic, &agi_stat, 0); write_cursor(&ino_btree_curs); /* * build free inode tree */ if (xfs_sb_version_hasfinobt(&mp->m_sb)) { magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC; build_ino_tree(mp, agno, &fino_btree_curs, magic, NULL, 1); write_cursor(&fino_btree_curs); } /* build the agi */ build_agi(mp, agno, &ino_btree_curs, &fino_btree_curs, &agi_stat); /* * tear down cursors */ finish_cursor(&bno_btree_curs); finish_cursor(&ino_btree_curs); if (xfs_sb_version_hasfinobt(&mp->m_sb)) finish_cursor(&fino_btree_curs); finish_cursor(&bcnt_btree_curs); /* * release the incore per-AG bno/bcnt trees so * the extent nodes can be recycled */ release_agbno_extent_tree(agno); release_agbcnt_extent_tree(agno); } PROG_RPT_INC(prog_rpt_done[agno], 1); }