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