Blame gfs2/fsck/rgrepair.c

Packit Service 360c39
#include "clusterautoconfig.h"
Packit Service 360c39
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <inttypes.h>
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdint.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <errno.h>
Packit Service 360c39
#include <libintl.h>
Packit Service 360c39
#define _(String) gettext(String)
Packit Service 360c39
Packit Service 360c39
#include <logging.h>
Packit Service 360c39
#include "libgfs2.h"
Packit Service 360c39
#include "osi_list.h"
Packit Service 360c39
#include "fsck.h"
Packit Service 360c39
#include "fs_recovery.h"
Packit Service 360c39
Packit Service 360c39
int rindex_modified = FALSE;
Packit Service 360c39
struct special_blocks false_rgrps;
Packit Service 360c39
Packit Service 360c39
#define BAD_RG_PERCENT_TOLERANCE 11
Packit Service 360c39
#define AWAY_FROM_BITMAPS 0x1000
Packit Service 360c39
#define MAX_RGSEGMENTS 20
Packit Service 360c39
Packit Service 360c39
#define ri_equal(ondisk, expected, field) (ondisk.field == expected.field)
Packit Service 360c39
Packit Service 360c39
#define ri_compare(rg, ondisk, expected, field, fmt, type)	\
Packit Service 360c39
	if (ondisk.field != expected.field) { \
Packit Service 360c39
		log_warn( _("rindex #%d " #field " discrepancy: index 0x%" \
Packit Service 360c39
			    fmt	" != expected: 0x%" fmt "\n"),		\
Packit Service 360c39
			  rg + 1, (type)ondisk.field, (type)expected.field);	\
Packit Service 360c39
		ondisk.field = expected.field;				\
Packit Service 360c39
		rindex_modified = TRUE;					\
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * find_journal_entry_rgs - find all RG blocks within all journals
Packit Service 360c39
 *
Packit Service 360c39
 * Since Resource Groups (RGs) are journaled, it is not uncommon for them
Packit Service 360c39
 * to appear inside a journal.  But if there is severe damage to the rindex
Packit Service 360c39
 * file or some of the RGs, we may need to hunt and peck for RGs and in that
Packit Service 360c39
 * case, we don't want to mistake these blocks that look just a real RG
Packit Service 360c39
 * for a real RG block.  These are "fake" RGs that need to be ignored for
Packit Service 360c39
 * the purposes of finding where things are.
Packit Service 360c39
 *
Packit Service 360c39
 * NOTE: This function assumes that the jindex and journals have been read in,
Packit Service 360c39
 *       which isn't often the case. Normally the rindex needs to be read in
Packit Service 360c39
 *       first. If the rindex is damaged, that's not an option.
Packit Service 360c39
 */
Packit Service 360c39
static void find_journaled_rgs(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	int j, new = 0;
Packit Service 360c39
	unsigned int jblocks;
Packit Service 360c39
	uint64_t b, dblock;
Packit Service 360c39
	struct gfs2_inode *ip;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	int false_count;
Packit Service 360c39
Packit Service 360c39
	osi_list_init(&false_rgrps.list);
Packit Service 360c39
	for (j = 0; j < sdp->md.journals; j++) {
Packit Service 360c39
		ip = sdp->md.journal[j];
Packit Service 360c39
		log_debug(_("Checking for rgrps in journal%d which starts "
Packit Service 360c39
			    "at block 0x%llx.\n"), j,
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
		jblocks = ip->i_di.di_size / sdp->sd_sb.sb_bsize;
Packit Service 360c39
		false_count = 0;
Packit Service 360c39
		for (b = 0; b < jblocks; b++) {
Packit Service 360c39
			block_map(ip, b, &new, &dblock, NULL, 0);
Packit Service 360c39
			if (!dblock)
Packit Service 360c39
				break;
Packit Service 360c39
			bh = bread(sdp, dblock);
Packit Service 360c39
			if (!gfs2_check_meta(bh, GFS2_METATYPE_RG)) {
Packit Service 360c39
				/* False rgrp found at block dblock */
Packit Service 360c39
				false_count++;
Packit Service 360c39
				gfs2_special_set(&false_rgrps, dblock);
Packit Service 360c39
			}
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
		}
Packit Service 360c39
		log_debug("\n%d false positives identified.\n", false_count);
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int is_false_rg(uint64_t block)
Packit Service 360c39
{
Packit Service 360c39
	if (blockfind(&false_rgrps, block))
Packit Service 360c39
		return 1;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * find_shortest_rgdist - hunt and peck for the shortest distance between RGs.
Packit Service 360c39
 *
Packit Service 360c39
 * Sample several of them because an RG that's been blasted may
Packit Service 360c39
 * look like twice the distance.  If we can find 6 of them, that
Packit Service 360c39
 * should be enough to figure out the correct layout.
Packit Service 360c39
 * This also figures out first_rg_dist since that's always different.
Packit Service 360c39
 *
Packit Service 360c39
 * This function was revised to return the number of segments, usually 2.
Packit Service 360c39
 * The shortest distance is now returned in the highest entry in rg_dist
Packit Service 360c39
 */
Packit Service 360c39
static int find_shortest_rgdist(struct gfs2_sbd *sdp, uint64_t *dist_array,
Packit Service 360c39
				int *dist_cnt)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t blk, block_last_rg, shortest_dist_btwn_rgs;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	int rgs_sampled = 0;
Packit Service 360c39
	struct gfs2_rindex buf, tmpndx;
Packit Service 360c39
	uint64_t initial_first_rg_dist;
Packit Service 360c39
	int gsegment = 0;
Packit Service 360c39
	int is_rgrp;
Packit Service 360c39
Packit Service 360c39
	/* Figure out if there are any RG-looking blocks in the journal we
Packit Service 360c39
	   need to ignore. */
Packit Service 360c39
	find_journaled_rgs(sdp);
Packit Service 360c39
Packit Service 360c39
	initial_first_rg_dist = dist_array[0] = block_last_rg =
Packit Service 360c39
		LGFS2_SB_ADDR(sdp) + 1;
Packit Service 360c39
	shortest_dist_btwn_rgs = sdp->device.length;
Packit Service 360c39
Packit Service 360c39
	for (blk = LGFS2_SB_ADDR(sdp) + 1; blk < sdp->device.length; blk++) {
Packit Service 360c39
		uint64_t dist;
Packit Service 360c39
Packit Service 360c39
		if (blk == LGFS2_SB_ADDR(sdp) + 1)
Packit Service 360c39
			is_rgrp = 1;
Packit Service 360c39
		else if (is_false_rg(blk))
Packit Service 360c39
			is_rgrp = 0;
Packit Service 360c39
		else {
Packit Service 360c39
			bh = bread(sdp, blk);
Packit Service 360c39
			is_rgrp = (gfs2_check_meta(bh, GFS2_METATYPE_RG) == 0);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
		}
Packit Service 360c39
		if (!is_rgrp) {
Packit Service 360c39
			if (rgs_sampled >= 6) {
Packit Service 360c39
				uint64_t nblk;
Packit Service 360c39
Packit Service 360c39
				log_info(_("rgrp not found at block 0x%llx. "
Packit Service 360c39
					   "Last found rgrp was 0x%llx. "
Packit Service 360c39
					   "Checking the next one.\n"),
Packit Service 360c39
					 (unsigned long long)blk,
Packit Service 360c39
					 (unsigned long long)block_last_rg);
Packit Service 360c39
				/* check for just a damaged rgrp */
Packit Service 360c39
				nblk = blk + dist_array[gsegment];
Packit Service 360c39
				if (is_false_rg(nblk)) {
Packit Service 360c39
					is_rgrp = 0;
Packit Service 360c39
				} else {
Packit Service 360c39
					bh = bread(sdp, nblk);
Packit Service 360c39
					is_rgrp = (((gfs2_check_meta(bh,
Packit Service 360c39
						GFS2_METATYPE_RG) == 0)));
Packit Service 360c39
					brelse(bh);
Packit Service 360c39
				}
Packit Service 360c39
				if (is_rgrp) {
Packit Service 360c39
					log_info(_("Next rgrp is intact, so "
Packit Service 360c39
						   "this one is damaged.\n"));
Packit Service 360c39
					blk = nblk - 1;
Packit Service 360c39
					dist_cnt[gsegment]++;
Packit Service 360c39
					continue;
Packit Service 360c39
				}
Packit Service 360c39
				log_info(_("Looking for new segment.\n"));
Packit Service 360c39
				blk -= 16;
Packit Service 360c39
				rgs_sampled = 0;
Packit Service 360c39
				shortest_dist_btwn_rgs = sdp->device.length;
Packit Service 360c39
				/* That last one didn't pan out, so: */
Packit Service 360c39
				dist_cnt[gsegment]--;
Packit Service 360c39
				gsegment++;
Packit Service 360c39
				if (gsegment >= MAX_RGSEGMENTS)
Packit Service 360c39
					break;
Packit Service 360c39
			}
Packit Service 360c39
			if ((blk - block_last_rg) > (524288 * 2)) {
Packit Service 360c39
				log_info(_("No rgrps were found within 4GB "
Packit Service 360c39
					   "of the last rgrp. Must be the "
Packit Service 360c39
					   "end of the file system.\n"));
Packit Service 360c39
Packit Service 360c39
				break;
Packit Service 360c39
			}
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		dist_cnt[gsegment]++;
Packit Service 360c39
		if (rgs_sampled >= 6) {
Packit Service 360c39
			block_last_rg = blk;
Packit Service 360c39
			blk += dist_array[gsegment] - 1; /* prev value in
Packit Service 360c39
							    array minus 1. */
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
		log_info(_("segment %d: rgrp found at block 0x%llx\n"),
Packit Service 360c39
			 gsegment + 1, (unsigned long long)blk);
Packit Service 360c39
		dist = blk - block_last_rg;
Packit Service 360c39
		if (blk > LGFS2_SB_ADDR(sdp) + 1) { /* not the very first rgrp */
Packit Service 360c39
Packit Service 360c39
			log_info("dist 0x%llx = 0x%llx - 0x%llx ",
Packit Service 360c39
				 (unsigned long long)dist,
Packit Service 360c39
				 (unsigned long long)blk,
Packit Service 360c39
				 (unsigned long long)block_last_rg);
Packit Service 360c39
			/**
Packit Service 360c39
			 * We found an RG.  Check to see if we need to set the
Packit Service 360c39
			 * first_rg_dist based on whether it is still at its
Packit Service 360c39
			 * initial value (i.e. the fs.)  The first rg distance
Packit Service 360c39
			 * is different from the rest because of the
Packit Service 360c39
			 * superblock and 64K dead space.
Packit Service 360c39
			 **/
Packit Service 360c39
			if (dist_array[0] == initial_first_rg_dist) {
Packit Service 360c39
				dist_array[0] = dist;
Packit Service 360c39
				dist_cnt[0] = 1;
Packit Service 360c39
				rgs_sampled = 0;
Packit Service 360c39
			}
Packit Service 360c39
			if (dist < shortest_dist_btwn_rgs) {
Packit Service 360c39
				shortest_dist_btwn_rgs = dist;
Packit Service 360c39
				log_info( _("(shortest so far)"));
Packit Service 360c39
			}
Packit Service 360c39
			log_info("\n");
Packit Service 360c39
			if (++rgs_sampled == 6) {
Packit Service 360c39
				dist_array[gsegment] = shortest_dist_btwn_rgs;
Packit Service 360c39
				log_info(_("Settled on distance 0x%llx for "
Packit Service 360c39
					   "segment %d\n"),
Packit Service 360c39
					 (unsigned long long)
Packit Service 360c39
					 dist_array[gsegment], gsegment + 1);
Packit Service 360c39
			}
Packit Service 360c39
		} else {
Packit Service 360c39
			gsegment++;
Packit Service 360c39
			if (gsegment >= MAX_RGSEGMENTS)
Packit Service 360c39
				break;
Packit Service 360c39
		}
Packit Service 360c39
		block_last_rg = blk;
Packit Service 360c39
		if (rgs_sampled < 6)
Packit Service 360c39
			blk += 250; /* skip ahead for performance */
Packit Service 360c39
		else
Packit Service 360c39
			blk += shortest_dist_btwn_rgs - 1;
Packit Service 360c39
	}
Packit Service 360c39
	if (gsegment >= MAX_RGSEGMENTS) {
Packit Service 360c39
		log_err(_("Maximum number of rgrp grow segments reached.\n"));
Packit Service 360c39
		log_err(_("This file system has more than %d resource "
Packit Service 360c39
			  "group segments.\n"), MAX_RGSEGMENTS);
Packit Service 360c39
	}
Packit Service 360c39
	/* -------------------------------------------------------------- */
Packit Service 360c39
	/* Sanity-check our first_rg_dist. If RG #2 got nuked, the        */
Packit Service 360c39
	/* first_rg_dist would measure from #1 to #3, which would be bad. */
Packit Service 360c39
	/* We need to take remedial measures to fix it (from the index).  */
Packit Service 360c39
	/* -------------------------------------------------------------- */
Packit Service 360c39
	if (*dist_array >= shortest_dist_btwn_rgs +
Packit Service 360c39
	    (shortest_dist_btwn_rgs / 4)) {
Packit Service 360c39
		/* read in the second RG index entry for this subd. */
Packit Service 360c39
		gfs2_readi(sdp->md.riinode, (char *)&buf,
Packit Service 360c39
			   sizeof(struct gfs2_rindex),
Packit Service 360c39
			   sizeof(struct gfs2_rindex));
Packit Service 360c39
		gfs2_rindex_in(&tmpndx, (char *)&buf;;
Packit Service 360c39
		if (tmpndx.ri_addr > LGFS2_SB_ADDR(sdp) + 1) { /* sanity check */
Packit Service 360c39
			log_warn( _("rgrp 2 is damaged: getting dist from index: "));
Packit Service 360c39
			*dist_array = tmpndx.ri_addr - (LGFS2_SB_ADDR(sdp) + 1);
Packit Service 360c39
			log_warn("0x%llx\n", (unsigned long long)*dist_array);
Packit Service 360c39
		} else {
Packit Service 360c39
			log_warn( _("rgrp index 2 is damaged: extrapolating dist: "));
Packit Service 360c39
			*dist_array = sdp->device.length - (sdp->rgrps - 1) *
Packit Service 360c39
				(sdp->device.length / sdp->rgrps);
Packit Service 360c39
			log_warn("0x%llx\n", (unsigned long long)*dist_array);
Packit Service 360c39
		}
Packit Service 360c39
		log_debug( _("Adjusted first rgrp distance: 0x%llx\n"),
Packit Service 360c39
			   (unsigned long long)*dist_array);
Packit Service 360c39
	} /* if first RG distance is within tolerance */
Packit Service 360c39
Packit Service 360c39
	gfs2_special_free(&false_rgrps);
Packit Service 360c39
	return gsegment;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * count_usedspace - count the used bits in a rgrp bitmap buffer
Packit Service 360c39
 */
Packit Service 360c39
static uint64_t count_usedspace(struct gfs2_sbd *sdp, int first,
Packit Service 360c39
				struct gfs2_buffer_head *bh)
Packit Service 360c39
{
Packit Service 360c39
	int off, x, y, bytes_to_check;
Packit Service 360c39
	uint32_t rg_used = 0;
Packit Service 360c39
	unsigned int state;
Packit Service 360c39
Packit Service 360c39
	/* Count up the free blocks in the bitmap */
Packit Service 360c39
	if (first) {
Packit Service 360c39
		if (sdp->gfs1)
Packit Service 360c39
			off = sizeof(struct gfs_rgrp);
Packit Service 360c39
		else
Packit Service 360c39
			off = sizeof(struct gfs2_rgrp);
Packit Service 360c39
	} else
Packit Service 360c39
		off = sizeof(struct gfs2_meta_header);
Packit Service 360c39
	bytes_to_check = sdp->bsize - off;
Packit Service 360c39
	for (x = 0; x < bytes_to_check; x++) {
Packit Service 360c39
		unsigned char *byte;
Packit Service 360c39
Packit Service 360c39
		byte = (unsigned char *)&bh->b_data[off + x];
Packit Service 360c39
		if (*byte == 0x55) {
Packit Service 360c39
			rg_used += GFS2_NBBY;
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
		if (*byte == 0x00)
Packit Service 360c39
			continue;
Packit Service 360c39
		for (y = 0; y < GFS2_NBBY; y++) {
Packit Service 360c39
			state = (*byte >> (GFS2_BIT_SIZE * y)) & GFS2_BIT_MASK;
Packit Service 360c39
			if (state == GFS2_BLKST_FREE ||
Packit Service 360c39
			    state == GFS2_BLKST_UNLINKED)
Packit Service 360c39
				continue;
Packit Service 360c39
			rg_used++;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return rg_used;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * find_next_rgrp_dist - find the distance to the next rgrp
Packit Service 360c39
 *
Packit Service 360c39
 * This function is only called if the rgrps are determined to be on uneven
Packit Service 360c39
 * boundaries.  In a normal gfs2 file system, after mkfs.gfs2, all the
Packit Service 360c39
 * rgrps but the first and second one will be the same distance from the
Packit Service 360c39
 * previous rgrp.  (The first rgrp will predictably be after the superblock
Packit Service 360c39
 * and the second one will be adjusted based on the number 64KB skipped
Packit Service 360c39
 * at the start of the file system.)  The only way we can deviate from that
Packit Service 360c39
 * pattern is if the user did gfs_grow on a gfs1 file system, then converted
Packit Service 360c39
 * it to gfs2 using gfs2_convert.
Packit Service 360c39
 *
Packit Service 360c39
 * This function finds the distance to the next rgrp for these cases.
Packit Service 360c39
 */
Packit Service 360c39
static uint64_t find_next_rgrp_dist(struct gfs2_sbd *sdp, uint64_t blk,
Packit Service 360c39
				    struct rgrp_tree *prevrgd)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	uint64_t rgrp_dist = 0, used_blocks, block, next_block, twogigs;
Packit Service 360c39
	struct rgrp_tree *rgd = NULL, *next_rgd;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	struct gfs2_meta_header mh;
Packit Service 360c39
	int first, length, b, found;
Packit Service 360c39
	uint64_t mega_in_blocks;
Packit Service 360c39
	uint32_t free_blocks;
Packit Service 360c39
Packit Service 360c39
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		if (rgd->ri.ri_addr == blk)
Packit Service 360c39
			break;
Packit Service 360c39
	}
Packit Service 360c39
	if (rgd && n && osi_next(n) && rgd->ri.ri_addr == blk) {
Packit Service 360c39
		n = osi_next(n);
Packit Service 360c39
		next_rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		rgrp_dist = next_rgd->ri.ri_addr - rgd->ri.ri_addr;
Packit Service 360c39
		return rgrp_dist;
Packit Service 360c39
	}
Packit Service 360c39
	mega_in_blocks = (1024 * 1024)  / sdp->bsize;
Packit Service 360c39
	twogigs = (uint64_t)mega_in_blocks * 2048;
Packit Service 360c39
	/* Unfortunately, if we fall through to here we can't trust the
Packit Service 360c39
	   rindex.  So we have to analyze the current rgrp to figure out
Packit Service 360c39
	   the bare minimum block number where it ends. If we don't have
Packit Service 360c39
	   rindex, all we know about this rgrp is what's on disk: its
Packit Service 360c39
	   rg_free.  If we analyze the rgrp's bitmap and the bitmaps that
Packit Service 360c39
	   follow, we can figure out how many bits are used.  If we add
Packit Service 360c39
	   rg_free, we get the total number of blocks this rgrp
Packit Service 360c39
	   represents.  After that should be the next rgrp, but it may
Packit Service 360c39
	   skip a few blocks (hopefully no more than 4).  */
Packit Service 360c39
	used_blocks = 0;
Packit Service 360c39
	length = 0;
Packit Service 360c39
	block = prevrgd->ri.ri_addr;
Packit Service 360c39
	first = 1;
Packit Service 360c39
	found = 0;
Packit Service 360c39
	while (1) {
Packit Service 360c39
		if (block >= sdp->device.length)
Packit Service 360c39
			break;
Packit Service 360c39
		if (block >= prevrgd->ri.ri_addr + twogigs)
Packit Service 360c39
			break;
Packit Service 360c39
		bh = bread(sdp, block);
Packit Service 360c39
		gfs2_meta_header_in(&mh, bh->b_data);
Packit Service 360c39
		if ((mh.mh_magic != GFS2_MAGIC) ||
Packit Service 360c39
		    (first && mh.mh_type != GFS2_METATYPE_RG) ||
Packit Service 360c39
		    (!first && mh.mh_type != GFS2_METATYPE_RB)) {
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
		if (first) {
Packit Service 360c39
			struct gfs2_rgrp *rg;
Packit Service 360c39
Packit Service 360c39
			rg = (struct gfs2_rgrp *)bh->b_data;
Packit Service 360c39
			free_blocks = be32_to_cpu(rg->rg_free);
Packit Service 360c39
		}
Packit Service 360c39
		used_blocks += count_usedspace(sdp, first, bh);
Packit Service 360c39
		first = 0;
Packit Service 360c39
		block++;
Packit Service 360c39
		length++;
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
		/* Check if this distance points to an rgrp:
Packit Service 360c39
		   We have to look for blocks that resemble rgrps and bitmaps.
Packit Service 360c39
		   If they do, we need to count blocks used and free and see
Packit Service 360c39
		   if adding that number of free blocks accounts for the
Packit Service 360c39
		   next rgrp we find. Otherwise, you could have a length of
Packit Service 360c39
		   6 with additional user blocks that just happen to look like
Packit Service 360c39
		   bitmap blocks.  Count them all as bitmaps and you'll be
Packit Service 360c39
		   hopelessly lost. */
Packit Service 360c39
		rgrp_dist = used_blocks + free_blocks + length;
Packit Service 360c39
		next_block = prevrgd->ri.ri_addr + rgrp_dist;
Packit Service 360c39
		/* Now we account for block rounding done by mkfs.gfs2 */
Packit Service 360c39
		for (b = 0; b <= length + GFS2_NBBY; b++) {
Packit Service 360c39
			if (next_block >= sdp->device.length)
Packit Service 360c39
				break;
Packit Service 360c39
			bh = bread(sdp, next_block + b);
Packit Service 360c39
			gfs2_meta_header_in(&mh, bh->b_data);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			if (mh.mh_magic == GFS2_MAGIC) {
Packit Service 360c39
				if (mh.mh_type == GFS2_METATYPE_RG) {
Packit Service 360c39
					found = 1;
Packit Service 360c39
					break;
Packit Service 360c39
				}
Packit Service 360c39
				/* if the first thing we find is a bitmap,
Packit Service 360c39
				   there must be a damaged rgrp on the
Packit Service 360c39
				   previous block. */
Packit Service 360c39
				if (mh.mh_type == GFS2_METATYPE_RB) {
Packit Service 360c39
					found = 1;
Packit Service 360c39
					rgrp_dist--;
Packit Service 360c39
					break;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			rgrp_dist++;
Packit Service 360c39
		}
Packit Service 360c39
		if (found) {
Packit Service 360c39
			log_info( _("rgrp found at 0x%llx, length=%d, "
Packit Service 360c39
				    "used=%llu, free=%d\n"),
Packit Service 360c39
				  prevrgd->ri.ri_addr, length,
Packit Service 360c39
				  (unsigned long long)used_blocks,
Packit Service 360c39
				  free_blocks);
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return rgrp_dist;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * hunt_and_peck - find the distance to the next rgrp
Packit Service 360c39
 *
Packit Service 360c39
 * This function is only called if the rgrps are determined to be on uneven
Packit Service 360c39
 * boundaries, and also corrupt.  So we have to go out searching for one.
Packit Service 360c39
 */
Packit Service 360c39
static uint64_t hunt_and_peck(struct gfs2_sbd *sdp, uint64_t blk,
Packit Service 360c39
			      struct rgrp_tree *prevrgd, uint64_t last_bump)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t rgrp_dist = 0, block, twogigs, last_block, last_meg;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	struct gfs2_meta_header mh;
Packit Service 360c39
	int b, mega_in_blocks;
Packit Service 360c39
Packit Service 360c39
	/* Skip ahead the previous amount: we might get lucky.
Packit Service 360c39
	   If we're close to the end of the device, take the rest. */
Packit Service 360c39
	if (gfs2_check_range(sdp, blk + last_bump))
Packit Service 360c39
		return sdp->fssize - blk;
Packit Service 360c39
Packit Service 360c39
	bh = bread(sdp, blk + last_bump);
Packit Service 360c39
	gfs2_meta_header_in(&mh, bh->b_data);
Packit Service 360c39
	brelse(bh);
Packit Service 360c39
	if (mh.mh_magic == GFS2_MAGIC && mh.mh_type == GFS2_METATYPE_RG) {
Packit Service 360c39
		log_info( _("rgrp found at 0x%llx, length=%lld\n"),
Packit Service 360c39
			  (unsigned long long)blk + last_bump,
Packit Service 360c39
			  (unsigned long long)last_bump);
Packit Service 360c39
		return last_bump;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	rgrp_dist = AWAY_FROM_BITMAPS; /* Get away from any bitmaps
Packit Service 360c39
					  associated with the previous rgrp */
Packit Service 360c39
	block = prevrgd->ri.ri_addr + rgrp_dist;
Packit Service 360c39
	/* Now we account for block rounding done by mkfs.gfs2.  A rgrp can
Packit Service 360c39
	   be at most 2GB in size, so that's where we call it. We do somewhat
Packit Service 360c39
	   obscure math here to avoid integer overflows. */
Packit Service 360c39
	mega_in_blocks = (1024 * 1024)  / sdp->bsize;
Packit Service 360c39
	twogigs = 2048 * mega_in_blocks;
Packit Service 360c39
	if (block + twogigs <= sdp->fssize) {
Packit Service 360c39
		last_block = twogigs;
Packit Service 360c39
		last_meg = 0;
Packit Service 360c39
	} else {
Packit Service 360c39
		/* There won't be a rgrp in the last megabyte. */
Packit Service 360c39
		last_block = sdp->fssize - block - mega_in_blocks;
Packit Service 360c39
		last_meg = mega_in_blocks;
Packit Service 360c39
	}
Packit Service 360c39
	for (b = AWAY_FROM_BITMAPS; b < last_block; b++) {
Packit Service 360c39
		bh = bread(sdp, block + b);
Packit Service 360c39
		gfs2_meta_header_in(&mh, bh->b_data);
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
		if (mh.mh_magic == GFS2_MAGIC) {
Packit Service 360c39
			if (mh.mh_type == GFS2_METATYPE_RG)
Packit Service 360c39
				break;
Packit Service 360c39
			/* if the first thing we find is a bitmap, there must
Packit Service 360c39
			   be a damaged rgrp on the previous block. */
Packit Service 360c39
			if (mh.mh_type == GFS2_METATYPE_RB) {
Packit Service 360c39
				rgrp_dist--;
Packit Service 360c39
				break;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		rgrp_dist++;
Packit Service 360c39
	}
Packit Service 360c39
	return rgrp_dist + last_meg;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * gfs2_rindex_rebuild - rebuild a corrupt Resource Group (RG) index manually
Packit Service 360c39
 *                        where trust_lvl == distrust
Packit Service 360c39
 *
Packit Service 360c39
 * If this routine is called, it means we have RGs in odd/unexpected places,
Packit Service 360c39
 * and there is a corrupt RG or RG index entry.  It also means we can't trust
Packit Service 360c39
 * the RG index to be sane, and the RGs don't agree with how mkfs would have
Packit Service 360c39
 * built them by default.  So we have no choice but to go through and count
Packit Service 360c39
 * them by hand.  We've tried twice to recover the RGs and RG index, and
Packit Service 360c39
 * failed, so this is our last chance to remedy the situation.
Packit Service 360c39
 *
Packit Service 360c39
 * This routine tries to minimize performance impact by:
Packit Service 360c39
 * 1. Skipping through the filesystem at known increments when possible.
Packit Service 360c39
 * 2. Shuffle through every block when RGs are not found at the predicted
Packit Service 360c39
 *    locations.
Packit Service 360c39
 *
Packit Service 360c39
 * Note: A GFS2 filesystem differs from a GFS1 file system in that there will
Packit Service 360c39
 * only be ONE chunk (i.e. no artificial subdevices on either size of the
Packit Service 360c39
 * journals).  The journals and even the rindex are kept as part of the file
Packit Service 360c39
 * system, so we need to rebuild that information by hand.  Also, with GFS1,
Packit Service 360c39
 * the different chunks ("subdevices") could have different RG sizes, which
Packit Service 360c39
 * made for quite a mess when trying to recover RGs.  GFS2 always uses the
Packit Service 360c39
 * same RG size determined by the original mkfs, so recovery is easier.
Packit Service 360c39
 *
Packit Service 360c39
 * If "gfs_grow" is specified the file system was most likely converted
Packit Service 360c39
 * from gfs1 to gfs2 after a gfs_grow operation.  In that case, the rgrps
Packit Service 360c39
 * will not be on predictable boundaries.
Packit Service 360c39
 */
Packit Service 360c39
static int gfs2_rindex_rebuild(struct gfs2_sbd *sdp, int *num_rgs,
Packit Service 360c39
			       int gfs_grow)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	uint64_t rg_dist[MAX_RGSEGMENTS] = {0, };
Packit Service 360c39
	int rg_dcnt[MAX_RGSEGMENTS] = {0, };
Packit Service 360c39
	uint64_t blk;
Packit Service 360c39
	uint64_t fwd_block, block_bump;
Packit Service 360c39
	struct rgrp_tree *calc_rgd, *prev_rgd;
Packit Service 360c39
	int number_of_rgs, rgi, segment_rgs;
Packit Service 360c39
	int rg_was_fnd = FALSE, corrupt_rgs = 0;
Packit Service 360c39
	int error = -1, j, i;
Packit Service 360c39
	int grow_segments, segment = 0;
Packit Service 360c39
Packit Service 360c39
	/*
Packit Service 360c39
	 * In order to continue, we need to initialize the jindex. We need
Packit Service 360c39
	 * the journals in order to correctly eliminate false positives during
Packit Service 360c39
	 * rgrp repair. IOW, we need to properly ignore rgrps that appear in
Packit Service 360c39
	 * the journals, and we can only do that if we have the journals.
Packit Service 360c39
	 * To make matters worse, journals may span several (small) rgrps,
Packit Service 360c39
	 * so we can't go by the rgrps.
Packit Service 360c39
	 */
Packit Service 360c39
	if (init_jindex(sdp, 0) != 0) {
Packit Service 360c39
		log_crit(_("Error: Can't read jindex required for rindex "
Packit Service 360c39
			   "repairs.\n"));
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	sdp->rgcalc.osi_node = NULL;
Packit Service 360c39
	grow_segments = find_shortest_rgdist(sdp, &rg_dist[0], &rg_dcnt[0]);
Packit Service 360c39
	for (i = 0; i < grow_segments; i++)
Packit Service 360c39
		log_info(_("Segment %d: rgrp distance: 0x%llx, count: %d\n"),
Packit Service 360c39
			  i + 1, (unsigned long long)rg_dist[i], rg_dcnt[i]);
Packit Service 360c39
	number_of_rgs = segment_rgs = 0;
Packit Service 360c39
	/* -------------------------------------------------------------- */
Packit Service 360c39
	/* Now go through the RGs and verify their integrity, fixing as   */
Packit Service 360c39
	/* needed when corruption is encountered.                         */
Packit Service 360c39
	/* -------------------------------------------------------------- */
Packit Service 360c39
	prev_rgd = NULL;
Packit Service 360c39
	block_bump = rg_dist[0];
Packit Service 360c39
	blk = LGFS2_SB_ADDR(sdp) + 1;
Packit Service 360c39
	while (blk <= sdp->device.length) {
Packit Service 360c39
		log_debug( _("Block 0x%llx\n"), (unsigned long long)blk);
Packit Service 360c39
		bh = bread(sdp, blk);
Packit Service 360c39
		rg_was_fnd = (!gfs2_check_meta(bh, GFS2_METATYPE_RG));
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
		/* Allocate a new RG and index. */
Packit Service 360c39
		calc_rgd = rgrp_insert(&sdp->rgcalc, blk);
Packit Service 360c39
		if (!calc_rgd) {
Packit Service 360c39
			log_crit( _("Can't allocate memory for rgrp repair.\n"));
Packit Service 360c39
			goto out;
Packit Service 360c39
		}
Packit Service 360c39
		calc_rgd->ri.ri_length = 1;
Packit Service 360c39
		if (!rg_was_fnd) { /* if not an RG */
Packit Service 360c39
			/* ------------------------------------------------- */
Packit Service 360c39
			/* This SHOULD be an RG but isn't.                   */
Packit Service 360c39
			/* ------------------------------------------------- */
Packit Service 360c39
			corrupt_rgs++;
Packit Service 360c39
			if (corrupt_rgs < 5)
Packit Service 360c39
				log_debug(_("Missing or damaged rgrp at block "
Packit Service 360c39
					    "%llu (0x%llx)\n"),
Packit Service 360c39
					  (unsigned long long)blk,
Packit Service 360c39
					  (unsigned long long)blk);
Packit Service 360c39
			else {
Packit Service 360c39
				log_crit( _("Error: too many missing or "
Packit Service 360c39
					    "damaged rgrps using this method. "
Packit Service 360c39
					    "Time to try another method.\n"));
Packit Service 360c39
				goto out;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		/* ------------------------------------------------ */
Packit Service 360c39
		/* Now go through and count the bitmaps for this RG */
Packit Service 360c39
		/* ------------------------------------------------ */
Packit Service 360c39
		for (fwd_block = blk + 1; fwd_block < sdp->device.length; fwd_block++) {
Packit Service 360c39
			int bitmap_was_fnd;
Packit Service 360c39
			bh = bread(sdp, fwd_block);
Packit Service 360c39
			bitmap_was_fnd = !gfs2_check_meta(bh, GFS2_METATYPE_RB);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			if (bitmap_was_fnd) /* if a bitmap */
Packit Service 360c39
				calc_rgd->ri.ri_length++;
Packit Service 360c39
			else
Packit Service 360c39
				break; /* end of bitmap, so call it quits. */
Packit Service 360c39
		} /* for subsequent bitmaps */
Packit Service 360c39
		
Packit Service 360c39
		gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, calc_rgd);
Packit Service 360c39
		calc_rgd->ri.ri_data0 = calc_rgd->ri.ri_addr +
Packit Service 360c39
			calc_rgd->ri.ri_length;
Packit Service 360c39
		if (prev_rgd) {
Packit Service 360c39
			uint32_t rgblocks;
Packit Service 360c39
Packit Service 360c39
			prev_rgd->ri.ri_length = rgblocks2bitblocks(sdp->bsize, block_bump, &rgblocks);
Packit Service 360c39
			prev_rgd->ri.ri_data = rgblocks;
Packit Service 360c39
			prev_rgd->ri.ri_data0 = prev_rgd->ri.ri_addr +
Packit Service 360c39
				prev_rgd->ri.ri_length;
Packit Service 360c39
			prev_rgd->ri.ri_data -= prev_rgd->ri.ri_data %
Packit Service 360c39
				GFS2_NBBY;
Packit Service 360c39
			prev_rgd->ri.ri_bitbytes = prev_rgd->ri.ri_data /
Packit Service 360c39
				GFS2_NBBY;
Packit Service 360c39
			log_debug( _("Prev ri_data set to: %lx.\n"),
Packit Service 360c39
				  (unsigned long)prev_rgd->ri.ri_data);
Packit Service 360c39
		}
Packit Service 360c39
		number_of_rgs++;
Packit Service 360c39
		segment_rgs++;
Packit Service 360c39
		if (rg_was_fnd)
Packit Service 360c39
			log_info( _("  rgrp %d at block 0x%llx intact\n"),
Packit Service 360c39
				  number_of_rgs, (unsigned long long)blk);
Packit Service 360c39
		else
Packit Service 360c39
			log_warn( _("* rgrp %d at block 0x%llx *** DAMAGED ***\n"),
Packit Service 360c39
				  number_of_rgs, (unsigned long long)blk);
Packit Service 360c39
		prev_rgd = calc_rgd;
Packit Service 360c39
		/*
Packit Service 360c39
		 * Figure out where our next rgrp should be.
Packit Service 360c39
		 */
Packit Service 360c39
		if ((blk == LGFS2_SB_ADDR(sdp) + 1) || (!gfs_grow)) {
Packit Service 360c39
			block_bump = rg_dist[segment];
Packit Service 360c39
			if (segment_rgs >= rg_dcnt[segment]) {
Packit Service 360c39
				log_debug(_("End of segment %d\n"), ++segment);
Packit Service 360c39
				segment_rgs = 0;
Packit Service 360c39
				if (segment >= grow_segments) {
Packit Service 360c39
					log_debug(_("Last segment.\n"));
Packit Service 360c39
					break;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			/* if we have uniformly-spaced rgrps, there may be
Packit Service 360c39
			   some wasted space at the end of the device.
Packit Service 360c39
			   Since we don't want to create a short rgrp and
Packit Service 360c39
			   break our uniformity, just quit here. */
Packit Service 360c39
			if (blk + (2 * block_bump) > sdp->device.length)
Packit Service 360c39
				break;
Packit Service 360c39
		} else if (rg_was_fnd)
Packit Service 360c39
			block_bump = find_next_rgrp_dist(sdp, blk, prev_rgd);
Packit Service 360c39
		else
Packit Service 360c39
			block_bump = hunt_and_peck(sdp, blk, prev_rgd,
Packit Service 360c39
						   block_bump);
Packit Service 360c39
		if (block_bump != 1) {
Packit Service 360c39
			if (rg_was_fnd)
Packit Service 360c39
				log_info( _(" [length 0x%llx]\n"),
Packit Service 360c39
					  (unsigned long long)block_bump);
Packit Service 360c39
			else
Packit Service 360c39
				log_warn( _(" [length 0x%llx]\n"),
Packit Service 360c39
					  (unsigned long long)block_bump);
Packit Service 360c39
		} else {
Packit Service 360c39
			log_warn("\n");
Packit Service 360c39
		}
Packit Service 360c39
		blk += block_bump;
Packit Service 360c39
	} /* for each rg block */
Packit Service 360c39
	/* ----------------------------------------------------------------- */
Packit Service 360c39
	/* If we got to the end of the fs, we still need to fix the          */
Packit Service 360c39
	/* allocation information for the very last RG.                      */
Packit Service 360c39
	/* ----------------------------------------------------------------- */
Packit Service 360c39
	if (prev_rgd && !prev_rgd->ri.ri_data) {
Packit Service 360c39
		uint32_t rgblocks;
Packit Service 360c39
Packit Service 360c39
		prev_rgd->ri.ri_length = rgblocks2bitblocks(sdp->bsize, block_bump, &rgblocks);
Packit Service 360c39
		prev_rgd->ri.ri_data0 = prev_rgd->ri.ri_addr +
Packit Service 360c39
			prev_rgd->ri.ri_length;
Packit Service 360c39
		prev_rgd->ri.ri_data = rgblocks;
Packit Service 360c39
		prev_rgd->ri.ri_data -= prev_rgd->ri.ri_data % GFS2_NBBY;
Packit Service 360c39
		prev_rgd->ri.ri_bitbytes = prev_rgd->ri.ri_data / GFS2_NBBY;
Packit Service 360c39
		log_debug( _("Prev ri_data set to: %lx.\n"),
Packit Service 360c39
			  (unsigned long)prev_rgd->ri.ri_data);
Packit Service 360c39
		prev_rgd = NULL; /* make sure we don't use it later */
Packit Service 360c39
	}
Packit Service 360c39
        /* ---------------------------------------------- */
Packit Service 360c39
        /* Now dump out the information (if verbose mode) */      
Packit Service 360c39
        /* ---------------------------------------------- */
Packit Service 360c39
        log_debug( _("rindex rebuilt as follows:\n"));
Packit Service 360c39
	for (n = osi_first(&sdp->rgcalc), rgi = 0; n; n = next, rgi++) {
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		calc_rgd = (struct rgrp_tree *)n;
Packit Service 360c39
                log_debug("%d: 0x%llx / %x / 0x%llx"
Packit Service 360c39
			  " / 0x%x / 0x%x\n", rgi + 1,
Packit Service 360c39
			  (unsigned long long)calc_rgd->ri.ri_addr,
Packit Service 360c39
			  calc_rgd->ri.ri_length,
Packit Service 360c39
			  calc_rgd->ri.ri_data0, calc_rgd->ri.ri_data, 
Packit Service 360c39
			  calc_rgd->ri.ri_bitbytes);
Packit Service 360c39
        }
Packit Service 360c39
	*num_rgs = number_of_rgs;
Packit Service 360c39
	error = 0;
Packit Service 360c39
out:
Packit Service 360c39
	for (j = 0; j < sdp->md.journals; j++)
Packit Service 360c39
		inode_put(&sdp->md.journal[j]);
Packit Service 360c39
	free(sdp->md.journal);
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
#define DIV_RU(x, y) (((x) + (y) - 1) / (y))
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * how_many_rgrps - figure out how many RG to put in a subdevice
Packit Service 360c39
 * @w: the command line
Packit Service 360c39
 * @dev: the device
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: the number of RGs
Packit Service 360c39
 */
Packit Service 360c39
static uint64_t how_many_rgrps(struct gfs2_sbd *sdp, struct device *dev, int rgsize_specified)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t nrgrp;
Packit Service 360c39
	uint32_t rgblocks1, rgblocksn, bitblocks1, bitblocksn;
Packit Service 360c39
	int bitmap_overflow = 0;
Packit Service 360c39
Packit Service 360c39
	while (1) {
Packit Service 360c39
		nrgrp = DIV_RU(dev->length, (sdp->rgsize << 20) / sdp->bsize);
Packit Service 360c39
Packit Service 360c39
		/* check to see if the rg length overflows max # bitblks */
Packit Service 360c39
		bitblocksn = rgblocks2bitblocks(sdp->bsize, dev->length / nrgrp, &rgblocksn);
Packit Service 360c39
		/* calculate size of the first rgrp */
Packit Service 360c39
		bitblocks1 = rgblocks2bitblocks(sdp->bsize, dev->length - (nrgrp - 1) * (dev->length / nrgrp),
Packit Service 360c39
		                                &rgblocks1);
Packit Service 360c39
		if (bitblocks1 > 2149 || bitblocksn > 2149) {
Packit Service 360c39
			bitmap_overflow = 1;
Packit Service 360c39
			if (sdp->rgsize <= GFS2_DEFAULT_RGSIZE) {
Packit Service 360c39
				fprintf(stderr, "error: It is not possible "
Packit Service 360c39
					"to use the entire device with "
Packit Service 360c39
					"block size %u bytes.\n",
Packit Service 360c39
					sdp->bsize);
Packit Service 360c39
				exit(-1);
Packit Service 360c39
			}
Packit Service 360c39
			sdp->rgsize -= GFS2_DEFAULT_RGSIZE; /* smaller rgs */
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
		if (bitmap_overflow ||
Packit Service 360c39
		    rgsize_specified || /* If user specified an rg size or */
Packit Service 360c39
		    nrgrp <= GFS2_EXCESSIVE_RGS || /* not an excessive # or  */
Packit Service 360c39
		    sdp->rgsize >= 2048)   /* we reached the max rg size */
Packit Service 360c39
			break;
Packit Service 360c39
Packit Service 360c39
		sdp->rgsize += GFS2_DEFAULT_RGSIZE; /* bigger rgs */
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	log_debug("  rg sz = %"PRIu32"\n  nrgrp = %"PRIu64"\n", sdp->rgsize,
Packit Service 360c39
		  nrgrp);
Packit Service 360c39
Packit Service 360c39
	return nrgrp;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * compute_rgrp_layout - figure out where the RG in a FS are
Packit Service 360c39
 */
Packit Service 360c39
static void compute_rgrp_layout(struct gfs2_sbd *sdp, struct osi_root *rgtree, int rgsize_specified)
Packit Service 360c39
{
Packit Service 360c39
	struct device *dev;
Packit Service 360c39
	struct rgrp_tree *rl, *rlast = NULL;
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	unsigned int rgrp = 0, nrgrp, rglength;
Packit Service 360c39
	uint64_t rgaddr;
Packit Service 360c39
Packit Service 360c39
	sdp->new_rgrps = 0;
Packit Service 360c39
	dev = &sdp->device;
Packit Service 360c39
Packit Service 360c39
	/* If this is a new file system, compute the length and number */
Packit Service 360c39
	/* of rgs based on the size of the device.                     */
Packit Service 360c39
	/* If we have existing RGs (i.e. gfs2_grow) find the last one. */
Packit Service 360c39
	if (!rgtree->osi_node) {
Packit Service 360c39
		dev->length -= LGFS2_SB_ADDR(sdp) + 1;
Packit Service 360c39
		nrgrp = how_many_rgrps(sdp, dev, rgsize_specified);
Packit Service 360c39
		rglength = dev->length / nrgrp;
Packit Service 360c39
		sdp->new_rgrps = nrgrp;
Packit Service 360c39
	} else {
Packit Service 360c39
		uint64_t old_length, new_chunk;
Packit Service 360c39
Packit Service 360c39
		printf("Existing resource groups:\n");
Packit Service 360c39
		for (rgrp = 0, n = osi_first(rgtree); n; n = next, rgrp++) {
Packit Service 360c39
			next = osi_next(n);
Packit Service 360c39
			rl = (struct rgrp_tree *)n;
Packit Service 360c39
Packit Service 360c39
			printf("%d: start: %" PRIu64 " (0x%"
Packit Service 360c39
				 PRIx64 "), length = %"PRIu64" (0x%"
Packit Service 360c39
				 PRIx64 ")\n", rgrp + 1, rl->start, rl->start,
Packit Service 360c39
				 rl->length, rl->length);
Packit Service 360c39
			rlast = rl;
Packit Service 360c39
		}
Packit Service 360c39
		rlast->start = rlast->ri.ri_addr;
Packit Service 360c39
		rglength = rgrp_size(rlast);
Packit Service 360c39
		rlast->length = rglength;
Packit Service 360c39
		old_length = rlast->ri.ri_addr + rglength;
Packit Service 360c39
		new_chunk = dev->length - old_length;
Packit Service 360c39
		sdp->new_rgrps = new_chunk / rglength;
Packit Service 360c39
		nrgrp = rgrp + sdp->new_rgrps;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (rgrp < nrgrp)
Packit Service 360c39
		printf("\nNew resource groups:\n");
Packit Service 360c39
	for (; rgrp < nrgrp; rgrp++) {
Packit Service 360c39
		if (rgrp) {
Packit Service 360c39
			rgaddr = rlast->start + rlast->length;
Packit Service 360c39
			rl = rgrp_insert(rgtree, rgaddr);
Packit Service 360c39
			rl->length = rglength;
Packit Service 360c39
		} else {
Packit Service 360c39
			rgaddr = LGFS2_SB_ADDR(sdp) + 1;
Packit Service 360c39
			rl = rgrp_insert(rgtree, rgaddr);
Packit Service 360c39
			rl->length = dev->length -
Packit Service 360c39
				(nrgrp - 1) * (dev->length / nrgrp);
Packit Service 360c39
		}
Packit Service 360c39
		rl->start = rgaddr;
Packit Service 360c39
		/* printf("%d: start: %" PRIu64 " (0x%"
Packit Service 360c39
			 PRIx64 "), length = %"PRIu64" (0x%"
Packit Service 360c39
			 PRIx64 ")\n", rgrp + 1, rl->start, rl->start,
Packit Service 360c39
			 rl->length, rl->length);*/
Packit Service 360c39
		rlast = rl;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	sdp->rgrps = nrgrp;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * gfs2_rindex_calculate - calculate what the rindex should look like
Packit Service 360c39
 *                          in a perfect world (trust_lvl == open_minded)
Packit Service 360c39
 *
Packit Service 360c39
 * Calculate what the rindex should look like, 
Packit Service 360c39
 * so we can later check if all RG index entries are sane.
Packit Service 360c39
 * This is a lot easier for gfs2 because we can just call the same libgfs2 
Packit Service 360c39
 * functions used by mkfs.
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 on success, -1 on failure
Packit Service 360c39
 * Sets:    sdp->rglist to a linked list of fsck_rgrp structs representing
Packit Service 360c39
 *          what we think the rindex should really look like.
Packit Service 360c39
 */
Packit Service 360c39
static int gfs2_rindex_calculate(struct gfs2_sbd *sdp, int *num_rgs)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t num_rgrps = 0;
Packit Service 360c39
Packit Service 360c39
	/* ----------------------------------------------------------------- */
Packit Service 360c39
	/* Calculate how many RGs there are supposed to be based on the      */
Packit Service 360c39
	/* rindex filesize.  Remember that our trust level is open-minded    */
Packit Service 360c39
	/* here.  If the filesize of the rindex file is not a multiple of    */
Packit Service 360c39
	/* our rindex structures, then something's wrong and we can't trust  */
Packit Service 360c39
	/* the index.                                                        */
Packit Service 360c39
	/* ----------------------------------------------------------------- */
Packit Service 360c39
	*num_rgs = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex);
Packit Service 360c39
Packit Service 360c39
	sdp->rgcalc.osi_node = NULL;
Packit Service 360c39
	fix_device_geometry(sdp);
Packit Service 360c39
Packit Service 360c39
	/* Try all possible rgrp sizes: 2048, 1024, 512, 256, 128, 64, 32 */
Packit Service 360c39
	for (sdp->rgsize = GFS2_DEFAULT_RGSIZE; sdp->rgsize >= 32;
Packit Service 360c39
	     sdp->rgsize /= 2) {
Packit Service 360c39
		num_rgrps = how_many_rgrps(sdp, &sdp->device, TRUE);
Packit Service 360c39
		if (num_rgrps == *num_rgs) {
Packit Service 360c39
			log_info(_("rgsize must be: %lld (0x%llx)\n"),
Packit Service 360c39
				 (unsigned long long)sdp->rgsize,
Packit Service 360c39
				 (unsigned long long)sdp->rgsize);
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Compute the default resource group layout as mkfs would have done */
Packit Service 360c39
	compute_rgrp_layout(sdp, &sdp->rgcalc, TRUE);
Packit Service 360c39
	if (build_rgrps(sdp, FALSE)) { /* FALSE = calc but don't write to disk. */
Packit Service 360c39
		fprintf(stderr, _("Failed to build resource groups\n"));
Packit Service 360c39
		exit(-1);
Packit Service 360c39
	}
Packit Service 360c39
	log_debug( _("fs_total_size = 0x%llx blocks.\n"),
Packit Service 360c39
		  (unsigned long long)sdp->device.length);
Packit Service 360c39
	log_warn( _("L3: number of rgs in the index = %d.\n"), *num_rgs);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * rewrite_rg_block - rewrite ("fix") a buffer with rg or bitmap data
Packit Service 360c39
 * returns: 0 if the rg was repaired, otherwise 1
Packit Service 360c39
 */
Packit Service 360c39
static int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_tree *rg,
Packit Service 360c39
			    uint64_t errblock)
Packit Service 360c39
{
Packit Service 360c39
	int x = errblock - rg->ri.ri_addr;
Packit Service 360c39
	const char *typedesc = x ? "GFS2_METATYPE_RB" : "GFS2_METATYPE_RG";
Packit Service 360c39
Packit Service 360c39
	log_err( _("Block #%lld (0x%llx) (%d of %d) is not %s.\n"),
Packit Service 360c39
		 (unsigned long long)rg->ri.ri_addr + x,
Packit Service 360c39
		 (unsigned long long)rg->ri.ri_addr + x,
Packit Service 360c39
		 (int)x+1, (int)rg->ri.ri_length, typedesc);
Packit Service 360c39
	if (query( _("Fix the Resource Group? (y/n)"))) {
Packit Service 360c39
		log_err( _("Attempting to repair the rgrp.\n"));
Packit Service 360c39
		rg->bits[x].bi_bh = bread(sdp, rg->ri.ri_addr + x);
Packit Service 360c39
		if (x) {
Packit Service 360c39
			struct gfs2_meta_header mh;
Packit Service 360c39
Packit Service 360c39
			mh.mh_magic = GFS2_MAGIC;
Packit Service 360c39
			mh.mh_type = GFS2_METATYPE_RB;
Packit Service 360c39
			mh.mh_format = GFS2_FORMAT_RB;
Packit Service 360c39
			gfs2_meta_header_out(&mh, rg->bits[x].bi_bh->b_data);
Packit Service 360c39
		} else {
Packit Service 360c39
			if (sdp->gfs1)
Packit Service 360c39
				memset(&rg->rg, 0, sizeof(struct gfs_rgrp));
Packit Service 360c39
			else
Packit Service 360c39
				memset(&rg->rg, 0, sizeof(struct gfs2_rgrp));
Packit Service 360c39
			rg->rg.rg_header.mh_magic = GFS2_MAGIC;
Packit Service 360c39
			rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
Packit Service 360c39
			rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
Packit Service 360c39
			rg->rg.rg_free = rg->ri.ri_data;
Packit Service 360c39
			if (sdp->gfs1)
Packit Service 360c39
				gfs_rgrp_out((struct gfs_rgrp *)&rg->rg, rg->bits[x].bi_bh);
Packit Service 360c39
			else
Packit Service 360c39
				gfs2_rgrp_out(&rg->rg, rg->bits[x].bi_bh->b_data);
Packit Service 360c39
		}
Packit Service 360c39
		bmodified(rg->bits[x].bi_bh);
Packit Service 360c39
		brelse(rg->bits[x].bi_bh);
Packit Service 360c39
		rg->bits[x].bi_bh = NULL;
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	return 1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * expect_rindex_sanity - the rindex file seems trustworthy, so use those
Packit Service 360c39
 *                        values as our expected values and assume the
Packit Service 360c39
 *                        damage is only to the rgrps themselves.
Packit Service 360c39
 */
Packit Service 360c39
static int expect_rindex_sanity(struct gfs2_sbd *sdp, int *num_rgs)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	struct rgrp_tree *rgd, *exp;
Packit Service 360c39
Packit Service 360c39
	*num_rgs = sdp->md.riinode->i_di.di_size / sizeof(struct gfs2_rindex) ;
Packit Service 360c39
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		exp = rgrp_insert(&sdp->rgcalc, rgd->ri.ri_addr);
Packit Service 360c39
		if (exp == NULL) {
Packit Service 360c39
			fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
Packit Service 360c39
			exit(-1);
Packit Service 360c39
		}
Packit Service 360c39
		exp->start = rgd->start;
Packit Service 360c39
		exp->length = rgd->length;
Packit Service 360c39
		memcpy(&exp->ri, &rgd->ri, sizeof(exp->ri));
Packit Service 360c39
		memcpy(&exp->rg, &rgd->rg, sizeof(exp->rg));
Packit Service 360c39
		exp->bits = NULL;
Packit Service 360c39
		gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, exp);
Packit Service 360c39
	}
Packit Service 360c39
	sdp->rgrps = *num_rgs;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * rg_repair - try to repair a damaged rg index (rindex)
Packit Service 360c39
 * trust_lvl - This is how much we trust the rindex file.
Packit Service 360c39
 *             blind_faith means we take the rindex at face value.
Packit Service 360c39
 *             open_minded means it might be okay, but we should verify it.
Packit Service 360c39
 *             distrust means it's not to be trusted, so we should go to
Packit Service 360c39
 *             greater lengths to build it from scratch.
Packit Service 360c39
 *             indignation means we have corruption, but the file system
Packit Service 360c39
 *             was converted from GFS via gfs2_convert, and its rgrps are
Packit Service 360c39
 *             not on nice boundaries thanks to previous gfs_grow ops. Lovely.
Packit Service 360c39
 */
Packit Service 360c39
int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count, int *sane)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL, *e, *enext;
Packit Service 360c39
	int error, discrepancies, percent;
Packit Service 360c39
	int calc_rg_count = 0, rg;
Packit Service 360c39
	struct gfs2_rindex buf;
Packit Service 360c39
Packit Service 360c39
	if (trust_lvl == blind_faith)
Packit Service 360c39
		return 0;
Packit Service 360c39
	if (trust_lvl == ye_of_little_faith) { /* if rindex seems sane */
Packit Service 360c39
		/* Don't free previous incarnations in memory, if any.
Packit Service 360c39
		 * We need them to copy in the next function:
Packit Service 360c39
		 * gfs2_rgrp_free(&sdp->rglist); */
Packit Service 360c39
		if (!(*sane)) {
Packit Service 360c39
			log_err(_("The rindex file does not meet our "
Packit Service 360c39
				  "expectations.\n"));
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
		error = expect_rindex_sanity(sdp, &calc_rg_count);
Packit Service 360c39
		if (error) {
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			return error;
Packit Service 360c39
		}
Packit Service 360c39
	} else if (trust_lvl == open_minded) { /* If we can't trust RG index */
Packit Service 360c39
		/* Free previous incarnations in memory, if any. */
Packit Service 360c39
		gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
Packit Service 360c39
		/* Calculate our own RG index for comparison */
Packit Service 360c39
		error = gfs2_rindex_calculate(sdp, &calc_rg_count);
Packit Service 360c39
		if (error) { /* If calculated RGs don't match the fs */
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	} else if (trust_lvl == distrust) { /* If we can't trust RG index */
Packit Service 360c39
		/* Free previous incarnations in memory, if any. */
Packit Service 360c39
		gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
Packit Service 360c39
		error = gfs2_rindex_rebuild(sdp, &calc_rg_count, 0);
Packit Service 360c39
		if (error) {
Packit Service 360c39
			log_crit( _("Error rebuilding rgrp list.\n"));
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	} else if (trust_lvl == indignation) { /* If we can't trust anything */
Packit Service 360c39
		/* Free previous incarnations in memory, if any. */
Packit Service 360c39
		gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
Packit Service 360c39
		error = gfs2_rindex_rebuild(sdp, &calc_rg_count, 1);
Packit Service 360c39
		if (error) {
Packit Service 360c39
			log_crit( _("Error rebuilding rgrp list.\n"));
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Read in the rindex */
Packit Service 360c39
	sdp->rgtree.osi_node = NULL; /* Just to be safe */
Packit Service 360c39
	rindex_read(sdp, 0, &sdp->rgrps, sane);
Packit Service 360c39
	if (sdp->md.riinode->i_di.di_size % sizeof(struct gfs2_rindex)) {
Packit Service 360c39
		log_warn( _("WARNING: rindex file has an invalid size.\n"));
Packit Service 360c39
		if (!query( _("Truncate the rindex size? (y/n)"))) {
Packit Service 360c39
			log_err(_("The rindex was not repaired.\n"));
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
		sdp->md.riinode->i_di.di_size /= sizeof(struct gfs2_rindex);
Packit Service 360c39
		sdp->md.riinode->i_di.di_size *= sizeof(struct gfs2_rindex);
Packit Service 360c39
		bmodified(sdp->md.riinode->i_bh);
Packit Service 360c39
		log_err(_("Changing rindex size to %lld.\n"),
Packit Service 360c39
			(unsigned long long)sdp->md.riinode->i_di.di_size);
Packit Service 360c39
	}
Packit Service 360c39
	log_warn( _("L%d: number of rgs expected     = %lld.\n"), trust_lvl + 1,
Packit Service 360c39
		 (unsigned long long)sdp->rgrps);
Packit Service 360c39
	if (calc_rg_count != sdp->rgrps) {
Packit Service 360c39
		int most_that_fit;
Packit Service 360c39
Packit Service 360c39
		log_warn( _("L%d: They don't match; either (1) the fs was "
Packit Service 360c39
			    "extended, (2) an odd\n"), trust_lvl + 1);
Packit Service 360c39
		log_warn( _("L%d: rgrp size was used, or (3) we have a corrupt "
Packit Service 360c39
			    "rg index.\n"), trust_lvl + 1);
Packit Service 360c39
		/* If the trust level is open_minded, we would have calculated
Packit Service 360c39
		   the rindex based on the device size. If it's not the same
Packit Service 360c39
		   number, don't trust it. Complain about the discrepancy,
Packit Service 360c39
		   then try again with a little more distrust. */
Packit Service 360c39
		if ((trust_lvl < distrust) ||
Packit Service 360c39
		    !query( _("Attempt to use what rgrps we can? (y/n)"))) {
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
			log_err(_("The rindex was not repaired.\n"));
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
		/* We cannot grow rindex at this point. Since pass1 has not
Packit Service 360c39
		   yet run, we can't allocate blocks. Therefore we must use
Packit Service 360c39
		   whatever will fix in the space given. */
Packit Service 360c39
		most_that_fit = sdp->md.riinode->i_di.di_size /
Packit Service 360c39
			sizeof(struct gfs2_rindex);
Packit Service 360c39
		log_debug(_("The most we can fit is %d rgrps\n"),
Packit Service 360c39
			  most_that_fit);
Packit Service 360c39
		if (most_that_fit < calc_rg_count)
Packit Service 360c39
			calc_rg_count = most_that_fit;
Packit Service 360c39
		log_err(_("Attempting to fix rindex with %d rgrps.\n"),
Packit Service 360c39
			calc_rg_count);
Packit Service 360c39
	}
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	/* Now compare the rindex to what we think it should be.         */
Packit Service 360c39
	/* See how far off our expected values are.  If too much, abort. */
Packit Service 360c39
	/* The theory is: if we calculated the index to have 32 RGs and  */
Packit Service 360c39
	/* we have a large number that are completely wrong, we should   */
Packit Service 360c39
	/* abandon this method of recovery and try a better one.         */
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	discrepancies = 0;
Packit Service 360c39
	for (rg = 0, n = osi_first(&sdp->rgtree), e = osi_first(&sdp->rgcalc);
Packit Service 360c39
	     n && e && !fsck_abort && rg < calc_rg_count; rg++) {
Packit Service 360c39
		struct rgrp_tree *expected, *actual;
Packit Service 360c39
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		enext = osi_next(e);
Packit Service 360c39
Packit Service 360c39
		expected = (struct rgrp_tree *)e;
Packit Service 360c39
		actual = (struct rgrp_tree *)n;
Packit Service 360c39
		if (actual->ri.ri_addr < expected->ri.ri_addr) {
Packit Service 360c39
			n = next;
Packit Service 360c39
			discrepancies++;
Packit Service 360c39
			log_info(_("%d addr: 0x%llx < 0x%llx * mismatch\n"),
Packit Service 360c39
				 rg + 1, actual->ri.ri_addr,
Packit Service 360c39
				 expected->ri.ri_addr);
Packit Service 360c39
			continue;
Packit Service 360c39
		} else if (expected->ri.ri_addr < actual->ri.ri_addr) {
Packit Service 360c39
			e = enext;
Packit Service 360c39
			discrepancies++;
Packit Service 360c39
			log_info(_("%d addr: 0x%llx > 0x%llx * mismatch\n"),
Packit Service 360c39
				 rg + 1, actual->ri.ri_addr,
Packit Service 360c39
				 expected->ri.ri_addr);
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
		if (!ri_equal(actual->ri, expected->ri, ri_length) ||
Packit Service 360c39
		    !ri_equal(actual->ri, expected->ri, ri_data0) ||
Packit Service 360c39
		    !ri_equal(actual->ri, expected->ri, ri_data) ||
Packit Service 360c39
		    !ri_equal(actual->ri, expected->ri, ri_bitbytes)) {
Packit Service 360c39
			discrepancies++;
Packit Service 360c39
			log_info(_("%d addr: 0x%llx 0x%llx * has mismatch\n"),
Packit Service 360c39
				 rg + 1, actual->ri.ri_addr,
Packit Service 360c39
				 expected->ri.ri_addr);
Packit Service 360c39
		}
Packit Service 360c39
		n = next;
Packit Service 360c39
		e = enext;
Packit Service 360c39
	}
Packit Service 360c39
	if (rg) {
Packit Service 360c39
		/* Check to see if more than 2% of the rgrps are wrong.  */
Packit Service 360c39
		percent = (discrepancies * 100) / rg;
Packit Service 360c39
		if (percent > BAD_RG_PERCENT_TOLERANCE) {
Packit Service 360c39
			log_warn( _("Level %d didn't work.  Too many "
Packit Service 360c39
				    "discrepancies.\n"), trust_lvl + 1);
Packit Service 360c39
			log_warn( _("%d out of %d rgrps (%d percent) did not "
Packit Service 360c39
				    "match what was expected.\n"),
Packit Service 360c39
				  discrepancies, rg, percent);
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
			gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	log_debug("Calculated %d rgrps: Total: %d Match: %d Mismatch: %d\n",
Packit Service 360c39
		  calc_rg_count, rg, rg - discrepancies, discrepancies);
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	/* Now compare the rindex to what we think it should be.         */
Packit Service 360c39
	/* Our rindex should be pretty predictable unless we've grown    */
Packit Service 360c39
	/* so look for index problems first before looking at the rgs.   */
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	for (rg = 0, n = osi_first(&sdp->rgtree), e = osi_first(&sdp->rgcalc);
Packit Service 360c39
	     e && !fsck_abort && rg < calc_rg_count; rg++) {
Packit Service 360c39
		struct rgrp_tree *expected, *actual;
Packit Service 360c39
Packit Service 360c39
		if (n)
Packit Service 360c39
			next = osi_next(n);
Packit Service 360c39
		enext = osi_next(e);
Packit Service 360c39
		expected = (struct rgrp_tree *)e;
Packit Service 360c39
		actual = (struct rgrp_tree *)n;
Packit Service 360c39
Packit Service 360c39
		/* If the next "actual" rgrp in memory is too far away,
Packit Service 360c39
		   fill in a new one with the expected value. -or-
Packit Service 360c39
		   If we ran out of actual rindex entries due to rindex
Packit Service 360c39
		   damage, fill in a new one with the expected values. */
Packit Service 360c39
		if (!n || /* end of actual rindex */
Packit Service 360c39
		    expected->ri.ri_addr < actual->ri.ri_addr) {
Packit Service 360c39
			log_err( _("Entry missing from rindex: 0x%llx\n"),
Packit Service 360c39
				 (unsigned long long)expected->ri.ri_addr);
Packit Service 360c39
			actual = rgrp_insert(&sdp->rgtree,
Packit Service 360c39
					     expected->ri.ri_addr);
Packit Service 360c39
			if (!actual) {
Packit Service 360c39
				log_err(_("Out of memory!\n"));
Packit Service 360c39
				break;
Packit Service 360c39
			}
Packit Service 360c39
			rindex_modified = 1;
Packit Service 360c39
			next = n; /* Ensure that the old actual gets checked
Packit Service 360c39
				     against a new expected, since we added */
Packit Service 360c39
		} else {
Packit Service 360c39
			ri_compare(rg, actual->ri, expected->ri, ri_addr,
Packit Service 360c39
				   "llx", unsigned long long);
Packit Service 360c39
			ri_compare(rg, actual->ri, expected->ri, ri_length,
Packit Service 360c39
				   "lx", unsigned long);
Packit Service 360c39
			ri_compare(rg, actual->ri, expected->ri, ri_data0,
Packit Service 360c39
				   "llx", unsigned long long);
Packit Service 360c39
			ri_compare(rg, actual->ri, expected->ri, ri_data,
Packit Service 360c39
				   "lx", unsigned long);
Packit Service 360c39
			ri_compare(rg, actual->ri, expected->ri, ri_bitbytes,
Packit Service 360c39
				   "lx", unsigned long);
Packit Service 360c39
		}
Packit Service 360c39
		/* If we modified the index, write it back to disk. */
Packit Service 360c39
		if (rindex_modified) {
Packit Service 360c39
			if (query( _("Fix the index? (y/n)"))) {
Packit Service 360c39
				gfs2_rindex_out(&expected->ri, (char *)&buf;;
Packit Service 360c39
				gfs2_writei(sdp->md.riinode, (char *)&buf,
Packit Service 360c39
					    rg * sizeof(struct gfs2_rindex),
Packit Service 360c39
					    sizeof(struct gfs2_rindex));
Packit Service 360c39
				actual->ri.ri_addr = expected->ri.ri_addr;
Packit Service 360c39
				actual->ri.ri_length = expected->ri.ri_length;
Packit Service 360c39
				actual->ri.ri_data0 = expected->ri.ri_data0;
Packit Service 360c39
				actual->ri.ri_data = expected->ri.ri_data;
Packit Service 360c39
				actual->ri.ri_bitbytes =
Packit Service 360c39
					expected->ri.ri_bitbytes;
Packit Service 360c39
				/* If our rindex was hosed, ri_length is bad */
Packit Service 360c39
				/* Therefore, gfs2_compute_bitstructs might  */
Packit Service 360c39
				/* have malloced the wrong length for bitmap */
Packit Service 360c39
				/* buffers.  So we have to redo it.          */
Packit Service 360c39
				if (actual->bits) {
Packit Service 360c39
					free(actual->bits);
Packit Service 360c39
					actual->bits = NULL;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			else
Packit Service 360c39
				log_err( _("rindex not fixed.\n"));
Packit Service 360c39
			gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, actual);
Packit Service 360c39
			rindex_modified = FALSE;
Packit Service 360c39
		}
Packit Service 360c39
		e = enext;
Packit Service 360c39
		if (n)
Packit Service 360c39
			n = next;
Packit Service 360c39
	}
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	/* Read the real RGs and check their integrity.                  */
Packit Service 360c39
	/* Now we can somewhat trust the rindex and the RG addresses,    */
Packit Service 360c39
	/* so let's read them in, check them and optionally fix them.    */
Packit Service 360c39
	/* ------------------------------------------------------------- */
Packit Service 360c39
	for (rg = 0, n = osi_first(&sdp->rgtree); n && !fsck_abort &&
Packit Service 360c39
		     rg < calc_rg_count; n = next, rg++) {
Packit Service 360c39
		struct rgrp_tree *rgd;
Packit Service 360c39
		uint64_t prev_err = 0, errblock;
Packit Service 360c39
		int i;
Packit Service 360c39
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		/* Now we try repeatedly to read in the rg.  For every block */
Packit Service 360c39
		/* we encounter that has errors, repair it and try again.    */
Packit Service 360c39
		i = 0;
Packit Service 360c39
		do {
Packit Service 360c39
			rgd = (struct rgrp_tree *)n;
Packit Service 360c39
			errblock = gfs2_rgrp_read(sdp, rgd);
Packit Service 360c39
			if (errblock) {
Packit Service 360c39
				if (errblock == prev_err)
Packit Service 360c39
					break;
Packit Service 360c39
				prev_err = errblock;
Packit Service 360c39
				rewrite_rg_block(sdp, rgd, errblock);
Packit Service 360c39
			} else {
Packit Service 360c39
				gfs2_rgrp_relse(rgd);
Packit Service 360c39
				break;
Packit Service 360c39
			}
Packit Service 360c39
			i++;
Packit Service 360c39
		} while (i < rgd->ri.ri_length);
Packit Service 360c39
	}
Packit Service 360c39
	*rg_count = rg;
Packit Service 360c39
	gfs2_rgrp_free(&sdp->rgcalc);
Packit Service 360c39
	gfs2_rgrp_free(&sdp->rgtree);
Packit Service 360c39
	/* We shouldn't need to worry about getting the user's permission to
Packit Service 360c39
	   make changes here. If b_modified is true, they already gave their
Packit Service 360c39
	   permission. */
Packit Service 360c39
	if (sdp->md.riinode->i_bh->b_modified) {
Packit Service 360c39
		log_debug("Syncing rindex inode changes to disk.\n");
Packit Service 360c39
		gfs2_dinode_out(&sdp->md.riinode->i_di, sdp->md.riinode->i_bh->b_data);
Packit Service 360c39
		bwrite(sdp->md.riinode->i_bh);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}