static void process_agi_unlinked( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_buf *bp; struct xfs_agi *agip; xfs_agnumber_t i; int agi_dirty = 0; bp = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE, 0, &xfs_agi_buf_ops); if (!bp) do_error(_("cannot read agi block %" PRId64 " for ag %u\n"), XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), agno); agip = XFS_BUF_TO_AGI(bp); ASSERT(be32_to_cpu(agip->agi_seqno) == agno); for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { if (agip->agi_unlinked[i] != cpu_to_be32(NULLAGINO)) { agip->agi_unlinked[i] = cpu_to_be32(NULLAGINO); agi_dirty = 1; } } if (agi_dirty) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); }
static int newfile( xfs_trans_t *tp, xfs_inode_t *ip, xfs_bmap_free_t *flist, xfs_fsblock_t *first, int dolocal, int logit, char *buf, int len) { xfs_buf_t *bp; xfs_daddr_t d; int error; int flags; xfs_bmbt_irec_t map; xfs_mount_t *mp; xfs_extlen_t nb; int nmap; flags = 0; mp = ip->i_mount; if (dolocal && len <= XFS_IFORK_DSIZE(ip)) { xfs_idata_realloc(ip, len, XFS_DATA_FORK); if (buf) memmove(ip->i_df.if_u1.if_data, buf, len); ip->i_d.di_size = len; ip->i_df.if_flags &= ~XFS_IFEXTENTS; ip->i_df.if_flags |= XFS_IFINLINE; ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; flags = XFS_ILOG_DDATA; } else if (len > 0) { nb = XFS_B_TO_FSB(mp, len); nmap = 1; error = libxfs_bmapi(tp, ip, 0, nb, XFS_BMAPI_WRITE, first, nb, &map, &nmap, flist); if (error) { fail(_("error allocating space for a file"), error); } if (nmap != 1) { fprintf(stderr, _("%s: cannot allocate space for file\n"), progname); exit(1); } d = XFS_FSB_TO_DADDR(mp, map.br_startblock); bp = libxfs_trans_get_buf(logit ? tp : 0, mp->m_dev, d, nb << mp->m_blkbb_log, 0); memmove(XFS_BUF_PTR(bp), buf, len); if (len < XFS_BUF_COUNT(bp)) memset(XFS_BUF_PTR(bp) + len, 0, XFS_BUF_COUNT(bp) - len); if (logit) libxfs_trans_log_buf(tp, bp, 0, XFS_BUF_COUNT(bp) - 1); else libxfs_writebuf(bp, LIBXFS_EXIT_ON_FAILURE); } ip->i_d.di_size = len; return flags; }
static void write_cursor(bt_status_t *curs) { int i; for (i = 0; i < curs->num_levels; i++) { #if defined(XR_BLD_FREE_TRACE) || defined(XR_BLD_INO_TRACE) fprintf(stderr, "writing bt block %u\n", curs->level[i].agbno); #endif if (curs->level[i].prev_buf_p != NULL) { ASSERT(curs->level[i].prev_agbno != NULLAGBLOCK); #if defined(XR_BLD_FREE_TRACE) || defined(XR_BLD_INO_TRACE) fprintf(stderr, "writing bt prev block %u\n", curs->level[i].prev_agbno); #endif libxfs_writebuf(curs->level[i].prev_buf_p, 0); } libxfs_writebuf(curs->level[i].buf_p, 0); } }
/* * update the superblock counters, sync the sb version numbers and * feature bits to the filesystem, and sync up the on-disk superblock * to match the incore superblock. */ static void sync_sb(xfs_mount_t *mp) { xfs_buf_t *bp; bp = libxfs_getsb(mp, 0); if (!bp) do_error(_("couldn't get superblock\n")); mp->m_sb.sb_icount = sb_icount; mp->m_sb.sb_ifree = sb_ifree; mp->m_sb.sb_fdblocks = sb_fdblocks; mp->m_sb.sb_frextents = sb_frextents; update_sb_version(mp); libxfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); libxfs_writebuf(bp, 0); }
/* * 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); }
/* * Start processing for a leaf or fuller btree. * A leaf directory is one where the attribute fork is too big for * the inode but is small enough to fit into one btree block * outside the inode. This code is modelled after process_leaf_dir_block. * * returns 0 if things are ok, 1 if bad (attributes needs to be junked) * repair is set, if anything was changed, but attributes can live thru it */ static int process_longform_attr( xfs_mount_t *mp, xfs_ino_t ino, xfs_dinode_t *dip, blkmap_t *blkmap, int *repair) /* out - 1 if something was fixed */ { xfs_attr_leafblock_t *leaf; xfs_fsblock_t bno; xfs_buf_t *bp; xfs_dahash_t next_hashval; int repairlinks = 0; struct xfs_attr3_icleaf_hdr leafhdr; int error; *repair = 0; bno = blkmap_get(blkmap, 0); if ( bno == NULLFSBLOCK ) { if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS && be16_to_cpu(dip->di_anextents) == 0) return(0); /* the kernel can handle this state */ do_warn( _("block 0 of inode %" PRIu64 " attribute fork is missing\n"), ino); return(1); } /* FIX FOR bug 653709 -- EKN */ if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) { do_warn( _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino); return(1); } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops); if (!bp) { do_warn( _("can't read block 0 of inode %" PRIu64 " attribute fork\n"), ino); return(1); } if (bp->b_error == -EFSBADCRC) (*repair)++; /* is this block sane? */ if (__check_attr_header(mp, bp, ino)) { *repair = 0; libxfs_putbuf(bp); return 1; } /* verify leaf block */ leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); /* check sibling pointers in leaf block or root block 0 before * we have to release the btree block */ if (leafhdr.forw != 0 || leafhdr.back != 0) { if (!no_modify) { do_warn( _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino); repairlinks = 1; leafhdr.forw = 0; leafhdr.back = 0; xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr); } else { do_warn( _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino); } } /* * use magic number to tell us what type of attribute this is. * it's possible to have a node or leaf attribute in either an * extent format or btree format attribute fork. */ switch (leafhdr.magic) { case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */ case XFS_ATTR3_LEAF_MAGIC: if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap, 0, &next_hashval, repair)) { *repair = 0; /* the block is bad. lose the attribute fork. */ libxfs_putbuf(bp); return(1); } *repair = *repair || repairlinks; break; case XFS_DA_NODE_MAGIC: /* btree-form attribute */ case XFS_DA3_NODE_MAGIC: /* must do this now, to release block 0 before the traversal */ if ((*repair || repairlinks) && !no_modify) { *repair = 1; libxfs_writebuf(bp, 0); } else libxfs_putbuf(bp); error = process_node_attr(mp, ino, dip, blkmap); /* + repair */ if (error) *repair = 0; return error; default: do_warn( _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"), be16_to_cpu(leaf->hdr.info.magic), ino); libxfs_putbuf(bp); *repair = 0; return(1); } if (*repair && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); return(0); /* repair may be set */ }
/* * returns 0 if the attribute fork is ok, 1 if it has to be junked. */ static int process_leaf_attr_level(xfs_mount_t *mp, da_bt_cursor_t *da_cursor) { int repair; xfs_attr_leafblock_t *leaf; xfs_buf_t *bp; xfs_ino_t ino; xfs_fsblock_t dev_bno; xfs_dablk_t da_bno; xfs_dablk_t prev_bno; xfs_dahash_t current_hashval = 0; xfs_dahash_t greatest_hashval; struct xfs_attr3_icleaf_hdr leafhdr; da_bno = da_cursor->level[0].bno; ino = da_cursor->ino; prev_bno = 0; do { repair = 0; dev_bno = blkmap_get(da_cursor->blkmap, da_bno); /* * 0 is the root block and no block * pointer can point to the root block of the btree */ ASSERT(da_bno != 0); if (dev_bno == NULLFSBLOCK) { do_warn( _("can't map block %u for attribute fork for inode %" PRIu64 "\n"), da_bno, ino); goto error_out; } bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno), XFS_FSB_TO_BB(mp, 1), 0, &xfs_attr3_leaf_buf_ops); if (!bp) { do_warn( _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"), da_bno, dev_bno, ino); goto error_out; } leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); /* check magic number for leaf directory btree block */ if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC || leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) { do_warn( _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"), leafhdr.magic, ino); libxfs_putbuf(bp); goto error_out; } /* * for each block, process the block, verify its path, * then get next block. update cursor values along the way */ if (process_leaf_attr_block(mp, leaf, da_bno, ino, da_cursor->blkmap, current_hashval, &greatest_hashval, &repair)) { libxfs_putbuf(bp); goto error_out; } /* * index can be set to hdr.count so match the * indexes of the interior blocks -- which at the * end of the block will point to 1 after the final * real entry in the block */ da_cursor->level[0].hashval = greatest_hashval; da_cursor->level[0].bp = bp; da_cursor->level[0].bno = da_bno; da_cursor->level[0].index = leafhdr.count; da_cursor->level[0].dirty = repair; if (leafhdr.back != prev_bno) { do_warn( _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"), da_bno, ino); libxfs_putbuf(bp); goto error_out; } prev_bno = da_bno; da_bno = leafhdr.forw; if (da_bno != 0) { if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) { libxfs_putbuf(bp); goto error_out; } } current_hashval = greatest_hashval; /* * If block looks ok but CRC didn't match, make sure to * recompute it. */ if (!no_modify && bp->b_error == -EFSBADCRC) repair++; if (repair && !no_modify) libxfs_writebuf(bp, 0); else libxfs_putbuf(bp); } while (da_bno != 0); if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) { /* * verify the final path up (right-hand-side) if still ok */ do_warn( _("bad hash path in attribute fork for inode %" PRIu64 "\n"), da_cursor->ino); goto error_out; } /* releases all buffers holding interior btree blocks */ release_da_cursor(mp, da_cursor, 0); return(0); error_out: /* release all buffers holding interior btree blocks */ err_release_da_cursor(mp, da_cursor, 0); return(1); }
/* * rebuilds a freespace tree given a cursor and magic number of type * of tree to build (bno or bcnt). returns the number of free blocks * represented by the tree. */ static xfs_extlen_t build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, __uint32_t magic) { xfs_agnumber_t i; xfs_agblock_t j; struct xfs_btree_block *bt_hdr; xfs_alloc_rec_t *bt_rec; int level; xfs_agblock_t agbno; extent_tree_node_t *ext_ptr; bt_stat_level_t *lptr; xfs_extlen_t freeblks; __uint32_t crc_magic; #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "in build_freespace_tree, agno = %d\n", agno); #endif level = btree_curs->num_levels; freeblks = 0; ASSERT(level > 0); if (magic == XFS_ABTB_MAGIC) crc_magic = XFS_ABTB_CRC_MAGIC; else crc_magic = XFS_ABTC_CRC_MAGIC; /* * initialize the first block on each btree level */ 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_allocbt_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, crc_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_freespace_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 (magic == XFS_ABTB_MAGIC) ext_ptr = findfirst_bno_extent(agno); else ext_ptr = findfirst_bcnt_extent(agno); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bft, agno = %d, start = %u, count = %u\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); #endif lptr = &btree_curs->level[0]; for (i = 0; i < btree_curs->level[0].num_blocks; i++) { /* * block initialization, lay in block header */ lptr->buf_p->b_ops = &xfs_allocbt_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, crc_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)); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bft, bb_numrecs = %d\n", be16_to_cpu(bt_hdr->bb_numrecs)); #endif if (lptr->modulo > 0) lptr->modulo--; /* * initialize values in the path up to the root if * this is a multi-level btree */ if (btree_curs->num_levels > 1) prop_freespace_cursor(mp, agno, btree_curs, ext_ptr->ex_startblock, ext_ptr->ex_blockcount, 0, magic); bt_rec = (xfs_alloc_rec_t *) ((char *)bt_hdr + XFS_ALLOC_BLOCK_LEN(mp)); for (j = 0; j < be16_to_cpu(bt_hdr->bb_numrecs); j++) { ASSERT(ext_ptr != NULL); bt_rec[j].ar_startblock = cpu_to_be32( ext_ptr->ex_startblock); bt_rec[j].ar_blockcount = cpu_to_be32( ext_ptr->ex_blockcount); freeblks += ext_ptr->ex_blockcount; if (magic == XFS_ABTB_MAGIC) ext_ptr = findnext_bno_extent(ext_ptr); else ext_ptr = findnext_bcnt_extent(agno, ext_ptr); #if 0 #ifdef XR_BLD_FREE_TRACE if (ext_ptr == NULL) fprintf(stderr, "null extent pointer, j = %d\n", j); else fprintf(stderr, "bft, agno = %d, start = %u, count = %u\n", agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); #endif #endif } if (ext_ptr != NULL) { /* * get next leaf level block */ if (lptr->prev_buf_p != NULL) { #ifdef XR_BLD_FREE_TRACE fprintf(stderr, " writing fst 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)); } } return(freeblks); }
static void prop_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_agblock_t startblock, xfs_extlen_t blockcount, int level, __uint32_t magic) { struct xfs_btree_block *bt_hdr; xfs_alloc_key_t *bt_key; xfs_alloc_ptr_t *bt_ptr; xfs_agblock_t agbno; bt_stat_level_t *lptr; __uint32_t crc_magic; if (magic == XFS_ABTB_MAGIC) crc_magic = XFS_ABTB_CRC_MAGIC; else crc_magic = XFS_ABTC_CRC_MAGIC; level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * only happens once when initializing the * left-hand side of the tree. */ prop_freespace_cursor(mp, agno, btree_curs, startblock, blockcount, level, magic); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_FREE_TRACE fprintf(stderr, " %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno;; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * initialize block header */ lptr->buf_p->b_ops = &xfs_allocbt_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, crc_magic, level, 0, agno, XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block(mp, lptr->buf_p, magic, level, 0, agno, 0); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_freespace_cursor(mp, agno, btree_curs, startblock, blockcount, level, magic); } /* * add extent info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_ALLOC_KEY_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_ALLOC_PTR_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), mp->m_alloc_mxr[1]); bt_key->ar_startblock = cpu_to_be32(startblock); bt_key->ar_blockcount = cpu_to_be32(blockcount); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); }
/* * build both the agf and the agfl for an agno given both * btree cursors. * * XXX: yet more common code that can be shared with mkfs/growfs. */ static void build_agf_agfl(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *bno_bt, bt_status_t *bcnt_bt, xfs_extlen_t freeblks, /* # free blocks in tree */ int lostblocks) /* # blocks that will be lost */ { extent_tree_node_t *ext_ptr; xfs_buf_t *agf_buf, *agfl_buf; int i; int j; xfs_agfl_t *agfl; xfs_agf_t *agf; __be32 *freelist; agf_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agf_buf->b_ops = &xfs_agf_buf_ops; agf = XFS_BUF_TO_AGF(agf_buf); memset(agf, 0, mp->m_sb.sb_sectsize); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "agf = 0x%p, agf_buf->b_addr = 0x%p\n", agf, agf_buf->b_addr); #endif /* * set up fixed part of agf */ agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); agf->agf_seqno = cpu_to_be32(agno); if (agno < mp->m_sb.sb_agcount - 1) agf->agf_length = cpu_to_be32(mp->m_sb.sb_agblocks); else agf->agf_length = cpu_to_be32(mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * agno); agf->agf_roots[XFS_BTNUM_BNO] = cpu_to_be32(bno_bt->root); agf->agf_levels[XFS_BTNUM_BNO] = cpu_to_be32(bno_bt->num_levels); agf->agf_roots[XFS_BTNUM_CNT] = cpu_to_be32(bcnt_bt->root); agf->agf_levels[XFS_BTNUM_CNT] = cpu_to_be32(bcnt_bt->num_levels); agf->agf_freeblks = cpu_to_be32(freeblks); /* * Count and record the number of btree blocks consumed if required. */ if (xfs_sb_version_haslazysbcount(&mp->m_sb)) { /* * Don't count the root blocks as they are already * accounted for. */ agf->agf_btreeblks = cpu_to_be32( (bno_bt->num_tot_blocks - bno_bt->num_free_blocks) + (bcnt_bt->num_tot_blocks - bcnt_bt->num_free_blocks) - 2); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "agf->agf_btreeblks = %u\n", be32_to_cpu(agf->agf_btreeblks)); #endif } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "bno root = %u, bcnt root = %u, indices = %u %u\n", be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), XFS_BTNUM_BNO, XFS_BTNUM_CNT); #endif if (xfs_sb_version_hascrc(&mp->m_sb)) platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); /* initialise the AGFL, then fill it if there are blocks left over. */ agfl_buf = libxfs_getbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), mp->m_sb.sb_sectsize/BBSIZE); agfl_buf->b_ops = &xfs_agfl_buf_ops; agfl = XFS_BUF_TO_AGFL(agfl_buf); /* setting to 0xff results in initialisation to NULLAGBLOCK */ memset(agfl, 0xff, mp->m_sb.sb_sectsize); if (xfs_sb_version_hascrc(&mp->m_sb)) { agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); agfl->agfl_seqno = cpu_to_be32(agno); platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); for (i = 0; i < XFS_AGFL_SIZE(mp); i++) agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK); } freelist = XFS_BUF_TO_AGFL_BNO(mp, agfl_buf); /* * do we have left-over blocks in the btree cursors that should * be used to fill the AGFL? */ if (bno_bt->num_free_blocks > 0 || bcnt_bt->num_free_blocks > 0) { /* * yes, now grab as many blocks as we can */ i = j = 0; while (bno_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE(mp)) { freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bno_bt)); i++; } while (bcnt_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE(mp)) { freelist[i] = cpu_to_be32( get_next_blockaddr(agno, 0, bcnt_bt)); i++; } /* * now throw the rest of the blocks away and complain */ while (bno_bt->num_free_blocks > 0) { (void) get_next_blockaddr(agno, 0, bno_bt); j++; } while (bcnt_bt->num_free_blocks > 0) { (void) get_next_blockaddr(agno, 0, bcnt_bt); j++; } if (j > 0) { if (j == lostblocks) do_warn(_("lost %d blocks in ag %u\n"), j, agno); else do_warn(_("thought we were going to lose %d " "blocks in ag %u, actually lost " "%d\n"), lostblocks, j, agno); } agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(i - 1); agf->agf_flcount = cpu_to_be32(i); #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "writing agfl for ag %u\n", agno); #endif } else { agf->agf_flfirst = 0; agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1); agf->agf_flcount = 0; } libxfs_writebuf(agfl_buf, 0); ext_ptr = findbiggest_bcnt_extent(agno); agf->agf_longest = cpu_to_be32((ext_ptr != NULL) ? ext_ptr->ex_blockcount : 0); ASSERT(be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNOi]) != be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNTi])); libxfs_writebuf(agf_buf, 0); /* * now fix up the free list appropriately * XXX: code lifted from mkfs, should be shared. */ { xfs_alloc_arg_t args; xfs_trans_t *tp; struct xfs_trans_res tres = {0}; int error; memset(&args, 0, sizeof(args)); args.tp = tp = libxfs_trans_alloc(mp, 0); args.mp = mp; args.agno = agno; args.alignment = 1; args.pag = xfs_perag_get(mp,agno); libxfs_trans_reserve(tp, &tres, xfs_alloc_min_freelist(mp, args.pag), 0); error = libxfs_alloc_fix_freelist(&args, 0); xfs_perag_put(args.pag); if (error) { do_error(_("failed to fix AGFL on AG %d, error %d\n"), agno, error); } libxfs_trans_commit(tp); } #ifdef XR_BLD_FREE_TRACE fprintf(stderr, "wrote agf for ag %u\n", agno); #endif }
/* * 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; } }
static void prop_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, xfs_agino_t startino, int level) { struct xfs_btree_block *bt_hdr; xfs_inobt_key_t *bt_key; xfs_inobt_ptr_t *bt_ptr; xfs_agblock_t agbno; bt_stat_level_t *lptr; level++; if (level >= btree_curs->num_levels) return; lptr = &btree_curs->level[level]; bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p); if (be16_to_cpu(bt_hdr->bb_numrecs) == 0) { /* * this only happens once to initialize the * first path up the left side of the tree * where the agbno's are already set up */ prop_ino_cursor(mp, agno, btree_curs, startino, level); } if (be16_to_cpu(bt_hdr->bb_numrecs) == lptr->num_recs_pb + (lptr->modulo > 0)) { /* * write out current prev block, grab us a new block, * and set the rightsib pointer of current block */ #ifdef XR_BLD_INO_TRACE fprintf(stderr, " ino prop agbno %d ", lptr->prev_agbno); #endif if (lptr->prev_agbno != NULLAGBLOCK) { ASSERT(lptr->prev_buf_p != NULL); libxfs_writebuf(lptr->prev_buf_p, 0); } lptr->prev_agbno = lptr->agbno;; lptr->prev_buf_p = lptr->buf_p; agbno = get_next_blockaddr(agno, level, btree_curs); bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(agbno); lptr->buf_p = libxfs_getbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), XFS_FSB_TO_BB(mp, 1)); lptr->agbno = agbno; if (lptr->modulo) lptr->modulo--; /* * 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, XFS_IBT_CRC_MAGIC, level, 0, agno, XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC, level, 0, agno, 0); bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno); /* * propagate extent record for first extent in new block up */ prop_ino_cursor(mp, agno, btree_curs, startino, level); } /* * add inode info to current block */ be16_add_cpu(&bt_hdr->bb_numrecs, 1); bt_key = XFS_INOBT_KEY_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs)); bt_ptr = XFS_INOBT_PTR_ADDR(mp, bt_hdr, be16_to_cpu(bt_hdr->bb_numrecs), mp->m_inobt_mxr[1]); bt_key->ir_startino = cpu_to_be32(startino); *bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno); }