18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Oracle.  All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
118c2ecf20Sopenharmony_ci#include "xfs_mount.h"
128c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
138c2ecf20Sopenharmony_ci#include "xfs_trans.h"
148c2ecf20Sopenharmony_ci#include "xfs_rtalloc.h"
158c2ecf20Sopenharmony_ci#include "xfs_inode.h"
168c2ecf20Sopenharmony_ci#include "xfs_bmap.h"
178c2ecf20Sopenharmony_ci#include "scrub/scrub.h"
188c2ecf20Sopenharmony_ci#include "scrub/common.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* Set us up with the realtime metadata locked. */
218c2ecf20Sopenharmony_ciint
228c2ecf20Sopenharmony_cixchk_setup_rt(
238c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
248c2ecf20Sopenharmony_ci	struct xfs_inode	*ip)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	int			error;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	error = xchk_setup_fs(sc, ip);
298c2ecf20Sopenharmony_ci	if (error)
308c2ecf20Sopenharmony_ci		return error;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	sc->ilock_flags = XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP;
338c2ecf20Sopenharmony_ci	sc->ip = sc->mp->m_rbmip;
348c2ecf20Sopenharmony_ci	xfs_ilock(sc->ip, sc->ilock_flags);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return 0;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Realtime bitmap. */
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Scrub a free extent record from the realtime bitmap. */
428c2ecf20Sopenharmony_ciSTATIC int
438c2ecf20Sopenharmony_cixchk_rtbitmap_rec(
448c2ecf20Sopenharmony_ci	struct xfs_trans	*tp,
458c2ecf20Sopenharmony_ci	struct xfs_rtalloc_rec	*rec,
468c2ecf20Sopenharmony_ci	void			*priv)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc = priv;
498c2ecf20Sopenharmony_ci	xfs_rtblock_t		startblock;
508c2ecf20Sopenharmony_ci	xfs_rtblock_t		blockcount;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	startblock = rec->ar_startext * tp->t_mountp->m_sb.sb_rextsize;
538c2ecf20Sopenharmony_ci	blockcount = rec->ar_extcount * tp->t_mountp->m_sb.sb_rextsize;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (startblock + blockcount <= startblock ||
568c2ecf20Sopenharmony_ci	    !xfs_verify_rtbno(sc->mp, startblock) ||
578c2ecf20Sopenharmony_ci	    !xfs_verify_rtbno(sc->mp, startblock + blockcount - 1))
588c2ecf20Sopenharmony_ci		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
598c2ecf20Sopenharmony_ci	return 0;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Make sure the entire rtbitmap file is mapped with written extents. */
638c2ecf20Sopenharmony_ciSTATIC int
648c2ecf20Sopenharmony_cixchk_rtbitmap_check_extents(
658c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = sc->mp;
688c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	map;
698c2ecf20Sopenharmony_ci	xfs_rtblock_t		off;
708c2ecf20Sopenharmony_ci	int			nmap;
718c2ecf20Sopenharmony_ci	int			error = 0;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	for (off = 0; off < mp->m_sb.sb_rbmblocks;) {
748c2ecf20Sopenharmony_ci		if (xchk_should_terminate(sc, &error) ||
758c2ecf20Sopenharmony_ci		    (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
768c2ecf20Sopenharmony_ci			break;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		/* Make sure we have a written extent. */
798c2ecf20Sopenharmony_ci		nmap = 1;
808c2ecf20Sopenharmony_ci		error = xfs_bmapi_read(mp->m_rbmip, off,
818c2ecf20Sopenharmony_ci				mp->m_sb.sb_rbmblocks - off, &map, &nmap,
828c2ecf20Sopenharmony_ci				XFS_DATA_FORK);
838c2ecf20Sopenharmony_ci		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
848c2ecf20Sopenharmony_ci			break;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) {
878c2ecf20Sopenharmony_ci			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
888c2ecf20Sopenharmony_ci			break;
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		off += map.br_blockcount;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return error;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Scrub the realtime bitmap. */
988c2ecf20Sopenharmony_ciint
998c2ecf20Sopenharmony_cixchk_rtbitmap(
1008c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int			error;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* Is the size of the rtbitmap correct? */
1058c2ecf20Sopenharmony_ci	if (sc->mp->m_rbmip->i_d.di_size !=
1068c2ecf20Sopenharmony_ci	    XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks)) {
1078c2ecf20Sopenharmony_ci		xchk_ino_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
1088c2ecf20Sopenharmony_ci		return 0;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* Invoke the fork scrubber. */
1128c2ecf20Sopenharmony_ci	error = xchk_metadata_inode_forks(sc);
1138c2ecf20Sopenharmony_ci	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
1148c2ecf20Sopenharmony_ci		return error;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	error = xchk_rtbitmap_check_extents(sc);
1178c2ecf20Sopenharmony_ci	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
1188c2ecf20Sopenharmony_ci		return error;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	error = xfs_rtalloc_query_all(sc->tp, xchk_rtbitmap_rec, sc);
1218c2ecf20Sopenharmony_ci	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
1228c2ecf20Sopenharmony_ci		goto out;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ciout:
1258c2ecf20Sopenharmony_ci	return error;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Scrub the realtime summary. */
1298c2ecf20Sopenharmony_ciint
1308c2ecf20Sopenharmony_cixchk_rtsummary(
1318c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct xfs_inode	*rsumip = sc->mp->m_rsumip;
1348c2ecf20Sopenharmony_ci	struct xfs_inode	*old_ip = sc->ip;
1358c2ecf20Sopenharmony_ci	uint			old_ilock_flags = sc->ilock_flags;
1368c2ecf20Sopenharmony_ci	int			error = 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * We ILOCK'd the rt bitmap ip in the setup routine, now lock the
1408c2ecf20Sopenharmony_ci	 * rt summary ip in compliance with the rt inode locking rules.
1418c2ecf20Sopenharmony_ci	 *
1428c2ecf20Sopenharmony_ci	 * Since we switch sc->ip to rsumip we have to save the old ilock
1438c2ecf20Sopenharmony_ci	 * flags so that we don't mix up the inode state that @sc tracks.
1448c2ecf20Sopenharmony_ci	 */
1458c2ecf20Sopenharmony_ci	sc->ip = rsumip;
1468c2ecf20Sopenharmony_ci	sc->ilock_flags = XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM;
1478c2ecf20Sopenharmony_ci	xfs_ilock(sc->ip, sc->ilock_flags);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* Invoke the fork scrubber. */
1508c2ecf20Sopenharmony_ci	error = xchk_metadata_inode_forks(sc);
1518c2ecf20Sopenharmony_ci	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
1528c2ecf20Sopenharmony_ci		goto out;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* XXX: implement this some day */
1558c2ecf20Sopenharmony_ci	xchk_set_incomplete(sc);
1568c2ecf20Sopenharmony_ciout:
1578c2ecf20Sopenharmony_ci	/* Switch back to the rtbitmap inode and lock flags. */
1588c2ecf20Sopenharmony_ci	xfs_iunlock(sc->ip, sc->ilock_flags);
1598c2ecf20Sopenharmony_ci	sc->ilock_flags = old_ilock_flags;
1608c2ecf20Sopenharmony_ci	sc->ip = old_ip;
1618c2ecf20Sopenharmony_ci	return error;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* xref check that the extent is not free in the rtbitmap */
1668c2ecf20Sopenharmony_civoid
1678c2ecf20Sopenharmony_cixchk_xref_is_used_rt_space(
1688c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
1698c2ecf20Sopenharmony_ci	xfs_rtblock_t		fsbno,
1708c2ecf20Sopenharmony_ci	xfs_extlen_t		len)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	xfs_rtblock_t		startext;
1738c2ecf20Sopenharmony_ci	xfs_rtblock_t		endext;
1748c2ecf20Sopenharmony_ci	xfs_rtblock_t		extcount;
1758c2ecf20Sopenharmony_ci	bool			is_free;
1768c2ecf20Sopenharmony_ci	int			error;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (xchk_skip_xref(sc->sm))
1798c2ecf20Sopenharmony_ci		return;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	startext = fsbno;
1828c2ecf20Sopenharmony_ci	endext = fsbno + len - 1;
1838c2ecf20Sopenharmony_ci	do_div(startext, sc->mp->m_sb.sb_rextsize);
1848c2ecf20Sopenharmony_ci	do_div(endext, sc->mp->m_sb.sb_rextsize);
1858c2ecf20Sopenharmony_ci	extcount = endext - startext + 1;
1868c2ecf20Sopenharmony_ci	xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
1878c2ecf20Sopenharmony_ci	error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext, extcount,
1888c2ecf20Sopenharmony_ci			&is_free);
1898c2ecf20Sopenharmony_ci	if (!xchk_should_check_xref(sc, &error, NULL))
1908c2ecf20Sopenharmony_ci		goto out_unlock;
1918c2ecf20Sopenharmony_ci	if (is_free)
1928c2ecf20Sopenharmony_ci		xchk_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
1938c2ecf20Sopenharmony_ciout_unlock:
1948c2ecf20Sopenharmony_ci	xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
1958c2ecf20Sopenharmony_ci}
196