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