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_log_format.h" |
13 | #include "xfs_trans.h" |
14 | #include "xfs_rtbitmap.h" |
15 | #include "xfs_inode.h" |
16 | #include "xfs_bmap.h" |
17 | #include "xfs_bit.h" |
18 | #include "xfs_sb.h" |
19 | #include "scrub/scrub.h" |
20 | #include "scrub/common.h" |
21 | #include "scrub/repair.h" |
22 | #include "scrub/rtbitmap.h" |
23 | |
24 | /* Set us up with the realtime metadata locked. */ |
25 | int |
26 | xchk_setup_rtbitmap( |
27 | struct xfs_scrub *sc) |
28 | { |
29 | struct xfs_mount *mp = sc->mp; |
30 | struct xchk_rtbitmap *rtb; |
31 | int error; |
32 | |
33 | rtb = kzalloc(sizeof(struct xchk_rtbitmap), XCHK_GFP_FLAGS); |
34 | if (!rtb) |
35 | return -ENOMEM; |
36 | sc->buf = rtb; |
37 | |
38 | if (xchk_could_repair(sc)) { |
39 | error = xrep_setup_rtbitmap(sc, rtb); |
40 | if (error) |
41 | return error; |
42 | } |
43 | |
44 | error = xchk_trans_alloc(sc, rtb->resblks); |
45 | if (error) |
46 | return error; |
47 | |
48 | error = xchk_install_live_inode(sc, sc->mp->m_rbmip); |
49 | if (error) |
50 | return error; |
51 | |
52 | error = xchk_ino_dqattach(sc); |
53 | if (error) |
54 | return error; |
55 | |
56 | xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP); |
57 | |
58 | /* |
59 | * Now that we've locked the rtbitmap, we can't race with growfsrt |
60 | * trying to expand the bitmap or change the size of the rt volume. |
61 | * Hence it is safe to compute and check the geometry values. |
62 | */ |
63 | if (mp->m_sb.sb_rblocks) { |
64 | rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks); |
65 | rtb->rextslog = xfs_compute_rextslog(rtb->rextents); |
66 | rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents); |
67 | } |
68 | return 0; |
69 | } |
70 | |
71 | /* Realtime bitmap. */ |
72 | |
73 | /* Scrub a free extent record from the realtime bitmap. */ |
74 | STATIC int |
75 | xchk_rtbitmap_rec( |
76 | struct xfs_mount *mp, |
77 | struct xfs_trans *tp, |
78 | const struct xfs_rtalloc_rec *rec, |
79 | void *priv) |
80 | { |
81 | struct xfs_scrub *sc = priv; |
82 | xfs_rtblock_t startblock; |
83 | xfs_filblks_t blockcount; |
84 | |
85 | startblock = xfs_rtx_to_rtb(mp, rec->ar_startext); |
86 | blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount); |
87 | |
88 | if (!xfs_verify_rtbext(mp, startblock, blockcount)) |
89 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); |
90 | return 0; |
91 | } |
92 | |
93 | /* Make sure the entire rtbitmap file is mapped with written extents. */ |
94 | STATIC int |
95 | xchk_rtbitmap_check_extents( |
96 | struct xfs_scrub *sc) |
97 | { |
98 | struct xfs_bmbt_irec map; |
99 | struct xfs_iext_cursor icur; |
100 | struct xfs_mount *mp = sc->mp; |
101 | struct xfs_inode *ip = sc->ip; |
102 | xfs_fileoff_t off = 0; |
103 | xfs_fileoff_t endoff; |
104 | int error = 0; |
105 | |
106 | /* Mappings may not cross or lie beyond EOF. */ |
107 | endoff = XFS_B_TO_FSB(mp, ip->i_disk_size); |
108 | if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) { |
109 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff); |
110 | return 0; |
111 | } |
112 | |
113 | while (off < endoff) { |
114 | int nmap = 1; |
115 | |
116 | if (xchk_should_terminate(sc, &error) || |
117 | (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) |
118 | break; |
119 | |
120 | /* Make sure we have a written extent. */ |
121 | error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap, |
122 | XFS_DATA_FORK); |
123 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) |
124 | break; |
125 | |
126 | if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) { |
127 | xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); |
128 | break; |
129 | } |
130 | |
131 | off += map.br_blockcount; |
132 | } |
133 | |
134 | return error; |
135 | } |
136 | |
137 | /* Scrub the realtime bitmap. */ |
138 | int |
139 | xchk_rtbitmap( |
140 | struct xfs_scrub *sc) |
141 | { |
142 | struct xfs_mount *mp = sc->mp; |
143 | struct xchk_rtbitmap *rtb = sc->buf; |
144 | int error; |
145 | |
146 | /* Is sb_rextents correct? */ |
147 | if (mp->m_sb.sb_rextents != rtb->rextents) { |
148 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
149 | return 0; |
150 | } |
151 | |
152 | /* Is sb_rextslog correct? */ |
153 | if (mp->m_sb.sb_rextslog != rtb->rextslog) { |
154 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
155 | return 0; |
156 | } |
157 | |
158 | /* |
159 | * Is sb_rbmblocks large enough to handle the current rt volume? In no |
160 | * case can we exceed 4bn bitmap blocks since the super field is a u32. |
161 | */ |
162 | if (rtb->rbmblocks > U32_MAX) { |
163 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
164 | return 0; |
165 | } |
166 | if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks) { |
167 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
168 | return 0; |
169 | } |
170 | |
171 | /* The bitmap file length must be aligned to an fsblock. */ |
172 | if (mp->m_rbmip->i_disk_size & mp->m_blockmask) { |
173 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
174 | return 0; |
175 | } |
176 | |
177 | /* |
178 | * Is the bitmap file itself large enough to handle the rt volume? |
179 | * growfsrt expands the bitmap file before updating sb_rextents, so the |
180 | * file can be larger than sb_rbmblocks. |
181 | */ |
182 | if (mp->m_rbmip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks)) { |
183 | xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); |
184 | return 0; |
185 | } |
186 | |
187 | /* Invoke the fork scrubber. */ |
188 | error = xchk_metadata_inode_forks(sc); |
189 | if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) |
190 | return error; |
191 | |
192 | error = xchk_rtbitmap_check_extents(sc); |
193 | if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) |
194 | return error; |
195 | |
196 | error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc); |
197 | if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error)) |
198 | return error; |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | /* xref check that the extent is not free in the rtbitmap */ |
204 | void |
205 | xchk_xref_is_used_rt_space( |
206 | struct xfs_scrub *sc, |
207 | xfs_rtblock_t rtbno, |
208 | xfs_extlen_t len) |
209 | { |
210 | xfs_rtxnum_t startext; |
211 | xfs_rtxnum_t endext; |
212 | bool is_free; |
213 | int error; |
214 | |
215 | if (xchk_skip_xref(sc->sm)) |
216 | return; |
217 | |
218 | startext = xfs_rtb_to_rtx(sc->mp, rtbno); |
219 | endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1); |
220 | xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); |
221 | error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext, |
222 | endext - startext + 1, &is_free); |
223 | if (!xchk_should_check_xref(sc, &error, NULL)) |
224 | goto out_unlock; |
225 | if (is_free) |
226 | xchk_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino); |
227 | out_unlock: |
228 | xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); |
229 | } |
230 | |