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