]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/phase4.c
xfs: create bmbt update intent log items
[thirdparty/xfsprogs-dev.git] / repair / phase4.c
1 /*
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libxfs.h"
20 #include "threads.h"
21 #include "prefetch.h"
22 #include "avl.h"
23 #include "globals.h"
24 #include "agheader.h"
25 #include "incore.h"
26 #include "protos.h"
27 #include "err_protos.h"
28 #include "dinode.h"
29 #include "bmap.h"
30 #include "versions.h"
31 #include "dir2.h"
32 #include "progress.h"
33 #include "slab.h"
34 #include "rmap.h"
35
36 bool collect_rmaps;
37
38 /*
39 * null out quota inode fields in sb if they point to non-existent inodes.
40 * this isn't as redundant as it looks since it's possible that the sb field
41 * might be set but the imap and inode(s) agree that the inode is
42 * free in which case they'd never be cleared so the fields wouldn't
43 * be cleared by process_dinode().
44 */
45 static void
46 quotino_check(xfs_mount_t *mp)
47 {
48 ino_tree_node_t *irec;
49
50 if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) {
51 if (verify_inum(mp, mp->m_sb.sb_uquotino))
52 irec = NULL;
53 else
54 irec = find_inode_rec(mp,
55 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino),
56 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
57
58 if (irec == NULL || is_inode_free(irec,
59 mp->m_sb.sb_uquotino - irec->ino_startnum)) {
60 mp->m_sb.sb_uquotino = NULLFSINO;
61 lost_uquotino = 1;
62 } else
63 lost_uquotino = 0;
64 }
65
66 if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) {
67 if (verify_inum(mp, mp->m_sb.sb_gquotino))
68 irec = NULL;
69 else
70 irec = find_inode_rec(mp,
71 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino),
72 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
73
74 if (irec == NULL || is_inode_free(irec,
75 mp->m_sb.sb_gquotino - irec->ino_startnum)) {
76 mp->m_sb.sb_gquotino = NULLFSINO;
77 lost_gquotino = 1;
78 } else
79 lost_gquotino = 0;
80 }
81
82 if (mp->m_sb.sb_pquotino != NULLFSINO && mp->m_sb.sb_pquotino != 0) {
83 if (verify_inum(mp, mp->m_sb.sb_pquotino))
84 irec = NULL;
85 else
86 irec = find_inode_rec(mp,
87 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino),
88 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino));
89
90 if (irec == NULL || is_inode_free(irec,
91 mp->m_sb.sb_pquotino - irec->ino_startnum)) {
92 mp->m_sb.sb_pquotino = NULLFSINO;
93 lost_pquotino = 1;
94 } else
95 lost_pquotino = 0;
96 }
97 }
98
99 static void
100 quota_sb_check(xfs_mount_t *mp)
101 {
102 /*
103 * if the sb says we have quotas and we lost both,
104 * signal a superblock downgrade. that will cause
105 * the quota flags to get zeroed. (if we only lost
106 * one quota inode, do nothing and complain later.)
107 *
108 * if the sb says we have quotas but we didn't start out
109 * with any quota inodes, signal a superblock downgrade.
110 *
111 * The sb downgrades are so that older systems can mount
112 * the filesystem.
113 *
114 * if the sb says we don't have quotas but it looks like
115 * we do have quota inodes, then signal a superblock upgrade.
116 *
117 * if the sb says we don't have quotas and we have no
118 * quota inodes, then leave will enough alone.
119 */
120
121 if (fs_quotas &&
122 (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) &&
123 (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0) &&
124 (mp->m_sb.sb_pquotino == NULLFSINO || mp->m_sb.sb_pquotino == 0)) {
125 lost_quotas = 1;
126 fs_quotas = 0;
127 } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) &&
128 !verify_inum(mp, mp->m_sb.sb_gquotino) &&
129 !verify_inum(mp, mp->m_sb.sb_pquotino)) {
130 fs_quotas = 1;
131 }
132 }
133
134
135 static void
136 process_ag_func(
137 work_queue_t *wq,
138 xfs_agnumber_t agno,
139 void *arg)
140 {
141 wait_for_inode_prefetch(arg);
142 do_log(_(" - agno = %d\n"), agno);
143 process_aginodes(wq->mp, arg, agno, 0, 1, 0);
144 blkmap_free_final();
145 cleanup_inode_prefetch(arg);
146
147 /*
148 * now recycle the per-AG duplicate extent records
149 */
150 release_dup_extent_tree(agno);
151 }
152
153 static void
154 process_ags(
155 xfs_mount_t *mp)
156 {
157 xfs_agnumber_t i;
158 int error;
159
160 do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
161 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
162 error = rmap_finish_collecting_fork_recs(mp, i);
163 if (error)
164 do_error(
165 _("unable to finish adding attr/data fork reverse-mapping data for AG %u.\n"),
166 i);
167 }
168 }
169
170 static void
171 check_rmap_btrees(
172 work_queue_t *wq,
173 xfs_agnumber_t agno,
174 void *arg)
175 {
176 int error;
177
178 error = rmap_add_fixed_ag_rec(wq->mp, agno);
179 if (error)
180 do_error(
181 _("unable to add AG %u metadata reverse-mapping data.\n"), agno);
182
183 error = rmap_fold_raw_recs(wq->mp, agno);
184 if (error)
185 do_error(
186 _("unable to merge AG %u metadata reverse-mapping data.\n"), agno);
187
188 error = rmaps_verify_btree(wq->mp, agno);
189 if (error)
190 do_error(
191 _("%s while checking reverse-mappings"),
192 strerror(-error));
193 }
194
195 static void
196 process_rmap_data(
197 struct xfs_mount *mp)
198 {
199 struct work_queue wq;
200 xfs_agnumber_t i;
201
202 if (!rmap_needs_work(mp))
203 return;
204
205 create_work_queue(&wq, mp, libxfs_nproc());
206 for (i = 0; i < mp->m_sb.sb_agcount; i++)
207 queue_work(&wq, check_rmap_btrees, i, NULL);
208 destroy_work_queue(&wq);
209 }
210
211 void
212 phase4(xfs_mount_t *mp)
213 {
214 ino_tree_node_t *irec;
215 xfs_rtblock_t bno;
216 xfs_rtblock_t rt_start;
217 xfs_extlen_t rt_len;
218 xfs_agnumber_t i;
219 xfs_agblock_t j;
220 xfs_agblock_t ag_end;
221 xfs_extlen_t blen;
222 int ag_hdr_len = 4 * mp->m_sb.sb_sectsize;
223 int ag_hdr_block;
224 int bstate;
225
226 if (rmap_needs_work(mp))
227 collect_rmaps = true;
228 ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
229
230 do_log(_("Phase 4 - check for duplicate blocks...\n"));
231 do_log(_(" - setting up duplicate extent list...\n"));
232
233 set_progress_msg(PROG_FMT_DUP_EXTENT, (__uint64_t) glob_agcount);
234
235 irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
236 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
237
238 /*
239 * we always have a root inode, even if it's free...
240 * if the root is free, forget it, lost+found is already gone
241 */
242 if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) {
243 need_root_inode = 1;
244 if (no_modify)
245 do_warn(_("root inode would be lost\n"));
246 else
247 do_warn(_("root inode lost\n"));
248 }
249
250 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
251 ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks :
252 mp->m_sb.sb_dblocks -
253 (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i;
254
255 /*
256 * set up duplicate extent list for this ag
257 */
258 for (j = ag_hdr_block; j < ag_end; j += blen) {
259 bstate = get_bmap_ext(i, j, ag_end, &blen);
260 switch (bstate) {
261 case XR_E_BAD_STATE:
262 default:
263 do_warn(
264 _("unknown block state, ag %d, block %d\n"),
265 i, j);
266 /* fall through .. */
267 case XR_E_UNKNOWN:
268 case XR_E_FREE1:
269 case XR_E_FREE:
270 case XR_E_INUSE:
271 case XR_E_INUSE_FS:
272 case XR_E_INO:
273 case XR_E_FS_MAP:
274 break;
275 case XR_E_MULT:
276 add_dup_extent(i, j, blen);
277 break;
278 }
279 }
280
281 PROG_RPT_INC(prog_rpt_done[i], 1);
282 }
283 print_final_rpt();
284
285 /*
286 * initialize realtime bitmap
287 */
288 rt_start = 0;
289 rt_len = 0;
290
291 for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) {
292 bstate = get_rtbmap(bno);
293 switch (bstate) {
294 case XR_E_BAD_STATE:
295 default:
296 do_warn(
297 _("unknown rt extent state, extent %" PRIu64 "\n"),
298 bno);
299 /* fall through .. */
300 case XR_E_UNKNOWN:
301 case XR_E_FREE1:
302 case XR_E_FREE:
303 case XR_E_INUSE:
304 case XR_E_INUSE_FS:
305 case XR_E_INO:
306 case XR_E_FS_MAP:
307 if (rt_start == 0)
308 continue;
309 else {
310 /*
311 * add extent and reset extent state
312 */
313 add_rt_dup_extent(rt_start, rt_len);
314 rt_start = 0;
315 rt_len = 0;
316 }
317 break;
318 case XR_E_MULT:
319 if (rt_start == 0) {
320 rt_start = bno;
321 rt_len = 1;
322 } else if (rt_len == MAXEXTLEN) {
323 /*
324 * large extent case
325 */
326 add_rt_dup_extent(rt_start, rt_len);
327 rt_start = bno;
328 rt_len = 1;
329 } else
330 rt_len++;
331 break;
332 }
333 }
334
335 /*
336 * catch tail-case, extent hitting the end of the ag
337 */
338 if (rt_start != 0)
339 add_rt_dup_extent(rt_start, rt_len);
340
341 /*
342 * initialize bitmaps for all AGs
343 */
344 reset_bmaps(mp);
345
346 do_log(_(" - check for inodes claiming duplicate blocks...\n"));
347 set_progress_msg(PROG_FMT_DUP_BLOCKS, (__uint64_t) mp->m_sb.sb_icount);
348
349 /*
350 * ok, now process the inodes -- signal 2-pass check per inode.
351 * first pass checks if the inode conflicts with a known
352 * duplicate extent. if so, the inode is cleared and second
353 * pass is skipped. second pass sets the block bitmap
354 * for all blocks claimed by the inode. directory
355 * and attribute processing is turned OFF since we did that
356 * already in phase 3.
357 */
358 process_ags(mp);
359
360 /*
361 * Process all the reverse-mapping data that we collected. This
362 * involves checking the rmap data against the btree.
363 */
364 process_rmap_data(mp);
365
366 print_final_rpt();
367
368 /*
369 * free up memory used to track trealtime duplicate extents
370 */
371 if (rt_start != 0)
372 free_rt_dup_extent_tree(mp);
373
374 /*
375 * ensure consistency of quota inode pointers in superblock,
376 * make sure they point to real inodes
377 */
378 quotino_check(mp);
379 quota_sb_check(mp);
380 }