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