+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
*/
-
-#include <errno.h>
-#include <libxfs.h>
-#include <malloc.h>
+#include "libfrog.h"
+#include "libxfs.h"
+#include "libxcmd.h"
+#include "libxlog.h"
#include "agheader.h"
#include "globals.h"
#include "protos.h"
#include "err_protos.h"
+#include "xfs_multidisk.h"
+#define BSIZE (1024 * 1024)
/*
* copy the fields of a superblock that are present in primary and
* secondaries -- preserve fields that are different in the primary.
*/
-void
+static void
copy_sb(xfs_sb_t *source, xfs_sb_t *dest)
{
xfs_ino_t rootino;
xfs_ino_t rbmino;
xfs_ino_t rsumino;
xfs_ino_t uquotino;
+ xfs_ino_t gquotino;
xfs_ino_t pquotino;
- __uint16_t versionnum;
+ uint16_t versionnum;
rootino = dest->sb_rootino;
rbmino = dest->sb_rbmino;
rsumino = dest->sb_rsumino;
uquotino = dest->sb_uquotino;
+ gquotino = dest->sb_gquotino;
pquotino = dest->sb_pquotino;
versionnum = dest->sb_versionnum;
dest->sb_rbmino = rbmino;
dest->sb_rsumino = rsumino;
dest->sb_uquotino = uquotino;
+ dest->sb_gquotino = gquotino;
dest->sb_pquotino = pquotino;
dest->sb_versionnum = versionnum;
* secondaries and cannot be changed at run time in
* the primary superblock
*/
- if (XFS_SB_VERSION_HASDALIGN(source))
- XFS_SB_VERSION_ADDDALIGN(dest);
- if (XFS_SB_VERSION_HASEXTFLGBIT(source))
- XFS_SB_VERSION_ADDEXTFLGBIT(dest);
+ if (xfs_sb_version_hasdalign(source))
+ dest->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT;
+ dest->sb_versionnum |= XFS_SB_VERSION_EXTFLGBIT;
/*
* these are all supposed to be zero or will get reset anyway
dest->sb_fdblocks = 0;
dest->sb_frextents = 0;
- bzero(source->sb_fname, 12);
+ memset(source->sb_fname, 0, 12);
}
-#define BSIZE (1024 * 1024)
+static int
+verify_sb_blocksize(xfs_sb_t *sb)
+{
+ /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
+ if (sb->sb_blocksize == 0)
+ return XR_BAD_BLOCKSIZE;
+ if (sb->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
+ sb->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG)
+ return XR_BAD_BLOCKLOG;
+ if (sb->sb_blocksize != (1 << sb->sb_blocklog))
+ return XR_BAD_BLOCKLOG;
+
+ return 0;
+}
/*
- * find a secondary superblock, copy it into the sb buffer
+ * find a secondary superblock, copy it into the sb buffer.
+ * start is the point to begin reading BSIZE bytes.
+ * skip contains a byte-count of how far to advance for next read.
*/
-int
-find_secondary_sb(xfs_sb_t *rsb)
+static int
+__find_secondary_sb(
+ xfs_sb_t *rsb,
+ uint64_t start,
+ uint64_t skip)
{
xfs_off_t off;
xfs_sb_t *sb;
int retval;
int bsize;
- do_warn("\nattempting to find secondary superblock...\n");
-
- sb = (xfs_sb_t *) memalign(MEM_ALIGN, BSIZE);
+ sb = (xfs_sb_t *)memalign(libxfs_device_alignment(), BSIZE);
if (!sb) {
do_error(
- "error finding secondary superblock -- failed to memalign buffer\n");
+ _("error finding secondary superblock -- failed to memalign buffer\n"));
exit(1);
}
- bzero(&bufsb, sizeof(xfs_sb_t));
+ memset(&bufsb, 0, sizeof(xfs_sb_t));
retval = 0;
dirty = 0;
bsize = 0;
/*
* skip first sector since we know that's bad
*/
- for (done = 0, off = XFS_AG_MIN_BYTES; !done ; off += bsize) {
+ for (done = 0, off = start; !done ; off += skip) {
/*
* read disk 1 MByte at a time.
*/
- if (lseek64(fs_fd, off, SEEK_SET) != off) {
+ if (lseek(x.dfd, off, SEEK_SET) != off) {
done = 1;
}
- if (!done && (bsize = read(fs_fd, sb, BSIZE)) == 0) {
+ if (!done && (bsize = read(x.dfd, sb, BSIZE)) <= 0) {
done = 1;
}
* we don't know how big the sectors really are.
*/
for (i = 0; !done && i < bsize; i += BBSIZE) {
- c_bufsb = (char *) sb + i;
- libxfs_xlate_sb(c_bufsb, &bufsb, 1, ARCH_CONVERT,
- XFS_SB_ALL_BITS);
+ c_bufsb = (char *)sb + i;
+ libxfs_sb_from_disk(&bufsb, (xfs_dsb_t *)c_bufsb);
- if (verify_sb(&bufsb, 0) != XR_OK)
+ if (verify_sb(c_bufsb, &bufsb, 0) != XR_OK)
continue;
- do_warn("found candidate secondary superblock...\n");
+ do_warn(_("found candidate secondary superblock...\n"));
/*
* found one. now verify it by looking
* for other secondaries.
*/
- bcopy(&bufsb, rsb, bufsb.sb_sectsize);
+ memmove(rsb, &bufsb, sizeof(xfs_sb_t));
rsb->sb_inprogress = 0;
- clear_sunit = 1;
+ copied_sunit = 1;
if (verify_set_primary_sb(rsb, 0, &dirty) == XR_OK) {
- do_warn("verified secondary superblock...\n");
+ do_warn(
+ _("verified secondary superblock...\n"));
done = 1;
retval = 1;
} else {
do_warn(
- "unable to verify superblock, continuing...\n");
+ _("unable to verify superblock, continuing...\n"));
}
}
}
free(sb);
- return(retval);
+ return retval;
+}
+
+static int
+guess_default_geometry(
+ uint64_t *agsize,
+ uint64_t *agcount,
+ libxfs_init_t *x)
+{
+ struct fs_topology ft;
+ int blocklog;
+ uint64_t dblocks;
+ int multidisk;
+
+ memset(&ft, 0, sizeof(ft));
+ get_topology(x, &ft, 1);
+
+ /*
+ * get geometry from get_topology result.
+ * Use default block size (2^12)
+ */
+ blocklog = 12;
+ multidisk = ft.dswidth | ft.dsunit;
+ dblocks = x->dsize >> (blocklog - BBSHIFT);
+ calc_default_ag_geometry(blocklog, dblocks, multidisk,
+ agsize, agcount);
+
+ return blocklog;
+}
+
+int
+find_secondary_sb(xfs_sb_t *rsb)
+{
+ int retval = 0;
+ uint64_t agcount;
+ uint64_t agsize;
+ uint64_t skip;
+ int blocklog;
+
+ /*
+ * Attempt to find secondary sb with a coarse approach,
+ * first trying agblocks and blocksize read from sb, providing
+ * they're sane.
+ */
+ do_warn(_("\nattempting to find secondary superblock...\n"));
+
+ if (verify_sb_blocksize(rsb) == 0) {
+ skip = (uint64_t)rsb->sb_agblocks * rsb->sb_blocksize;
+ if (skip >= XFS_AG_MIN_BYTES && skip <= XFS_AG_MAX_BYTES)
+ retval = __find_secondary_sb(rsb, skip, skip);
+ }
+
+ /* If that failed, retry coarse approach, using default geometry */
+ if (!retval) {
+ blocklog = guess_default_geometry(&agsize, &agcount, &x);
+ skip = agsize << blocklog;
+ retval = __find_secondary_sb(rsb, skip, skip);
+ }
+
+ /* If that failed, fall back to the brute force method */
+ if (!retval)
+ retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE);
+
+ return retval;
}
/*
- * calculate what inode alignment field ought to be
- * based on internal superblock info
+ * Calculate what the inode alignment field ought to be based on internal
+ * superblock info and determine if it is valid.
+ *
+ * For standard v5 superblocks, the inode alignment must either match
+ * XFS_INODE_BIG_CLUSTER_SIZE or a multiple based on the inode size. For v5
+ * superblocks with sparse inode chunks enabled, inode alignment must match the
+ * inode chunk size.
+ *
+ * Return true if the alignment is valid, false otherwise.
*/
-int
-calc_ino_align(xfs_sb_t *sb)
+static bool
+sb_validate_ino_align(struct xfs_sb *sb)
{
- xfs_extlen_t align;
+ xfs_extlen_t align;
+
+ if (!xfs_sb_version_hasalign(sb))
+ return true;
+ /* standard cluster size alignment is always valid */
align = XFS_INODE_BIG_CLUSTER_SIZE >> sb->sb_blocklog;
+ if (align == sb->sb_inoalignmt)
+ return true;
+
+ /* alignment scaled by inode size is v5 only for now */
+ if (!xfs_sb_version_hascrc(sb))
+ return false;
+
+ align = (XFS_INODE_BIG_CLUSTER_SIZE *
+ sb->sb_inodesize / XFS_DINODE_MIN_SIZE) >> sb->sb_blocklog;
+ if (align == sb->sb_inoalignmt)
+ return true;
- return(align);
+ /*
+ * Sparse inodes requires inoalignmt to match full inode chunk size and
+ * spino_align to match the scaled alignment (as calculated above).
+ */
+ if (xfs_sb_version_hassparseinodes(sb)) {
+ if (align != sb->sb_spino_align)
+ return false;
+
+ align = (sb->sb_inodesize * XFS_INODES_PER_CHUNK)
+ >> sb->sb_blocklog;
+ if (align == sb->sb_inoalignmt)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Validate the given log space. Derived from xfs_log_mount, though we
+ * can't validate the minimum log size until later. We only do this
+ * validation on V5 filesystems because the kernel doesn't reject malformed
+ * log geometry on older revision filesystems.
+ *
+ * Returns false if the log is garbage.
+ */
+static bool
+verify_sb_loginfo(
+ struct xfs_sb *sb)
+{
+ if (xfs_sb_version_hascrc(sb) &&
+ (sb->sb_logblocks == 0 ||
+ sb->sb_logblocks > XFS_MAX_LOG_BLOCKS ||
+ ((unsigned long long)sb->sb_logblocks << sb->sb_blocklog) >
+ XFS_MAX_LOG_BYTES))
+ return false;
+
+ if (sb->sb_logsunit > 1 && sb->sb_logsunit % sb->sb_blocksize)
+ return false;
+
+ return true;
}
/*
* sector size info -
* sb_sectsize
* sb_sectlog
+ * sb_logsectsize
+ * sb_logsectlog
*
* not checked here -
* sb_rootino
*/
int
-verify_sb(xfs_sb_t *sb, int is_primary_sb)
+verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
{
- __uint32_t bsize;
- xfs_extlen_t align;
+ uint32_t bsize;
int i;
-
+ int ret;
+
/* check magic number and version number */
if (sb->sb_magicnum != XFS_SB_MAGIC)
return(XR_BAD_MAGIC);
- if (!XFS_SB_GOOD_VERSION(sb))
+ if (!xfs_sb_good_version(sb))
return(XR_BAD_VERSION);
/* does sb think mkfs really finished ? */
if (is_primary_sb && sb->sb_inprogress == 1)
return(XR_BAD_INPROGRESS);
- /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */
+ /*
+ * before going *any further*, validate the sector size and if the
+ * version says we should have CRCs enabled, validate that.
+ */
- if (sb->sb_blocksize == 0)
- return(XR_BAD_BLOCKSIZE);
+ /* check to make sure sectorsize is legal 2^N, 9 <= N <= 15 */
+ if (sb->sb_sectsize == 0)
+ return(XR_BAD_SECT_SIZE_DATA);
bsize = 1;
-
- for (i = 0; bsize < sb->sb_blocksize && i < 32; i++) {
+ for (i = 0; bsize < sb->sb_sectsize &&
+ i < sizeof(sb->sb_sectsize) * NBBY; i++) {
bsize <<= 1;
}
- if (i < XR_LOG2BSIZE_MIN || i > XR_LOG2BSIZE_MAX)
- return(XR_BAD_BLOCKSIZE);
+ if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG)
+ return(XR_BAD_SECT_SIZE_DATA);
+
+ /* check sb sectorsize field against sb sectlog field */
+ if (i != sb->sb_sectlog)
+ return(XR_BAD_SECT_SIZE_DATA);
- /* check sb blocksize field against sb blocklog field */
+ /* sector size in range - CRC check time */
+ if (xfs_sb_version_hascrc(sb) &&
+ !libxfs_verify_cksum(sb_buf, sb->sb_sectsize, XFS_SB_CRC_OFF))
+ return XR_BAD_CRC;
- if (i != sb->sb_blocklog)
- return(XR_BAD_BLOCKLOG);
+ /* check to ensure blocksize and blocklog are legal */
+ ret = verify_sb_blocksize(sb);
+ if (ret != 0)
+ return ret;
/* sanity check ag count, size fields against data size field */
if (sb->sb_dblocks == 0 ||
- sb->sb_dblocks > sb->sb_agcount * sb->sb_agblocks ||
- sb->sb_dblocks < (sb->sb_agcount - 1)
- * sb->sb_agblocks + XFS_MIN_AG_BLOCKS)
+ sb->sb_dblocks > XFS_MAX_DBLOCKS(sb) ||
+ sb->sb_dblocks < XFS_MIN_DBLOCKS(sb))
return(XR_BAD_FS_SIZE_DATA);
- if (sb->sb_agblklog != (__uint8_t)libxfs_log2_roundup(sb->sb_agblocks))
+ if (sb->sb_agblklog != (uint8_t)log2_roundup(sb->sb_agblocks))
return(XR_BAD_FS_SIZE_DATA);
- if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE ||
- sb->sb_inodesize > XFS_DINODE_MAX_SIZE ||
- sb->sb_inopblock != howmany(sb->sb_blocksize,sb->sb_inodesize))
- return(XR_BAD_INO_SIZE_DATA);
+ if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE ||
+ sb->sb_inodesize > XFS_DINODE_MAX_SIZE ||
+ sb->sb_inodelog < XFS_DINODE_MIN_LOG ||
+ sb->sb_inodelog > XFS_DINODE_MAX_LOG ||
+ sb->sb_inodesize != (1 << sb->sb_inodelog) ||
+ sb->sb_logsunit > XLOG_MAX_RECORD_BSIZE ||
+ sb->sb_inopblock != howmany(sb->sb_blocksize, sb->sb_inodesize) ||
+ (sb->sb_blocklog - sb->sb_inodelog != sb->sb_inopblog))
+ return XR_BAD_INO_SIZE_DATA;
- /* check sector size against log(sector size) field */
+ if (!verify_sb_loginfo(sb))
+ return XR_BAD_LOG_GEOMETRY;
- bsize = 1;
+ if (xfs_sb_version_hassector(sb)) {
- for (i = 0; bsize < sb->sb_sectsize && i < 15; i++) {
- bsize <<= 1;
- }
+ /* check to make sure log sector is legal 2^N, 9 <= N <= 15 */
- if (sb->sb_sectsize == 0 || i == 16 ||
- sb->sb_sectsize != (1 << i))
- return(XR_BAD_SECT_SIZE_DATA);
+ if (sb->sb_logsectsize == 0)
+ return(XR_BAD_SECT_SIZE_DATA);
+
+ bsize = 1;
+
+ for (i = 0; bsize < sb->sb_logsectsize &&
+ i < sizeof(sb->sb_logsectsize) * NBBY; i++) {
+ bsize <<= 1;
+ }
+
+ if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG)
+ return(XR_BAD_SECT_SIZE_DATA);
+
+ /* check sb log sectorsize field against sb log sectlog field */
+
+ if (i != sb->sb_logsectlog)
+ return(XR_BAD_SECT_SIZE_DATA);
+ }
/*
* real-time extent size is always set
/*
* verify correctness of inode alignment if it's there
*/
- if (XFS_SB_VERSION_HASALIGN(sb)) {
- align = calc_ino_align(sb);
-
- if (align != sb->sb_inoalignmt)
- return(XR_BAD_INO_ALIGN);
- }
+ if (!sb_validate_ino_align(sb))
+ return(XR_BAD_INO_ALIGN);
/*
* verify max. % of inodes (sb_imax_pct)
/*
* verify stripe alignment fields if present
*/
- if (XFS_SB_VERSION_HASDALIGN(sb)) {
- if ((!sb->sb_unit && sb->sb_width) ||
- (sb->sb_unit && sb->sb_agblocks % sb->sb_unit))
+ if (xfs_sb_version_hasdalign(sb)) {
+ if ((!sb->sb_unit && sb->sb_width) ||
+ (sb->sb_unit && sb->sb_agblocks % sb->sb_unit))
return(XR_BAD_SB_UNIT);
if ((sb->sb_unit && !sb->sb_width) ||
(sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit))
return(XR_BAD_SB_WIDTH);
- }
+ } else if (sb->sb_unit || sb->sb_width)
+ return XR_BAD_SB_WIDTH;
- /*
- * if shared bit is set, verify that the version number is sane
- */
- if (XFS_SB_VERSION_HASSHARED(sb)) {
- if (sb->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
- return(XR_BAD_SVN);
- }
-
- /*
- * mkfs's that stamped a feature bit besides the ones in the
- * mask below could leave garbage in the secondary superblock
- * sectors. Anything stamping the shared fs bit or better into
- * the secondaries is ok and should generate clean secondary
- * superblock sectors.
- *
- * check primary and clean secondary superblocks more strictly
- */
- if (is_primary_sb || sb->sb_versionnum & XR_PART_SECSB_VNMASK) {
- /*
- * return errors if shared vn or alignment fields
- * are set without their feature bits being set
- */
- if (!pre_65_beta && sb->sb_versionnum & XR_PART_SECSB_VNMASK ||
- pre_65_beta && sb->sb_versionnum & XR_ALPHA_SECSB_VNMASK) {
- /*
- * shared version # and inode alignment fields
- * should be valid
- */
- if (sb->sb_shared_vn && !XFS_SB_VERSION_HASSHARED(sb))
- return(XR_BAD_SVN);
- if (sb->sb_inoalignmt && !XFS_SB_VERSION_HASALIGN(sb))
- return(XR_BAD_INO_ALIGN);
- }
- if ((!pre_65_beta &&
- (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK)) ||
- (pre_65_beta &&
- (sb->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))) {
- /*
- * stripe alignment values should be valid
- */
- if (sb->sb_unit && !XFS_SB_VERSION_HASDALIGN(sb))
- return(XR_BAD_SB_UNIT);
- if (sb->sb_width && !XFS_SB_VERSION_HASDALIGN(sb))
- return(XR_BAD_SB_WIDTH);
- }
-
-#if 0
- /*
- * checks involving later superblock fields get added here...
- */
- if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) {
- }
-#endif
- }
+ /* Directory block log */
+ if (sb->sb_blocklog + sb->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG)
+ return XR_BAD_DIR_SIZE_DATA;
return(XR_OK);
}
void
write_primary_sb(xfs_sb_t *sbp, int size)
{
- void *buf;
-
+ xfs_dsb_t *buf;
+
if (no_modify)
return;
-
- if ((buf = calloc(size, 1)) == NULL) {
- do_error("failed to malloc superblock buffer\n");
- return;
+
+ buf = memalign(libxfs_device_alignment(), size);
+ if (buf == NULL) {
+ do_error(_("failed to memalign superblock buffer\n"));
+ return;
}
+ memset(buf, 0, size);
- if (lseek64(fs_fd, 0LL, SEEK_SET) != 0LL) {
- free(buf);
- do_error("couldn't seek to offset 0 in filesystem\n");
- }
-
- libxfs_xlate_sb(buf, sbp, -1, ARCH_CONVERT, XFS_SB_ALL_BITS);
+ if (lseek(x.dfd, 0LL, SEEK_SET) != 0LL) {
+ free(buf);
+ do_error(_("couldn't seek to offset 0 in filesystem\n"));
+ }
- if (write(fs_fd, buf, size) != size) {
- free(buf);
- do_error("primary superblock write failed!\n");
- }
+ libxfs_sb_to_disk(buf, sbp);
+
+ if (xfs_sb_version_hascrc(sbp))
+ xfs_update_cksum((char *)buf, size, XFS_SB_CRC_OFF);
+
+ if (write(x.dfd, buf, size) != size) {
+ free(buf);
+ do_error(_("primary superblock write failed!\n"));
+ }
- free(buf);
+ free(buf);
}
/*
- * get a possible superblock -- don't check for internal consistency
+ * get a possible superblock -- checks for internal consistency
*/
int
get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno)
{
int error, rval;
- void *buf;
-
- if ((buf = calloc(size, 1)) == NULL) {
+ xfs_dsb_t *buf;
+
+ buf = memalign(libxfs_device_alignment(), size);
+ if (buf == NULL) {
do_error(
- "error reading superblock %u -- failed to malloc buffer\n",
- agno, off);
+ _("error reading superblock %u -- failed to memalign buffer\n"),
+ agno);
exit(1);
}
+ memset(buf, 0, size);
+ memset(sbp, 0, sizeof(*sbp));
/* try and read it first */
- if (lseek64(fs_fd, off, SEEK_SET) != off) {
+ if (lseek(x.dfd, off, SEEK_SET) != off) {
do_warn(
- "error reading superblock %u -- seek to offset %lld failed\n",
+ _("error reading superblock %u -- seek to offset %" PRId64 " failed\n"),
agno, off);
+ free(buf);
return(XR_EOF);
}
- if ((rval = read(fs_fd, buf, size)) != size) {
+ if ((rval = read(x.dfd, buf, size)) != size) {
error = errno;
do_warn(
-"superblock read failed, offset %lld, size %d, ag %u, rval %d\n",
- off, size, rval, agno);
+ _("superblock read failed, offset %" PRId64 ", size %d, ag %u, rval %d\n"),
+ off, size, agno, rval);
do_error("%s\n", strerror(error));
}
- libxfs_xlate_sb(buf, sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
- free(buf);
+ libxfs_sb_from_disk(sbp, buf);
- return (verify_sb(sbp, 0));
+ rval = verify_sb((char *)buf, sbp, agno == 0);
+ free(buf);
+ return rval;
}
-#if 0
-int
-check_growfs(xfs_off_t off, int bufnum, xfs_agnumber_t agnum)
-{
- int rval;
-
- ASSERT(bufnum < NUM_SBS);
-
- /* try and read it first */
-
- if (lseek64(fs_fd, off, SEEK_SET) != off)
- return(XR_EOF);
-
- if ((rval = read(fs_fd, sb_bufs[bufnum], sbbuf_size)) != sbbuf_size) {
- /*
- * we didn't get a full block so the filesystem
- * could not have been grown. return a non-XR_OK
- * result code.
- */
- return(XR_EOF);
- }
-
- return(get_sb(off, bufnum, agnum));
-}
-#endif
/* returns element on list with highest reference count */
-
-fs_geo_list_t *
+static fs_geo_list_t *
get_best_geo(fs_geo_list_t *list)
{
int cnt = 0;
}
/* adds geometry info to linked list. returns (sometimes new) head of list */
-
-fs_geo_list_t *
+static fs_geo_list_t *
add_geo(fs_geo_list_t *list, fs_geometry_t *geo_p, int index)
{
fs_geo_list_t *current = list;
-
+
while (current != NULL) {
if (memcmp(geo_p, ¤t->geo, sizeof(fs_geometry_t)) == 0) {
current->refs++;
}
if ((current = malloc(sizeof(fs_geo_list_t))) == NULL) {
- do_error("couldn't malloc geometry structure\n");
+ do_error(_("couldn't malloc geometry structure\n"));
exit(1);
}
return(current);
}
-void
+static void
free_geo(fs_geo_list_t *list)
{
fs_geo_list_t *next;
fs_geo_list_t *current;
- current = list;
-
for (current = list; current != NULL; current = next) {
next = current->next;
free(current);
void
get_sb_geometry(fs_geometry_t *geo, xfs_sb_t *sbp)
{
- bzero(geo, sizeof(fs_geometry_t));
+ memset(geo, 0, sizeof(fs_geometry_t));
/*
* blindly set fields that we know are always good
geo->sb_sectsize = sbp->sb_sectsize;
geo->sb_inodesize = sbp->sb_inodesize;
- if (XFS_SB_VERSION_HASALIGN(sbp))
+ if (xfs_sb_version_hasalign(sbp))
geo->sb_ialignbit = 1;
- if (XFS_SB_VERSION_HASSHARED(sbp) ||
- sbp->sb_versionnum & XR_PART_SECSB_VNMASK)
- geo->sb_sharedbit = 1;
-
- if (XFS_SB_VERSION_HASDALIGN(sbp))
+ if (xfs_sb_version_hasdalign(sbp))
geo->sb_salignbit = 1;
- if (XFS_SB_VERSION_HASEXTFLGBIT(sbp))
- geo->sb_extflgbit = 1;
-
- /*
- * protect against pre-6.5 mkfs-generated garbaged
- * fields in the secondary superblocks. pay attention
- * to those fields if and only if their corresponding
- * feature bits are set in the feature bits of the
- * version number or we can deduce from the version bits
- * that are set that our field was properly initialized
- * because a field after the field we care about was
- * properly initialized as well.
- */
-
- /*
- * inode alignment field lives before the data alignment field
- */
- if (!pre_65_beta && sbp->sb_versionnum & XR_PART_SECSB_VNMASK ||
- pre_65_beta && sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK)
- geo->sb_inoalignmt = sbp->sb_inoalignmt;
-
- if (!pre_65_beta && sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK ||
- pre_65_beta && XFS_SB_VERSION_HASDALIGN(sbp)) {
- geo->sb_unit = sbp->sb_unit;
- geo->sb_width = sbp->sb_width;
- }
-
- /*
- * shared vn always set if either ino or data alignment is on
- * since that field lives between the quota and inode alignment
- * fields
- */
- if (sbp->sb_versionnum & XR_PART_SECSB_VNMASK)
- geo->sb_shared_vn = sbp->sb_shared_vn;
-
- /*
- * superblock fields located after sb_widthfields get set
- * into the geometry structure only if we can determine
- * from the features enabled in this superblock whether
- * or not the sector was bzero'd at mkfs time.
- */
- if (!pre_65_beta && sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK ||
- pre_65_beta && sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK) {
- geo->sb_fully_zeroed = 1;
- }
+ geo->sb_extflgbit = 1;
+ geo->sb_fully_zeroed = 1;
}
/*
* primary and compare the geometries in the secondaries against
* the geometry indicated by the primary.
*
- * returns 1 if bad, 0 if ok
+ * returns 0 if ok, else error code (XR_EOF, XR_INSUFF_SEC_SB, etc).
*/
int
verify_set_primary_sb(xfs_sb_t *rsb,
int sb_index,
int *sb_modified)
{
- xfs_off_t off;
+ xfs_off_t off;
fs_geometry_t geo;
xfs_sb_t *sb;
fs_geo_list_t *list;
fs_geo_list_t *current;
- char *checked;
xfs_agnumber_t agno;
int num_sbs;
- int skip;
int size;
int num_ok;
int retval;
- int round;
/*
- * select the number of secondaries to try for
+ * We haven't been able to validate the sector size yet properly
+ * (e.g. in the case of repairing an image in a file), so we need to
+ * take into account sector mismatches and so use the maximum possible
+ * sector size rather than the sector size in @rsb.
*/
- num_sbs = MIN(NUM_SBS, rsb->sb_agcount);
- skip = howmany(num_sbs, rsb->sb_agcount);
- size = NUM_AGH_SECTS * rsb->sb_sectsize;
- retval = 0;
+ size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG));
list = NULL;
num_ok = 0;
*sb_modified = 0;
+ num_sbs = rsb->sb_agcount;
sb = (xfs_sb_t *) alloc_ag_buf(size);
- checked = calloc(rsb->sb_agcount, sizeof(char));
- if (!checked) {
- do_error("calloc failed in verify_set_primary_sb\n");
- exit(1);
- }
/*
* put the primary sb geometry info onto the geometry list
*/
- checked[sb_index] = 1;
get_sb_geometry(&geo, rsb);
list = add_geo(list, &geo, sb_index);
/*
- * grab N secondaries. check them off as we get them
- * so we only process each one once
+ * scan the secondaries and check them off as we get them so we only
+ * process each one once
*/
- for (round = 0; round < skip; round++) {
- for (agno = round; agno < rsb->sb_agcount; agno += skip) {
- if (checked[agno])
- continue;
+ for (agno = 1; agno < rsb->sb_agcount; agno++) {
+ off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
- off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;
+ retval = get_sb(sb, off, size, agno);
+ if (retval == XR_EOF)
+ goto out_free_list;
- checked[agno] = 1;
-
- if (get_sb(sb, off, size, agno) == XR_EOF) {
- retval = 1;
- goto out;
- }
-
- if (verify_sb(sb, 0) == XR_OK) {
- /*
- * save away geometry info.
- * don't bother checking the sb
- * against the agi/agf as the odds
- * of the sb being corrupted in a way
- * that it is internally consistent
- * but not consistent with the rest
- * of the filesystem is really really low.
- */
- get_sb_geometry(&geo, sb);
- list = add_geo(list, &geo, agno);
- num_ok++;
- }
+ if (retval == XR_OK) {
+ /*
+ * save away geometry info. don't bother checking the
+ * sb against the agi/agf as the odds of the sb being
+ * corrupted in a way that it is internally consistent
+ * but not consistent with the rest of the filesystem is
+ * really really low.
+ */
+ get_sb_geometry(&geo, sb);
+ list = add_geo(list, &geo, agno);
+ num_ok++;
}
}
/*
* see if we have enough superblocks to bother with
*/
- if (num_ok < num_sbs / 2)
- return(XR_INSUFF_SEC_SB);
+ retval = 0;
+ if (num_ok < num_sbs / 2) {
+ retval = XR_INSUFF_SEC_SB;
+ goto out_free_list;
+ }
current = get_best_geo(list);
switch (num_sbs) {
case 2:
/*
- * all them have to be right. if not, report geometry
- * and get out unless force option is in effect (-F)
+ * If we only have two allocation groups, and the superblock
+ * in the second allocation group differs from the primary
+ * superblock we can't verify the geometry information.
+ * Warn the user about this situation and get out unless
+ * explicitly overridden.
*/
if (current->refs != 2) {
if (!force_geo) {
- do_warn("Only two AGs detected and they do not match - cannot proceed.\n");
+ do_warn(
+ _("Only two AGs detected and they do not match - "
+ "cannot validate filesystem geometry.\n"
+ "Use the -o force_geometry option to proceed.\n"));
exit(1);
}
}
- break;
+ goto out_free_list;
case 1:
/*
- * just report the geometry info and get out.
- * refuse to run further unless the force (-F)
- * option is in effect.
+ * If we only have a single allocation group there is no
+ * secondary superblock that we can use to verify the geometry
+ * information. Warn the user about this situation and get
+ * out unless explicitly overridden.
*/
if (!force_geo) {
- do_warn("Only one AG detected - cannot proceed.\n");
+ do_warn(
+ _("Only one AG detected - "
+ "cannot validate filesystem geometry.\n"
+ "Use the -o force_geometry option to proceed.\n"));
exit(1);
}
+ goto out_free_list;
default:
/*
* at least half of the probed superblocks have
* XFS normally doesn't alter the secondary superblocks.
*/
if (current->refs < num_sbs / 2) {
- do_warn("Not enough matching superblocks - cannot proceed.\n");
+ do_warn(
+ _("Not enough matching superblocks - cannot proceed.\n"));
exit(1);
}
}
if (current->index != sb_index) {
*sb_modified = 1;
- off = current->index * current->geo.sb_agblocks
+ off = (xfs_off_t)current->index * current->geo.sb_agblocks
* current->geo.sb_blocksize;
if (get_sb(sb, off, current->geo.sb_sectsize,
current->index) != XR_OK)
- do_error("could not read superblock\n");
+ do_error(_("could not read superblock\n"));
copy_sb(sb, rsb);
sb_width = sb->sb_width;
}
+out_free_list:
free_geo(list);
-out:
free(sb);
- free(checked);
- return(retval);
+ return retval;
}