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