]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/sb.c
libxfs: rename struct libxfs_xinit to libxfs_init
[thirdparty/xfsprogs-dev.git] / repair / sb.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18 5 */
660b5d96 6#include "libfrog/util.h"
6b803e5a 7#include "libxfs.h"
1b1b5359 8#include "libxcmd.h"
6b803e5a 9#include "libxlog.h"
2bd0ea18
NS
10#include "agheader.h"
11#include "globals.h"
12#include "protos.h"
13#include "err_protos.h"
ef12e076 14#include "xfs_multidisk.h"
2bd0ea18 15
92217f0c
NS
16#define BSIZE (1024 * 1024)
17
2bd0ea18
NS
18/*
19 * copy the fields of a superblock that are present in primary and
20 * secondaries -- preserve fields that are different in the primary.
21 */
8b8a6b02 22static void
2bd0ea18
NS
23copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
24{
25 xfs_ino_t rootino;
26 xfs_ino_t rbmino;
27 xfs_ino_t rsumino;
28 xfs_ino_t uquotino;
b36eef04 29 xfs_ino_t gquotino;
0340d706 30 xfs_ino_t pquotino;
14f8b681 31 uint16_t versionnum;
2bd0ea18
NS
32
33 rootino = dest->sb_rootino;
34 rbmino = dest->sb_rbmino;
35 rsumino = dest->sb_rsumino;
36 uquotino = dest->sb_uquotino;
b36eef04 37 gquotino = dest->sb_gquotino;
0340d706 38 pquotino = dest->sb_pquotino;
2bd0ea18
NS
39
40 versionnum = dest->sb_versionnum;
41
42 *dest = *source;
43
44 dest->sb_rootino = rootino;
45 dest->sb_rbmino = rbmino;
46 dest->sb_rsumino = rsumino;
47 dest->sb_uquotino = uquotino;
b36eef04 48 dest->sb_gquotino = gquotino;
0340d706 49 dest->sb_pquotino = pquotino;
2bd0ea18
NS
50
51 dest->sb_versionnum = versionnum;
52
53 /*
54 * copy over version bits that are stamped into all
55 * secondaries and cannot be changed at run time in
56 * the primary superblock
57 */
5e656dbb
BN
58 if (xfs_sb_version_hasdalign(source))
59 dest->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT;
b7fdeb4d 60 dest->sb_versionnum |= XFS_SB_VERSION_EXTFLGBIT;
2bd0ea18
NS
61
62 /*
63 * these are all supposed to be zero or will get reset anyway
64 */
65 dest->sb_icount = 0;
66 dest->sb_ifree = 0;
67 dest->sb_fdblocks = 0;
68 dest->sb_frextents = 0;
69
dab9b8d6 70 memset(source->sb_fname, 0, 12);
2bd0ea18
NS
71}
72
00ff2b10 73static int
ef12e076
BD
74verify_sb_blocksize(xfs_sb_t *sb)
75{
76 /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
77 if (sb->sb_blocksize == 0)
78 return XR_BAD_BLOCKSIZE;
ef12e076
BD
79 if (sb->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
80 sb->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG)
81 return XR_BAD_BLOCKLOG;
25f9772a
DW
82 if (sb->sb_blocksize != (1 << sb->sb_blocklog))
83 return XR_BAD_BLOCKLOG;
ef12e076
BD
84
85 return 0;
86}
87
2bd0ea18 88/*
1b1b5359
BD
89 * find a secondary superblock, copy it into the sb buffer.
90 * start is the point to begin reading BSIZE bytes.
91 * skip contains a byte-count of how far to advance for next read.
2bd0ea18 92 */
1b1b5359
BD
93static int
94__find_secondary_sb(
95 xfs_sb_t *rsb,
14f8b681
DW
96 uint64_t start,
97 uint64_t skip)
2bd0ea18
NS
98{
99 xfs_off_t off;
100 xfs_sb_t *sb;
101 xfs_sb_t bufsb;
102 char *c_bufsb;
103 int done;
104 int i;
105 int dirty;
106 int retval;
107 int bsize;
108
b74a1f6a 109 sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE);
2bd0ea18
NS
110 if (!sb) {
111 do_error(
507f4e33 112 _("error finding secondary superblock -- failed to memalign buffer\n"));
2bd0ea18
NS
113 exit(1);
114 }
115
dab9b8d6 116 memset(&bufsb, 0, sizeof(xfs_sb_t));
2bd0ea18
NS
117 retval = 0;
118 dirty = 0;
119 bsize = 0;
120
121 /*
122 * skip first sector since we know that's bad
123 */
1b1b5359 124 for (done = 0, off = start; !done ; off += skip) {
2bd0ea18
NS
125 /*
126 * read disk 1 MByte at a time.
127 */
dc8878f4 128 if (lseek(x.dfd, off, SEEK_SET) != off) {
2bd0ea18
NS
129 done = 1;
130 }
131
2e4741ac 132 if (!done && (bsize = read(x.dfd, sb, BSIZE)) <= 0) {
2bd0ea18
NS
133 done = 1;
134 }
135
136 do_warn(".");
137
138 /*
139 * check the buffer 512 bytes at a time since
140 * we don't know how big the sectors really are.
141 */
142 for (i = 0; !done && i < bsize; i += BBSIZE) {
5e656dbb 143 c_bufsb = (char *)sb + i;
045b32d5 144 libxfs_sb_from_disk(&bufsb, (struct xfs_dsb *)c_bufsb);
2bd0ea18 145
88f364a9 146 if (verify_sb(c_bufsb, &bufsb, 0) != XR_OK)
2bd0ea18
NS
147 continue;
148
507f4e33 149 do_warn(_("found candidate secondary superblock...\n"));
2bd0ea18
NS
150
151 /*
152 * found one. now verify it by looking
153 * for other secondaries.
154 */
dab9b8d6 155 memmove(rsb, &bufsb, sizeof(xfs_sb_t));
2bd0ea18 156 rsb->sb_inprogress = 0;
6bf4721d 157 copied_sunit = 1;
2bd0ea18
NS
158
159 if (verify_set_primary_sb(rsb, 0, &dirty) == XR_OK) {
507f4e33
NS
160 do_warn(
161 _("verified secondary superblock...\n"));
2bd0ea18
NS
162 done = 1;
163 retval = 1;
164 } else {
165 do_warn(
507f4e33 166 _("unable to verify superblock, continuing...\n"));
2bd0ea18
NS
167 }
168 }
169 }
170
171 free(sb);
1b1b5359
BD
172 return retval;
173}
174
175static int
176guess_default_geometry(
14f8b681
DW
177 uint64_t *agsize,
178 uint64_t *agcount,
01dcfd9e 179 struct libxfs_init *x)
1b1b5359
BD
180{
181 struct fs_topology ft;
182 int blocklog;
14f8b681 183 uint64_t dblocks;
1b1b5359
BD
184 int multidisk;
185
186 memset(&ft, 0, sizeof(ft));
187 get_topology(x, &ft, 1);
188
189 /*
190 * get geometry from get_topology result.
191 * Use default block size (2^12)
192 */
193 blocklog = 12;
194 multidisk = ft.dswidth | ft.dsunit;
195 dblocks = x->dsize >> (blocklog - BBSHIFT);
196 calc_default_ag_geometry(blocklog, dblocks, multidisk,
197 agsize, agcount);
198
199 return blocklog;
200}
201
202int
203find_secondary_sb(xfs_sb_t *rsb)
204{
ef12e076 205 int retval = 0;
14f8b681
DW
206 uint64_t agcount;
207 uint64_t agsize;
208 uint64_t skip;
1b1b5359
BD
209 int blocklog;
210
211 /*
ef12e076
BD
212 * Attempt to find secondary sb with a coarse approach,
213 * first trying agblocks and blocksize read from sb, providing
214 * they're sane.
1b1b5359 215 */
ef12e076 216 do_warn(_("\nattempting to find secondary superblock...\n"));
1b1b5359 217
ef12e076 218 if (verify_sb_blocksize(rsb) == 0) {
14f8b681 219 skip = (uint64_t)rsb->sb_agblocks * rsb->sb_blocksize;
ef12e076
BD
220 if (skip >= XFS_AG_MIN_BYTES && skip <= XFS_AG_MAX_BYTES)
221 retval = __find_secondary_sb(rsb, skip, skip);
1b1b5359 222 }
ef12e076
BD
223
224 /* If that failed, retry coarse approach, using default geometry */
225 if (!retval) {
226 blocklog = guess_default_geometry(&agsize, &agcount, &x);
227 skip = agsize << blocklog;
228 retval = __find_secondary_sb(rsb, skip, skip);
229 }
230
231 /* If that failed, fall back to the brute force method */
232 if (!retval)
233 retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE);
234
1b1b5359 235 return retval;
2bd0ea18
NS
236}
237
238/*
90c9ac9d
BF
239 * Calculate what the inode alignment field ought to be based on internal
240 * superblock info and determine if it is valid.
7b5f9801 241 *
90c9ac9d
BF
242 * For standard v5 superblocks, the inode alignment must either match
243 * XFS_INODE_BIG_CLUSTER_SIZE or a multiple based on the inode size. For v5
244 * superblocks with sparse inode chunks enabled, inode alignment must match the
245 * inode chunk size.
7b5f9801
DC
246 *
247 * Return true if the alignment is valid, false otherwise.
2bd0ea18 248 */
7b5f9801
DC
249static bool
250sb_validate_ino_align(struct xfs_sb *sb)
2bd0ea18 251{
7b5f9801 252 xfs_extlen_t align;
2bd0ea18 253
7b5f9801
DC
254 if (!xfs_sb_version_hasalign(sb))
255 return true;
256
257 /* standard cluster size alignment is always valid */
2bd0ea18 258 align = XFS_INODE_BIG_CLUSTER_SIZE >> sb->sb_blocklog;
7b5f9801
DC
259 if (align == sb->sb_inoalignmt)
260 return true;
261
262 /* alignment scaled by inode size is v5 only for now */
263 if (!xfs_sb_version_hascrc(sb))
264 return false;
2bd0ea18 265
16e16276
BF
266 align = (XFS_INODE_BIG_CLUSTER_SIZE *
267 sb->sb_inodesize / XFS_DINODE_MIN_SIZE) >> sb->sb_blocklog;
7b5f9801
DC
268 if (align == sb->sb_inoalignmt)
269 return true;
270
90c9ac9d
BF
271 /*
272 * Sparse inodes requires inoalignmt to match full inode chunk size and
273 * spino_align to match the scaled alignment (as calculated above).
274 */
275 if (xfs_sb_version_hassparseinodes(sb)) {
276 if (align != sb->sb_spino_align)
277 return false;
278
279 align = (sb->sb_inodesize * XFS_INODES_PER_CHUNK)
280 >> sb->sb_blocklog;
281 if (align == sb->sb_inoalignmt)
282 return true;
283 }
284
7b5f9801 285 return false;
2bd0ea18
NS
286}
287
eb9cee60
DW
288/*
289 * Validate the given log space. Derived from xfs_log_mount, though we
290 * can't validate the minimum log size until later. We only do this
291 * validation on V5 filesystems because the kernel doesn't reject malformed
292 * log geometry on older revision filesystems.
293 *
294 * Returns false if the log is garbage.
295 */
296static bool
297verify_sb_loginfo(
298 struct xfs_sb *sb)
299{
300 if (xfs_sb_version_hascrc(sb) &&
301 (sb->sb_logblocks == 0 ||
302 sb->sb_logblocks > XFS_MAX_LOG_BLOCKS ||
7931f861
DW
303 ((unsigned long long)sb->sb_logblocks << sb->sb_blocklog) >
304 XFS_MAX_LOG_BYTES))
eb9cee60
DW
305 return false;
306
307 if (sb->sb_logsunit > 1 && sb->sb_logsunit % sb->sb_blocksize)
308 return false;
309
310 return true;
311}
312
2bd0ea18
NS
313/*
314 * verify a superblock -- does not verify root inode #
315 * can only check that geometry info is internally
316 * consistent. because of growfs, that's no guarantee
317 * of correctness (e.g. geometry may have changed)
318 *
319 * fields verified or consistency checked:
320 *
321 * sb_magicnum
322 *
323 * sb_versionnum
324 *
325 * sb_inprogress
326 *
327 * sb_blocksize (as a group)
328 * sb_blocklog
329 *
330 * geometry info - sb_dblocks (as a group)
331 * sb_agcount
332 * sb_agblocks
333 * sb_agblklog
334 *
335 * inode info - sb_inodesize (x-checked with geo info)
336 * sb_inopblock
337 *
338 * sector size info -
339 * sb_sectsize
340 * sb_sectlog
3cc4d0db
NS
341 * sb_logsectsize
342 * sb_logsectlog
2bd0ea18
NS
343 *
344 * not checked here -
345 * sb_rootino
346 * sb_fname
347 * sb_fpack
348 * sb_logstart
349 * sb_uuid
350 *
351 * ALL real-time fields
352 * final 4 summary counters
353 */
354
355int
88f364a9 356verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
2bd0ea18 357{
14f8b681 358 uint32_t bsize;
2bd0ea18 359 int i;
ef12e076 360 int ret;
dfc130f3 361
2bd0ea18
NS
362 /* check magic number and version number */
363
364 if (sb->sb_magicnum != XFS_SB_MAGIC)
365 return(XR_BAD_MAGIC);
366
5e656dbb 367 if (!xfs_sb_good_version(sb))
2bd0ea18
NS
368 return(XR_BAD_VERSION);
369
370 /* does sb think mkfs really finished ? */
0ce3577f 371 if (is_primary_sb && sb->sb_inprogress)
2bd0ea18
NS
372 return(XR_BAD_INPROGRESS);
373
88f364a9
DC
374 /*
375 * before going *any further*, validate the sector size and if the
376 * version says we should have CRCs enabled, validate that.
377 */
378
379 /* check to make sure sectorsize is legal 2^N, 9 <= N <= 15 */
380 if (sb->sb_sectsize == 0)
381 return(XR_BAD_SECT_SIZE_DATA);
382
383 bsize = 1;
384 for (i = 0; bsize < sb->sb_sectsize &&
385 i < sizeof(sb->sb_sectsize) * NBBY; i++) {
386 bsize <<= 1;
387 }
388
389 if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG)
390 return(XR_BAD_SECT_SIZE_DATA);
391
392 /* check sb sectorsize field against sb sectlog field */
393 if (i != sb->sb_sectlog)
394 return(XR_BAD_SECT_SIZE_DATA);
395
396 /* sector size in range - CRC check time */
397 if (xfs_sb_version_hascrc(sb) &&
e2f60652 398 !libxfs_verify_cksum(sb_buf, sb->sb_sectsize, XFS_SB_CRC_OFF))
88f364a9 399 return XR_BAD_CRC;
2bd0ea18 400
ef12e076
BD
401 /* check to ensure blocksize and blocklog are legal */
402 ret = verify_sb_blocksize(sb);
403 if (ret != 0)
404 return ret;
2bd0ea18
NS
405
406 /* sanity check ag count, size fields against data size field */
407
408 if (sb->sb_dblocks == 0 ||
02b56f87
DW
409 sb->sb_dblocks > XFS_MAX_DBLOCKS(sb) ||
410 sb->sb_dblocks < XFS_MIN_DBLOCKS(sb))
2bd0ea18
NS
411 return(XR_BAD_FS_SIZE_DATA);
412
24f4f998 413 if (sb->sb_agblklog != (uint8_t)log2_roundup(sb->sb_agblocks))
2bd0ea18
NS
414 return(XR_BAD_FS_SIZE_DATA);
415
02b56f87
DW
416 if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE ||
417 sb->sb_inodesize > XFS_DINODE_MAX_SIZE ||
418 sb->sb_inodelog < XFS_DINODE_MIN_LOG ||
419 sb->sb_inodelog > XFS_DINODE_MAX_LOG ||
420 sb->sb_inodesize != (1 << sb->sb_inodelog) ||
421 sb->sb_logsunit > XLOG_MAX_RECORD_BSIZE ||
422 sb->sb_inopblock != howmany(sb->sb_blocksize, sb->sb_inodesize) ||
423 (sb->sb_blocklog - sb->sb_inodelog != sb->sb_inopblog))
424 return XR_BAD_INO_SIZE_DATA;
2bd0ea18 425
eb9cee60
DW
426 if (!verify_sb_loginfo(sb))
427 return XR_BAD_LOG_GEOMETRY;
428
5e656dbb 429 if (xfs_sb_version_hassector(sb)) {
3cc4d0db
NS
430
431 /* check to make sure log sector is legal 2^N, 9 <= N <= 15 */
432
433 if (sb->sb_logsectsize == 0)
434 return(XR_BAD_SECT_SIZE_DATA);
435
436 bsize = 1;
437
438 for (i = 0; bsize < sb->sb_logsectsize &&
439 i < sizeof(sb->sb_logsectsize) * NBBY; i++) {
440 bsize <<= 1;
441 }
442
443 if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG)
444 return(XR_BAD_SECT_SIZE_DATA);
445
446 /* check sb log sectorsize field against sb log sectlog field */
447
448 if (i != sb->sb_logsectlog)
449 return(XR_BAD_SECT_SIZE_DATA);
450 }
451
2bd0ea18
NS
452 /*
453 * real-time extent size is always set
454 */
455 if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE)
456 return(XR_BAD_RT_GEO_DATA);
457
458 if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE)
459 return(XR_BAD_RT_GEO_DATA);
460
461 if (sb->sb_rblocks == 0) {
462 if (sb->sb_rextents != 0)
463 return(XR_BAD_RT_GEO_DATA);
464
465 if (sb->sb_rbmblocks != 0)
466 return(XR_BAD_RT_GEO_DATA);
467
468 if (sb->sb_rextslog != 0)
469 return(XR_BAD_RT_GEO_DATA);
470
471 if (sb->sb_frextents != 0)
472 return(XR_BAD_RT_GEO_DATA);
473 } else {
474 /*
475 * if we have a real-time partition, sanity-check geometry
476 */
477 if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents)
478 return(XR_BAD_RT_GEO_DATA);
479
480 if (sb->sb_rextslog !=
481 libxfs_highbit32((unsigned int)sb->sb_rextents))
482 return(XR_BAD_RT_GEO_DATA);
483
484 if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents,
485 NBBY * sb->sb_blocksize))
486 return(XR_BAD_RT_GEO_DATA);
487 }
488
489 /*
490 * verify correctness of inode alignment if it's there
491 */
7b5f9801
DC
492 if (!sb_validate_ino_align(sb))
493 return(XR_BAD_INO_ALIGN);
2bd0ea18
NS
494
495 /*
496 * verify max. % of inodes (sb_imax_pct)
497 */
498 if (sb->sb_imax_pct > 100)
499 return(XR_BAD_INO_MAX_PCT);
500
501 /*
502 * verify stripe alignment fields if present
503 */
5e656dbb 504 if (xfs_sb_version_hasdalign(sb)) {
dfc130f3
RC
505 if ((!sb->sb_unit && sb->sb_width) ||
506 (sb->sb_unit && sb->sb_agblocks % sb->sb_unit))
2bd0ea18
NS
507 return(XR_BAD_SB_UNIT);
508 if ((sb->sb_unit && !sb->sb_width) ||
509 (sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit))
510 return(XR_BAD_SB_WIDTH);
02b56f87
DW
511 } else if (sb->sb_unit || sb->sb_width)
512 return XR_BAD_SB_WIDTH;
513
514 /* Directory block log */
515 if (sb->sb_blocklog + sb->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG)
516 return XR_BAD_DIR_SIZE_DATA;
2bd0ea18 517
2bd0ea18
NS
518 return(XR_OK);
519}
520
521void
522write_primary_sb(xfs_sb_t *sbp, int size)
523{
045b32d5 524 struct xfs_dsb *buf;
dfc130f3 525
2bd0ea18
NS
526 if (no_modify)
527 return;
dfc130f3 528
5e656dbb
BN
529 buf = memalign(libxfs_device_alignment(), size);
530 if (buf == NULL) {
b74a1f6a 531 do_error(_("failed to memalign superblock buffer\n"));
dfc130f3 532 return;
2bd0ea18 533 }
b74a1f6a 534 memset(buf, 0, size);
2bd0ea18 535
dc8878f4 536 if (lseek(x.dfd, 0LL, SEEK_SET) != 0LL) {
dfc130f3 537 free(buf);
507f4e33 538 do_error(_("couldn't seek to offset 0 in filesystem\n"));
dfc130f3
RC
539 }
540
19ebedcf 541 libxfs_sb_to_disk(buf, sbp);
2bd0ea18 542
88f364a9
DC
543 if (xfs_sb_version_hascrc(sbp))
544 xfs_update_cksum((char *)buf, size, XFS_SB_CRC_OFF);
545
b74a1f6a 546 if (write(x.dfd, buf, size) != size) {
dfc130f3 547 free(buf);
507f4e33 548 do_error(_("primary superblock write failed!\n"));
dfc130f3 549 }
2bd0ea18 550
dfc130f3 551 free(buf);
2bd0ea18
NS
552}
553
554/*
88f364a9 555 * get a possible superblock -- checks for internal consistency
2bd0ea18
NS
556 */
557int
558get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno)
559{
560 int error, rval;
045b32d5 561 struct xfs_dsb *buf;
dfc130f3 562
5e656dbb
BN
563 buf = memalign(libxfs_device_alignment(), size);
564 if (buf == NULL) {
2bd0ea18 565 do_error(
b74a1f6a 566 _("error reading superblock %u -- failed to memalign buffer\n"),
5d1b7f0f 567 agno);
2bd0ea18
NS
568 exit(1);
569 }
b74a1f6a 570 memset(buf, 0, size);
419d647d 571 memset(sbp, 0, sizeof(*sbp));
2bd0ea18
NS
572
573 /* try and read it first */
574
dc8878f4 575 if (lseek(x.dfd, off, SEEK_SET) != off) {
2bd0ea18 576 do_warn(
5d1b7f0f 577 _("error reading superblock %u -- seek to offset %" PRId64 " failed\n"),
2bd0ea18 578 agno, off);
70ee4153 579 free(buf);
2bd0ea18
NS
580 return(XR_EOF);
581 }
582
b74a1f6a 583 if ((rval = read(x.dfd, buf, size)) != size) {
2bd0ea18
NS
584 error = errno;
585 do_warn(
5d1b7f0f 586 _("superblock read failed, offset %" PRId64 ", size %d, ag %u, rval %d\n"),
b74a1f6a 587 off, size, agno, rval);
2bd0ea18
NS
588 do_error("%s\n", strerror(error));
589 }
5e656dbb 590 libxfs_sb_from_disk(sbp, buf);
2bd0ea18 591
88f364a9
DC
592 rval = verify_sb((char *)buf, sbp, agno == 0);
593 free(buf);
594 return rval;
2bd0ea18
NS
595}
596
2bd0ea18 597/* returns element on list with highest reference count */
8b8a6b02 598static fs_geo_list_t *
2bd0ea18
NS
599get_best_geo(fs_geo_list_t *list)
600{
601 int cnt = 0;
602 fs_geo_list_t *current, *rval = NULL;
603
604 current = list;
605
606 while (current != NULL) {
607 if (current->refs > cnt) {
608 rval = current;
609 cnt = current->refs;
610 }
611 current = current->next;
612 }
613
614 return(rval);
615}
616
617/* adds geometry info to linked list. returns (sometimes new) head of list */
8b8a6b02 618static fs_geo_list_t *
2bd0ea18
NS
619add_geo(fs_geo_list_t *list, fs_geometry_t *geo_p, int index)
620{
621 fs_geo_list_t *current = list;
dfc130f3 622
2bd0ea18
NS
623 while (current != NULL) {
624 if (memcmp(geo_p, &current->geo, sizeof(fs_geometry_t)) == 0) {
625 current->refs++;
626 return(list);
627 }
628
629 current = current->next;
630 }
631
632 if ((current = malloc(sizeof(fs_geo_list_t))) == NULL) {
507f4e33 633 do_error(_("couldn't malloc geometry structure\n"));
2bd0ea18
NS
634 exit(1);
635 }
636
637 current->geo = *geo_p;
638 current->refs = 1;
639 current->next = list;
640 current->index = index;
641
642 return(current);
643}
644
8b8a6b02 645static void
2bd0ea18
NS
646free_geo(fs_geo_list_t *list)
647{
648 fs_geo_list_t *next;
649 fs_geo_list_t *current;
650
2bd0ea18
NS
651 for (current = list; current != NULL; current = next) {
652 next = current->next;
653 free(current);
654 }
655}
656
657void
658get_sb_geometry(fs_geometry_t *geo, xfs_sb_t *sbp)
659{
dab9b8d6 660 memset(geo, 0, sizeof(fs_geometry_t));
2bd0ea18
NS
661
662 /*
663 * blindly set fields that we know are always good
664 */
665 geo->sb_blocksize = sbp->sb_blocksize;
666 geo->sb_dblocks = sbp->sb_dblocks;
667 geo->sb_rblocks = sbp->sb_rblocks;
668 geo->sb_rextents = sbp->sb_rextents;
669 geo->sb_logstart = sbp->sb_logstart;
670 geo->sb_rextsize = sbp->sb_rextsize;
671 geo->sb_agblocks = sbp->sb_agblocks;
672 geo->sb_agcount = sbp->sb_agcount;
673 geo->sb_rbmblocks = sbp->sb_rbmblocks;
674 geo->sb_logblocks = sbp->sb_logblocks;
675 geo->sb_sectsize = sbp->sb_sectsize;
676 geo->sb_inodesize = sbp->sb_inodesize;
677
5e656dbb 678 if (xfs_sb_version_hasalign(sbp))
2bd0ea18
NS
679 geo->sb_ialignbit = 1;
680
5e656dbb 681 if (xfs_sb_version_hasdalign(sbp))
2bd0ea18
NS
682 geo->sb_salignbit = 1;
683
b7fdeb4d 684 geo->sb_extflgbit = 1;
5f6f3660 685 geo->sb_fully_zeroed = 1;
2bd0ea18
NS
686}
687
688/*
689 * the way to verify that a primary sb is consistent with the
690 * filesystem is find the secondaries given the info in the
691 * primary and compare the geometries in the secondaries against
692 * the geometry indicated by the primary.
693 *
ae181820 694 * returns 0 if ok, else error code (XR_EOF, XR_INSUFF_SEC_SB, etc).
2bd0ea18
NS
695 */
696int
697verify_set_primary_sb(xfs_sb_t *rsb,
698 int sb_index,
699 int *sb_modified)
700{
507f4e33 701 xfs_off_t off;
2bd0ea18
NS
702 fs_geometry_t geo;
703 xfs_sb_t *sb;
704 fs_geo_list_t *list;
705 fs_geo_list_t *current;
2bd0ea18
NS
706 xfs_agnumber_t agno;
707 int num_sbs;
2bd0ea18
NS
708 int size;
709 int num_ok;
710 int retval;
f63fd268
DC
711
712 /*
713 * We haven't been able to validate the sector size yet properly
714 * (e.g. in the case of repairing an image in a file), so we need to
715 * take into account sector mismatches and so use the maximum possible
716 * sector size rather than the sector size in @rsb.
717 */
718 size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG));
2bd0ea18
NS
719 list = NULL;
720 num_ok = 0;
721 *sb_modified = 0;
8216a58f 722 num_sbs = rsb->sb_agcount;
2bd0ea18
NS
723
724 sb = (xfs_sb_t *) alloc_ag_buf(size);
2bd0ea18
NS
725
726 /*
727 * put the primary sb geometry info onto the geometry list
728 */
2bd0ea18
NS
729 get_sb_geometry(&geo, rsb);
730 list = add_geo(list, &geo, sb_index);
731
732 /*
8216a58f
BF
733 * scan the secondaries and check them off as we get them so we only
734 * process each one once
2bd0ea18 735 */
8216a58f
BF
736 for (agno = 1; agno < rsb->sb_agcount; agno++) {
737 off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
2bd0ea18 738
8216a58f
BF
739 retval = get_sb(sb, off, size, agno);
740 if (retval == XR_EOF)
741 goto out_free_list;
742
743 if (retval == XR_OK) {
744 /*
745 * save away geometry info. don't bother checking the
746 * sb against the agi/agf as the odds of the sb being
747 * corrupted in a way that it is internally consistent
748 * but not consistent with the rest of the filesystem is
749 * really really low.
750 */
751 get_sb_geometry(&geo, sb);
752 list = add_geo(list, &geo, agno);
753 num_ok++;
2bd0ea18
NS
754 }
755 }
756
757 /*
758 * see if we have enough superblocks to bother with
759 */
6d23d9a5 760 retval = 0;
548c2e3e
LZ
761 if (num_ok < num_sbs / 2) {
762 retval = XR_INSUFF_SEC_SB;
763 goto out_free_list;
764 }
2bd0ea18
NS
765
766 current = get_best_geo(list);
767
768 /*
769 * check that enough sbs agree that we're willing to
770 * go with this geometry. if not, print out the
771 * geometry and a message about the force option.
772 */
773 switch (num_sbs) {
774 case 2:
775 /*
d4dd6ab5
CH
776 * If we only have two allocation groups, and the superblock
777 * in the second allocation group differs from the primary
778 * superblock we can't verify the geometry information.
779 * Warn the user about this situation and get out unless
780 * explicitly overridden.
2bd0ea18
NS
781 */
782 if (current->refs != 2) {
783 if (!force_geo) {
507f4e33 784 do_warn(
d4dd6ab5
CH
785 _("Only two AGs detected and they do not match - "
786 "cannot validate filesystem geometry.\n"
787 "Use the -o force_geometry option to proceed.\n"));
2bd0ea18
NS
788 exit(1);
789 }
790 }
d4dd6ab5 791 goto out_free_list;
2bd0ea18
NS
792 case 1:
793 /*
d4dd6ab5
CH
794 * If we only have a single allocation group there is no
795 * secondary superblock that we can use to verify the geometry
796 * information. Warn the user about this situation and get
797 * out unless explicitly overridden.
2bd0ea18
NS
798 */
799 if (!force_geo) {
d4dd6ab5
CH
800 do_warn(
801 _("Only one AG detected - "
802 "cannot validate filesystem geometry.\n"
803 "Use the -o force_geometry option to proceed.\n"));
2bd0ea18
NS
804 exit(1);
805 }
d4dd6ab5 806 goto out_free_list;
2bd0ea18
NS
807 default:
808 /*
809 * at least half of the probed superblocks have
810 * to agree. if they don't, this fs is probably
811 * too far gone anyway considering the fact that
812 * XFS normally doesn't alter the secondary superblocks.
813 */
814 if (current->refs < num_sbs / 2) {
507f4e33
NS
815 do_warn(
816 _("Not enough matching superblocks - cannot proceed.\n"));
2bd0ea18
NS
817 exit(1);
818 }
819 }
820
821 /*
822 * set the geometry into primary superblock if necessary.
823 */
824
825 if (current->index != sb_index) {
826 *sb_modified = 1;
41f361f8 827 off = (xfs_off_t)current->index * current->geo.sb_agblocks
2bd0ea18
NS
828 * current->geo.sb_blocksize;
829 if (get_sb(sb, off, current->geo.sb_sectsize,
830 current->index) != XR_OK)
507f4e33 831 do_error(_("could not read superblock\n"));
2bd0ea18
NS
832
833 copy_sb(sb, rsb);
834
835 /*
836 * turn off inprogress bit since this is the primary.
837 * also save away values that we need to ensure are
838 * consistent in the other secondaries.
839 */
840 rsb->sb_inprogress = 0;
841 sb_inoalignmt = sb->sb_inoalignmt;
842 sb_unit = sb->sb_unit;
843 sb_width = sb->sb_width;
844 }
845
d4dd6ab5 846out_free_list:
2bd0ea18 847 free_geo(list);
2bd0ea18 848 free(sb);
6d23d9a5 849 return retval;
2bd0ea18 850}