xref: /linux/fs/xfs/scrub/rtbitmap.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1739a2fe0SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
229b0767bSDarrick J. Wong /*
3ecc73f8aSDarrick J. Wong  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
4739a2fe0SDarrick J. Wong  * Author: Darrick J. Wong <djwong@kernel.org>
529b0767bSDarrick J. Wong  */
629b0767bSDarrick J. Wong #include "xfs.h"
729b0767bSDarrick J. Wong #include "xfs_fs.h"
829b0767bSDarrick J. Wong #include "xfs_shared.h"
929b0767bSDarrick J. Wong #include "xfs_format.h"
1029b0767bSDarrick J. Wong #include "xfs_trans_resv.h"
1129b0767bSDarrick J. Wong #include "xfs_mount.h"
1229b0767bSDarrick J. Wong #include "xfs_log_format.h"
1329b0767bSDarrick J. Wong #include "xfs_trans.h"
1413928113SDarrick J. Wong #include "xfs_rtbitmap.h"
1529b0767bSDarrick J. Wong #include "xfs_inode.h"
16f866560bSDarrick J. Wong #include "xfs_bmap.h"
1741991cf2SDarrick J. Wong #include "xfs_bit.h"
18*881f78f4SDarrick J. Wong #include "xfs_sb.h"
1929b0767bSDarrick J. Wong #include "scrub/scrub.h"
2029b0767bSDarrick J. Wong #include "scrub/common.h"
21ffd37b22SDarrick J. Wong #include "scrub/repair.h"
22ffd37b22SDarrick J. Wong #include "scrub/rtbitmap.h"
2341991cf2SDarrick J. Wong 
2429b0767bSDarrick J. Wong /* Set us up with the realtime metadata locked. */
2529b0767bSDarrick J. Wong int
xchk_setup_rtbitmap(struct xfs_scrub * sc)26526aab5fSDarrick J. Wong xchk_setup_rtbitmap(
27026f57ebSDarrick J. Wong 	struct xfs_scrub	*sc)
2829b0767bSDarrick J. Wong {
2941991cf2SDarrick J. Wong 	struct xfs_mount	*mp = sc->mp;
3041991cf2SDarrick J. Wong 	struct xchk_rtbitmap	*rtb;
318e630837SEric Sandeen 	int			error;
3229b0767bSDarrick J. Wong 
3341991cf2SDarrick J. Wong 	rtb = kzalloc(sizeof(struct xchk_rtbitmap), XCHK_GFP_FLAGS);
3441991cf2SDarrick J. Wong 	if (!rtb)
3541991cf2SDarrick J. Wong 		return -ENOMEM;
3641991cf2SDarrick J. Wong 	sc->buf = rtb;
3741991cf2SDarrick J. Wong 
38ffd37b22SDarrick J. Wong 	if (xchk_could_repair(sc)) {
39ffd37b22SDarrick J. Wong 		error = xrep_setup_rtbitmap(sc, rtb);
40ffd37b22SDarrick J. Wong 		if (error)
41ffd37b22SDarrick J. Wong 			return error;
42ffd37b22SDarrick J. Wong 	}
43ffd37b22SDarrick J. Wong 
44ffd37b22SDarrick J. Wong 	error = xchk_trans_alloc(sc, rtb->resblks);
4529b0767bSDarrick J. Wong 	if (error)
4629b0767bSDarrick J. Wong 		return error;
4729b0767bSDarrick J. Wong 
4817308539SDarrick J. Wong 	error = xchk_install_live_inode(sc, sc->mp->m_rbmip);
4917308539SDarrick J. Wong 	if (error)
5017308539SDarrick J. Wong 		return error;
5129b0767bSDarrick J. Wong 
52259ba1d3SDarrick J. Wong 	error = xchk_ino_dqattach(sc);
53259ba1d3SDarrick J. Wong 	if (error)
54259ba1d3SDarrick J. Wong 		return error;
55259ba1d3SDarrick J. Wong 
56294012fbSDarrick J. Wong 	xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
5741991cf2SDarrick J. Wong 
5841991cf2SDarrick J. Wong 	/*
5941991cf2SDarrick J. Wong 	 * Now that we've locked the rtbitmap, we can't race with growfsrt
6041991cf2SDarrick J. Wong 	 * trying to expand the bitmap or change the size of the rt volume.
6141991cf2SDarrick J. Wong 	 * Hence it is safe to compute and check the geometry values.
6241991cf2SDarrick J. Wong 	 */
6341991cf2SDarrick J. Wong 	if (mp->m_sb.sb_rblocks) {
6441991cf2SDarrick J. Wong 		rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
6541991cf2SDarrick J. Wong 		rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
6641991cf2SDarrick J. Wong 		rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
6741991cf2SDarrick J. Wong 	}
6829b0767bSDarrick J. Wong 	return 0;
6929b0767bSDarrick J. Wong }
7029b0767bSDarrick J. Wong 
7129b0767bSDarrick J. Wong /* Realtime bitmap. */
7229b0767bSDarrick J. Wong 
7329b0767bSDarrick J. Wong /* Scrub a free extent record from the realtime bitmap. */
7429b0767bSDarrick J. Wong STATIC int
xchk_rtbitmap_rec(struct xfs_mount * mp,struct xfs_trans * tp,const struct xfs_rtalloc_rec * rec,void * priv)75c517b3aaSDarrick J. Wong xchk_rtbitmap_rec(
76f34061f5SDarrick J. Wong 	struct xfs_mount	*mp,
7729b0767bSDarrick J. Wong 	struct xfs_trans	*tp,
78159eb69dSDarrick J. Wong 	const struct xfs_rtalloc_rec *rec,
7929b0767bSDarrick J. Wong 	void			*priv)
8029b0767bSDarrick J. Wong {
811d8a748aSDarrick J. Wong 	struct xfs_scrub	*sc = priv;
82a0e5c435SDarrick J. Wong 	xfs_rtblock_t		startblock;
833d2b6d03SDarrick J. Wong 	xfs_filblks_t		blockcount;
8429b0767bSDarrick J. Wong 
85fa5a3872SDarrick J. Wong 	startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
86fa5a3872SDarrick J. Wong 	blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
87a0e5c435SDarrick J. Wong 
883d2b6d03SDarrick J. Wong 	if (!xfs_verify_rtbext(mp, startblock, blockcount))
89c517b3aaSDarrick J. Wong 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
9029b0767bSDarrick J. Wong 	return 0;
9129b0767bSDarrick J. Wong }
9229b0767bSDarrick J. Wong 
93f866560bSDarrick J. Wong /* Make sure the entire rtbitmap file is mapped with written extents. */
94f866560bSDarrick J. Wong STATIC int
xchk_rtbitmap_check_extents(struct xfs_scrub * sc)95f866560bSDarrick J. Wong xchk_rtbitmap_check_extents(
96f866560bSDarrick J. Wong 	struct xfs_scrub	*sc)
97f866560bSDarrick J. Wong {
98f866560bSDarrick J. Wong 	struct xfs_bmbt_irec	map;
9941991cf2SDarrick J. Wong 	struct xfs_iext_cursor	icur;
10041991cf2SDarrick J. Wong 	struct xfs_mount	*mp = sc->mp;
10141991cf2SDarrick J. Wong 	struct xfs_inode	*ip = sc->ip;
10241991cf2SDarrick J. Wong 	xfs_fileoff_t		off = 0;
10341991cf2SDarrick J. Wong 	xfs_fileoff_t		endoff;
104f866560bSDarrick J. Wong 	int			error = 0;
105f866560bSDarrick J. Wong 
10641991cf2SDarrick J. Wong 	/* Mappings may not cross or lie beyond EOF. */
10741991cf2SDarrick J. Wong 	endoff = XFS_B_TO_FSB(mp, ip->i_disk_size);
10841991cf2SDarrick J. Wong 	if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) {
10941991cf2SDarrick J. Wong 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff);
11041991cf2SDarrick J. Wong 		return 0;
11141991cf2SDarrick J. Wong 	}
11241991cf2SDarrick J. Wong 
11341991cf2SDarrick J. Wong 	while (off < endoff) {
11441991cf2SDarrick J. Wong 		int		nmap = 1;
11541991cf2SDarrick J. Wong 
116f866560bSDarrick J. Wong 		if (xchk_should_terminate(sc, &error) ||
117f866560bSDarrick J. Wong 		    (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
118f866560bSDarrick J. Wong 			break;
119f866560bSDarrick J. Wong 
120f866560bSDarrick J. Wong 		/* Make sure we have a written extent. */
12141991cf2SDarrick J. Wong 		error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap,
122f866560bSDarrick J. Wong 				XFS_DATA_FORK);
123f866560bSDarrick J. Wong 		if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
124f866560bSDarrick J. Wong 			break;
125f866560bSDarrick J. Wong 
126f866560bSDarrick J. Wong 		if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) {
127f866560bSDarrick J. Wong 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
128f866560bSDarrick J. Wong 			break;
129f866560bSDarrick J. Wong 		}
130f866560bSDarrick J. Wong 
131f866560bSDarrick J. Wong 		off += map.br_blockcount;
132f866560bSDarrick J. Wong 	}
133f866560bSDarrick J. Wong 
134f866560bSDarrick J. Wong 	return error;
135f866560bSDarrick J. Wong }
136f866560bSDarrick J. Wong 
13729b0767bSDarrick J. Wong /* Scrub the realtime bitmap. */
13829b0767bSDarrick J. Wong int
xchk_rtbitmap(struct xfs_scrub * sc)139c517b3aaSDarrick J. Wong xchk_rtbitmap(
1401d8a748aSDarrick J. Wong 	struct xfs_scrub	*sc)
14129b0767bSDarrick J. Wong {
14241991cf2SDarrick J. Wong 	struct xfs_mount	*mp = sc->mp;
14341991cf2SDarrick J. Wong 	struct xchk_rtbitmap	*rtb = sc->buf;
14429b0767bSDarrick J. Wong 	int			error;
14529b0767bSDarrick J. Wong 
14641991cf2SDarrick J. Wong 	/* Is sb_rextents correct? */
14741991cf2SDarrick J. Wong 	if (mp->m_sb.sb_rextents != rtb->rextents) {
14841991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
14941991cf2SDarrick J. Wong 		return 0;
15041991cf2SDarrick J. Wong 	}
15141991cf2SDarrick J. Wong 
15241991cf2SDarrick J. Wong 	/* Is sb_rextslog correct? */
15341991cf2SDarrick J. Wong 	if (mp->m_sb.sb_rextslog != rtb->rextslog) {
15441991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
15541991cf2SDarrick J. Wong 		return 0;
15641991cf2SDarrick J. Wong 	}
15741991cf2SDarrick J. Wong 
15841991cf2SDarrick J. Wong 	/*
15941991cf2SDarrick J. Wong 	 * Is sb_rbmblocks large enough to handle the current rt volume?  In no
16041991cf2SDarrick J. Wong 	 * case can we exceed 4bn bitmap blocks since the super field is a u32.
16141991cf2SDarrick J. Wong 	 */
16241991cf2SDarrick J. Wong 	if (rtb->rbmblocks > U32_MAX) {
16341991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
16441991cf2SDarrick J. Wong 		return 0;
16541991cf2SDarrick J. Wong 	}
16641991cf2SDarrick J. Wong 	if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks) {
16741991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
16841991cf2SDarrick J. Wong 		return 0;
16941991cf2SDarrick J. Wong 	}
17041991cf2SDarrick J. Wong 
17141991cf2SDarrick J. Wong 	/* The bitmap file length must be aligned to an fsblock. */
17241991cf2SDarrick J. Wong 	if (mp->m_rbmip->i_disk_size & mp->m_blockmask) {
17341991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
17441991cf2SDarrick J. Wong 		return 0;
17541991cf2SDarrick J. Wong 	}
17641991cf2SDarrick J. Wong 
17741991cf2SDarrick J. Wong 	/*
17841991cf2SDarrick J. Wong 	 * Is the bitmap file itself large enough to handle the rt volume?
17941991cf2SDarrick J. Wong 	 * growfsrt expands the bitmap file before updating sb_rextents, so the
18041991cf2SDarrick J. Wong 	 * file can be larger than sb_rbmblocks.
18141991cf2SDarrick J. Wong 	 */
18241991cf2SDarrick J. Wong 	if (mp->m_rbmip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks)) {
18341991cf2SDarrick J. Wong 		xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
1842fb94e36SDarrick J. Wong 		return 0;
1852fb94e36SDarrick J. Wong 	}
1862fb94e36SDarrick J. Wong 
187517b32b7SDarrick J. Wong 	/* Invoke the fork scrubber. */
188c517b3aaSDarrick J. Wong 	error = xchk_metadata_inode_forks(sc);
189517b32b7SDarrick J. Wong 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
190517b32b7SDarrick J. Wong 		return error;
191517b32b7SDarrick J. Wong 
192f866560bSDarrick J. Wong 	error = xchk_rtbitmap_check_extents(sc);
193f866560bSDarrick J. Wong 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
194f866560bSDarrick J. Wong 		return error;
195f866560bSDarrick J. Wong 
19641991cf2SDarrick J. Wong 	error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
197c517b3aaSDarrick J. Wong 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
19829b0767bSDarrick J. Wong 		return error;
19941991cf2SDarrick J. Wong 
20041991cf2SDarrick J. Wong 	return 0;
20129b0767bSDarrick J. Wong }
20229b0767bSDarrick J. Wong 
20346d9bfb5SDarrick J. Wong /* xref check that the extent is not free in the rtbitmap */
20446d9bfb5SDarrick J. Wong void
xchk_xref_is_used_rt_space(struct xfs_scrub * sc,xfs_rtblock_t rtbno,xfs_extlen_t len)205c517b3aaSDarrick J. Wong xchk_xref_is_used_rt_space(
2061d8a748aSDarrick J. Wong 	struct xfs_scrub	*sc,
20705564124SDarrick J. Wong 	xfs_rtblock_t		rtbno,
20846d9bfb5SDarrick J. Wong 	xfs_extlen_t		len)
20946d9bfb5SDarrick J. Wong {
2102d5f216bSDarrick J. Wong 	xfs_rtxnum_t		startext;
2112d5f216bSDarrick J. Wong 	xfs_rtxnum_t		endext;
21246d9bfb5SDarrick J. Wong 	bool			is_free;
21346d9bfb5SDarrick J. Wong 	int			error;
21446d9bfb5SDarrick J. Wong 
215c517b3aaSDarrick J. Wong 	if (xchk_skip_xref(sc->sm))
2168389f3ffSDarrick J. Wong 		return;
2178389f3ffSDarrick J. Wong 
21805564124SDarrick J. Wong 	startext = xfs_rtb_to_rtx(sc->mp, rtbno);
21905564124SDarrick J. Wong 	endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1);
22046d9bfb5SDarrick J. Wong 	xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
22105564124SDarrick J. Wong 	error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext,
22205564124SDarrick J. Wong 			endext - startext + 1, &is_free);
223c517b3aaSDarrick J. Wong 	if (!xchk_should_check_xref(sc, &error, NULL))
22446d9bfb5SDarrick J. Wong 		goto out_unlock;
22546d9bfb5SDarrick J. Wong 	if (is_free)
226c517b3aaSDarrick J. Wong 		xchk_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
22746d9bfb5SDarrick J. Wong out_unlock:
22846d9bfb5SDarrick J. Wong 	xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
22946d9bfb5SDarrick J. Wong }
230