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