]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/phase2.c
xfs_repair: exit with status 2 if log dirtiness is unknown
[thirdparty/xfsprogs-dev.git] / repair / phase2.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 "libxlog.h"
21 #include "avl.h"
22 #include "globals.h"
23 #include "agheader.h"
24 #include "protos.h"
25 #include "err_protos.h"
26 #include "incore.h"
27 #include "progress.h"
28 #include "scan.h"
29
30 void set_mp(xfs_mount_t *mpp);
31
32 /* workaround craziness in the xlog routines */
33 int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
34 {
35 return 0;
36 }
37
38 static void
39 zero_log(
40 struct xfs_mount *mp)
41 {
42 int error;
43 xfs_daddr_t head_blk;
44 xfs_daddr_t tail_blk;
45 struct xlog *log = mp->m_log;
46
47 memset(log, 0, sizeof(struct xlog));
48 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
49 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
50 x.lbsize = BBSIZE;
51 if (xfs_sb_version_hassector(&mp->m_sb))
52 x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT);
53
54 log->l_dev = mp->m_logdev_targp;
55 log->l_logBBsize = x.logBBsize;
56 log->l_logBBstart = x.logBBstart;
57 log->l_sectBBsize = BTOBB(x.lbsize);
58 log->l_mp = mp;
59 if (xfs_sb_version_hassector(&mp->m_sb)) {
60 log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
61 ASSERT(log->l_sectbb_log <= mp->m_sectbb_log);
62 /* for larger sector sizes, must have v2 or external log */
63 ASSERT(log->l_sectbb_log == 0 ||
64 log->l_logBBstart == 0 ||
65 xfs_sb_version_haslogv2(&mp->m_sb));
66 ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT);
67 }
68 log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;
69
70 /*
71 * Find the log head and tail and alert the user to the situation if the
72 * log appears corrupted or contains data. In either case, we do not
73 * proceed past this point unless the user explicitly requests to zap
74 * the log.
75 */
76 error = xlog_find_tail(log, &head_blk, &tail_blk);
77 if (error) {
78 do_warn(
79 _("zero_log: cannot find log head/tail (xlog_find_tail=%d)\n"),
80 error);
81 if (!no_modify && !zap_log)
82 do_warn(_(
83 "ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n"
84 "filesystem to replay the log or use the -L option to destroy the log and\n"
85 "attempt a repair.\n"));
86 exit(2);
87 } else {
88 if (verbose) {
89 do_warn(
90 _("zero_log: head block %" PRId64 " tail block %" PRId64 "\n"),
91 head_blk, tail_blk);
92 }
93 if (!no_modify && head_blk != tail_blk) {
94 if (zap_log) {
95 do_warn(_(
96 "ALERT: The filesystem has valuable metadata changes in a log which is being\n"
97 "destroyed because the -L option was used.\n"));
98 } else {
99 do_warn(_(
100 "ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
101 "be replayed. Mount the filesystem to replay the log, and unmount it before\n"
102 "re-running xfs_repair. If you are unable to mount the filesystem, then use\n"
103 "the -L option to destroy the log and attempt a repair.\n"
104 "Note that destroying the log may cause corruption -- please attempt a mount\n"
105 "of the filesystem before doing this.\n"));
106 exit(2);
107 }
108 }
109 }
110
111 /*
112 * Only clear the log when explicitly requested. Doing so is unnecessary
113 * unless something is wrong. Further, this resets the current LSN of
114 * the filesystem and creates more work for repair of v5 superblock
115 * filesystems.
116 */
117 if (!no_modify && zap_log) {
118 libxfs_log_clear(log->l_dev, NULL,
119 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
120 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
121 &mp->m_sb.sb_uuid,
122 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
123 mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE, true);
124
125 /* update the log data structure with new state */
126 error = xlog_find_tail(log, &head_blk, &tail_blk);
127 if (error || head_blk != tail_blk)
128 do_error(_("failed to clear log"));
129 }
130
131 /*
132 * Finally, seed the max LSN from the current state of the log if this
133 * is a v5 filesystem.
134 */
135 if (xfs_sb_version_hascrc(&mp->m_sb))
136 libxfs_max_lsn = log->l_last_sync_lsn;
137 }
138
139 /*
140 * ok, at this point, the fs is mounted but the root inode may be
141 * trashed and the ag headers haven't been checked. So we have
142 * a valid xfs_mount_t and superblock but that's about it. That
143 * means we can use macros that use mount/sb fields in calculations
144 * but I/O or btree routines that depend on space maps or inode maps
145 * being correct are verboten.
146 */
147
148 void
149 phase2(
150 struct xfs_mount *mp,
151 int scan_threads)
152 {
153 int j;
154 ino_tree_node_t *ino_rec;
155
156 /* now we can start using the buffer cache routines */
157 set_mp(mp);
158
159 /* Check whether this fs has internal or external log */
160 if (mp->m_sb.sb_logstart == 0) {
161 if (!x.logname)
162 do_error(_("This filesystem has an external log. "
163 "Specify log device with the -l option.\n"));
164
165 do_log(_("Phase 2 - using external log on %s\n"), x.logname);
166 } else
167 do_log(_("Phase 2 - using internal log\n"));
168
169 /* Zero log if applicable */
170 do_log(_(" - zero log...\n"));
171 zero_log(mp);
172
173 do_log(_(" - scan filesystem freespace and inode maps...\n"));
174
175 bad_ino_btree = 0;
176
177 set_progress_msg(PROG_FMT_SCAN_AG, (__uint64_t) glob_agcount);
178
179 scan_ags(mp, scan_threads);
180
181 print_final_rpt();
182
183 /*
184 * make sure we know about the root inode chunk
185 */
186 if ((ino_rec = find_inode_rec(mp, 0, mp->m_sb.sb_rootino)) == NULL) {
187 ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 &&
188 mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2);
189 do_warn(_("root inode chunk not found\n"));
190
191 /*
192 * mark the first 3 used, the rest are free
193 */
194 ino_rec = set_inode_used_alloc(mp, 0,
195 (xfs_agino_t) mp->m_sb.sb_rootino);
196 set_inode_used(ino_rec, 1);
197 set_inode_used(ino_rec, 2);
198
199 for (j = 3; j < XFS_INODES_PER_CHUNK; j++)
200 set_inode_free(ino_rec, j);
201
202 /*
203 * also mark blocks
204 */
205 set_bmap_ext(0, XFS_INO_TO_AGBNO(mp, mp->m_sb.sb_rootino),
206 mp->m_ialloc_blks, XR_E_INO);
207 } else {
208 do_log(_(" - found root inode chunk\n"));
209
210 /*
211 * blocks are marked, just make sure they're in use
212 */
213 if (is_inode_free(ino_rec, 0)) {
214 do_warn(_("root inode marked free, "));
215 set_inode_used(ino_rec, 0);
216 if (!no_modify)
217 do_warn(_("correcting\n"));
218 else
219 do_warn(_("would correct\n"));
220 }
221
222 if (is_inode_free(ino_rec, 1)) {
223 do_warn(_("realtime bitmap inode marked free, "));
224 set_inode_used(ino_rec, 1);
225 if (!no_modify)
226 do_warn(_("correcting\n"));
227 else
228 do_warn(_("would correct\n"));
229 }
230
231 if (is_inode_free(ino_rec, 2)) {
232 do_warn(_("realtime summary inode marked free, "));
233 set_inode_used(ino_rec, 2);
234 if (!no_modify)
235 do_warn(_("correcting\n"));
236 else
237 do_warn(_("would correct\n"));
238 }
239 }
240 }