]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/phase4.c
xfs_repair: call IRELE(ip) after libxfs_trans_iget calls
[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"
2bd0ea18
NS
33
34
2bd0ea18
NS
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 */
8b8a6b02 42static void
2bd0ea18
NS
43quotino_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) {
6411f39c
BN
48 if (verify_inum(mp, mp->m_sb.sb_uquotino))
49 irec = NULL;
50 else
1ae311d5 51 irec = find_inode_rec(mp,
6411f39c
BN
52 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino),
53 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
2bd0ea18
NS
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
b36eef04 63 if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) {
6411f39c
BN
64 if (verify_inum(mp, mp->m_sb.sb_gquotino))
65 irec = NULL;
66 else
1ae311d5 67 irec = find_inode_rec(mp,
6411f39c
BN
68 XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino),
69 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
2bd0ea18
NS
70
71 if (irec == NULL || is_inode_free(irec,
b36eef04
NS
72 mp->m_sb.sb_gquotino - irec->ino_startnum)) {
73 mp->m_sb.sb_gquotino = NULLFSINO;
0340d706 74 lost_gquotino = 1;
2bd0ea18 75 } else
0340d706
CS
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;
2bd0ea18
NS
93 }
94}
95
8b8a6b02 96static void
2bd0ea18
NS
97quota_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) &&
0340d706
CS
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)) {
2bd0ea18
NS
122 lost_quotas = 1;
123 fs_quotas = 0;
124 } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) &&
0340d706
CS
125 !verify_inum(mp, mp->m_sb.sb_gquotino) &&
126 !verify_inum(mp, mp->m_sb.sb_pquotino)) {
2bd0ea18
NS
127 fs_quotas = 1;
128 }
129}
130
131
2556c98b
BN
132static void
133process_ag_func(
134 work_queue_t *wq,
135 xfs_agnumber_t agno,
136 void *arg)
3b6ac903 137{
2556c98b 138 wait_for_inode_prefetch(arg);
3b6ac903 139 do_log(_(" - agno = %d\n"), agno);
2556c98b
BN
140 process_aginodes(wq->mp, arg, agno, 0, 1, 0);
141 cleanup_inode_prefetch(arg);
3b6ac903
MV
142
143 /*
144 * now recycle the per-AG duplicate extent records
145 */
146 release_dup_extent_tree(agno);
147}
148
2556c98b
BN
149static void
150process_ags(
151 xfs_mount_t *mp)
152{
1164bde5 153 do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
2556c98b
BN
154}
155
156
2bd0ea18
NS
157void
158phase4(xfs_mount_t *mp)
159{
160 ino_tree_node_t *irec;
5a35bf2c
DC
161 xfs_rtblock_t bno;
162 xfs_rtblock_t rt_start;
2bd0ea18
NS
163 xfs_extlen_t rt_len;
164 xfs_agnumber_t i;
165 xfs_agblock_t j;
166 xfs_agblock_t ag_end;
8961bfde 167 xfs_extlen_t blen;
2bd0ea18
NS
168 int ag_hdr_len = 4 * mp->m_sb.sb_sectsize;
169 int ag_hdr_block;
170 int bstate;
dfc130f3 171
2bd0ea18
NS
172 ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
173
507f4e33
NS
174 do_log(_("Phase 4 - check for duplicate blocks...\n"));
175 do_log(_(" - setting up duplicate extent list...\n"));
2bd0ea18 176
06fbdda9
MV
177 set_progress_msg(PROG_FMT_DUP_EXTENT, (__uint64_t) glob_agcount);
178
1ae311d5 179 irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
2bd0ea18
NS
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)
507f4e33 189 do_warn(_("root inode would be lost\n"));
2bd0ea18 190 else
507f4e33 191 do_warn(_("root inode lost\n"));
2bd0ea18
NS
192 }
193
2bd0ea18
NS
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 -
5a35bf2c 197 (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i;
8961bfde 198
2bd0ea18
NS
199 /*
200 * set up duplicate extent list for this ag
201 */
8961bfde
BN
202 for (j = ag_hdr_block; j < ag_end; j += blen) {
203 bstate = get_bmap_ext(i, j, ag_end, &blen);
204 switch (bstate) {
2bd0ea18
NS
205 case XR_E_BAD_STATE:
206 default:
507f4e33
NS
207 do_warn(
208 _("unknown block state, ag %d, block %d\n"),
2bd0ea18
NS
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:
2bd0ea18
NS
218 break;
219 case XR_E_MULT:
8961bfde 220 add_dup_extent(i, j, blen);
2bd0ea18
NS
221 break;
222 }
223 }
8961bfde 224
06fbdda9 225 PROG_RPT_INC(prog_rpt_done[i], 1);
2bd0ea18 226 }
06fbdda9 227 print_final_rpt();
2bd0ea18
NS
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++) {
95650c4d 236 bstate = get_rtbmap(bno);
2bd0ea18
NS
237 switch (bstate) {
238 case XR_E_BAD_STATE:
239 default:
5d1b7f0f
CH
240 do_warn(
241 _("unknown rt extent state, extent %" PRIu64 "\n"),
507f4e33 242 bno);
2bd0ea18
NS
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 */
c1f7a46c 288 reset_bmaps(mp);
2bd0ea18 289
507f4e33 290 do_log(_(" - check for inodes claiming duplicate blocks...\n"));
06fbdda9 291 set_progress_msg(PROG_FMT_DUP_BLOCKS, (__uint64_t) mp->m_sb.sb_icount);
add3cb90
BN
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 */
2556c98b 302 process_ags(mp);
06fbdda9 303 print_final_rpt();
2bd0ea18
NS
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}