brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 7c7366c Raw
371 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017-2023 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_inode.h"14#include "xfs_log_format.h"15#include "xfs_trans.h"16#include "xfs_rtbitmap.h"17#include "xfs_bit.h"18#include "xfs_bmap.h"19#include "xfs_sb.h"20#include "xfs_exchmaps.h"21#include "scrub/scrub.h"22#include "scrub/common.h"23#include "scrub/trace.h"24#include "scrub/xfile.h"25#include "scrub/repair.h"26#include "scrub/tempexch.h"27#include "scrub/rtsummary.h"28 29/*30 * Realtime Summary31 * ================32 *33 * We check the realtime summary by scanning the realtime bitmap file to create34 * a new summary file incore, and then we compare the computed version against35 * the ondisk version.  We use the 'xfile' functionality to store this36 * (potentially large) amount of data in pageable memory.37 */38 39/* Set us up to check the rtsummary file. */40int41xchk_setup_rtsummary(42	struct xfs_scrub	*sc)43{44	struct xfs_mount	*mp = sc->mp;45	char			*descr;46	struct xchk_rtsummary	*rts;47	int			error;48 49	rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize),50			XCHK_GFP_FLAGS);51	if (!rts)52		return -ENOMEM;53	sc->buf = rts;54 55	if (xchk_could_repair(sc)) {56		error = xrep_setup_rtsummary(sc, rts);57		if (error)58			return error;59	}60 61	/*62	 * Create an xfile to construct a new rtsummary file.  The xfile allows63	 * us to avoid pinning kernel memory for this purpose.64	 */65	descr = xchk_xfile_descr(sc, "realtime summary file");66	error = xfile_create(descr, XFS_FSB_TO_B(mp, mp->m_rsumblocks),67			&sc->xfile);68	kfree(descr);69	if (error)70		return error;71 72	error = xchk_trans_alloc(sc, rts->resblks);73	if (error)74		return error;75 76	error = xchk_install_live_inode(sc, mp->m_rsumip);77	if (error)78		return error;79 80	error = xchk_ino_dqattach(sc);81	if (error)82		return error;83 84	/*85	 * Locking order requires us to take the rtbitmap first.  We must be86	 * careful to unlock it ourselves when we are done with the rtbitmap87	 * file since the scrub infrastructure won't do that for us.  Only88	 * then we can lock the rtsummary inode.89	 */90	xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);91	xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);92 93	/*94	 * Now that we've locked the rtbitmap and rtsummary, we can't race with95	 * growfsrt trying to expand the summary or change the size of the rt96	 * volume.  Hence it is safe to compute and check the geometry values.97	 */98	if (mp->m_sb.sb_rblocks) {99		int		rextslog;100 101		rts->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);102		rextslog = xfs_compute_rextslog(rts->rextents);103		rts->rsumlevels = rextslog + 1;104		rts->rbmblocks = xfs_rtbitmap_blockcount(mp, rts->rextents);105		rts->rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels,106				rts->rbmblocks);107	}108	return 0;109}110 111/* Helper functions to record suminfo words in an xfile. */112 113static inline int114xfsum_load(115	struct xfs_scrub	*sc,116	xfs_rtsumoff_t		sumoff,117	union xfs_suminfo_raw	*rawinfo)118{119	return xfile_load(sc->xfile, rawinfo,120			sizeof(union xfs_suminfo_raw),121			sumoff << XFS_WORDLOG);122}123 124static inline int125xfsum_store(126	struct xfs_scrub	*sc,127	xfs_rtsumoff_t		sumoff,128	const union xfs_suminfo_raw rawinfo)129{130	return xfile_store(sc->xfile, &rawinfo,131			sizeof(union xfs_suminfo_raw),132			sumoff << XFS_WORDLOG);133}134 135inline int136xfsum_copyout(137	struct xfs_scrub	*sc,138	xfs_rtsumoff_t		sumoff,139	union xfs_suminfo_raw	*rawinfo,140	unsigned int		nr_words)141{142	return xfile_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG,143			sumoff << XFS_WORDLOG);144}145 146static inline xfs_suminfo_t147xchk_rtsum_inc(148	struct xfs_mount	*mp,149	union xfs_suminfo_raw	*v)150{151	v->old += 1;152	return v->old;153}154 155/* Update the summary file to reflect the free extent that we've accumulated. */156STATIC int157xchk_rtsum_record_free(158	struct xfs_mount		*mp,159	struct xfs_trans		*tp,160	const struct xfs_rtalloc_rec	*rec,161	void				*priv)162{163	struct xfs_scrub		*sc = priv;164	xfs_fileoff_t			rbmoff;165	xfs_rtblock_t			rtbno;166	xfs_filblks_t			rtlen;167	xfs_rtsumoff_t			offs;168	unsigned int			lenlog;169	union xfs_suminfo_raw		v;170	xfs_suminfo_t			value;171	int				error = 0;172 173	if (xchk_should_terminate(sc, &error))174		return error;175 176	/* Compute the relevant location in the rtsum file. */177	rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext);178	lenlog = xfs_highbit64(rec->ar_extcount);179	offs = xfs_rtsumoffs(mp, lenlog, rbmoff);180 181	rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);182	rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);183 184	if (!xfs_verify_rtbext(mp, rtbno, rtlen)) {185		xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);186		return -EFSCORRUPTED;187	}188 189	/* Bump the summary count. */190	error = xfsum_load(sc, offs, &v);191	if (error)192		return error;193 194	value = xchk_rtsum_inc(sc->mp, &v);195	trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount,196			lenlog, offs, value);197 198	return xfsum_store(sc, offs, v);199}200 201/* Compute the realtime summary from the realtime bitmap. */202STATIC int203xchk_rtsum_compute(204	struct xfs_scrub	*sc)205{206	struct xfs_mount	*mp = sc->mp;207	unsigned long long	rtbmp_blocks;208 209	/* If the bitmap size doesn't match the computed size, bail. */210	rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);211	if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)212		return -EFSCORRUPTED;213 214	return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,215			sc);216}217 218/* Compare the rtsummary file against the one we computed. */219STATIC int220xchk_rtsum_compare(221	struct xfs_scrub	*sc)222{223	struct xfs_bmbt_irec	map;224	struct xfs_iext_cursor	icur;225 226	struct xfs_mount	*mp = sc->mp;227	struct xfs_inode	*ip = sc->ip;228	struct xchk_rtsummary	*rts = sc->buf;229	xfs_fileoff_t		off = 0;230	xfs_fileoff_t		endoff;231	xfs_rtsumoff_t		sumoff = 0;232	int			error = 0;233 234	rts->args.mp = sc->mp;235	rts->args.tp = sc->tp;236 237	/* Mappings may not cross or lie beyond EOF. */238	endoff = XFS_B_TO_FSB(mp, ip->i_disk_size);239	if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) {240		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff);241		return 0;242	}243 244	while (off < endoff) {245		int		nmap = 1;246 247		if (xchk_should_terminate(sc, &error))248			return error;249		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)250			return 0;251 252		/* Make sure we have a written extent. */253		error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap,254				XFS_DATA_FORK);255		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))256			return error;257 258		if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) {259			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);260			return 0;261		}262 263		off += map.br_blockcount;264	}265 266	for (off = 0; off < endoff; off++) {267		union xfs_suminfo_raw	*ondisk_info;268 269		/* Read a block's worth of ondisk rtsummary file. */270		error = xfs_rtsummary_read_buf(&rts->args, off);271		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))272			return error;273 274		/* Read a block's worth of computed rtsummary file. */275		error = xfsum_copyout(sc, sumoff, rts->words, mp->m_blockwsize);276		if (error) {277			xfs_rtbuf_cache_relse(&rts->args);278			return error;279		}280 281		ondisk_info = xfs_rsumblock_infoptr(&rts->args, 0);282		if (memcmp(ondisk_info, rts->words,283					mp->m_blockwsize << XFS_WORDLOG) != 0) {284			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);285			xfs_rtbuf_cache_relse(&rts->args);286			return error;287		}288 289		xfs_rtbuf_cache_relse(&rts->args);290		sumoff += mp->m_blockwsize;291	}292 293	return 0;294}295 296/* Scrub the realtime summary. */297int298xchk_rtsummary(299	struct xfs_scrub	*sc)300{301	struct xfs_mount	*mp = sc->mp;302	struct xchk_rtsummary	*rts = sc->buf;303	int			error = 0;304 305	/* Is sb_rextents correct? */306	if (mp->m_sb.sb_rextents != rts->rextents) {307		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);308		goto out_rbm;309	}310 311	/* Is m_rsumlevels correct? */312	if (mp->m_rsumlevels != rts->rsumlevels) {313		xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);314		goto out_rbm;315	}316 317	/* Is m_rsumsize correct? */318	if (mp->m_rsumblocks != rts->rsumblocks) {319		xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);320		goto out_rbm;321	}322 323	/* The summary file length must be aligned to an fsblock. */324	if (mp->m_rsumip->i_disk_size & mp->m_blockmask) {325		xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);326		goto out_rbm;327	}328 329	/*330	 * Is the summary file itself large enough to handle the rt volume?331	 * growfsrt expands the summary file before updating sb_rextents, so332	 * the file can be larger than rsumsize.333	 */334	if (mp->m_rsumip->i_disk_size < XFS_FSB_TO_B(mp, rts->rsumblocks)) {335		xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);336		goto out_rbm;337	}338 339	/* Invoke the fork scrubber. */340	error = xchk_metadata_inode_forks(sc);341	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))342		goto out_rbm;343 344	/* Construct the new summary file from the rtbitmap. */345	error = xchk_rtsum_compute(sc);346	if (error == -EFSCORRUPTED) {347		/*348		 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref349		 * error since we're checking the summary file.350		 */351		xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);352		error = 0;353		goto out_rbm;354	}355	if (error)356		goto out_rbm;357 358	/* Does the computed summary file match the actual rtsummary file? */359	error = xchk_rtsum_compare(sc);360 361out_rbm:362	/*363	 * Unlock the rtbitmap since we're done with it.  All other writers of364	 * the rt free space metadata grab the bitmap and summary ILOCKs in365	 * that order, so we're still protected against allocation activities366	 * even if we continue on to the repair function.367	 */368	xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);369	return error;370}371