1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
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 Summary
31 * ================
32 *
33 * We check the realtime summary by scanning the realtime bitmap file to create
34 * a new summary file incore, and then we compare the computed version against
35 * the ondisk version. We use the 'xfile' functionality to store this
36 * (potentially large) amount of data in pageable memory.
37 */
38
39 /* Set us up to check the rtsummary file. */
40 int
xchk_setup_rtsummary(struct xfs_scrub * sc)41 xchk_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 allows
63 * 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 be
86 * careful to unlock it ourselves when we are done with the rtbitmap
87 * file since the scrub infrastructure won't do that for us. Only
88 * 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 with
95 * growfsrt trying to expand the summary or change the size of the rt
96 * 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
113 static inline int
xfsum_load(struct xfs_scrub * sc,xfs_rtsumoff_t sumoff,union xfs_suminfo_raw * rawinfo)114 xfsum_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
124 static inline int
xfsum_store(struct xfs_scrub * sc,xfs_rtsumoff_t sumoff,const union xfs_suminfo_raw rawinfo)125 xfsum_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
135 inline int
xfsum_copyout(struct xfs_scrub * sc,xfs_rtsumoff_t sumoff,union xfs_suminfo_raw * rawinfo,unsigned int nr_words)136 xfsum_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
146 static inline xfs_suminfo_t
xchk_rtsum_inc(struct xfs_mount * mp,union xfs_suminfo_raw * v)147 xchk_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. */
156 STATIC int
xchk_rtsum_record_free(struct xfs_mount * mp,struct xfs_trans * tp,const struct xfs_rtalloc_rec * rec,void * priv)157 xchk_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. */
202 STATIC int
xchk_rtsum_compute(struct xfs_scrub * sc)203 xchk_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. */
219 STATIC int
xchk_rtsum_compare(struct xfs_scrub * sc)220 xchk_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. */
297 int
xchk_rtsummary(struct xfs_scrub * sc)298 xchk_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, so
332 * 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 xref
349 * 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
361 out_rbm:
362 /*
363 * Unlock the rtbitmap since we're done with it. All other writers of
364 * the rt free space metadata grab the bitmap and summary ILOCKs in
365 * that order, so we're still protected against allocation activities
366 * 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