Пример #1
0
/*
 * the way to verify that a primary sb is consistent with the
 * filesystem is find the secondaries given the info in the
 * primary and compare the geometries in the secondaries against
 * the geometry indicated by the primary.
 *
 * returns 1 if bad, 0 if ok
 */
int
verify_set_primary_sb(xfs_sb_t		*rsb,
			int		sb_index,
			int		*sb_modified)
{
	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
	 */
	num_sbs = MIN(NUM_SBS, rsb->sb_agcount);
	skip = howmany(num_sbs, rsb->sb_agcount);

	/*
	 * 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.
	 */
	size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG));
	retval = 0;
	list = NULL;
	num_ok = 0;
	*sb_modified = 0;

	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
	 */
	for (round = 0; round < skip; round++)  {
		for (agno = round; agno < rsb->sb_agcount; agno += skip)  {
			if (checked[agno])
				continue;

			off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog;

			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++;
			}
		}
	}

	/*
	 * see if we have enough superblocks to bother with
	 */
	if (num_ok < num_sbs / 2)
		return(XR_INSUFF_SEC_SB);

	current = get_best_geo(list);

	/*
	 * check that enough sbs agree that we're willing to
	 * go with this geometry.  if not, print out the
	 * geometry and a message about the force option.
	 */
	switch (num_sbs)  {
	case 2:
		/*
		 * 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 validate filesystem geometry.\n"
	  "Use the -o force_geometry option to proceed.\n"));
				exit(1);
			}
		}
		goto out_free_list;
	case 1:
		/*
		 * 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 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
		 * to agree.  if they don't, this fs is probably
		 * too far gone anyway considering the fact that
		 * XFS normally doesn't alter the secondary superblocks.
		 */
		if (current->refs < num_sbs / 2)  {
			do_warn(
		_("Not enough matching superblocks - cannot proceed.\n"));
			exit(1);
		}
	}

	/*
	 * set the geometry into primary superblock if necessary.
	 */

	if (current->index != sb_index)  {
		*sb_modified = 1;
		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"));

		copy_sb(sb, rsb);

		/*
		 * turn off inprogress bit since this is the primary.
		 * also save away values that we need to ensure are
		 * consistent in the other secondaries.
		 */
		rsb->sb_inprogress = 0;
		sb_inoalignmt = sb->sb_inoalignmt;
		sb_unit = sb->sb_unit;
		sb_width = sb->sb_width;
	}

out_free_list:
	free_geo(list);
out:
	free(sb);
	free(checked);
	return(retval);
}
Пример #2
0
/* ARGSUSED */
void
phase1(xfs_mount_t *mp)
{
	xfs_sb_t		*sb;
	char			*ag_bp;
	int			rval;

	do_log(_("Phase 1 - find and verify superblock...\n"));

	primary_sb_modified = 0;
	need_root_inode = 0;
	need_root_dotdot = 0;
	need_rbmino = 0;
	need_rsumino = 0;
	lost_quotas = 0;

	/*
	 * get AG 0 into ag header buf
	 */
	ag_bp = alloc_ag_buf(MAX_SECTSIZE);
	sb = (xfs_sb_t *) ag_bp;

	if (get_sb(sb, 0LL, MAX_SECTSIZE, 0) == XR_EOF)
		do_error(_("error reading primary superblock\n"));

	/*
	 * is this really an sb, verify internal consistency
	 */
	if ((rval = verify_sb(sb, 1)) != XR_OK)  {
		do_warn(_("bad primary superblock - %s !!!\n"),
			err_string(rval));
		if (!find_secondary_sb(sb))
			no_sb();
		primary_sb_modified = 1;
	} else if ((rval = verify_set_primary_sb(sb, 0,
					&primary_sb_modified)) != XR_OK)  {
		do_warn(_("couldn't verify primary superblock - %s !!!\n"),
			err_string(rval));
		if (!find_secondary_sb(sb))
			no_sb();
		primary_sb_modified = 1;
	}

	/*
	 * Check bad_features2 and make sure features2 the same as
	 * bad_features (ORing the two together). Leave bad_features2
	 * set so older kernels can still use it and not mount unsupported
	 * filesystems when it reads bad_features2.
	 */
	if (sb->sb_bad_features2 != 0 &&
			sb->sb_bad_features2 != sb->sb_features2) {
		sb->sb_features2 |= sb->sb_bad_features2;
		sb->sb_bad_features2 = sb->sb_features2;
		primary_sb_modified = 1;
		do_warn(_("superblock has a features2 mismatch, correcting\n"));
	}

	/*
	 * apply any version changes or conversions after the primary
	 * superblock has been verified or repaired
	 *
	 * Send output to stdout as do_log and everything else in repair
	 * is sent to stderr and there is no "quiet" option. xfs_admin
	 * will filter stderr but not stdout. This situation must be improved.
	 */
	if (convert_lazy_count) {
		if (lazy_count && !xfs_sb_version_haslazysbcount(sb)) {
			sb->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
			sb->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT;
			sb->sb_bad_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT;
			primary_sb_modified = 1;
			printf(_("Enabling lazy-counters\n"));
		} else
		if (!lazy_count && xfs_sb_version_haslazysbcount(sb)) {
			sb->sb_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT;
			sb->sb_bad_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT;
			printf(_("Disabling lazy-counters\n"));
			primary_sb_modified = 1;
		} else {
			printf(_("Lazy-counters are already %s\n"),
				lazy_count ? _("enabled") : _("disabled"));
			exit(0); /* no conversion required, exit */
		}
	}

	if (primary_sb_modified)  {
		if (!no_modify)  {
			do_warn(_("writing modified primary superblock\n"));
			write_primary_sb(sb, sb->sb_sectsize);
		} else  {
			do_warn(_("would write modified primary superblock\n"));
		}
	}

	/*
	 * misc. global var initialization
	 */
	sb_ifree = sb_icount = sb_fdblocks = sb_frextents = 0;

	free(sb);
}