xref: /openbmc/linux/fs/xfs/scrub/alloc.c (revision 8bd1369b)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
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_defer.h"
13 #include "xfs_btree.h"
14 #include "xfs_bit.h"
15 #include "xfs_log_format.h"
16 #include "xfs_trans.h"
17 #include "xfs_sb.h"
18 #include "xfs_alloc.h"
19 #include "xfs_rmap.h"
20 #include "xfs_alloc.h"
21 #include "scrub/xfs_scrub.h"
22 #include "scrub/scrub.h"
23 #include "scrub/common.h"
24 #include "scrub/btree.h"
25 #include "scrub/trace.h"
26 
27 /*
28  * Set us up to scrub free space btrees.
29  */
30 int
31 xfs_scrub_setup_ag_allocbt(
32 	struct xfs_scrub_context	*sc,
33 	struct xfs_inode		*ip)
34 {
35 	return xfs_scrub_setup_ag_btree(sc, ip, false);
36 }
37 
38 /* Free space btree scrubber. */
39 /*
40  * Ensure there's a corresponding cntbt/bnobt record matching this
41  * bnobt/cntbt record, respectively.
42  */
43 STATIC void
44 xfs_scrub_allocbt_xref_other(
45 	struct xfs_scrub_context	*sc,
46 	xfs_agblock_t			agbno,
47 	xfs_extlen_t			len)
48 {
49 	struct xfs_btree_cur		**pcur;
50 	xfs_agblock_t			fbno;
51 	xfs_extlen_t			flen;
52 	int				has_otherrec;
53 	int				error;
54 
55 	if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
56 		pcur = &sc->sa.cnt_cur;
57 	else
58 		pcur = &sc->sa.bno_cur;
59 	if (!*pcur || xfs_scrub_skip_xref(sc->sm))
60 		return;
61 
62 	error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
63 	if (!xfs_scrub_should_check_xref(sc, &error, pcur))
64 		return;
65 	if (!has_otherrec) {
66 		xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
67 		return;
68 	}
69 
70 	error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
71 	if (!xfs_scrub_should_check_xref(sc, &error, pcur))
72 		return;
73 	if (!has_otherrec) {
74 		xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
75 		return;
76 	}
77 
78 	if (fbno != agbno || flen != len)
79 		xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0);
80 }
81 
82 /* Cross-reference with the other btrees. */
83 STATIC void
84 xfs_scrub_allocbt_xref(
85 	struct xfs_scrub_context	*sc,
86 	xfs_agblock_t			agbno,
87 	xfs_extlen_t			len)
88 {
89 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
90 		return;
91 
92 	xfs_scrub_allocbt_xref_other(sc, agbno, len);
93 	xfs_scrub_xref_is_not_inode_chunk(sc, agbno, len);
94 	xfs_scrub_xref_has_no_owner(sc, agbno, len);
95 	xfs_scrub_xref_is_not_shared(sc, agbno, len);
96 }
97 
98 /* Scrub a bnobt/cntbt record. */
99 STATIC int
100 xfs_scrub_allocbt_rec(
101 	struct xfs_scrub_btree		*bs,
102 	union xfs_btree_rec		*rec)
103 {
104 	struct xfs_mount		*mp = bs->cur->bc_mp;
105 	xfs_agnumber_t			agno = bs->cur->bc_private.a.agno;
106 	xfs_agblock_t			bno;
107 	xfs_extlen_t			len;
108 	int				error = 0;
109 
110 	bno = be32_to_cpu(rec->alloc.ar_startblock);
111 	len = be32_to_cpu(rec->alloc.ar_blockcount);
112 
113 	if (bno + len <= bno ||
114 	    !xfs_verify_agbno(mp, agno, bno) ||
115 	    !xfs_verify_agbno(mp, agno, bno + len - 1))
116 		xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0);
117 
118 	xfs_scrub_allocbt_xref(bs->sc, bno, len);
119 
120 	return error;
121 }
122 
123 /* Scrub the freespace btrees for some AG. */
124 STATIC int
125 xfs_scrub_allocbt(
126 	struct xfs_scrub_context	*sc,
127 	xfs_btnum_t			which)
128 {
129 	struct xfs_owner_info		oinfo;
130 	struct xfs_btree_cur		*cur;
131 
132 	xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
133 	cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur;
134 	return xfs_scrub_btree(sc, cur, xfs_scrub_allocbt_rec, &oinfo, NULL);
135 }
136 
137 int
138 xfs_scrub_bnobt(
139 	struct xfs_scrub_context	*sc)
140 {
141 	return xfs_scrub_allocbt(sc, XFS_BTNUM_BNO);
142 }
143 
144 int
145 xfs_scrub_cntbt(
146 	struct xfs_scrub_context	*sc)
147 {
148 	return xfs_scrub_allocbt(sc, XFS_BTNUM_CNT);
149 }
150 
151 /* xref check that the extent is not free */
152 void
153 xfs_scrub_xref_is_used_space(
154 	struct xfs_scrub_context	*sc,
155 	xfs_agblock_t			agbno,
156 	xfs_extlen_t			len)
157 {
158 	bool				is_freesp;
159 	int				error;
160 
161 	if (!sc->sa.bno_cur || xfs_scrub_skip_xref(sc->sm))
162 		return;
163 
164 	error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp);
165 	if (!xfs_scrub_should_check_xref(sc, &error, &sc->sa.bno_cur))
166 		return;
167 	if (is_freesp)
168 		xfs_scrub_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0);
169 }
170