From: Dave Chinner <david@fromorbit.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 10/21] xfs: add helper routines for the repair code
Date: Fri, 6 Apr 2018 10:52:51 +1000 [thread overview]
Message-ID: <20180406005251.GO23861@dastard> (raw)
In-Reply-To: <152269903810.16346.11410639151264264247.stgit@magnolia>
On Mon, Apr 02, 2018 at 12:57:18PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
>
> Add some helper functions for repair functions that will help us to
> allocate and initialize new metadata blocks for btrees that we're
> rebuilding.
This is more than "helper functions" - my replay is almost 700 lines
long!
i.e. This is a stack of extent invalidation, freeing and rmap/free
space rebuild code. Needs a lot more description and context than
"helper functions".
.....
> @@ -574,7 +575,10 @@ xfs_scrub_setup_fs(
> struct xfs_scrub_context *sc,
> struct xfs_inode *ip)
> {
> - return xfs_scrub_trans_alloc(sc->sm, sc->mp, &sc->tp);
> + uint resblks;
> +
> + resblks = xfs_repair_calc_ag_resblks(sc);
> + return xfs_scrub_trans_alloc(sc->sm, sc->mp, resblks, &sc->tp);
> }
What's the block reservation for?
> +/*
> + * Roll a transaction, keeping the AG headers locked and reinitializing
> + * the btree cursors.
> + */
> +int
> +xfs_repair_roll_ag_trans(
> + struct xfs_scrub_context *sc)
> +{
> + struct xfs_trans *tp;
> + int error;
> +
> + /* Keep the AG header buffers locked so we can keep going. */
> + xfs_trans_bhold(sc->tp, sc->sa.agi_bp);
> + xfs_trans_bhold(sc->tp, sc->sa.agf_bp);
> + xfs_trans_bhold(sc->tp, sc->sa.agfl_bp);
> +
> + /* Roll the transaction. */
> + tp = sc->tp;
> + error = xfs_trans_roll(&sc->tp);
> + if (error)
> + return error;
Who releases those buffers if we get an error here?
> +
> + /* Join the buffer to the new transaction or release the hold. */
> + if (sc->tp != tp) {
When does xfs_trans_roll() return successfully without allocating a
new transaction?
> + xfs_trans_bjoin(sc->tp, sc->sa.agi_bp);
> + xfs_trans_bjoin(sc->tp, sc->sa.agf_bp);
> + xfs_trans_bjoin(sc->tp, sc->sa.agfl_bp);
> + } else {
> + xfs_trans_bhold_release(sc->tp, sc->sa.agi_bp);
> + xfs_trans_bhold_release(sc->tp, sc->sa.agf_bp);
> + xfs_trans_bhold_release(sc->tp, sc->sa.agfl_bp);
> + }
> +
> + return error;
> +}
.....
> +/* Allocate a block in an AG. */
> +int
> +xfs_repair_alloc_ag_block(
> + struct xfs_scrub_context *sc,
> + struct xfs_owner_info *oinfo,
> + xfs_fsblock_t *fsbno,
> + enum xfs_ag_resv_type resv)
> +{
> + struct xfs_alloc_arg args = {0};
> + xfs_agblock_t bno;
> + int error;
> +
> + if (resv == XFS_AG_RESV_AGFL) {
> + error = xfs_alloc_get_freelist(sc->tp, sc->sa.agf_bp, &bno, 1);
> + if (error)
> + return error;
> + if (bno == NULLAGBLOCK)
> + return -ENOSPC;
> + xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno,
> + 1, false);
> + *fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
> + return 0;
> + }
> +
> + args.tp = sc->tp;
> + args.mp = sc->mp;
> + args.oinfo = *oinfo;
> + args.fsbno = XFS_AGB_TO_FSB(args.mp, sc->sa.agno, 0);
So our target BNO is the start of the AG.
> + args.minlen = 1;
> + args.maxlen = 1;
> + args.prod = 1;
> + args.type = XFS_ALLOCTYPE_NEAR_BNO;
And we do a "near" search" for a single block. i.e. we are looking
for a single block near to the start of the AG. Basically, we are
looking for the extent at the left edge of the by-bno tree, which
may not be a single block.
Would it be better to do a XFS_ALLOCTYPE_THIS_AG allocation here so
we look up the by-size btree for a single block extent? The left
edge of that tree will always be the smallest free extent closest to
the start of the AG, and so using THIS_AG will tend to fill
small freespace holes rather than tear up larger free spaces for
single block allocations.....
> +/* Put a block back on the AGFL. */
> +int
> +xfs_repair_put_freelist(
> + struct xfs_scrub_context *sc,
> + xfs_agblock_t agbno)
> +{
> + struct xfs_owner_info oinfo;
> + int error;
> +
> + /*
> + * Since we're "freeing" a lost block onto the AGFL, we have to
> + * create an rmap for the block prior to merging it or else other
> + * parts will break.
> + */
> + xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
> + error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
> + &oinfo);
> + if (error)
> + return error;
> +
> + /* Put the block on the AGFL. */
> + error = xfs_alloc_put_freelist(sc->tp, sc->sa.agf_bp, sc->sa.agfl_bp,
> + agbno, 0);
At what point do we check there's actually room in the AGFL for this
block?
> + if (error)
> + return error;
> + xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1,
> + XFS_EXTENT_BUSY_SKIP_DISCARD);
> +
> + /* Make sure the AGFL doesn't overfill. */
> + return xfs_repair_fix_freelist(sc, true);
i.e. shouldn't this be done first?
> +}
> +
> +/*
> + * For a given metadata extent and owner, delete the associated rmap.
> + * If the block has no other owners, free it.
> + */
> +STATIC int
> +xfs_repair_free_or_unmap_extent(
> + struct xfs_scrub_context *sc,
> + xfs_fsblock_t fsbno,
> + xfs_extlen_t len,
> + struct xfs_owner_info *oinfo,
> + enum xfs_ag_resv_type resv)
> +{
> + struct xfs_mount *mp = sc->mp;
> + struct xfs_btree_cur *rmap_cur;
> + struct xfs_buf *agf_bp = NULL;
> + xfs_agnumber_t agno;
> + xfs_agblock_t agbno;
> + bool has_other_rmap;
> + int error = 0;
> +
> + ASSERT(xfs_sb_version_hasrmapbt(&mp->m_sb));
> + agno = XFS_FSB_TO_AGNO(mp, fsbno);
> + agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
> +
> + trace_xfs_repair_free_or_unmap_extent(mp, agno, agbno, len);
> +
> + for (; len > 0 && !error; len--, agbno++, fsbno++) {
> + ASSERT(sc->ip != NULL || agno == sc->sa.agno);
> +
> + /* Can we find any other rmappings? */
> + if (sc->ip) {
> + error = xfs_alloc_read_agf(mp, sc->tp, agno, 0,
> + &agf_bp);
> + if (error)
> + break;
> + if (!agf_bp) {
> + error = -ENOMEM;
> + break;
> + }
> + }
> + rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp,
> + agf_bp ? agf_bp : sc->sa.agf_bp, agno);
Why is the inode case treated differently here - why do we have a
special reference to agf_bp here rather than using sc->sa.agf_bp?
> + error = xfs_rmap_has_other_keys(rmap_cur, agbno, 1, oinfo,
> + &has_other_rmap);
> + if (error)
> + goto out_cur;
> + xfs_btree_del_cursor(rmap_cur, XFS_BTREE_NOERROR);
> + if (agf_bp)
> + xfs_trans_brelse(sc->tp, agf_bp);
agf_bp released here.
> +
> + /*
> + * If there are other rmappings, this block is cross
> + * linked and must not be freed. Remove the reverse
> + * mapping and move on. Otherwise, we were the only
> + * owner of the block, so free the extent, which will
> + * also remove the rmap.
> + */
> + if (has_other_rmap)
> + error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1,
> + oinfo);
And then used here. Use-after-free?
> + else if (resv == XFS_AG_RESV_AGFL)
> + error = xfs_repair_put_freelist(sc, agbno);
> + else
> + error = xfs_free_extent(sc->tp, fsbno, 1, oinfo, resv);
> + if (error)
> + break;
> +
> + if (sc->ip)
> + error = xfs_trans_roll_inode(&sc->tp, sc->ip);
> + else
> + error = xfs_repair_roll_ag_trans(sc);
why don't we break on error here?
> + }
> +
> + return error;
> +out_cur:
> + xfs_btree_del_cursor(rmap_cur, XFS_BTREE_ERROR);
> + if (agf_bp)
> + xfs_trans_brelse(sc->tp, agf_bp);
> + return error;
Can you put a blank line preceeding the out label so there is clear
separation between the normal return code and error handling stack?
> +}
> +
> +/* Collect a dead btree extent for later disposal. */
> +int
> +xfs_repair_collect_btree_extent(
> + struct xfs_scrub_context *sc,
> + struct xfs_repair_extent_list *exlist,
> + xfs_fsblock_t fsbno,
> + xfs_extlen_t len)
> +{
> + struct xfs_repair_extent *rae;
What's "rae" short for? "rex" I'd understand, but I can't work out
what the "a" in rae means :/
> +
> + trace_xfs_repair_collect_btree_extent(sc->mp,
> + XFS_FSB_TO_AGNO(sc->mp, fsbno),
> + XFS_FSB_TO_AGBNO(sc->mp, fsbno), len);
> +
> + rae = kmem_alloc(sizeof(struct xfs_repair_extent),
> + KM_MAYFAIL | KM_NOFS);
Why KM_NOFS?
> + if (!rae)
> + return -ENOMEM;
> +
> + INIT_LIST_HEAD(&rae->list);
> + rae->fsbno = fsbno;
> + rae->len = len;
> + list_add_tail(&rae->list, &exlist->list);
> +
> + return 0;
> +}
> +
> +/* Invalidate buffers for blocks we're dumping. */
> +int
> +xfs_repair_invalidate_blocks(
> + struct xfs_scrub_context *sc,
> + struct xfs_repair_extent_list *exlist)
> +{
> + struct xfs_repair_extent *rae;
> + struct xfs_repair_extent *n;
> + struct xfs_buf *bp;
> + xfs_agnumber_t agno;
> + xfs_agblock_t agbno;
> + xfs_agblock_t i;
> +
> + for_each_xfs_repair_extent_safe(rae, n, exlist) {
> + agno = XFS_FSB_TO_AGNO(sc->mp, rae->fsbno);
> + agbno = XFS_FSB_TO_AGBNO(sc->mp, rae->fsbno);
> + for (i = 0; i < rae->len; i++) {
> + bp = xfs_btree_get_bufs(sc->mp, sc->tp, agno,
> + agbno + i, 0);
> + xfs_trans_binval(sc->tp, bp);
> + }
> + }
What if they are data blocks we are dumping? xfs_trans_binval is
fine for metadata blocks, but creating a stale metadata buffer and
logging a buffer cancel for user data blocks doesn't make any sense
to me....
> +/* Dispose of dead btree extents. If oinfo is NULL, just delete the list. */
> +int
> +xfs_repair_reap_btree_extents(
> + struct xfs_scrub_context *sc,
> + struct xfs_repair_extent_list *exlist,
> + struct xfs_owner_info *oinfo,
> + enum xfs_ag_resv_type type)
> +{
> + struct xfs_repair_extent *rae;
> + struct xfs_repair_extent *n;
> + int error = 0;
> +
> + for_each_xfs_repair_extent_safe(rae, n, exlist) {
> + if (oinfo) {
> + error = xfs_repair_free_or_unmap_extent(sc, rae->fsbno,
> + rae->len, oinfo, type);
> + if (error)
> + oinfo = NULL;
> + }
> + list_del(&rae->list);
> + kmem_free(rae);
> + }
> +
> + return error;
> +}
So does this happen before or after the extent list invalidation?
> +/* Errors happened, just delete the dead btree extent list. */
> +void
> +xfs_repair_cancel_btree_extents(
> + struct xfs_scrub_context *sc,
> + struct xfs_repair_extent_list *exlist)
> +{
> + xfs_repair_reap_btree_extents(sc, exlist, NULL, XFS_AG_RESV_NONE);
> +}
So if an error happened durign rebuild, we just trash whatever we
were trying to rebuild?
> +/* Compare two btree extents. */
> +static int
> +xfs_repair_btree_extent_cmp(
> + void *priv,
> + struct list_head *a,
> + struct list_head *b)
> +{
> + struct xfs_repair_extent *ap;
> + struct xfs_repair_extent *bp;
> +
> + ap = container_of(a, struct xfs_repair_extent, list);
> + bp = container_of(b, struct xfs_repair_extent, list);
> +
> + if (ap->fsbno > bp->fsbno)
> + return 1;
> + else if (ap->fsbno < bp->fsbno)
> + return -1;
> + return 0;
> +}
> +
> +/* Remove all the blocks in sublist from exlist. */
> +#define LEFT_CONTIG (1 << 0)
> +#define RIGHT_CONTIG (1 << 1)
Namespace, please.
> +int
> +xfs_repair_subtract_extents(
> + struct xfs_scrub_context *sc,
> + struct xfs_repair_extent_list *exlist,
> + struct xfs_repair_extent_list *sublist)
What is this function supposed to do? I can't really review the code
(looks complex) because I don't know what it's function is supposed
to be.
> +struct xfs_repair_find_ag_btree_roots_info {
> + struct xfs_buf *agfl_bp;
> + struct xfs_repair_find_ag_btree *btree_info;
> +};
> +
> +/* Is this an OWN_AG block in the AGFL? */
> +STATIC bool
> +xfs_repair_is_block_in_agfl(
> + struct xfs_mount *mp,
> + uint64_t rmap_owner,
> + xfs_agblock_t agbno,
> + struct xfs_buf *agf_bp,
> + struct xfs_buf *agfl_bp)
> +{
> + struct xfs_agf *agf;
> + __be32 *agfl_bno;
> + unsigned int flfirst;
> + unsigned int fllast;
> + int i;
> +
> + if (rmap_owner != XFS_RMAP_OWN_AG)
> + return false;
> +
> + agf = XFS_BUF_TO_AGF(agf_bp);
> + agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agfl_bp);
> + flfirst = be32_to_cpu(agf->agf_flfirst);
> + fllast = be32_to_cpu(agf->agf_fllast);
> +
> + /* Skip an empty AGFL. */
> + if (agf->agf_flcount == cpu_to_be32(0))
> + return false;
> +
> + /* first to last is a consecutive list. */
> + if (fllast >= flfirst) {
> + for (i = flfirst; i <= fllast; i++) {
> + if (be32_to_cpu(agfl_bno[i]) == agbno)
> + return true;
> + }
> +
> + return false;
> + }
> +
> + /* first to the end */
> + for (i = flfirst; i < xfs_agfl_size(mp); i++) {
> + if (be32_to_cpu(agfl_bno[i]) == agbno)
> + return true;
> + }
> +
> + /* the start to last. */
> + for (i = 0; i <= fllast; i++) {
> + if (be32_to_cpu(agfl_bno[i]) == agbno)
> + return true;
> + }
> +
> + return false;
Didn't you just create a generic agfl walk function for this?
> +}
> +
> +/* Find btree roots from the AGF. */
> +STATIC int
> +xfs_repair_find_ag_btree_roots_helper(
> + struct xfs_btree_cur *cur,
> + struct xfs_rmap_irec *rec,
> + void *priv)
Again, I'm not sure exactly what this function is doing. It look
slike it's trying to tell if a freed block is a btree block,
but I'm not sure of that, nor the context in which we'd be searching
free blocks for a specific metadata contents.
> +/* Find the roots of the given btrees from the rmap info. */
> +int
> +xfs_repair_find_ag_btree_roots(
> + struct xfs_scrub_context *sc,
> + struct xfs_buf *agf_bp,
> + struct xfs_repair_find_ag_btree *btree_info,
> + struct xfs_buf *agfl_bp)
> +{
> + struct xfs_mount *mp = sc->mp;
> + struct xfs_repair_find_ag_btree_roots_info ri;
> + struct xfs_repair_find_ag_btree *fab;
> + struct xfs_btree_cur *cur;
> + int error;
> +
> + ri.btree_info = btree_info;
> + ri.agfl_bp = agfl_bp;
> + for (fab = btree_info; fab->buf_ops; fab++) {
> + ASSERT(agfl_bp || fab->rmap_owner != XFS_RMAP_OWN_AG);
> + fab->root = NULLAGBLOCK;
> + fab->level = 0;
> + }
> +
> + cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> + error = xfs_rmap_query_all(cur, xfs_repair_find_ag_btree_roots_helper,
> + &ri);
> + xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
> +
> + for (fab = btree_info; !error && fab->buf_ops; fab++)
> + if (fab->root != NULLAGBLOCK)
> + fab->level++;
> +
> + return error;
> +}
> +
> +/* Reset the superblock counters from the AGF/AGI. */
> +int
> +xfs_repair_reset_counters(
> + struct xfs_mount *mp)
> +{
> + struct xfs_trans *tp;
> + struct xfs_buf *agi_bp;
> + struct xfs_buf *agf_bp;
> + struct xfs_agi *agi;
> + struct xfs_agf *agf;
> + xfs_agnumber_t agno;
> + xfs_ino_t icount = 0;
> + xfs_ino_t ifree = 0;
> + xfs_filblks_t fdblocks = 0;
> + int64_t delta_icount;
> + int64_t delta_ifree;
> + int64_t delta_fdblocks;
> + int error;
> +
> + trace_xfs_repair_reset_counters(mp);
> +
> + error = xfs_trans_alloc_empty(mp, &tp);
> + if (error)
> + return error;
> +
> + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> + /* Count all the inodes... */
> + error = xfs_ialloc_read_agi(mp, tp, agno, &agi_bp);
> + if (error)
> + goto out;
> + agi = XFS_BUF_TO_AGI(agi_bp);
> + icount += be32_to_cpu(agi->agi_count);
> + ifree += be32_to_cpu(agi->agi_freecount);
> +
> + /* Add up the free/freelist/bnobt/cntbt blocks... */
> + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp);
> + if (error)
> + goto out;
> + if (!agf_bp) {
> + error = -ENOMEM;
> + goto out;
> + }
> + agf = XFS_BUF_TO_AGF(agf_bp);
> + fdblocks += be32_to_cpu(agf->agf_freeblks);
> + fdblocks += be32_to_cpu(agf->agf_flcount);
> + fdblocks += be32_to_cpu(agf->agf_btreeblks);
> + }
> +
> + /*
> + * Reinitialize the counters. The on-disk and in-core counters
> + * differ by the number of inodes/blocks reserved by the admin,
> + * the per-AG reservation, and any transactions in progress, so
> + * we have to account for that.
> + */
> + spin_lock(&mp->m_sb_lock);
> + delta_icount = (int64_t)mp->m_sb.sb_icount - icount;
> + delta_ifree = (int64_t)mp->m_sb.sb_ifree - ifree;
> + delta_fdblocks = (int64_t)mp->m_sb.sb_fdblocks - fdblocks;
> + mp->m_sb.sb_icount = icount;
> + mp->m_sb.sb_ifree = ifree;
> + mp->m_sb.sb_fdblocks = fdblocks;
> + spin_unlock(&mp->m_sb_lock);
This is largely a copy and paste of the code run by mount after log
recovery on an unclean mount. Can you factor this into a single
function?
> +
> + if (delta_icount) {
> + error = xfs_mod_icount(mp, delta_icount);
> + if (error)
> + goto out;
> + }
> + if (delta_ifree) {
> + error = xfs_mod_ifree(mp, delta_ifree);
> + if (error)
> + goto out;
> + }
> + if (delta_fdblocks) {
> + error = xfs_mod_fdblocks(mp, delta_fdblocks, false);
> + if (error)
> + goto out;
> + }
> +
> +out:
> + xfs_trans_cancel(tp);
> + return error;
Ummmm - why do we do all this superblock modification work in a
transaction context, and then just cancel it?
> +}
> +
> +/* Figure out how many blocks to reserve for an AG repair. */
> +xfs_extlen_t
> +xfs_repair_calc_ag_resblks(
> + struct xfs_scrub_context *sc)
> +{
> + struct xfs_mount *mp = sc->mp;
> + struct xfs_scrub_metadata *sm = sc->sm;
> + struct xfs_agi *agi;
> + struct xfs_agf *agf;
> + struct xfs_buf *bp;
> + xfs_agino_t icount;
> + xfs_extlen_t aglen;
> + 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;
> +
> + /*
> + * Try to get the actual counters from disk; if not, make
> + * some worst case assumptions.
> + */
> + error = xfs_read_agi(mp, NULL, sm->sm_agno, &bp);
> + if (!error) {
> + agi = XFS_BUF_TO_AGI(bp);
> + icount = be32_to_cpu(agi->agi_count);
> + xfs_trans_brelse(NULL, bp);
xfs_buf_relse(bp)?
And, well, why not just use pag->pagi_count rather than having to
read it from the on-disk buffer?
> + } else {
> + icount = mp->m_sb.sb_agblocks / mp->m_sb.sb_inopblock;
> + }
> +
> + error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp);
> + if (!error && bp) {
> + agf = XFS_BUF_TO_AGF(bp);
> + aglen = be32_to_cpu(agf->agf_length);
> + freelen = be32_to_cpu(agf->agf_freeblks);
> + usedlen = aglen - freelen;
> + xfs_trans_brelse(NULL, bp);
> + } else {
> + aglen = mp->m_sb.sb_agblocks;
> + freelen = aglen;
> + usedlen = aglen;
> + }
ditto for there - it's all in the xfs_perag, right?
> +
> + trace_xfs_repair_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)) {
> + rmapbt_sz = xfs_rmapbt_calc_size(mp, aglen);
> + refcbt_sz = xfs_refcountbt_calc_size(mp, usedlen);
> + } else {
> + rmapbt_sz = xfs_rmapbt_calc_size(mp, usedlen);
> + refcbt_sz = 0;
> + }
> + if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
> + rmapbt_sz = 0;
> +
> + trace_xfs_repair_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));
Why are we only returning the resblks for a single tree rebuild?
Shouldn't it return the total blocks require to rebuild all all the
trees?
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
next prev parent reply other threads:[~2018-04-06 0:52 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-02 19:56 [PATCH v14.1 00/21] xfs: online repair support Darrick J. Wong
2018-04-02 19:56 ` [PATCH 01/21] xfs: add helpers to calculate btree size Darrick J. Wong
2018-04-02 19:56 ` [PATCH 02/21] xfs: expose various functions to repair code Darrick J. Wong
2018-04-02 19:56 ` [PATCH 03/21] xfs: add repair helpers for the reverse mapping btree Darrick J. Wong
2018-04-05 23:02 ` Dave Chinner
2018-04-06 16:31 ` Darrick J. Wong
2018-04-02 19:56 ` [PATCH 04/21] xfs: add repair helpers for the reference count btree Darrick J. Wong
2018-04-02 19:56 ` [PATCH 05/21] xfs: add BMAPI_NORMAP flag to perform block remapping without updating rmapbt Darrick J. Wong
2018-04-05 23:07 ` Dave Chinner
2018-04-06 16:41 ` Darrick J. Wong
2018-04-02 19:56 ` [PATCH 06/21] xfs: make xfs_bmapi_remapi work with attribute forks Darrick J. Wong
2018-04-05 23:12 ` Dave Chinner
2018-04-06 17:31 ` Darrick J. Wong
2018-04-02 19:56 ` [PATCH 07/21] xfs: halt auto-reclamation activities while rebuilding rmap Darrick J. Wong
2018-04-05 23:14 ` Dave Chinner
2018-04-02 19:57 ` [PATCH 08/21] xfs: create tracepoints for online repair Darrick J. Wong
2018-04-05 23:15 ` Dave Chinner
2018-04-02 19:57 ` [PATCH 09/21] xfs: implement the metadata repair ioctl flag Darrick J. Wong
2018-04-05 23:24 ` Dave Chinner
2018-04-02 19:57 ` [PATCH 10/21] xfs: add helper routines for the repair code Darrick J. Wong
2018-04-06 0:52 ` Dave Chinner [this message]
2018-04-07 17:55 ` Darrick J. Wong
2018-04-09 0:23 ` Dave Chinner
2018-04-09 17:19 ` Darrick J. Wong
2018-04-02 19:57 ` [PATCH 11/21] xfs: repair superblocks Darrick J. Wong
2018-04-06 1:05 ` Dave Chinner
2018-04-07 18:04 ` Darrick J. Wong
2018-04-09 0:26 ` Dave Chinner
2018-04-09 17:36 ` Darrick J. Wong
2018-04-02 19:57 ` [PATCH 12/21] xfs: repair the AGF and AGFL Darrick J. Wong
2018-04-02 19:57 ` [PATCH 13/21] xfs: repair the AGI Darrick J. Wong
2018-04-02 19:57 ` [PATCH 14/21] xfs: repair free space btrees Darrick J. Wong
2018-04-02 19:57 ` [PATCH 15/21] xfs: repair inode btrees Darrick J. Wong
2018-04-02 19:57 ` [PATCH 16/21] xfs: repair the rmapbt Darrick J. Wong
2018-04-02 19:58 ` [PATCH 17/21] xfs: repair refcount btrees Darrick J. Wong
2018-04-02 19:58 ` [PATCH 18/21] xfs: repair inode records Darrick J. Wong
2018-04-02 19:58 ` [PATCH 19/21] xfs: zap broken inode forks Darrick J. Wong
2018-04-02 19:58 ` [PATCH 20/21] xfs: repair inode block maps Darrick J. Wong
2018-04-02 19:58 ` [PATCH 21/21] xfs: repair damaged symlinks Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180406005251.GO23861@dastard \
--to=david@fromorbit.com \
--cc=darrick.wong@oracle.com \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.