174 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_trans_resv.h"11#include "xfs_mount.h"12#include "xfs_btree.h"13#include "xfs_log_format.h"14#include "xfs_trans.h"15#include "xfs_rtalloc.h"16#include "xfs_inode.h"17#include "xfs_bit.h"18#include "xfs_bmap.h"19#include "xfs_bmap_btree.h"20#include "xfs_exchmaps.h"21#include "xfs_rtbitmap.h"22#include "scrub/scrub.h"23#include "scrub/common.h"24#include "scrub/trace.h"25#include "scrub/repair.h"26#include "scrub/tempfile.h"27#include "scrub/tempexch.h"28#include "scrub/reap.h"29#include "scrub/xfile.h"30#include "scrub/rtsummary.h"31 32/* Set us up to repair the rtsummary file. */33int34xrep_setup_rtsummary(35 struct xfs_scrub *sc,36 struct xchk_rtsummary *rts)37{38 struct xfs_mount *mp = sc->mp;39 unsigned long long blocks;40 int error;41 42 error = xrep_tempfile_create(sc, S_IFREG);43 if (error)44 return error;45 46 /*47 * If we're doing a repair, we reserve enough blocks to write out a48 * completely new summary file, plus twice as many blocks as we would49 * need if we can only allocate one block per data fork mapping. This50 * should cover the preallocation of the temporary file and exchanging51 * the extent mappings.52 *53 * We cannot use xfs_exchmaps_estimate because we have not yet54 * constructed the replacement rtsummary and therefore do not know how55 * many extents it will use. By the time we do, we will have a dirty56 * transaction (which we cannot drop because we cannot drop the57 * rtsummary ILOCK) and cannot ask for more reservation.58 */59 blocks = mp->m_rsumblocks;60 blocks += xfs_bmbt_calc_size(mp, blocks) * 2;61 if (blocks > UINT_MAX)62 return -EOPNOTSUPP;63 64 rts->resblks += blocks;65 return 0;66}67 68static int69xrep_rtsummary_prep_buf(70 struct xfs_scrub *sc,71 struct xfs_buf *bp,72 void *data)73{74 struct xchk_rtsummary *rts = data;75 struct xfs_mount *mp = sc->mp;76 union xfs_suminfo_raw *ondisk;77 int error;78 79 rts->args.mp = sc->mp;80 rts->args.tp = sc->tp;81 rts->args.sumbp = bp;82 ondisk = xfs_rsumblock_infoptr(&rts->args, 0);83 rts->args.sumbp = NULL;84 85 bp->b_ops = &xfs_rtbuf_ops;86 87 error = xfsum_copyout(sc, rts->prep_wordoff, ondisk, mp->m_blockwsize);88 if (error)89 return error;90 91 rts->prep_wordoff += mp->m_blockwsize;92 xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF);93 return 0;94}95 96/* Repair the realtime summary. */97int98xrep_rtsummary(99 struct xfs_scrub *sc)100{101 struct xchk_rtsummary *rts = sc->buf;102 struct xfs_mount *mp = sc->mp;103 int error;104 105 /* We require the rmapbt to rebuild anything. */106 if (!xfs_has_rmapbt(mp))107 return -EOPNOTSUPP;108 /* We require atomic file exchange range to rebuild anything. */109 if (!xfs_has_exchange_range(mp))110 return -EOPNOTSUPP;111 112 /* Walk away if we disagree on the size of the rt bitmap. */113 if (rts->rbmblocks != mp->m_sb.sb_rbmblocks)114 return 0;115 116 /* Make sure any problems with the fork are fixed. */117 error = xrep_metadata_inode_forks(sc);118 if (error)119 return error;120 121 /*122 * Try to take ILOCK_EXCL of the temporary file. We had better be the123 * only ones holding onto this inode, but we can't block while holding124 * the rtsummary file's ILOCK_EXCL.125 */126 while (!xrep_tempfile_ilock_nowait(sc)) {127 if (xchk_should_terminate(sc, &error))128 return error;129 delay(1);130 }131 132 /* Make sure we have space allocated for the entire summary file. */133 xfs_trans_ijoin(sc->tp, sc->ip, 0);134 xfs_trans_ijoin(sc->tp, sc->tempip, 0);135 error = xrep_tempfile_prealloc(sc, 0, rts->rsumblocks);136 if (error)137 return error;138 139 /* Last chance to abort before we start committing fixes. */140 if (xchk_should_terminate(sc, &error))141 return error;142 143 /* Copy the rtsummary file that we generated. */144 error = xrep_tempfile_copyin(sc, 0, rts->rsumblocks,145 xrep_rtsummary_prep_buf, rts);146 if (error)147 return error;148 error = xrep_tempfile_set_isize(sc, XFS_FSB_TO_B(mp, rts->rsumblocks));149 if (error)150 return error;151 152 /*153 * Now exchange the contents. Nothing in repair uses the temporary154 * buffer, so we can reuse it for the tempfile exchrange information.155 */156 error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, &rts->tempexch);157 if (error)158 return error;159 160 error = xrep_tempexch_contents(sc, &rts->tempexch);161 if (error)162 return error;163 164 /* Reset incore state and blow out the summary cache. */165 if (mp->m_rsum_cache)166 memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);167 168 mp->m_rsumlevels = rts->rsumlevels;169 mp->m_rsumblocks = rts->rsumblocks;170 171 /* Free the old rtsummary blocks if they're not in use. */172 return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);173}174