]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/phase4.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / repair / phase4.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a 7#include "libxfs.h"
1164bde5
DC
8#include "threads.h"
9#include "prefetch.h"
2bd0ea18
NS
10#include "avl.h"
11#include "globals.h"
12#include "agheader.h"
13#include "incore.h"
14#include "protos.h"
15#include "err_protos.h"
16#include "dinode.h"
2bd0ea18
NS
17#include "bmap.h"
18#include "versions.h"
19#include "dir2.h"
06fbdda9 20#include "progress.h"
9e0f480e
DW
21#include "slab.h"
22#include "rmap.h"
2bd0ea18 23
9e0f480e 24bool collect_rmaps;
2bd0ea18 25
2bd0ea18
NS
26/*
27 * null out quota inode fields in sb if they point to non-existent inodes.
28 * this isn't as redundant as it looks since it's possible that the sb field
29 * might be set but the imap and inode(s) agree that the inode is
30 * free in which case they'd never be cleared so the fields wouldn't
31 * be cleared by process_dinode().
32 */
8b8a6b02 33static void
2bd0ea18
NS
34quotino_check(xfs_mount_t *mp)
35{
36 ino_tree_node_t *irec;
37
38 if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) {
6411f39c
BN
39 if (verify_inum(mp, mp->m_sb.sb_uquotino))
40 irec = NULL;
41 else
1ae311d5 42 irec = find_inode_rec(mp,
6411f39c
BN
43 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino),
44 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
2bd0ea18
NS
45
46 if (irec == NULL || is_inode_free(irec,
47 mp->m_sb.sb_uquotino - irec->ino_startnum)) {
48 mp->m_sb.sb_uquotino = NULLFSINO;
49 lost_uquotino = 1;
50 } else
51 lost_uquotino = 0;
52 }
53
b36eef04 54 if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) {
6411f39c
BN
55 if (verify_inum(mp, mp->m_sb.sb_gquotino))
56 irec = NULL;
57 else
1ae311d5 58 irec = find_inode_rec(mp,
6411f39c
BN
59 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino),
60 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
2bd0ea18
NS
61
62 if (irec == NULL || is_inode_free(irec,
b36eef04
NS
63 mp->m_sb.sb_gquotino - irec->ino_startnum)) {
64 mp->m_sb.sb_gquotino = NULLFSINO;
0340d706 65 lost_gquotino = 1;
2bd0ea18 66 } else
0340d706
CS
67 lost_gquotino = 0;
68 }
69
70 if (mp->m_sb.sb_pquotino != NULLFSINO && mp->m_sb.sb_pquotino != 0) {
71 if (verify_inum(mp, mp->m_sb.sb_pquotino))
72 irec = NULL;
73 else
74 irec = find_inode_rec(mp,
75 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino),
76 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino));
77
78 if (irec == NULL || is_inode_free(irec,
79 mp->m_sb.sb_pquotino - irec->ino_startnum)) {
80 mp->m_sb.sb_pquotino = NULLFSINO;
81 lost_pquotino = 1;
82 } else
83 lost_pquotino = 0;
2bd0ea18
NS
84 }
85}
86
8b8a6b02 87static void
2bd0ea18
NS
88quota_sb_check(xfs_mount_t *mp)
89{
90 /*
91 * if the sb says we have quotas and we lost both,
92 * signal a superblock downgrade. that will cause
93 * the quota flags to get zeroed. (if we only lost
94 * one quota inode, do nothing and complain later.)
95 *
96 * if the sb says we have quotas but we didn't start out
97 * with any quota inodes, signal a superblock downgrade.
98 *
99 * The sb downgrades are so that older systems can mount
100 * the filesystem.
101 *
102 * if the sb says we don't have quotas but it looks like
103 * we do have quota inodes, then signal a superblock upgrade.
104 *
105 * if the sb says we don't have quotas and we have no
106 * quota inodes, then leave will enough alone.
107 */
108
109 if (fs_quotas &&
110 (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) &&
0340d706
CS
111 (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0) &&
112 (mp->m_sb.sb_pquotino == NULLFSINO || mp->m_sb.sb_pquotino == 0)) {
2bd0ea18
NS
113 lost_quotas = 1;
114 fs_quotas = 0;
115 } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) &&
0340d706
CS
116 !verify_inum(mp, mp->m_sb.sb_gquotino) &&
117 !verify_inum(mp, mp->m_sb.sb_pquotino)) {
2bd0ea18
NS
118 fs_quotas = 1;
119 }
120}
121
122
2556c98b
BN
123static void
124process_ag_func(
62843f36 125 struct workqueue *wq,
2556c98b
BN
126 xfs_agnumber_t agno,
127 void *arg)
3b6ac903 128{
2556c98b 129 wait_for_inode_prefetch(arg);
3b6ac903 130 do_log(_(" - agno = %d\n"), agno);
62843f36 131 process_aginodes(wq->wq_ctx, arg, agno, 0, 1, 0);
bd758142 132 blkmap_free_final();
2556c98b 133 cleanup_inode_prefetch(arg);
3b6ac903
MV
134
135 /*
136 * now recycle the per-AG duplicate extent records
137 */
138 release_dup_extent_tree(agno);
139}
140
2556c98b
BN
141static void
142process_ags(
143 xfs_mount_t *mp)
144{
b7f12e53
DW
145 xfs_agnumber_t i;
146 int error;
147
1164bde5 148 do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
b7f12e53 149 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
2d273771 150 error = rmap_finish_collecting_fork_recs(mp, i);
b7f12e53
DW
151 if (error)
152 do_error(
153_("unable to finish adding attr/data fork reverse-mapping data for AG %u.\n"),
154 i);
155 }
2556c98b
BN
156}
157
713b6817
DW
158static void
159check_rmap_btrees(
62843f36 160 struct workqueue*wq,
713b6817
DW
161 xfs_agnumber_t agno,
162 void *arg)
163{
164 int error;
165
62843f36 166 error = rmap_add_fixed_ag_rec(wq->wq_ctx, agno);
713b6817
DW
167 if (error)
168 do_error(
169_("unable to add AG %u metadata reverse-mapping data.\n"), agno);
170
62843f36 171 error = rmap_fold_raw_recs(wq->wq_ctx, agno);
713b6817
DW
172 if (error)
173 do_error(
174_("unable to merge AG %u metadata reverse-mapping data.\n"), agno);
11b9e510 175
62843f36 176 error = rmaps_verify_btree(wq->wq_ctx, agno);
11b9e510
DW
177 if (error)
178 do_error(
179_("%s while checking reverse-mappings"),
180 strerror(-error));
713b6817
DW
181}
182
00f34bca
DW
183static void
184compute_ag_refcounts(
62843f36 185 struct workqueue*wq,
00f34bca
DW
186 xfs_agnumber_t agno,
187 void *arg)
188{
189 int error;
190
62843f36 191 error = compute_refcounts(wq->wq_ctx, agno);
00f34bca
DW
192 if (error)
193 do_error(
194_("%s while computing reference count records.\n"),
195 strerror(-error));
196}
197
ca8d7d6a
DW
198static void
199process_inode_reflink_flags(
62843f36 200 struct workqueue *wq,
ca8d7d6a
DW
201 xfs_agnumber_t agno,
202 void *arg)
203{
204 int error;
205
62843f36 206 error = fix_inode_reflink_flags(wq->wq_ctx, agno);
ca8d7d6a
DW
207 if (error)
208 do_error(
209_("%s while fixing inode reflink flags.\n"),
210 strerror(-error));
211}
212
80dbc783
DW
213static void
214check_refcount_btrees(
62843f36 215 struct workqueue*wq,
80dbc783
DW
216 xfs_agnumber_t agno,
217 void *arg)
218{
219 int error;
220
62843f36 221 error = check_refcounts(wq->wq_ctx, agno);
80dbc783
DW
222 if (error)
223 do_error(
224_("%s while checking reference counts"),
225 strerror(-error));
226}
227
713b6817
DW
228static void
229process_rmap_data(
230 struct xfs_mount *mp)
231{
62843f36 232 struct workqueue wq;
713b6817
DW
233 xfs_agnumber_t i;
234
2d273771 235 if (!rmap_needs_work(mp))
713b6817
DW
236 return;
237
238 create_work_queue(&wq, mp, libxfs_nproc());
239 for (i = 0; i < mp->m_sb.sb_agcount; i++)
240 queue_work(&wq, check_rmap_btrees, i, NULL);
241 destroy_work_queue(&wq);
00f34bca
DW
242
243 if (!xfs_sb_version_hasreflink(&mp->m_sb))
244 return;
245
246 create_work_queue(&wq, mp, libxfs_nproc());
247 for (i = 0; i < mp->m_sb.sb_agcount; i++)
248 queue_work(&wq, compute_ag_refcounts, i, NULL);
249 destroy_work_queue(&wq);
ca8d7d6a
DW
250
251 create_work_queue(&wq, mp, libxfs_nproc());
80dbc783 252 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
ca8d7d6a 253 queue_work(&wq, process_inode_reflink_flags, i, NULL);
80dbc783
DW
254 queue_work(&wq, check_refcount_btrees, i, NULL);
255 }
ca8d7d6a 256 destroy_work_queue(&wq);
713b6817 257}
2556c98b 258
2bd0ea18
NS
259void
260phase4(xfs_mount_t *mp)
261{
262 ino_tree_node_t *irec;
5a35bf2c
DC
263 xfs_rtblock_t bno;
264 xfs_rtblock_t rt_start;
2bd0ea18
NS
265 xfs_extlen_t rt_len;
266 xfs_agnumber_t i;
267 xfs_agblock_t j;
268 xfs_agblock_t ag_end;
8961bfde 269 xfs_extlen_t blen;
2bd0ea18
NS
270 int ag_hdr_len = 4 * mp->m_sb.sb_sectsize;
271 int ag_hdr_block;
272 int bstate;
dfc130f3 273
2d273771 274 if (rmap_needs_work(mp))
9e0f480e 275 collect_rmaps = true;
2bd0ea18
NS
276 ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
277
507f4e33
NS
278 do_log(_("Phase 4 - check for duplicate blocks...\n"));
279 do_log(_(" - setting up duplicate extent list...\n"));
2bd0ea18 280
14f8b681 281 set_progress_msg(PROG_FMT_DUP_EXTENT, (uint64_t) glob_agcount);
06fbdda9 282
1ae311d5 283 irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
2bd0ea18
NS
284 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
285
286 /*
287 * we always have a root inode, even if it's free...
288 * if the root is free, forget it, lost+found is already gone
289 */
290 if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) {
291 need_root_inode = 1;
292 if (no_modify)
507f4e33 293 do_warn(_("root inode would be lost\n"));
2bd0ea18 294 else
507f4e33 295 do_warn(_("root inode lost\n"));
2bd0ea18
NS
296 }
297
2bd0ea18
NS
298 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
299 ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks :
300 mp->m_sb.sb_dblocks -
5a35bf2c 301 (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i;
8961bfde 302
2bd0ea18
NS
303 /*
304 * set up duplicate extent list for this ag
305 */
8961bfde
BN
306 for (j = ag_hdr_block; j < ag_end; j += blen) {
307 bstate = get_bmap_ext(i, j, ag_end, &blen);
308 switch (bstate) {
2bd0ea18
NS
309 case XR_E_BAD_STATE:
310 default:
507f4e33
NS
311 do_warn(
312 _("unknown block state, ag %d, block %d\n"),
2bd0ea18
NS
313 i, j);
314 /* fall through .. */
315 case XR_E_UNKNOWN:
316 case XR_E_FREE1:
317 case XR_E_FREE:
318 case XR_E_INUSE:
319 case XR_E_INUSE_FS:
320 case XR_E_INO:
321 case XR_E_FS_MAP:
2bd0ea18
NS
322 break;
323 case XR_E_MULT:
8961bfde 324 add_dup_extent(i, j, blen);
2bd0ea18
NS
325 break;
326 }
327 }
8961bfde 328
06fbdda9 329 PROG_RPT_INC(prog_rpt_done[i], 1);
2bd0ea18 330 }
06fbdda9 331 print_final_rpt();
2bd0ea18
NS
332
333 /*
334 * initialize realtime bitmap
335 */
336 rt_start = 0;
337 rt_len = 0;
338
339 for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) {
95650c4d 340 bstate = get_rtbmap(bno);
2bd0ea18
NS
341 switch (bstate) {
342 case XR_E_BAD_STATE:
343 default:
5d1b7f0f
CH
344 do_warn(
345 _("unknown rt extent state, extent %" PRIu64 "\n"),
507f4e33 346 bno);
2bd0ea18
NS
347 /* fall through .. */
348 case XR_E_UNKNOWN:
349 case XR_E_FREE1:
350 case XR_E_FREE:
351 case XR_E_INUSE:
352 case XR_E_INUSE_FS:
353 case XR_E_INO:
354 case XR_E_FS_MAP:
355 if (rt_start == 0)
356 continue;
357 else {
358 /*
359 * add extent and reset extent state
360 */
361 add_rt_dup_extent(rt_start, rt_len);
362 rt_start = 0;
363 rt_len = 0;
364 }
365 break;
366 case XR_E_MULT:
367 if (rt_start == 0) {
368 rt_start = bno;
369 rt_len = 1;
370 } else if (rt_len == MAXEXTLEN) {
371 /*
372 * large extent case
373 */
374 add_rt_dup_extent(rt_start, rt_len);
375 rt_start = bno;
376 rt_len = 1;
377 } else
378 rt_len++;
379 break;
380 }
381 }
382
383 /*
384 * catch tail-case, extent hitting the end of the ag
385 */
386 if (rt_start != 0)
387 add_rt_dup_extent(rt_start, rt_len);
388
389 /*
390 * initialize bitmaps for all AGs
391 */
c1f7a46c 392 reset_bmaps(mp);
2bd0ea18 393
507f4e33 394 do_log(_(" - check for inodes claiming duplicate blocks...\n"));
14f8b681 395 set_progress_msg(PROG_FMT_DUP_BLOCKS, (uint64_t) mp->m_sb.sb_icount);
add3cb90
BN
396
397 /*
398 * ok, now process the inodes -- signal 2-pass check per inode.
399 * first pass checks if the inode conflicts with a known
400 * duplicate extent. if so, the inode is cleared and second
401 * pass is skipped. second pass sets the block bitmap
402 * for all blocks claimed by the inode. directory
403 * and attribute processing is turned OFF since we did that
404 * already in phase 3.
405 */
2556c98b 406 process_ags(mp);
713b6817
DW
407
408 /*
409 * Process all the reverse-mapping data that we collected. This
00f34bca
DW
410 * involves checking the rmap data against the btree, computing
411 * reference counts based on the rmap data, and checking the counts
412 * against the refcount btree.
713b6817
DW
413 */
414 process_rmap_data(mp);
415
06fbdda9 416 print_final_rpt();
2bd0ea18
NS
417
418 /*
419 * free up memory used to track trealtime duplicate extents
420 */
421 if (rt_start != 0)
422 free_rt_dup_extent_tree(mp);
423
424 /*
425 * ensure consistency of quota inode pointers in superblock,
426 * make sure they point to real inodes
427 */
428 quotino_check(mp);
429 quota_sb_check(mp);
430}