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