]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/phase4.c
repair: track logical to physical block mapping more effeciently
[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
19#include <libxfs.h>
20#include "avl.h"
21#include "globals.h"
22#include "agheader.h"
23#include "incore.h"
24#include "protos.h"
25#include "err_protos.h"
26#include "dinode.h"
27#include "dir.h"
28#include "bmap.h"
29#include "versions.h"
30#include "dir2.h"
3b6ac903 31#include "threads.h"
06fbdda9 32#include "progress.h"
2556c98b 33#include "prefetch.h"
2bd0ea18
NS
34
35
2bd0ea18
NS
36/*
37 * null out quota inode fields in sb if they point to non-existent inodes.
38 * this isn't as redundant as it looks since it's possible that the sb field
39 * might be set but the imap and inode(s) agree that the inode is
40 * free in which case they'd never be cleared so the fields wouldn't
41 * be cleared by process_dinode().
42 */
43void
44quotino_check(xfs_mount_t *mp)
45{
46 ino_tree_node_t *irec;
47
48 if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) {
6411f39c
BN
49 if (verify_inum(mp, mp->m_sb.sb_uquotino))
50 irec = NULL;
51 else
52 irec = find_inode_rec(
53 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino),
54 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
2bd0ea18
NS
55
56 if (irec == NULL || is_inode_free(irec,
57 mp->m_sb.sb_uquotino - irec->ino_startnum)) {
58 mp->m_sb.sb_uquotino = NULLFSINO;
59 lost_uquotino = 1;
60 } else
61 lost_uquotino = 0;
62 }
63
b36eef04 64 if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) {
6411f39c
BN
65 if (verify_inum(mp, mp->m_sb.sb_gquotino))
66 irec = NULL;
67 else
68 irec = find_inode_rec(
69 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino),
70 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
2bd0ea18
NS
71
72 if (irec == NULL || is_inode_free(irec,
b36eef04
NS
73 mp->m_sb.sb_gquotino - irec->ino_startnum)) {
74 mp->m_sb.sb_gquotino = NULLFSINO;
9b27bdbb
NS
75 if (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT)
76 lost_gquotino = 1;
77 else
78 lost_pquotino = 1;
2bd0ea18 79 } else
9b27bdbb 80 lost_gquotino = lost_pquotino = 0;
2bd0ea18
NS
81 }
82}
83
84void
85quota_sb_check(xfs_mount_t *mp)
86{
87 /*
88 * if the sb says we have quotas and we lost both,
89 * signal a superblock downgrade. that will cause
90 * the quota flags to get zeroed. (if we only lost
91 * one quota inode, do nothing and complain later.)
92 *
93 * if the sb says we have quotas but we didn't start out
94 * with any quota inodes, signal a superblock downgrade.
95 *
96 * The sb downgrades are so that older systems can mount
97 * the filesystem.
98 *
99 * if the sb says we don't have quotas but it looks like
100 * we do have quota inodes, then signal a superblock upgrade.
101 *
102 * if the sb says we don't have quotas and we have no
103 * quota inodes, then leave will enough alone.
104 */
105
106 if (fs_quotas &&
107 (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) &&
b36eef04 108 (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0)) {
2bd0ea18
NS
109 lost_quotas = 1;
110 fs_quotas = 0;
111 } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) &&
b36eef04 112 !verify_inum(mp, mp->m_sb.sb_gquotino)) {
2bd0ea18
NS
113 fs_quotas = 1;
114 }
115}
116
117
2556c98b
BN
118static void
119process_ag_func(
120 work_queue_t *wq,
121 xfs_agnumber_t agno,
122 void *arg)
3b6ac903 123{
2556c98b 124 wait_for_inode_prefetch(arg);
3b6ac903 125 do_log(_(" - agno = %d\n"), agno);
2556c98b
BN
126 process_aginodes(wq->mp, arg, agno, 0, 1, 0);
127 cleanup_inode_prefetch(arg);
3b6ac903
MV
128
129 /*
130 * now recycle the per-AG duplicate extent records
131 */
132 release_dup_extent_tree(agno);
133}
134
2556c98b
BN
135static void
136process_ags(
137 xfs_mount_t *mp)
138{
139 int i, j;
af2984c9 140 xfs_agnumber_t agno;
2556c98b
BN
141 work_queue_t *queues;
142 prefetch_args_t *pf_args[2];
143
144 queues = malloc(thread_count * sizeof(work_queue_t));
145
146 if (!libxfs_bcache_overflowed()) {
147 queues[0].mp = mp;
148 create_work_queue(&queues[0], mp, libxfs_nproc());
149 for (i = 0; i < mp->m_sb.sb_agcount; i++)
150 queue_work(&queues[0], process_ag_func, i, NULL);
151 destroy_work_queue(&queues[0]);
152 } else {
153 if (ag_stride) {
154 /*
155 * create one worker thread for each segment of the volume
156 */
af2984c9 157 for (i = 0, agno = 0; i < thread_count; i++) {
2556c98b
BN
158 create_work_queue(&queues[i], mp, 1);
159 pf_args[0] = NULL;
af2984c9
BN
160 for (j = 0; j < ag_stride && agno < mp->m_sb.sb_agcount;
161 j++, agno++) {
162 pf_args[0] = start_inode_prefetch(agno, 0, pf_args[0]);
163 queue_work(&queues[i], process_ag_func, agno, pf_args[0]);
2556c98b
BN
164 }
165 }
166 /*
167 * wait for workers to complete
168 */
169 for (i = 0; i < thread_count; i++)
170 destroy_work_queue(&queues[i]);
171 } else {
172 queues[0].mp = mp;
173 pf_args[0] = start_inode_prefetch(0, 0, NULL);
174 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
175 pf_args[(~i) & 1] = start_inode_prefetch(i + 1,
176 0, pf_args[i & 1]);
177 process_ag_func(&queues[0], i, pf_args[i & 1]);
178 }
179 }
180 }
181 free(queues);
182}
183
184
2bd0ea18
NS
185void
186phase4(xfs_mount_t *mp)
187{
188 ino_tree_node_t *irec;
189 xfs_drtbno_t bno;
190 xfs_drtbno_t rt_start;
191 xfs_extlen_t rt_len;
192 xfs_agnumber_t i;
193 xfs_agblock_t j;
194 xfs_agblock_t ag_end;
195 xfs_agblock_t extent_start;
196 xfs_extlen_t extent_len;
197 int ag_hdr_len = 4 * mp->m_sb.sb_sectsize;
198 int ag_hdr_block;
199 int bstate;
200 int count_bcnt_extents(xfs_agnumber_t agno);
201 int count_bno_extents(xfs_agnumber_t agno);
dfc130f3 202
2bd0ea18
NS
203 ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
204
507f4e33
NS
205 do_log(_("Phase 4 - check for duplicate blocks...\n"));
206 do_log(_(" - setting up duplicate extent list...\n"));
2bd0ea18 207
06fbdda9
MV
208 set_progress_msg(PROG_FMT_DUP_EXTENT, (__uint64_t) glob_agcount);
209
2bd0ea18
NS
210 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
211 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
212
213 /*
214 * we always have a root inode, even if it's free...
215 * if the root is free, forget it, lost+found is already gone
216 */
217 if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) {
218 need_root_inode = 1;
219 if (no_modify)
507f4e33 220 do_warn(_("root inode would be lost\n"));
2bd0ea18 221 else
507f4e33 222 do_warn(_("root inode lost\n"));
2bd0ea18
NS
223 }
224
2bd0ea18
NS
225 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
226 ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks :
227 mp->m_sb.sb_dblocks -
228 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i;
229 extent_start = extent_len = 0;
230 /*
231 * set up duplicate extent list for this ag
232 */
233 for (j = ag_hdr_block; j < ag_end; j++) {
234
1e77098c
MV
235 /* Process in chunks of 16 (XR_BB_UNIT/XR_BB) */
236 if ((extent_start == 0) && ((j & XR_BB_MASK) == 0)) {
237 switch(ba_bmap[i][j>>XR_BB]) {
238 case XR_E_UNKNOWN_LL:
239 case XR_E_FREE1_LL:
240 case XR_E_FREE_LL:
241 case XR_E_INUSE_LL:
242 case XR_E_INUSE_FS_LL:
243 case XR_E_INO_LL:
244 case XR_E_FS_MAP_LL:
245 j += (XR_BB_UNIT/XR_BB) - 1;
246 continue;
247 }
248 }
249
2bd0ea18
NS
250 bstate = get_agbno_state(mp, i, j);
251
252 switch (bstate) {
253 case XR_E_BAD_STATE:
254 default:
507f4e33
NS
255 do_warn(
256 _("unknown block state, ag %d, block %d\n"),
2bd0ea18
NS
257 i, j);
258 /* fall through .. */
259 case XR_E_UNKNOWN:
260 case XR_E_FREE1:
261 case XR_E_FREE:
262 case XR_E_INUSE:
263 case XR_E_INUSE_FS:
264 case XR_E_INO:
265 case XR_E_FS_MAP:
266 if (extent_start == 0)
267 continue;
268 else {
269 /*
270 * add extent and reset extent state
271 */
272 add_dup_extent(i, extent_start,
273 extent_len);
274 extent_start = 0;
275 extent_len = 0;
276 }
277 break;
278 case XR_E_MULT:
279 if (extent_start == 0) {
280 extent_start = j;
281 extent_len = 1;
282 } else if (extent_len == MAXEXTLEN) {
283 add_dup_extent(i, extent_start,
284 extent_len);
285 extent_start = j;
286 extent_len = 1;
287 } else
288 extent_len++;
289 break;
290 }
291 }
292 /*
293 * catch tail-case, extent hitting the end of the ag
294 */
295 if (extent_start != 0)
296 add_dup_extent(i, extent_start, extent_len);
06fbdda9 297 PROG_RPT_INC(prog_rpt_done[i], 1);
2bd0ea18 298 }
06fbdda9 299 print_final_rpt();
2bd0ea18
NS
300
301 /*
302 * initialize realtime bitmap
303 */
304 rt_start = 0;
305 rt_len = 0;
306
307 for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) {
308
309 bstate = get_rtbno_state(mp, bno);
310
311 switch (bstate) {
312 case XR_E_BAD_STATE:
313 default:
507f4e33
NS
314 do_warn(_("unknown rt extent state, extent %llu\n"),
315 bno);
2bd0ea18
NS
316 /* fall through .. */
317 case XR_E_UNKNOWN:
318 case XR_E_FREE1:
319 case XR_E_FREE:
320 case XR_E_INUSE:
321 case XR_E_INUSE_FS:
322 case XR_E_INO:
323 case XR_E_FS_MAP:
324 if (rt_start == 0)
325 continue;
326 else {
327 /*
328 * add extent and reset extent state
329 */
330 add_rt_dup_extent(rt_start, rt_len);
331 rt_start = 0;
332 rt_len = 0;
333 }
334 break;
335 case XR_E_MULT:
336 if (rt_start == 0) {
337 rt_start = bno;
338 rt_len = 1;
339 } else if (rt_len == MAXEXTLEN) {
340 /*
341 * large extent case
342 */
343 add_rt_dup_extent(rt_start, rt_len);
344 rt_start = bno;
345 rt_len = 1;
346 } else
347 rt_len++;
348 break;
349 }
350 }
351
352 /*
353 * catch tail-case, extent hitting the end of the ag
354 */
355 if (rt_start != 0)
356 add_rt_dup_extent(rt_start, rt_len);
357
358 /*
359 * initialize bitmaps for all AGs
360 */
361 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
2bd0ea18
NS
362 /*
363 * now reset the bitmap for all ags
364 */
dab9b8d6 365 memset(ba_bmap[i], 0,
13002e23 366 roundup((mp->m_sb.sb_agblocks+(NBBY/XR_BB)-1)/(NBBY/XR_BB),
2bd0ea18
NS
367 sizeof(__uint64_t)));
368 for (j = 0; j < ag_hdr_block; j++)
369 set_agbno_state(mp, i, j, XR_E_INUSE_FS);
370 }
371 set_bmap_rt(mp->m_sb.sb_rextents);
372 set_bmap_log(mp);
373 set_bmap_fs(mp);
374
507f4e33 375 do_log(_(" - check for inodes claiming duplicate blocks...\n"));
06fbdda9 376 set_progress_msg(PROG_FMT_DUP_BLOCKS, (__uint64_t) mp->m_sb.sb_icount);
add3cb90
BN
377
378 /*
379 * ok, now process the inodes -- signal 2-pass check per inode.
380 * first pass checks if the inode conflicts with a known
381 * duplicate extent. if so, the inode is cleared and second
382 * pass is skipped. second pass sets the block bitmap
383 * for all blocks claimed by the inode. directory
384 * and attribute processing is turned OFF since we did that
385 * already in phase 3.
386 */
2556c98b 387 process_ags(mp);
06fbdda9 388 print_final_rpt();
2bd0ea18
NS
389
390 /*
391 * free up memory used to track trealtime duplicate extents
392 */
393 if (rt_start != 0)
394 free_rt_dup_extent_tree(mp);
395
396 /*
397 * ensure consistency of quota inode pointers in superblock,
398 * make sure they point to real inodes
399 */
400 quotino_check(mp);
401 quota_sb_check(mp);
402}