]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/sb.c
Merge whitespace changes over
[thirdparty/xfsprogs-dev.git] / repair / sb.c
CommitLineData
2bd0ea18 1/*
0d3e0b37 2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
dfc130f3 3 *
2bd0ea18
NS
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
dfc130f3 7 *
2bd0ea18
NS
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dfc130f3 11 *
2bd0ea18
NS
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
dfc130f3 18 *
2bd0ea18
NS
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
dfc130f3 22 *
2bd0ea18
NS
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
dfc130f3
RC
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
2bd0ea18
NS
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
2bd0ea18 33#include <libxfs.h>
2bd0ea18
NS
34#include "agheader.h"
35#include "globals.h"
36#include "protos.h"
37#include "err_protos.h"
38
39
40/*
41 * copy the fields of a superblock that are present in primary and
42 * secondaries -- preserve fields that are different in the primary.
43 */
44void
45copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
46{
47 xfs_ino_t rootino;
48 xfs_ino_t rbmino;
49 xfs_ino_t rsumino;
50 xfs_ino_t uquotino;
b36eef04 51 xfs_ino_t gquotino;
2bd0ea18
NS
52 __uint16_t versionnum;
53
54 rootino = dest->sb_rootino;
55 rbmino = dest->sb_rbmino;
56 rsumino = dest->sb_rsumino;
57 uquotino = dest->sb_uquotino;
b36eef04 58 gquotino = dest->sb_gquotino;
2bd0ea18
NS
59
60 versionnum = dest->sb_versionnum;
61
62 *dest = *source;
63
64 dest->sb_rootino = rootino;
65 dest->sb_rbmino = rbmino;
66 dest->sb_rsumino = rsumino;
67 dest->sb_uquotino = uquotino;
b36eef04 68 dest->sb_gquotino = gquotino;
2bd0ea18
NS
69
70 dest->sb_versionnum = versionnum;
71
72 /*
73 * copy over version bits that are stamped into all
74 * secondaries and cannot be changed at run time in
75 * the primary superblock
76 */
77 if (XFS_SB_VERSION_HASDALIGN(source))
78 XFS_SB_VERSION_ADDDALIGN(dest);
79 if (XFS_SB_VERSION_HASEXTFLGBIT(source))
80 XFS_SB_VERSION_ADDEXTFLGBIT(dest);
81
82 /*
83 * these are all supposed to be zero or will get reset anyway
84 */
85 dest->sb_icount = 0;
86 dest->sb_ifree = 0;
87 dest->sb_fdblocks = 0;
88 dest->sb_frextents = 0;
89
90 bzero(source->sb_fname, 12);
91}
92
93#define BSIZE (1024 * 1024)
94
95/*
96 * find a secondary superblock, copy it into the sb buffer
97 */
98int
99find_secondary_sb(xfs_sb_t *rsb)
100{
101 xfs_off_t off;
102 xfs_sb_t *sb;
103 xfs_sb_t bufsb;
104 char *c_bufsb;
105 int done;
106 int i;
107 int dirty;
108 int retval;
109 int bsize;
110
507f4e33 111 do_warn(_("\nattempting to find secondary superblock...\n"));
2bd0ea18
NS
112
113 sb = (xfs_sb_t *) memalign(MEM_ALIGN, BSIZE);
114 if (!sb) {
115 do_error(
507f4e33 116 _("error finding secondary superblock -- failed to memalign buffer\n"));
2bd0ea18
NS
117 exit(1);
118 }
119
120 bzero(&bufsb, sizeof(xfs_sb_t));
121 retval = 0;
122 dirty = 0;
123 bsize = 0;
124
125 /*
126 * skip first sector since we know that's bad
127 */
128 for (done = 0, off = XFS_AG_MIN_BYTES; !done ; off += bsize) {
129 /*
130 * read disk 1 MByte at a time.
131 */
132 if (lseek64(fs_fd, off, SEEK_SET) != off) {
133 done = 1;
134 }
135
136 if (!done && (bsize = read(fs_fd, sb, BSIZE)) == 0) {
137 done = 1;
138 }
139
140 do_warn(".");
141
142 /*
143 * check the buffer 512 bytes at a time since
144 * we don't know how big the sectors really are.
145 */
146 for (i = 0; !done && i < bsize; i += BBSIZE) {
147 c_bufsb = (char *) sb + i;
148 libxfs_xlate_sb(c_bufsb, &bufsb, 1, ARCH_CONVERT,
149 XFS_SB_ALL_BITS);
150
151 if (verify_sb(&bufsb, 0) != XR_OK)
152 continue;
153
507f4e33 154 do_warn(_("found candidate secondary superblock...\n"));
2bd0ea18
NS
155
156 /*
157 * found one. now verify it by looking
158 * for other secondaries.
159 */
160 bcopy(&bufsb, rsb, bufsb.sb_sectsize);
161 rsb->sb_inprogress = 0;
162 clear_sunit = 1;
163
164 if (verify_set_primary_sb(rsb, 0, &dirty) == XR_OK) {
507f4e33
NS
165 do_warn(
166 _("verified secondary superblock...\n"));
2bd0ea18
NS
167 done = 1;
168 retval = 1;
169 } else {
170 do_warn(
507f4e33 171 _("unable to verify superblock, continuing...\n"));
2bd0ea18
NS
172 }
173 }
174 }
175
176 free(sb);
177 return(retval);
178}
179
180/*
181 * calculate what inode alignment field ought to be
182 * based on internal superblock info
183 */
184int
185calc_ino_align(xfs_sb_t *sb)
186{
187 xfs_extlen_t align;
188
189 align = XFS_INODE_BIG_CLUSTER_SIZE >> sb->sb_blocklog;
190
191 return(align);
192}
193
194/*
195 * verify a superblock -- does not verify root inode #
196 * can only check that geometry info is internally
197 * consistent. because of growfs, that's no guarantee
198 * of correctness (e.g. geometry may have changed)
199 *
200 * fields verified or consistency checked:
201 *
202 * sb_magicnum
203 *
204 * sb_versionnum
205 *
206 * sb_inprogress
207 *
208 * sb_blocksize (as a group)
209 * sb_blocklog
210 *
211 * geometry info - sb_dblocks (as a group)
212 * sb_agcount
213 * sb_agblocks
214 * sb_agblklog
215 *
216 * inode info - sb_inodesize (x-checked with geo info)
217 * sb_inopblock
218 *
219 * sector size info -
220 * sb_sectsize
221 * sb_sectlog
222 *
223 * not checked here -
224 * sb_rootino
225 * sb_fname
226 * sb_fpack
227 * sb_logstart
228 * sb_uuid
229 *
230 * ALL real-time fields
231 * final 4 summary counters
232 */
233
234int
235verify_sb(xfs_sb_t *sb, int is_primary_sb)
236{
237 __uint32_t bsize;
238 xfs_extlen_t align;
239 int i;
dfc130f3 240
2bd0ea18
NS
241 /* check magic number and version number */
242
243 if (sb->sb_magicnum != XFS_SB_MAGIC)
244 return(XR_BAD_MAGIC);
245
246 if (!XFS_SB_GOOD_VERSION(sb))
247 return(XR_BAD_VERSION);
248
249 /* does sb think mkfs really finished ? */
250
251 if (is_primary_sb && sb->sb_inprogress == 1)
252 return(XR_BAD_INPROGRESS);
253
254 /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
255
256 if (sb->sb_blocksize == 0)
257 return(XR_BAD_BLOCKSIZE);
258
259 bsize = 1;
260
261 for (i = 0; bsize < sb->sb_blocksize && i < 32; i++) {
262 bsize <<= 1;
263 }
264
265 if (i < XR_LOG2BSIZE_MIN || i > XR_LOG2BSIZE_MAX)
266 return(XR_BAD_BLOCKSIZE);
267
268 /* check sb blocksize field against sb blocklog field */
269
270 if (i != sb->sb_blocklog)
271 return(XR_BAD_BLOCKLOG);
272
273 /* sanity check ag count, size fields against data size field */
274
275 if (sb->sb_dblocks == 0 ||
276 sb->sb_dblocks > sb->sb_agcount * sb->sb_agblocks ||
277 sb->sb_dblocks < (sb->sb_agcount - 1)
278 * sb->sb_agblocks + XFS_MIN_AG_BLOCKS)
279 return(XR_BAD_FS_SIZE_DATA);
280
281 if (sb->sb_agblklog != (__uint8_t)libxfs_log2_roundup(sb->sb_agblocks))
282 return(XR_BAD_FS_SIZE_DATA);
283
284 if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE ||
285 sb->sb_inodesize > XFS_DINODE_MAX_SIZE ||
286 sb->sb_inopblock != howmany(sb->sb_blocksize,sb->sb_inodesize))
287 return(XR_BAD_INO_SIZE_DATA);
288
289 /* check sector size against log(sector size) field */
290
291 bsize = 1;
292
293 for (i = 0; bsize < sb->sb_sectsize && i < 15; i++) {
294 bsize <<= 1;
295 }
296
297 if (sb->sb_sectsize == 0 || i == 16 ||
298 sb->sb_sectsize != (1 << i))
299 return(XR_BAD_SECT_SIZE_DATA);
300
301 /*
302 * real-time extent size is always set
303 */
304 if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE)
305 return(XR_BAD_RT_GEO_DATA);
306
307 if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE)
308 return(XR_BAD_RT_GEO_DATA);
309
310 if (sb->sb_rblocks == 0) {
311 if (sb->sb_rextents != 0)
312 return(XR_BAD_RT_GEO_DATA);
313
314 if (sb->sb_rbmblocks != 0)
315 return(XR_BAD_RT_GEO_DATA);
316
317 if (sb->sb_rextslog != 0)
318 return(XR_BAD_RT_GEO_DATA);
319
320 if (sb->sb_frextents != 0)
321 return(XR_BAD_RT_GEO_DATA);
322 } else {
323 /*
324 * if we have a real-time partition, sanity-check geometry
325 */
326 if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents)
327 return(XR_BAD_RT_GEO_DATA);
328
329 if (sb->sb_rextslog !=
330 libxfs_highbit32((unsigned int)sb->sb_rextents))
331 return(XR_BAD_RT_GEO_DATA);
332
333 if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents,
334 NBBY * sb->sb_blocksize))
335 return(XR_BAD_RT_GEO_DATA);
336 }
337
338 /*
339 * verify correctness of inode alignment if it's there
340 */
341 if (XFS_SB_VERSION_HASALIGN(sb)) {
342 align = calc_ino_align(sb);
343
344 if (align != sb->sb_inoalignmt)
345 return(XR_BAD_INO_ALIGN);
346 }
347
348 /*
349 * verify max. % of inodes (sb_imax_pct)
350 */
351 if (sb->sb_imax_pct > 100)
352 return(XR_BAD_INO_MAX_PCT);
353
354 /*
355 * verify stripe alignment fields if present
356 */
357 if (XFS_SB_VERSION_HASDALIGN(sb)) {
dfc130f3
RC
358 if ((!sb->sb_unit && sb->sb_width) ||
359 (sb->sb_unit && sb->sb_agblocks % sb->sb_unit))
2bd0ea18
NS
360 return(XR_BAD_SB_UNIT);
361 if ((sb->sb_unit && !sb->sb_width) ||
362 (sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit))
363 return(XR_BAD_SB_WIDTH);
364 }
365
366 /*
367 * if shared bit is set, verify that the version number is sane
368 */
369 if (XFS_SB_VERSION_HASSHARED(sb)) {
370 if (sb->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
371 return(XR_BAD_SVN);
372 }
373
374 /*
375 * mkfs's that stamped a feature bit besides the ones in the
376 * mask below could leave garbage in the secondary superblock
377 * sectors. Anything stamping the shared fs bit or better into
378 * the secondaries is ok and should generate clean secondary
379 * superblock sectors.
380 *
381 * check primary and clean secondary superblocks more strictly
382 */
383 if (is_primary_sb || sb->sb_versionnum & XR_PART_SECSB_VNMASK) {
384 /*
385 * return errors if shared vn or alignment fields
386 * are set without their feature bits being set
387 */
27527004
NS
388 if ((!pre_65_beta && (sb->sb_versionnum & XR_PART_SECSB_VNMASK)) ||
389 (pre_65_beta && (sb->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) {
2bd0ea18
NS
390 /*
391 * shared version # and inode alignment fields
392 * should be valid
393 */
394 if (sb->sb_shared_vn && !XFS_SB_VERSION_HASSHARED(sb))
395 return(XR_BAD_SVN);
396 if (sb->sb_inoalignmt && !XFS_SB_VERSION_HASALIGN(sb))
397 return(XR_BAD_INO_ALIGN);
398 }
399 if ((!pre_65_beta &&
400 (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK)) ||
401 (pre_65_beta &&
402 (sb->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))) {
403 /*
404 * stripe alignment values should be valid
405 */
406 if (sb->sb_unit && !XFS_SB_VERSION_HASDALIGN(sb))
407 return(XR_BAD_SB_UNIT);
408 if (sb->sb_width && !XFS_SB_VERSION_HASDALIGN(sb))
409 return(XR_BAD_SB_WIDTH);
410 }
411
412#if 0
413 /*
414 * checks involving later superblock fields get added here...
415 */
416 if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) {
417 }
418#endif
419 }
420
421 return(XR_OK);
422}
423
424void
425write_primary_sb(xfs_sb_t *sbp, int size)
426{
dfc130f3
RC
427 void *buf;
428
2bd0ea18
NS
429 if (no_modify)
430 return;
dfc130f3
RC
431
432 if ((buf = calloc(size, 1)) == NULL) {
507f4e33 433 do_error(_("failed to malloc superblock buffer\n"));
dfc130f3 434 return;
2bd0ea18
NS
435 }
436
437 if (lseek64(fs_fd, 0LL, SEEK_SET) != 0LL) {
dfc130f3 438 free(buf);
507f4e33 439 do_error(_("couldn't seek to offset 0 in filesystem\n"));
dfc130f3
RC
440 }
441
2bd0ea18
NS
442 libxfs_xlate_sb(buf, sbp, -1, ARCH_CONVERT, XFS_SB_ALL_BITS);
443
444 if (write(fs_fd, buf, size) != size) {
dfc130f3 445 free(buf);
507f4e33 446 do_error(_("primary superblock write failed!\n"));
dfc130f3 447 }
2bd0ea18 448
dfc130f3 449 free(buf);
2bd0ea18
NS
450}
451
452/*
453 * get a possible superblock -- don't check for internal consistency
454 */
455int
456get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno)
457{
458 int error, rval;
dfc130f3
RC
459 void *buf;
460
461 if ((buf = calloc(size, 1)) == NULL) {
2bd0ea18 462 do_error(
507f4e33 463 _("error reading superblock %u -- failed to malloc buffer\n"),
2bd0ea18
NS
464 agno, off);
465 exit(1);
466 }
467
468 /* try and read it first */
469
470 if (lseek64(fs_fd, off, SEEK_SET) != off) {
471 do_warn(
507f4e33 472 _("error reading superblock %u -- seek to offset %lld failed\n"),
2bd0ea18
NS
473 agno, off);
474 return(XR_EOF);
475 }
476
477 if ((rval = read(fs_fd, buf, size)) != size) {
478 error = errno;
479 do_warn(
507f4e33 480 _("superblock read failed, offset %lld, size %d, ag %u, rval %d\n"),
2bd0ea18
NS
481 off, size, rval, agno);
482 do_error("%s\n", strerror(error));
483 }
484 libxfs_xlate_sb(buf, sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
485 free(buf);
486
487 return (verify_sb(sbp, 0));
488}
489
490#if 0
491int
492check_growfs(xfs_off_t off, int bufnum, xfs_agnumber_t agnum)
493{
494 int rval;
495
496 ASSERT(bufnum < NUM_SBS);
497
498 /* try and read it first */
499
500 if (lseek64(fs_fd, off, SEEK_SET) != off)
501 return(XR_EOF);
502
503 if ((rval = read(fs_fd, sb_bufs[bufnum], sbbuf_size)) != sbbuf_size) {
504 /*
505 * we didn't get a full block so the filesystem
506 * could not have been grown. return a non-XR_OK
507 * result code.
508 */
509 return(XR_EOF);
510 }
511
512 return(get_sb(off, bufnum, agnum));
513}
514#endif
515/* returns element on list with highest reference count */
516
517fs_geo_list_t *
518get_best_geo(fs_geo_list_t *list)
519{
520 int cnt = 0;
521 fs_geo_list_t *current, *rval = NULL;
522
523 current = list;
524
525 while (current != NULL) {
526 if (current->refs > cnt) {
527 rval = current;
528 cnt = current->refs;
529 }
530 current = current->next;
531 }
532
533 return(rval);
534}
535
536/* adds geometry info to linked list. returns (sometimes new) head of list */
537
538fs_geo_list_t *
539add_geo(fs_geo_list_t *list, fs_geometry_t *geo_p, int index)
540{
541 fs_geo_list_t *current = list;
dfc130f3 542
2bd0ea18
NS
543 while (current != NULL) {
544 if (memcmp(geo_p, &current->geo, sizeof(fs_geometry_t)) == 0) {
545 current->refs++;
546 return(list);
547 }
548
549 current = current->next;
550 }
551
552 if ((current = malloc(sizeof(fs_geo_list_t))) == NULL) {
507f4e33 553 do_error(_("couldn't malloc geometry structure\n"));
2bd0ea18
NS
554 exit(1);
555 }
556
557 current->geo = *geo_p;
558 current->refs = 1;
559 current->next = list;
560 current->index = index;
561
562 return(current);
563}
564
565void
566free_geo(fs_geo_list_t *list)
567{
568 fs_geo_list_t *next;
569 fs_geo_list_t *current;
570
571 current = list;
572
573 for (current = list; current != NULL; current = next) {
574 next = current->next;
575 free(current);
576 }
577}
578
579void
580get_sb_geometry(fs_geometry_t *geo, xfs_sb_t *sbp)
581{
582 bzero(geo, sizeof(fs_geometry_t));
583
584 /*
585 * blindly set fields that we know are always good
586 */
587 geo->sb_blocksize = sbp->sb_blocksize;
588 geo->sb_dblocks = sbp->sb_dblocks;
589 geo->sb_rblocks = sbp->sb_rblocks;
590 geo->sb_rextents = sbp->sb_rextents;
591 geo->sb_logstart = sbp->sb_logstart;
592 geo->sb_rextsize = sbp->sb_rextsize;
593 geo->sb_agblocks = sbp->sb_agblocks;
594 geo->sb_agcount = sbp->sb_agcount;
595 geo->sb_rbmblocks = sbp->sb_rbmblocks;
596 geo->sb_logblocks = sbp->sb_logblocks;
597 geo->sb_sectsize = sbp->sb_sectsize;
598 geo->sb_inodesize = sbp->sb_inodesize;
599
600 if (XFS_SB_VERSION_HASALIGN(sbp))
601 geo->sb_ialignbit = 1;
602
603 if (XFS_SB_VERSION_HASSHARED(sbp) ||
604 sbp->sb_versionnum & XR_PART_SECSB_VNMASK)
605 geo->sb_sharedbit = 1;
606
607 if (XFS_SB_VERSION_HASDALIGN(sbp))
608 geo->sb_salignbit = 1;
609
610 if (XFS_SB_VERSION_HASEXTFLGBIT(sbp))
611 geo->sb_extflgbit = 1;
612
613 /*
614 * protect against pre-6.5 mkfs-generated garbaged
615 * fields in the secondary superblocks. pay attention
616 * to those fields if and only if their corresponding
617 * feature bits are set in the feature bits of the
618 * version number or we can deduce from the version bits
619 * that are set that our field was properly initialized
620 * because a field after the field we care about was
621 * properly initialized as well.
622 */
623
624 /*
625 * inode alignment field lives before the data alignment field
626 */
27527004
NS
627 if ((!pre_65_beta && (sbp->sb_versionnum & XR_PART_SECSB_VNMASK)) ||
628 (pre_65_beta && (sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK)))
2bd0ea18
NS
629 geo->sb_inoalignmt = sbp->sb_inoalignmt;
630
27527004
NS
631 if ((!pre_65_beta && (sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK)) ||
632 (pre_65_beta && XFS_SB_VERSION_HASDALIGN(sbp))) {
2bd0ea18
NS
633 geo->sb_unit = sbp->sb_unit;
634 geo->sb_width = sbp->sb_width;
635 }
636
637 /*
638 * shared vn always set if either ino or data alignment is on
639 * since that field lives between the quota and inode alignment
640 * fields
641 */
642 if (sbp->sb_versionnum & XR_PART_SECSB_VNMASK)
643 geo->sb_shared_vn = sbp->sb_shared_vn;
644
645 /*
646 * superblock fields located after sb_widthfields get set
647 * into the geometry structure only if we can determine
648 * from the features enabled in this superblock whether
649 * or not the sector was bzero'd at mkfs time.
650 */
27527004
NS
651 if ((!pre_65_beta && (sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK)) ||
652 (pre_65_beta && (sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) {
2bd0ea18
NS
653 geo->sb_fully_zeroed = 1;
654 }
655}
656
657/*
658 * the way to verify that a primary sb is consistent with the
659 * filesystem is find the secondaries given the info in the
660 * primary and compare the geometries in the secondaries against
661 * the geometry indicated by the primary.
662 *
663 * returns 1 if bad, 0 if ok
664 */
665int
666verify_set_primary_sb(xfs_sb_t *rsb,
667 int sb_index,
668 int *sb_modified)
669{
507f4e33 670 xfs_off_t off;
2bd0ea18
NS
671 fs_geometry_t geo;
672 xfs_sb_t *sb;
673 fs_geo_list_t *list;
674 fs_geo_list_t *current;
675 char *checked;
676 xfs_agnumber_t agno;
677 int num_sbs;
678 int skip;
679 int size;
680 int num_ok;
681 int retval;
682 int round;
683
684 /*
685 * select the number of secondaries to try for
686 */
687 num_sbs = MIN(NUM_SBS, rsb->sb_agcount);
688 skip = howmany(num_sbs, rsb->sb_agcount);
689 size = NUM_AGH_SECTS * rsb->sb_sectsize;
690 retval = 0;
691 list = NULL;
692 num_ok = 0;
693 *sb_modified = 0;
694
695 sb = (xfs_sb_t *) alloc_ag_buf(size);
696 checked = calloc(rsb->sb_agcount, sizeof(char));
697 if (!checked) {
507f4e33 698 do_error(_("calloc failed in verify_set_primary_sb\n"));
2bd0ea18
NS
699 exit(1);
700 }
701
702 /*
703 * put the primary sb geometry info onto the geometry list
704 */
705 checked[sb_index] = 1;
706 get_sb_geometry(&geo, rsb);
707 list = add_geo(list, &geo, sb_index);
708
709 /*
710 * grab N secondaries. check them off as we get them
711 * so we only process each one once
712 */
713 for (round = 0; round < skip; round++) {
714 for (agno = round; agno < rsb->sb_agcount; agno += skip) {
715 if (checked[agno])
716 continue;
717
718 off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
719
720 checked[agno] = 1;
721
722 if (get_sb(sb, off, size, agno) == XR_EOF) {
723 retval = 1;
724 goto out;
725 }
726
727 if (verify_sb(sb, 0) == XR_OK) {
728 /*
729 * save away geometry info.
730 * don't bother checking the sb
731 * against the agi/agf as the odds
732 * of the sb being corrupted in a way
733 * that it is internally consistent
734 * but not consistent with the rest
735 * of the filesystem is really really low.
736 */
737 get_sb_geometry(&geo, sb);
738 list = add_geo(list, &geo, agno);
739 num_ok++;
740 }
741 }
742 }
743
744 /*
745 * see if we have enough superblocks to bother with
746 */
747 if (num_ok < num_sbs / 2)
748 return(XR_INSUFF_SEC_SB);
749
750 current = get_best_geo(list);
751
752 /*
753 * check that enough sbs agree that we're willing to
754 * go with this geometry. if not, print out the
755 * geometry and a message about the force option.
756 */
757 switch (num_sbs) {
758 case 2:
759 /*
760 * all them have to be right. if not, report geometry
761 * and get out unless force option is in effect (-F)
762 */
763 if (current->refs != 2) {
764 if (!force_geo) {
507f4e33
NS
765 do_warn(
766 _("Only two AGs detected and they do not match - cannot proceed.\n"));
2bd0ea18
NS
767 exit(1);
768 }
769 }
770 break;
771 case 1:
772 /*
773 * just report the geometry info and get out.
774 * refuse to run further unless the force (-F)
775 * option is in effect.
776 */
777 if (!force_geo) {
507f4e33 778 do_warn(_("Only one AG detected - cannot proceed.\n"));
2bd0ea18
NS
779 exit(1);
780 }
781 default:
782 /*
783 * at least half of the probed superblocks have
784 * to agree. if they don't, this fs is probably
785 * too far gone anyway considering the fact that
786 * XFS normally doesn't alter the secondary superblocks.
787 */
788 if (current->refs < num_sbs / 2) {
507f4e33
NS
789 do_warn(
790 _("Not enough matching superblocks - cannot proceed.\n"));
2bd0ea18
NS
791 exit(1);
792 }
793 }
794
795 /*
796 * set the geometry into primary superblock if necessary.
797 */
798
799 if (current->index != sb_index) {
800 *sb_modified = 1;
dfc130f3 801 off = current->index * current->geo.sb_agblocks
2bd0ea18
NS
802 * current->geo.sb_blocksize;
803 if (get_sb(sb, off, current->geo.sb_sectsize,
804 current->index) != XR_OK)
507f4e33 805 do_error(_("could not read superblock\n"));
2bd0ea18
NS
806
807 copy_sb(sb, rsb);
808
809 /*
810 * turn off inprogress bit since this is the primary.
811 * also save away values that we need to ensure are
812 * consistent in the other secondaries.
813 */
814 rsb->sb_inprogress = 0;
815 sb_inoalignmt = sb->sb_inoalignmt;
816 sb_unit = sb->sb_unit;
817 sb_width = sb->sb_width;
818 }
819
820 free_geo(list);
821out:
822 free(sb);
823 free(checked);
824 return(retval);
825}