| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Copyright (c) 2020-2024 Oracle. All Rights Reserved.
- * Author: Darrick J. Wong <djwong@kernel.org>
- */
- #include "xfs.h"
- #include "xfs_fs.h"
- #include "xfs_shared.h"
- #include "xfs_format.h"
- #include "xfs_trans_resv.h"
- #include "xfs_mount.h"
- #include "xfs_btree.h"
- #include "xfs_log_format.h"
- #include "xfs_trans.h"
- #include "xfs_rtalloc.h"
- #include "xfs_inode.h"
- #include "xfs_bit.h"
- #include "xfs_bmap.h"
- #include "xfs_bmap_btree.h"
- #include "xfs_exchmaps.h"
- #include "xfs_rtbitmap.h"
- #include "scrub/scrub.h"
- #include "scrub/common.h"
- #include "scrub/trace.h"
- #include "scrub/repair.h"
- #include "scrub/tempfile.h"
- #include "scrub/tempexch.h"
- #include "scrub/reap.h"
- #include "scrub/xfile.h"
- #include "scrub/rtsummary.h"
- /* Set us up to repair the rtsummary file. */
- int
- xrep_setup_rtsummary(
- struct xfs_scrub *sc,
- struct xchk_rtsummary *rts)
- {
- struct xfs_mount *mp = sc->mp;
- unsigned long long blocks;
- int error;
- error = xrep_tempfile_create(sc, S_IFREG);
- if (error)
- return error;
- /*
- * If we're doing a repair, we reserve enough blocks to write out a
- * completely new summary file, plus twice as many blocks as we would
- * need if we can only allocate one block per data fork mapping. This
- * should cover the preallocation of the temporary file and exchanging
- * the extent mappings.
- *
- * We cannot use xfs_exchmaps_estimate because we have not yet
- * constructed the replacement rtsummary and therefore do not know how
- * many extents it will use. By the time we do, we will have a dirty
- * transaction (which we cannot drop because we cannot drop the
- * rtsummary ILOCK) and cannot ask for more reservation.
- */
- blocks = mp->m_rsumblocks;
- blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
- if (blocks > UINT_MAX)
- return -EOPNOTSUPP;
- rts->resblks += blocks;
- return 0;
- }
- static int
- xrep_rtsummary_prep_buf(
- struct xfs_scrub *sc,
- struct xfs_buf *bp,
- void *data)
- {
- struct xchk_rtsummary *rts = data;
- struct xfs_mount *mp = sc->mp;
- union xfs_suminfo_raw *ondisk;
- int error;
- rts->args.mp = sc->mp;
- rts->args.tp = sc->tp;
- rts->args.sumbp = bp;
- ondisk = xfs_rsumblock_infoptr(&rts->args, 0);
- rts->args.sumbp = NULL;
- bp->b_ops = &xfs_rtbuf_ops;
- error = xfsum_copyout(sc, rts->prep_wordoff, ondisk, mp->m_blockwsize);
- if (error)
- return error;
- rts->prep_wordoff += mp->m_blockwsize;
- xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF);
- return 0;
- }
- /* Repair the realtime summary. */
- int
- xrep_rtsummary(
- struct xfs_scrub *sc)
- {
- struct xchk_rtsummary *rts = sc->buf;
- struct xfs_mount *mp = sc->mp;
- int error;
- /* We require the rmapbt to rebuild anything. */
- if (!xfs_has_rmapbt(mp))
- return -EOPNOTSUPP;
- /* We require atomic file exchange range to rebuild anything. */
- if (!xfs_has_exchange_range(mp))
- return -EOPNOTSUPP;
- /* Walk away if we disagree on the size of the rt bitmap. */
- if (rts->rbmblocks != mp->m_sb.sb_rbmblocks)
- return 0;
- /* Make sure any problems with the fork are fixed. */
- error = xrep_metadata_inode_forks(sc);
- if (error)
- return error;
- /*
- * Try to take ILOCK_EXCL of the temporary file. We had better be the
- * only ones holding onto this inode, but we can't block while holding
- * the rtsummary file's ILOCK_EXCL.
- */
- while (!xrep_tempfile_ilock_nowait(sc)) {
- if (xchk_should_terminate(sc, &error))
- return error;
- delay(1);
- }
- /* Make sure we have space allocated for the entire summary file. */
- xfs_trans_ijoin(sc->tp, sc->ip, 0);
- xfs_trans_ijoin(sc->tp, sc->tempip, 0);
- error = xrep_tempfile_prealloc(sc, 0, rts->rsumblocks);
- if (error)
- return error;
- /* Last chance to abort before we start committing fixes. */
- if (xchk_should_terminate(sc, &error))
- return error;
- /* Copy the rtsummary file that we generated. */
- error = xrep_tempfile_copyin(sc, 0, rts->rsumblocks,
- xrep_rtsummary_prep_buf, rts);
- if (error)
- return error;
- error = xrep_tempfile_set_isize(sc, XFS_FSB_TO_B(mp, rts->rsumblocks));
- if (error)
- return error;
- /*
- * Now exchange the contents. Nothing in repair uses the temporary
- * buffer, so we can reuse it for the tempfile exchrange information.
- */
- error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, &rts->tempexch);
- if (error)
- return error;
- error = xrep_tempexch_contents(sc, &rts->tempexch);
- if (error)
- return error;
- /* Reset incore state and blow out the summary cache. */
- if (mp->m_rsum_cache)
- memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
- mp->m_rsumlevels = rts->rsumlevels;
- mp->m_rsumblocks = rts->rsumblocks;
- /* Free the old rtsummary blocks if they're not in use. */
- return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
- }
|