Line data Source code
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 "scrub/scrub.h"
20 : #include "scrub/common.h"
21 : #include "scrub/trace.h"
22 : #include "scrub/xfile.h"
23 : #include "scrub/repair.h"
24 : #include "scrub/rtsummary.h"
25 :
26 : /*
27 : * Realtime Summary
28 : * ================
29 : *
30 : * We check the realtime summary by scanning the realtime bitmap file to create
31 : * a new summary file incore, and then we compare the computed version against
32 : * the ondisk version. We use the 'xfile' functionality to store this
33 : * (potentially large) amount of data in pageable memory.
34 : */
35 :
36 : /* Set us up to check the rtsummary file. */
37 : int
38 67522 : xchk_setup_rtsummary(
39 : struct xfs_scrub *sc)
40 : {
41 67522 : struct xfs_mount *mp = sc->mp;
42 67522 : char *descr;
43 67522 : size_t bufsize = mp->m_sb.sb_blocksize;
44 67522 : unsigned int wordcnt;
45 67522 : unsigned int resblks = 0;
46 67522 : int error;
47 :
48 135044 : if (xchk_could_repair(sc)) {
49 21328 : error = xrep_setup_rtsummary(sc, &resblks, &bufsize);
50 21328 : if (error)
51 : return error;
52 : }
53 :
54 : /*
55 : * Create an xfile to construct a new rtsummary file. The xfile allows
56 : * us to avoid pinning kernel memory for this purpose.
57 : */
58 67522 : wordcnt = xfs_rtsummary_wordcount(mp, mp->m_rsumlevels,
59 : mp->m_sb.sb_rbmblocks);
60 67522 : descr = xchk_xfile_descr(sc, "realtime summary file");
61 67522 : error = xfile_create(descr, wordcnt << XFS_WORDLOG, &sc->xfile);
62 67521 : kfree(descr);
63 67522 : if (error)
64 : return error;
65 :
66 67522 : error = xchk_trans_alloc(sc, resblks);
67 67522 : if (error)
68 : return error;
69 :
70 : /* Allocate a memory buffer for the summary comparison. */
71 67522 : sc->buf = kvmalloc(bufsize, XCHK_GFP_FLAGS);
72 67522 : if (!sc->buf)
73 : return -ENOMEM;
74 :
75 67522 : error = xchk_install_live_inode(sc, mp->m_rsumip);
76 67522 : if (error)
77 : return error;
78 :
79 67522 : error = xchk_ino_dqattach(sc);
80 67522 : if (error)
81 : return error;
82 :
83 67522 : xchk_rt_init(sc, &sc->sr,
84 : XCHK_RTLOCK_SUMMARY | XCHK_RTLOCK_BITMAP_SHARED);
85 67522 : return 0;
86 : }
87 :
88 : /* Helper functions to record suminfo words in an xfile. */
89 :
90 : static inline int
91 : xfsum_load(
92 : struct xfs_scrub *sc,
93 : xfs_rtsumoff_t sumoff,
94 : union xfs_suminfo_ondisk *rawinfo)
95 : {
96 7382430 : return xfile_obj_load(sc->xfile, rawinfo,
97 : sizeof(union xfs_suminfo_ondisk),
98 7382430 : sumoff << XFS_WORDLOG);
99 : }
100 :
101 : static inline int
102 : xfsum_store(
103 : struct xfs_scrub *sc,
104 : xfs_rtsumoff_t sumoff,
105 : const union xfs_suminfo_ondisk rawinfo)
106 : {
107 7382430 : return xfile_obj_store(sc->xfile, &rawinfo,
108 : sizeof(union xfs_suminfo_ondisk),
109 : sumoff << XFS_WORDLOG);
110 : }
111 :
112 : inline int
113 149296 : xfsum_copyout(
114 : struct xfs_scrub *sc,
115 : xfs_rtsumoff_t sumoff,
116 : union xfs_suminfo_ondisk *rawinfo,
117 : unsigned int nr_words)
118 : {
119 771210 : return xfile_obj_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG,
120 149296 : sumoff << XFS_WORDLOG);
121 : }
122 :
123 : /* Update the summary file to reflect the free extent that we've accumulated. */
124 : STATIC int
125 7382430 : xchk_rtsum_record_free(
126 : struct xfs_mount *mp,
127 : struct xfs_trans *tp,
128 : const struct xfs_rtalloc_rec *rec,
129 : void *priv)
130 : {
131 7382430 : struct xfs_scrub *sc = priv;
132 7382430 : xfs_fileoff_t rbmoff;
133 7382430 : xfs_rtxnum_t rtbno;
134 7382430 : xfs_filblks_t rtlen;
135 7382430 : xfs_rtsumoff_t offs;
136 7382430 : unsigned int lenlog;
137 7382430 : union xfs_suminfo_ondisk v;
138 7382430 : int error = 0;
139 :
140 7382430 : if (xchk_should_terminate(sc, &error))
141 0 : return error;
142 :
143 : /* Compute the relevant location in the rtsum file. */
144 7382430 : rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext);
145 7382430 : lenlog = XFS_RTBLOCKLOG(rec->ar_extcount);
146 7382430 : offs = xfs_rtsumoffs(mp, lenlog, rbmoff);
147 :
148 7382430 : rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
149 7382430 : rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
150 :
151 7382430 : if (!xfs_verify_rtbext(mp, rtbno, rtlen)) {
152 0 : xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
153 0 : return -EFSCORRUPTED;
154 : }
155 :
156 : /* Bump the summary count. */
157 7382430 : error = xfsum_load(sc, offs, &v);
158 7382430 : if (error)
159 : return error;
160 :
161 7382430 : xfs_suminfo_add(mp, &v, 1);
162 7382430 : trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount,
163 : lenlog, offs, &v);
164 :
165 7382430 : return xfsum_store(sc, offs, v);
166 : }
167 :
168 : /* Compute the realtime summary from the realtime bitmap. */
169 : STATIC int
170 67522 : xchk_rtsum_compute(
171 : struct xfs_scrub *sc)
172 : {
173 67522 : struct xfs_mount *mp = sc->mp;
174 67522 : unsigned long long rtbmp_blocks;
175 :
176 : /* If the bitmap size doesn't match the computed size, bail. */
177 67522 : rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
178 67522 : if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)
179 : return -EFSCORRUPTED;
180 :
181 67522 : return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
182 : sc);
183 : }
184 :
185 : /* Compare the rtsummary file against the one we computed. */
186 : STATIC int
187 67522 : xchk_rtsum_compare(
188 : struct xfs_scrub *sc)
189 : {
190 67522 : struct xfs_mount *mp = sc->mp;
191 67522 : struct xfs_buf *bp;
192 67522 : struct xfs_bmbt_irec map;
193 67522 : xfs_fileoff_t off;
194 67522 : xfs_rtsumoff_t sumoff = 0;
195 67522 : int nmap;
196 :
197 540140 : for (off = 0; off < XFS_B_TO_FSB(mp, mp->m_rsumsize); off++) {
198 472618 : union xfs_suminfo_ondisk *ondisk_info;
199 472618 : int error = 0;
200 :
201 472618 : if (xchk_should_terminate(sc, &error))
202 0 : return error;
203 472618 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
204 : return 0;
205 :
206 : /* Make sure we have a written extent. */
207 472618 : nmap = 1;
208 472618 : error = xfs_bmapi_read(mp->m_rsumip, off, 1, &map, &nmap,
209 : XFS_DATA_FORK);
210 472618 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
211 0 : return error;
212 :
213 472618 : if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) {
214 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
215 0 : return 0;
216 : }
217 :
218 : /* Read a block's worth of ondisk rtsummary file. */
219 472618 : error = xfs_rtbuf_get(mp, sc->tp, off, 1, &bp);
220 472618 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
221 0 : return error;
222 :
223 : /* Read a block's worth of computed rtsummary file. */
224 472618 : error = xfsum_copyout(sc, sumoff, sc->buf, mp->m_blockwsize);
225 472618 : if (error) {
226 0 : xfs_trans_brelse(sc->tp, bp);
227 0 : return error;
228 : }
229 :
230 472618 : ondisk_info = xfs_rsumblock_infoptr(bp, 0);
231 472618 : if (memcmp(ondisk_info, sc->buf,
232 472618 : mp->m_blockwsize << XFS_WORDLOG) != 0)
233 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
234 :
235 472618 : xfs_trans_brelse(sc->tp, bp);
236 472618 : sumoff += mp->m_blockwsize;
237 : }
238 :
239 : return 0;
240 : }
241 :
242 : /* Scrub the realtime summary. */
243 : int
244 67522 : xchk_rtsummary(
245 : struct xfs_scrub *sc)
246 : {
247 67522 : struct xfs_mount *mp = sc->mp;
248 67522 : int error = 0;
249 :
250 : /* Invoke the fork scrubber. */
251 67522 : error = xchk_metadata_inode_forks(sc);
252 67522 : if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
253 : return error;
254 :
255 : /* Construct the new summary file from the rtbitmap. */
256 67522 : error = xchk_rtsum_compute(sc);
257 67522 : if (error == -EFSCORRUPTED) {
258 : /*
259 : * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref
260 : * error since we're checking the summary file.
261 : */
262 0 : xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
263 0 : return 0;
264 : }
265 67522 : if (error)
266 : return error;
267 :
268 : /* Does the computed summary file match the actual rtsummary file? */
269 67522 : return xchk_rtsum_compare(sc);
270 : }
|