diff options
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r-- | fs/xfs/scrub/repair.c | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 832926c1fa9d..20667b8b2754 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -1027,6 +1027,20 @@ xrep_reap_ag_extent( roll_out: rs->deferred = 0; + if (sc->ip) { + /* + * If we're reaping file data, hold the AGF buffer across the + * transaction roll so that we don't have to reattach it to the + * xchk_ag structure. + */ + xfs_trans_bhold(sc->tp, sc->sa.agf_bp); + error = xfs_trans_roll_inode(&sc->tp, sc->ip); + if (error) + return error; + xfs_trans_bjoin(sc->tp, sc->sa.agf_bp); + return 0; + } + return xrep_roll_ag_trans(sc); } @@ -1086,8 +1100,24 @@ xrep_reap_extent( ASSERT(len <= MAXEXTLEN); - /* We don't support reaping file extents yet. */ - if (sc->ip != NULL || sc->sa.pag->pag_agno != agno) { + if (sc->ip != NULL) { + /* + * We're reaping blocks after repairing file metadata, which + * means that the blocks can be in any AG, so we have to init + * the xchk_ag structure before we can reap each extent and + * release it afterwards. + */ + ASSERT(!sc->sa.pag); + + sc->sa.pag = xfs_perag_get(sc->mp, agno); + if (!sc->sa.pag) + return -EFSCORRUPTED; + + error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, + &sc->sa.agf_bp); + if (error) + goto out_pag; + } else if (sc->sa.pag == NULL || sc->sa.pag->pag_agno != agno) { ASSERT(0); return -EFSCORRUPTED; } @@ -1124,6 +1154,15 @@ xrep_reap_extent( out_cur: if (cur) xfs_btree_del_cursor(cur, error); + if (sc->ip != NULL) { + xfs_trans_brelse(sc->tp, sc->sa.agf_bp); + sc->sa.agf_bp = NULL; + } +out_pag: + if (sc->ip != NULL) { + xfs_perag_put(sc->sa.pag); + sc->sa.pag = NULL; + } return error; } |