]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/agheader.c
xfsprogs: add crc format support to repair
[thirdparty/xfsprogs-dev.git] / repair / agheader.c
1 /*
2 * Copyright (c) 2000-2001,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 "globals.h"
21 #include "agheader.h"
22 #include "protos.h"
23 #include "err_protos.h"
24
25 /*
26 * XXX (dgc): What is the point of all the check and repair here when phase 5
27 * recreates the AGF/AGI/AGFL completely from scratch?
28 */
29
30 static int
31 verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
32 {
33 xfs_drfsbno_t agblocks;
34 int retval = 0;
35
36 /* check common fields */
37
38 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
39 retval = XR_AG_AGF;
40 do_warn(_("bad magic # 0x%x for agf %d\n"),
41 be32_to_cpu(agf->agf_magicnum), i);
42
43 if (!no_modify)
44 agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
45 }
46
47 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
48 retval = XR_AG_AGF;
49 do_warn(_("bad version # %d for agf %d\n"),
50 be32_to_cpu(agf->agf_versionnum), i);
51
52 if (!no_modify)
53 agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
54 }
55
56 if (be32_to_cpu(agf->agf_seqno) != i) {
57 retval = XR_AG_AGF;
58 do_warn(_("bad sequence # %d for agf %d\n"),
59 be32_to_cpu(agf->agf_seqno), i);
60
61 if (!no_modify)
62 agf->agf_seqno = cpu_to_be32(i);
63 }
64
65 if (be32_to_cpu(agf->agf_length) != mp->m_sb.sb_agblocks) {
66 if (i != mp->m_sb.sb_agcount - 1) {
67 retval = XR_AG_AGF;
68 do_warn(_("bad length %d for agf %d, should be %d\n"),
69 be32_to_cpu(agf->agf_length), i,
70 mp->m_sb.sb_agblocks);
71 if (!no_modify)
72 agf->agf_length =
73 cpu_to_be32(mp->m_sb.sb_agblocks);
74 } else {
75 agblocks = mp->m_sb.sb_dblocks -
76 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i;
77
78 if (be32_to_cpu(agf->agf_length) != agblocks) {
79 retval = XR_AG_AGF;
80 do_warn(
81 _("bad length %d for agf %d, should be %" PRIu64 "\n"),
82 be32_to_cpu(agf->agf_length),
83 i, agblocks);
84 if (!no_modify)
85 agf->agf_length = cpu_to_be32(agblocks);
86 }
87 }
88 }
89
90 /*
91 * check first/last AGF fields. if need be, lose the free
92 * space in the AGFL, we'll reclaim it later.
93 */
94 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp)) {
95 do_warn(_("flfirst %d in agf %d too large (max = %zu)\n"),
96 be32_to_cpu(agf->agf_flfirst),
97 i, XFS_AGFL_SIZE(mp));
98 if (!no_modify)
99 agf->agf_flfirst = cpu_to_be32(0);
100 }
101
102 if (be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
103 do_warn(_("fllast %d in agf %d too large (max = %zu)\n"),
104 be32_to_cpu(agf->agf_fllast),
105 i, XFS_AGFL_SIZE(mp));
106 if (!no_modify)
107 agf->agf_fllast = cpu_to_be32(0);
108 }
109
110 /* don't check freespace btrees -- will be checked by caller */
111
112 if (!xfs_sb_version_hascrc(&mp->m_sb))
113 return retval;
114
115 if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
116 char uu[64];
117
118 retval = XR_AG_AGF;
119 platform_uuid_unparse(&agf->agf_uuid, uu);
120 do_warn(_("bad uuid %s for agf %d\n"), uu, i);
121
122 if (!no_modify)
123 platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
124 }
125 return retval;
126 }
127
128 static int
129 verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t agno)
130 {
131 xfs_drfsbno_t agblocks;
132 int retval = 0;
133
134 /* check common fields */
135
136 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
137 retval = XR_AG_AGI;
138 do_warn(_("bad magic # 0x%x for agi %d\n"),
139 be32_to_cpu(agi->agi_magicnum), agno);
140
141 if (!no_modify)
142 agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
143 }
144
145 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
146 retval = XR_AG_AGI;
147 do_warn(_("bad version # %d for agi %d\n"),
148 be32_to_cpu(agi->agi_versionnum), agno);
149
150 if (!no_modify)
151 agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
152 }
153
154 if (be32_to_cpu(agi->agi_seqno) != agno) {
155 retval = XR_AG_AGI;
156 do_warn(_("bad sequence # %d for agi %d\n"),
157 be32_to_cpu(agi->agi_seqno), agno);
158
159 if (!no_modify)
160 agi->agi_seqno = cpu_to_be32(agno);
161 }
162
163 if (be32_to_cpu(agi->agi_length) != mp->m_sb.sb_agblocks) {
164 if (agno != mp->m_sb.sb_agcount - 1) {
165 retval = XR_AG_AGI;
166 do_warn(_("bad length # %d for agi %d, should be %d\n"),
167 be32_to_cpu(agi->agi_length), agno,
168 mp->m_sb.sb_agblocks);
169 if (!no_modify)
170 agi->agi_length =
171 cpu_to_be32(mp->m_sb.sb_agblocks);
172 } else {
173 agblocks = mp->m_sb.sb_dblocks -
174 (xfs_drfsbno_t) mp->m_sb.sb_agblocks * agno;
175
176 if (be32_to_cpu(agi->agi_length) != agblocks) {
177 retval = XR_AG_AGI;
178 do_warn(
179 _("bad length # %d for agi %d, should be %" PRIu64 "\n"),
180 be32_to_cpu(agi->agi_length),
181 agno, agblocks);
182 if (!no_modify)
183 agi->agi_length = cpu_to_be32(agblocks);
184 }
185 }
186 }
187
188 /* don't check inode btree -- will be checked by caller */
189
190 if (!xfs_sb_version_hascrc(&mp->m_sb))
191 return retval;
192
193 if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
194 char uu[64];
195
196 retval = XR_AG_AGI;
197 platform_uuid_unparse(&agi->agi_uuid, uu);
198 do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
199
200 if (!no_modify)
201 platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
202 }
203
204 return retval;
205 }
206
207 /*
208 * superblock comparison - compare arbitrary superblock with
209 * filesystem mount-point superblock
210 *
211 * the verified fields include id and geometry.
212 *
213 * the inprogress fields, version numbers, and counters
214 * are allowed to differ as well as all fields after the
215 * counters to cope with the pre-6.5 mkfs non-zeroed
216 * secondary superblock sectors.
217 */
218 static int
219 compare_sb(xfs_mount_t *mp, xfs_sb_t *sb)
220 {
221 fs_geometry_t fs_geo, sb_geo;
222
223 get_sb_geometry(&fs_geo, &mp->m_sb);
224 get_sb_geometry(&sb_geo, sb);
225
226 if (memcmp(&fs_geo, &sb_geo,
227 (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo))
228 return(XR_SB_GEO_MISMATCH);
229
230 return(XR_OK);
231 }
232
233 /*
234 * Possible fields that may have been set at mkfs time,
235 * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog.
236 * The quota inode fields in the secondaries should be zero.
237 * Likewise, the sb_flags and sb_shared_vn should also be
238 * zero and the shared version bit should be cleared for
239 * current mkfs's.
240 *
241 * And everything else in the buffer beyond either sb_width,
242 * sb_dirblklog (v2 dirs), or sb_logsectsize can be zeroed.
243 *
244 * Note: contrary to the name, this routine is called for all
245 * superblocks, not just the secondary superblocks.
246 */
247 static int
248 secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
249 xfs_agnumber_t i)
250 {
251 int do_bzero;
252 int size;
253 char *ip;
254 int rval;
255
256 rval = do_bzero = 0;
257
258 /*
259 * mkfs's that stamped a feature bit besides the ones in the mask
260 * (e.g. were pre-6.5 beta) could leave garbage in the secondary
261 * superblock sectors. Anything stamping the shared fs bit or better
262 * into the secondaries is ok and should generate clean secondary
263 * superblock sectors. so only run the zero check on the
264 * potentially garbaged secondaries.
265 */
266 if (pre_65_beta ||
267 (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) == 0 ||
268 sb->sb_versionnum < XFS_SB_VERSION_4) {
269 /*
270 * Check for garbage beyond the last field.
271 * Use field addresses instead so this code will still
272 * work against older filesystems when the superblock
273 * gets rev'ed again with new fields appended.
274 */
275 if (xfs_sb_version_hasmorebits(sb))
276 size = (__psint_t)&sb->sb_features2
277 + sizeof(sb->sb_features2) - (__psint_t)sb;
278 else if (xfs_sb_version_haslogv2(sb))
279 size = (__psint_t)&sb->sb_logsunit
280 + sizeof(sb->sb_logsunit) - (__psint_t)sb;
281 else if (xfs_sb_version_hassector(sb))
282 size = (__psint_t)&sb->sb_logsectsize
283 + sizeof(sb->sb_logsectsize) - (__psint_t)sb;
284 else if (xfs_sb_version_hasdirv2(sb))
285 size = (__psint_t)&sb->sb_dirblklog
286 + sizeof(sb->sb_dirblklog) - (__psint_t)sb;
287 else
288 size = (__psint_t)&sb->sb_width
289 + sizeof(sb->sb_width) - (__psint_t)sb;
290 for (ip = (char *)((__psint_t)sb + size);
291 ip < (char *)((__psint_t)sb + mp->m_sb.sb_sectsize);
292 ip++) {
293 if (*ip) {
294 do_bzero = 1;
295 break;
296 }
297 }
298
299 if (do_bzero) {
300 rval |= XR_AG_SB_SEC;
301 if (!no_modify) {
302 do_warn(
303 _("zeroing unused portion of %s superblock (AG #%u)\n"),
304 !i ? _("primary") : _("secondary"), i);
305 memset((void *)((__psint_t)sb + size), 0,
306 mp->m_sb.sb_sectsize - size);
307 } else
308 do_warn(
309 _("would zero unused portion of %s superblock (AG #%u)\n"),
310 !i ? _("primary") : _("secondary"), i);
311 }
312 }
313
314 /*
315 * now look for the fields we can manipulate directly.
316 * if we did a zero and that zero could have included
317 * the field in question, just silently reset it. otherwise,
318 * complain.
319 *
320 * for now, just zero the flags field since only
321 * the readonly flag is used
322 */
323 if (sb->sb_flags) {
324 if (!no_modify)
325 sb->sb_flags = 0;
326 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
327 rval |= XR_AG_SB;
328 do_warn(_("bad flags field in superblock %d\n"), i);
329 } else
330 rval |= XR_AG_SB_SEC;
331 }
332
333 /*
334 * quota inodes and flags in secondary superblocks
335 * are never set by mkfs. However, they could be set
336 * in a secondary if a fs with quotas was growfs'ed since
337 * growfs copies the new primary into the secondaries.
338 */
339 if (sb->sb_inprogress == 1 && sb->sb_uquotino) {
340 if (!no_modify)
341 sb->sb_uquotino = 0;
342 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
343 rval |= XR_AG_SB;
344 do_warn(
345 _("non-null user quota inode field in superblock %d\n"),
346 i);
347
348 } else
349 rval |= XR_AG_SB_SEC;
350 }
351
352 if (sb->sb_inprogress == 1 && sb->sb_gquotino) {
353 if (!no_modify)
354 sb->sb_gquotino = 0;
355 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
356 rval |= XR_AG_SB;
357 do_warn(
358 _("non-null group quota inode field in superblock %d\n"),
359 i);
360
361 } else
362 rval |= XR_AG_SB_SEC;
363 }
364
365 if (sb->sb_inprogress == 1 && sb->sb_qflags) {
366 if (!no_modify)
367 sb->sb_qflags = 0;
368 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
369 rval |= XR_AG_SB;
370 do_warn(_("non-null quota flags in superblock %d\n"),
371 i);
372 } else
373 rval |= XR_AG_SB_SEC;
374 }
375
376 /*
377 * if the secondaries agree on a stripe unit/width or inode
378 * alignment, those fields ought to be valid since they are
379 * written at mkfs time (and the corresponding sb version bits
380 * are set).
381 */
382 if (!xfs_sb_version_hasshared(sb) && sb->sb_shared_vn != 0) {
383 if (!no_modify)
384 sb->sb_shared_vn = 0;
385 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
386 rval |= XR_AG_SB;
387 do_warn(
388 _("bad shared version number in superblock %d\n"),
389 i);
390 } else
391 rval |= XR_AG_SB_SEC;
392 }
393
394 if (!xfs_sb_version_hasalign(sb) && sb->sb_inoalignmt != 0) {
395 if (!no_modify)
396 sb->sb_inoalignmt = 0;
397 if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) {
398 rval |= XR_AG_SB;
399 do_warn(
400 _("bad inode alignment field in superblock %d\n"),
401 i);
402 } else
403 rval |= XR_AG_SB_SEC;
404 }
405
406 if (!xfs_sb_version_hasdalign(sb) &&
407 (sb->sb_unit != 0 || sb->sb_width != 0)) {
408 if (!no_modify)
409 sb->sb_unit = sb->sb_width = 0;
410 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) {
411 rval |= XR_AG_SB;
412 do_warn(
413 _("bad stripe unit/width fields in superblock %d\n"),
414 i);
415 } else
416 rval |= XR_AG_SB_SEC;
417 }
418
419 if (!xfs_sb_version_hassector(sb) &&
420 (sb->sb_sectsize != BBSIZE || sb->sb_sectlog != BBSHIFT ||
421 sb->sb_logsectsize != 0 || sb->sb_logsectlog != 0)) {
422 if (!no_modify) {
423 sb->sb_sectsize = BBSIZE;
424 sb->sb_sectlog = BBSHIFT;
425 sb->sb_logsectsize = 0;
426 sb->sb_logsectlog = 0;
427 }
428 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) {
429 rval |= XR_AG_SB;
430 do_warn(
431 _("bad log/data device sector size fields in superblock %d\n"),
432 i);
433 } else
434 rval |= XR_AG_SB_SEC;
435 }
436
437 return(rval);
438 }
439
440 /*
441 * verify and reset the ag header if required.
442 *
443 * lower 4 bits of rval are set depending on what got modified.
444 * (see agheader.h for more details)
445 *
446 * NOTE -- this routine does not tell the user that it has
447 * altered things. Rather, it is up to the caller to do so
448 * using the bits encoded into the return value.
449 */
450
451 int
452 verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
453 xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i)
454 {
455 int rval = 0;
456 int status = XR_OK;
457 int status_sb = XR_OK;
458
459 status = verify_sb(sb, (i == 0));
460
461 if (status != XR_OK) {
462 do_warn(_("bad on-disk superblock %d - %s\n"),
463 i, err_string(status));
464 }
465
466 status_sb = compare_sb(mp, sb);
467
468 if (status_sb != XR_OK) {
469 do_warn(_("primary/secondary superblock %d conflict - %s\n"),
470 i, err_string(status_sb));
471 }
472
473 if (status != XR_OK || status_sb != XR_OK) {
474 if (!no_modify) {
475 *sb = mp->m_sb;
476
477 /*
478 * clear the more transient fields
479 */
480 sb->sb_inprogress = 1;
481
482 sb->sb_icount = 0;
483 sb->sb_ifree = 0;
484 sb->sb_fdblocks = 0;
485 sb->sb_frextents = 0;
486
487 sb->sb_qflags = 0;
488 }
489
490 rval |= XR_AG_SB;
491 }
492
493 rval |= secondary_sb_wack(mp, sbuf, sb, i);
494
495 rval |= verify_set_agf(mp, agf, i);
496 rval |= verify_set_agi(mp, agi, i);
497
498 return(rval);
499 }