]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/phase4.c
Merge branch 'progs-misc-fixes-2' into for-next
[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
34
35 /*
36 * null out quota inode fields in sb if they point to non-existent inodes.
37 * this isn't as redundant as it looks since it's possible that the sb field
38 * might be set but the imap and inode(s) agree that the inode is
39 * free in which case they'd never be cleared so the fields wouldn't
40 * be cleared by process_dinode().
41 */
42 static void
43 quotino_check(xfs_mount_t *mp)
44 {
45 ino_tree_node_t *irec;
46
47 if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) {
48 if (verify_inum(mp, mp->m_sb.sb_uquotino))
49 irec = NULL;
50 else
51 irec = find_inode_rec(mp,
52 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino),
53 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
54
55 if (irec == NULL || is_inode_free(irec,
56 mp->m_sb.sb_uquotino - irec->ino_startnum)) {
57 mp->m_sb.sb_uquotino = NULLFSINO;
58 lost_uquotino = 1;
59 } else
60 lost_uquotino = 0;
61 }
62
63 if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) {
64 if (verify_inum(mp, mp->m_sb.sb_gquotino))
65 irec = NULL;
66 else
67 irec = find_inode_rec(mp,
68 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino),
69 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
70
71 if (irec == NULL || is_inode_free(irec,
72 mp->m_sb.sb_gquotino - irec->ino_startnum)) {
73 mp->m_sb.sb_gquotino = NULLFSINO;
74 lost_gquotino = 1;
75 } else
76 lost_gquotino = 0;
77 }
78
79 if (mp->m_sb.sb_pquotino != NULLFSINO && mp->m_sb.sb_pquotino != 0) {
80 if (verify_inum(mp, mp->m_sb.sb_pquotino))
81 irec = NULL;
82 else
83 irec = find_inode_rec(mp,
84 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino),
85 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino));
86
87 if (irec == NULL || is_inode_free(irec,
88 mp->m_sb.sb_pquotino - irec->ino_startnum)) {
89 mp->m_sb.sb_pquotino = NULLFSINO;
90 lost_pquotino = 1;
91 } else
92 lost_pquotino = 0;
93 }
94 }
95
96 static void
97 quota_sb_check(xfs_mount_t *mp)
98 {
99 /*
100 * if the sb says we have quotas and we lost both,
101 * signal a superblock downgrade. that will cause
102 * the quota flags to get zeroed. (if we only lost
103 * one quota inode, do nothing and complain later.)
104 *
105 * if the sb says we have quotas but we didn't start out
106 * with any quota inodes, signal a superblock downgrade.
107 *
108 * The sb downgrades are so that older systems can mount
109 * the filesystem.
110 *
111 * if the sb says we don't have quotas but it looks like
112 * we do have quota inodes, then signal a superblock upgrade.
113 *
114 * if the sb says we don't have quotas and we have no
115 * quota inodes, then leave will enough alone.
116 */
117
118 if (fs_quotas &&
119 (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) &&
120 (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0) &&
121 (mp->m_sb.sb_pquotino == NULLFSINO || mp->m_sb.sb_pquotino == 0)) {
122 lost_quotas = 1;
123 fs_quotas = 0;
124 } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) &&
125 !verify_inum(mp, mp->m_sb.sb_gquotino) &&
126 !verify_inum(mp, mp->m_sb.sb_pquotino)) {
127 fs_quotas = 1;
128 }
129 }
130
131
132 static void
133 process_ag_func(
134 work_queue_t *wq,
135 xfs_agnumber_t agno,
136 void *arg)
137 {
138 wait_for_inode_prefetch(arg);
139 do_log(_(" - agno = %d\n"), agno);
140 process_aginodes(wq->mp, arg, agno, 0, 1, 0);
141 cleanup_inode_prefetch(arg);
142
143 /*
144 * now recycle the per-AG duplicate extent records
145 */
146 release_dup_extent_tree(agno);
147 }
148
149 static void
150 process_ags(
151 xfs_mount_t *mp)
152 {
153 do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
154 }
155
156
157 void
158 phase4(xfs_mount_t *mp)
159 {
160 ino_tree_node_t *irec;
161 xfs_rtblock_t bno;
162 xfs_rtblock_t rt_start;
163 xfs_extlen_t rt_len;
164 xfs_agnumber_t i;
165 xfs_agblock_t j;
166 xfs_agblock_t ag_end;
167 xfs_extlen_t blen;
168 int ag_hdr_len = 4 * mp->m_sb.sb_sectsize;
169 int ag_hdr_block;
170 int bstate;
171
172 ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
173
174 do_log(_("Phase 4 - check for duplicate blocks...\n"));
175 do_log(_(" - setting up duplicate extent list...\n"));
176
177 set_progress_msg(PROG_FMT_DUP_EXTENT, (__uint64_t) glob_agcount);
178
179 irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
180 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
181
182 /*
183 * we always have a root inode, even if it's free...
184 * if the root is free, forget it, lost+found is already gone
185 */
186 if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) {
187 need_root_inode = 1;
188 if (no_modify)
189 do_warn(_("root inode would be lost\n"));
190 else
191 do_warn(_("root inode lost\n"));
192 }
193
194 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
195 ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks :
196 mp->m_sb.sb_dblocks -
197 (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i;
198
199 /*
200 * set up duplicate extent list for this ag
201 */
202 for (j = ag_hdr_block; j < ag_end; j += blen) {
203 bstate = get_bmap_ext(i, j, ag_end, &blen);
204 switch (bstate) {
205 case XR_E_BAD_STATE:
206 default:
207 do_warn(
208 _("unknown block state, ag %d, block %d\n"),
209 i, j);
210 /* fall through .. */
211 case XR_E_UNKNOWN:
212 case XR_E_FREE1:
213 case XR_E_FREE:
214 case XR_E_INUSE:
215 case XR_E_INUSE_FS:
216 case XR_E_INO:
217 case XR_E_FS_MAP:
218 break;
219 case XR_E_MULT:
220 add_dup_extent(i, j, blen);
221 break;
222 }
223 }
224
225 PROG_RPT_INC(prog_rpt_done[i], 1);
226 }
227 print_final_rpt();
228
229 /*
230 * initialize realtime bitmap
231 */
232 rt_start = 0;
233 rt_len = 0;
234
235 for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) {
236 bstate = get_rtbmap(bno);
237 switch (bstate) {
238 case XR_E_BAD_STATE:
239 default:
240 do_warn(
241 _("unknown rt extent state, extent %" PRIu64 "\n"),
242 bno);
243 /* fall through .. */
244 case XR_E_UNKNOWN:
245 case XR_E_FREE1:
246 case XR_E_FREE:
247 case XR_E_INUSE:
248 case XR_E_INUSE_FS:
249 case XR_E_INO:
250 case XR_E_FS_MAP:
251 if (rt_start == 0)
252 continue;
253 else {
254 /*
255 * add extent and reset extent state
256 */
257 add_rt_dup_extent(rt_start, rt_len);
258 rt_start = 0;
259 rt_len = 0;
260 }
261 break;
262 case XR_E_MULT:
263 if (rt_start == 0) {
264 rt_start = bno;
265 rt_len = 1;
266 } else if (rt_len == MAXEXTLEN) {
267 /*
268 * large extent case
269 */
270 add_rt_dup_extent(rt_start, rt_len);
271 rt_start = bno;
272 rt_len = 1;
273 } else
274 rt_len++;
275 break;
276 }
277 }
278
279 /*
280 * catch tail-case, extent hitting the end of the ag
281 */
282 if (rt_start != 0)
283 add_rt_dup_extent(rt_start, rt_len);
284
285 /*
286 * initialize bitmaps for all AGs
287 */
288 reset_bmaps(mp);
289
290 do_log(_(" - check for inodes claiming duplicate blocks...\n"));
291 set_progress_msg(PROG_FMT_DUP_BLOCKS, (__uint64_t) mp->m_sb.sb_icount);
292
293 /*
294 * ok, now process the inodes -- signal 2-pass check per inode.
295 * first pass checks if the inode conflicts with a known
296 * duplicate extent. if so, the inode is cleared and second
297 * pass is skipped. second pass sets the block bitmap
298 * for all blocks claimed by the inode. directory
299 * and attribute processing is turned OFF since we did that
300 * already in phase 3.
301 */
302 process_ags(mp);
303 print_final_rpt();
304
305 /*
306 * free up memory used to track trealtime duplicate extents
307 */
308 if (rt_start != 0)
309 free_rt_dup_extent_tree(mp);
310
311 /*
312 * ensure consistency of quota inode pointers in superblock,
313 * make sure they point to real inodes
314 */
315 quotino_check(mp);
316 quota_sb_check(mp);
317 }