Blame gfs2/fsck/initialize.c.bz1622050-1-fsck_gfs2_Don_t_check_fs_formats_we_don_t_recognise

Packit c433c4
#include "clusterautoconfig.h"
Packit c433c4
Packit c433c4
#include <stdio.h>
Packit c433c4
#include <stdint.h>
Packit c433c4
#include <inttypes.h>
Packit c433c4
#include <stdlib.h>
Packit c433c4
#include <sys/types.h>
Packit c433c4
#include <sys/stat.h>
Packit c433c4
#include <fcntl.h>
Packit c433c4
#include <string.h>
Packit c433c4
#include <unistd.h>
Packit c433c4
#include <libintl.h>
Packit c433c4
#include <errno.h>
Packit c433c4
#include <time.h>
Packit c433c4
Packit c433c4
#define _(String) gettext(String)
Packit c433c4
Packit c433c4
#include <logging.h>
Packit c433c4
#include "libgfs2.h"
Packit c433c4
#include "fsck.h"
Packit c433c4
#include "util.h"
Packit c433c4
#include "fs_recovery.h"
Packit c433c4
#include "metawalk.h"
Packit c433c4
#include "inode_hash.h"
Packit c433c4
Packit c433c4
#define CLEAR_POINTER(x) \
Packit c433c4
	if (x) { \
Packit c433c4
		free(x); \
Packit c433c4
		x = NULL; \
Packit c433c4
	}
Packit c433c4
#define HIGHEST_BLOCK 0xffffffffffffffff
Packit c433c4
Packit c433c4
static int was_mounted_ro = 0;
Packit c433c4
static uint64_t possible_root = HIGHEST_BLOCK;
Packit c433c4
static struct master_dir fix_md;
Packit c433c4
static unsigned long long blks_2free = 0;
Packit c433c4
extern int sb_fixed;
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * block_mounters
Packit c433c4
 *
Packit c433c4
 * Change the lock protocol so nobody can mount the fs
Packit c433c4
 *
Packit c433c4
 */
Packit c433c4
static int block_mounters(struct gfs2_sbd *sdp, int block_em)
Packit c433c4
{
Packit c433c4
	if (block_em) {
Packit c433c4
		/* verify it starts with lock_ */
Packit c433c4
		if (!strncmp(sdp->sd_sb.sb_lockproto, "lock_", 5)) {
Packit c433c4
			/* Change lock_ to fsck_ */
Packit c433c4
			memcpy(sdp->sd_sb.sb_lockproto, "fsck_", 5);
Packit c433c4
		}
Packit c433c4
		/* FIXME: Need to do other verification in the else
Packit c433c4
		 * case */
Packit c433c4
	} else {
Packit c433c4
		/* verify it starts with fsck_ */
Packit c433c4
		/* verify it starts with lock_ */
Packit c433c4
		if (!strncmp(sdp->sd_sb.sb_lockproto, "fsck_", 5)) {
Packit c433c4
			/* Change fsck_ to lock_ */
Packit c433c4
			memcpy(sdp->sd_sb.sb_lockproto, "lock_", 5);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (lgfs2_sb_write(&sdp->sd_sb, sdp->device_fd, sdp->bsize)) {
Packit c433c4
		stack;
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
static void gfs2_dup_free(void)
Packit c433c4
{
Packit c433c4
	struct osi_node *n;
Packit c433c4
	struct duptree *dt;
Packit c433c4
Packit c433c4
	while ((n = osi_first(&dup_blocks))) {
Packit c433c4
		dt = (struct duptree *)n;
Packit c433c4
		dup_delete(dt);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
static void gfs2_dirtree_free(void)
Packit c433c4
{
Packit c433c4
	struct osi_node *n;
Packit c433c4
	struct dir_info *dt;
Packit c433c4
Packit c433c4
	while ((n = osi_first(&dirtree))) {
Packit c433c4
		dt = (struct dir_info *)n;
Packit c433c4
		dirtree_delete(dt);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
static void gfs2_inodetree_free(void)
Packit c433c4
{
Packit c433c4
	struct osi_node *n;
Packit c433c4
	struct inode_info *dt;
Packit c433c4
Packit c433c4
	while ((n = osi_first(&inodetree))) {
Packit c433c4
		dt = (struct inode_info *)n;
Packit c433c4
		inodetree_delete(dt);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
/*
Packit c433c4
 * empty_super_block - free all structures in the super block
Packit c433c4
 * sdp: the in-core super block
Packit c433c4
 *
Packit c433c4
 * This function frees all allocated structures within the
Packit c433c4
 * super block.  It does not free the super block itself.
Packit c433c4
 *
Packit c433c4
 * Returns: Nothing
Packit c433c4
 */
Packit c433c4
static void empty_super_block(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	log_info( _("Freeing buffers.\n"));
Packit c433c4
	gfs2_rgrp_free(&sdp->rgtree);
Packit c433c4
Packit c433c4
	gfs2_inodetree_free();
Packit c433c4
	gfs2_dirtree_free();
Packit c433c4
	gfs2_dup_free();
Packit c433c4
}
Packit c433c4
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * set_block_ranges
Packit c433c4
 * @sdp: superblock
Packit c433c4
 *
Packit c433c4
 * Uses info in rgrps and jindex to determine boundaries of the
Packit c433c4
 * file system.
Packit c433c4
 *
Packit c433c4
 * Returns: 0 on success, -1 on failure
Packit c433c4
 */
Packit c433c4
static int set_block_ranges(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	struct osi_node *n, *next = NULL;
Packit c433c4
	struct rgrp_tree *rgd;
Packit c433c4
	struct gfs2_rindex *ri;
Packit c433c4
	char buf[sdp->sd_sb.sb_bsize];
Packit c433c4
	uint64_t rmax = 0;
Packit c433c4
	uint64_t rmin = 0;
Packit c433c4
	int error;
Packit c433c4
Packit c433c4
	log_info( _("Setting block ranges..."));
Packit c433c4
Packit c433c4
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit c433c4
		next = osi_next(n);
Packit c433c4
		rgd = (struct rgrp_tree *)n;
Packit c433c4
		ri = &rgd->ri;
Packit c433c4
		if (ri->ri_data0 + ri->ri_data &&
Packit c433c4
		    ri->ri_data0 + ri->ri_data - 1 > rmax)
Packit c433c4
			rmax = ri->ri_data0 + ri->ri_data - 1;
Packit c433c4
		if (!rmin || ri->ri_data0 < rmin)
Packit c433c4
			rmin = ri->ri_data0;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	last_fs_block = rmax;
Packit c433c4
	if (last_fs_block > 0xffffffff && sizeof(unsigned long) <= 4) {
Packit c433c4
		log_crit( _("This file system is too big for this computer to handle.\n"));
Packit c433c4
		log_crit( _("Last fs block = 0x%llx, but sizeof(unsigned long) is %zu bytes.\n"),
Packit c433c4
			 (unsigned long long)last_fs_block,
Packit c433c4
			 sizeof(unsigned long));
Packit c433c4
		goto fail;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	last_data_block = rmax;
Packit c433c4
	first_data_block = rmin;
Packit c433c4
Packit c433c4
	if (fsck_lseek(sdp->device_fd, (last_fs_block * sdp->sd_sb.sb_bsize))){
Packit c433c4
		log_crit( _("Can't seek to last block in file system: %llu"
Packit c433c4
			 " (0x%llx)\n"), (unsigned long long)last_fs_block,
Packit c433c4
			 (unsigned long long)last_fs_block);
Packit c433c4
		goto fail;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	memset(buf, 0, sdp->sd_sb.sb_bsize);
Packit c433c4
	error = read(sdp->device_fd, buf, sdp->sd_sb.sb_bsize);
Packit c433c4
	if (error != sdp->sd_sb.sb_bsize){
Packit c433c4
		log_crit( _("Can't read last block in file system (error %u), "
Packit c433c4
			 "last_fs_block: %llu (0x%llx)\n"), error,
Packit c433c4
			 (unsigned long long)last_fs_block,
Packit c433c4
			 (unsigned long long)last_fs_block);
Packit c433c4
		goto fail;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	log_info(_("0x%llx to 0x%llx\n"), (unsigned long long)first_data_block,
Packit c433c4
		 (unsigned long long)last_data_block);
Packit c433c4
	return 0;
Packit c433c4
Packit c433c4
 fail:
Packit c433c4
	log_info( _("Error\n"));
Packit c433c4
	return -1;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * check_rgrp_integrity - verify a rgrp free block count against the bitmap
Packit c433c4
 */
Packit c433c4
static void check_rgrp_integrity(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit c433c4
				 int *fixit, int *this_rg_fixed,
Packit c433c4
				 int *this_rg_bad, int *this_rg_cleaned)
Packit c433c4
{
Packit c433c4
	uint32_t rg_free, rg_reclaimed, rg_unlinked, rg_usedmeta, rg_useddi;
Packit c433c4
	int rgb, x, y, off, bytes_to_check, total_bytes_to_check, asked = 0;
Packit c433c4
	unsigned int state;
Packit c433c4
	struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
Packit c433c4
	uint64_t diblock;
Packit c433c4
	struct gfs2_buffer_head *bh;
Packit c433c4
Packit c433c4
	rg_free = rg_reclaimed = rg_unlinked = rg_usedmeta = rg_useddi = 0;
Packit c433c4
	total_bytes_to_check = rgd->ri.ri_bitbytes;
Packit c433c4
Packit c433c4
	*this_rg_fixed = *this_rg_bad = *this_rg_cleaned = 0;
Packit c433c4
Packit c433c4
	diblock = rgd->ri.ri_data0;
Packit c433c4
	for (rgb = 0; rgb < rgd->ri.ri_length; rgb++){
Packit c433c4
		/* Count up the free blocks in the bitmap */
Packit c433c4
		off = (rgb) ? sizeof(struct gfs2_meta_header) :
Packit c433c4
			sizeof(struct gfs2_rgrp);
Packit c433c4
		if (total_bytes_to_check <= sdp->bsize - off)
Packit c433c4
			bytes_to_check = total_bytes_to_check;
Packit c433c4
		else
Packit c433c4
			bytes_to_check = sdp->bsize - off;
Packit c433c4
		total_bytes_to_check -= bytes_to_check;
Packit c433c4
		for (x = 0; x < bytes_to_check; x++) {
Packit c433c4
			unsigned char *byte;
Packit c433c4
Packit c433c4
			byte = (unsigned char *)&rgd->bits[rgb].bi_bh->b_data[off + x];
Packit c433c4
			if (*byte == 0x55) {
Packit c433c4
				diblock += GFS2_NBBY;
Packit c433c4
				continue;
Packit c433c4
			}
Packit c433c4
			if (*byte == 0x00) {
Packit c433c4
				diblock += GFS2_NBBY;
Packit c433c4
				rg_free += GFS2_NBBY;
Packit c433c4
				continue;
Packit c433c4
			}
Packit c433c4
			for (y = 0; y < GFS2_NBBY; y++) {
Packit c433c4
				state = (*byte >>
Packit c433c4
					 (GFS2_BIT_SIZE * y)) & GFS2_BIT_MASK;
Packit c433c4
				if (state == GFS2_BLKST_USED) {
Packit c433c4
					diblock++;
Packit c433c4
					continue;
Packit c433c4
				}
Packit c433c4
				if (state == GFS2_BLKST_DINODE) {
Packit c433c4
					if (sdp->gfs1) {
Packit c433c4
						bh = bread(sdp, diblock);
Packit c433c4
						if (!gfs2_check_meta(bh,
Packit c433c4
							GFS2_METATYPE_DI))
Packit c433c4
							rg_useddi++;
Packit c433c4
						else
Packit c433c4
							rg_usedmeta++;
Packit c433c4
						brelse(bh);
Packit c433c4
					}
Packit c433c4
					diblock++;
Packit c433c4
					continue;
Packit c433c4
				}
Packit c433c4
				if (state == GFS2_BLKST_FREE) {
Packit c433c4
					diblock++;
Packit c433c4
					rg_free++;
Packit c433c4
					continue;
Packit c433c4
				}
Packit c433c4
				/* GFS2_BLKST_UNLINKED */
Packit c433c4
				if (sdp->gfs1)
Packit c433c4
					log_info(_("Free metadata block 0x%llx"
Packit c433c4
						   " found.\n"),
Packit c433c4
						 (unsigned long long)diblock);
Packit c433c4
				else
Packit c433c4
					log_info(_("Unlinked dinode 0x%llx "
Packit c433c4
						   "found.\n"),
Packit c433c4
						 (unsigned long long)diblock);
Packit c433c4
				if (!asked) {
Packit c433c4
					char msg[256];
Packit c433c4
Packit c433c4
					asked = 1;
Packit c433c4
					sprintf(msg,
Packit c433c4
						_("Okay to reclaim free "
Packit c433c4
						  "metadata in resource group "
Packit c433c4
						  "%lld (0x%llx)? (y/n)"),
Packit c433c4
						(unsigned long long)rgd->ri.ri_addr,
Packit c433c4
						(unsigned long long)rgd->ri.ri_addr);
Packit c433c4
					if (query("%s", msg))
Packit c433c4
						*fixit = 1;
Packit c433c4
				}
Packit c433c4
				if (!(*fixit)) {
Packit c433c4
					rg_unlinked++;
Packit c433c4
					diblock++;
Packit c433c4
					continue;
Packit c433c4
				}
Packit c433c4
				*byte &= ~(GFS2_BIT_MASK <<
Packit c433c4
					   (GFS2_BIT_SIZE * y));
Packit c433c4
				bmodified(rgd->bits[rgb].bi_bh);
Packit c433c4
				rg_reclaimed++;
Packit c433c4
				rg_free++;
Packit c433c4
				rgd->rg.rg_free++;
Packit c433c4
				if (sdp->gfs1 && gfs1rg->rg_freemeta)
Packit c433c4
					gfs1rg->rg_freemeta--;
Packit c433c4
				log_info(_("Free metadata block %lld (0x%llx) "
Packit c433c4
					   "reclaimed.\n"),
Packit c433c4
					 (unsigned long long)diblock,
Packit c433c4
					 (unsigned long long)diblock);
Packit c433c4
				bh = bread(sdp, diblock);
Packit c433c4
				if (!gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
Packit c433c4
					struct gfs2_inode *ip =
Packit c433c4
						fsck_inode_get(sdp, rgd, bh);
Packit c433c4
					if (ip->i_di.di_blocks > 1) {
Packit c433c4
						blks_2free +=
Packit c433c4
							ip->i_di.di_blocks - 1;
Packit c433c4
						log_info(_("%lld blocks "
Packit c433c4
							   "(total) may need "
Packit c433c4
							   "to be freed in "
Packit c433c4
							   "pass 5.\n"),
Packit c433c4
							 blks_2free);
Packit c433c4
					}
Packit c433c4
					fsck_inode_put(&ip);
Packit c433c4
				}
Packit c433c4
				brelse(bh);
Packit c433c4
				diblock++;
Packit c433c4
			}
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
	/* The unlinked blocks we reclaim shouldn't be considered errors,
Packit c433c4
	   since we're just reclaiming them as a courtesy. If we already
Packit c433c4
	   got permission to reclaim them, we adjust the rgrp counts
Packit c433c4
	   accordingly. That way, only "real" rgrp count inconsistencies
Packit c433c4
	   will be reported. */
Packit c433c4
	if (rg_reclaimed && *fixit) {
Packit c433c4
		if (sdp->gfs1)
Packit c433c4
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit c433c4
		else
Packit c433c4
			gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit c433c4
		bmodified(rgd->bits[0].bi_bh);
Packit c433c4
		*this_rg_cleaned = 1;
Packit c433c4
		log_info( _("The rgrp at %lld (0x%llx) was cleaned of %d "
Packit c433c4
			    "free metadata blocks.\n"),
Packit c433c4
			  (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			  (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			  rg_reclaimed);
Packit c433c4
	}
Packit c433c4
	if (rgd->rg.rg_free != rg_free) {
Packit c433c4
		*this_rg_bad = 1;
Packit c433c4
		*this_rg_cleaned = 0;
Packit c433c4
		log_err( _("Error: resource group %lld (0x%llx): "
Packit c433c4
			   "free space (%d) does not match bitmap (%d)\n"),
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 rgd->rg.rg_free, rg_free);
Packit c433c4
		if (query( _("Fix the rgrp free blocks count? (y/n)"))) {
Packit c433c4
			rgd->rg.rg_free = rg_free;
Packit c433c4
			if (sdp->gfs1)
Packit c433c4
				gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit c433c4
			else
Packit c433c4
				gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit c433c4
			bmodified(rgd->bits[0].bi_bh);
Packit c433c4
			*this_rg_fixed = 1;
Packit c433c4
			log_err( _("The rgrp was fixed.\n"));
Packit c433c4
		} else
Packit c433c4
			log_err( _("The rgrp was not fixed.\n"));
Packit c433c4
	}
Packit c433c4
	if (!sdp->gfs1)
Packit c433c4
		return;
Packit c433c4
Packit c433c4
	if (gfs1rg->rg_freemeta != rg_unlinked) {
Packit c433c4
		*this_rg_bad = 1;
Packit c433c4
		*this_rg_cleaned = 0;
Packit c433c4
		log_err( _("Error: resource group %lld (0x%llx): "
Packit c433c4
			   "free meta  (%d) does not match bitmap (%d)\n"),
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 gfs1rg->rg_freemeta, rg_unlinked);
Packit c433c4
		if (query( _("Fix the rgrp free meta blocks count? (y/n)"))) {
Packit c433c4
			gfs1rg->rg_freemeta = rg_unlinked;
Packit c433c4
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit c433c4
			*this_rg_fixed = 1;
Packit c433c4
			log_err( _("The rgrp was fixed.\n"));
Packit c433c4
		} else
Packit c433c4
			log_err( _("The rgrp was not fixed.\n"));
Packit c433c4
	}
Packit c433c4
	if (gfs1rg->rg_useddi != rg_useddi) {
Packit c433c4
		*this_rg_bad = 1;
Packit c433c4
		*this_rg_cleaned = 0;
Packit c433c4
		log_err( _("Error: resource group %lld (0x%llx): used dinode "
Packit c433c4
			   "count (%d) does not match bitmap (%d)\n"),
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 gfs1rg->rg_useddi, rg_useddi);
Packit c433c4
		if (query( _("Fix the rgrp used dinode block count? (y/n)"))) {
Packit c433c4
			gfs1rg->rg_useddi = rg_useddi;
Packit c433c4
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
Packit c433c4
				     rgd->bits[0].bi_bh);
Packit c433c4
			*this_rg_fixed = 1;
Packit c433c4
			log_err( _("The rgrp was fixed.\n"));
Packit c433c4
		} else
Packit c433c4
			log_err( _("The rgrp was not fixed.\n"));
Packit c433c4
	}
Packit c433c4
	if (gfs1rg->rg_usedmeta != rg_usedmeta) {
Packit c433c4
		*this_rg_bad = 1;
Packit c433c4
		*this_rg_cleaned = 0;
Packit c433c4
		log_err( _("Error: resource group %lld (0x%llx): used "
Packit c433c4
			   "metadata (%d) does not match bitmap (%d)\n"),
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			 gfs1rg->rg_usedmeta, rg_usedmeta);
Packit c433c4
		if (query( _("Fix the rgrp used meta blocks count? (y/n)"))) {
Packit c433c4
			gfs1rg->rg_usedmeta = rg_usedmeta;
Packit c433c4
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg,
Packit c433c4
				     rgd->bits[0].bi_bh);
Packit c433c4
			*this_rg_fixed = 1;
Packit c433c4
			log_err( _("The rgrp was fixed.\n"));
Packit c433c4
		} else
Packit c433c4
			log_err( _("The rgrp was not fixed.\n"));
Packit c433c4
	}
Packit c433c4
	/*
Packit c433c4
	else {
Packit c433c4
		log_debug( _("Resource group %lld (0x%llx) free space "
Packit c433c4
			     "is consistent: free: %d reclaimed: %d\n"),
Packit c433c4
			   (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			   (unsigned long long)rgd->ri.ri_addr,
Packit c433c4
			   rg_free, rg_reclaimed);
Packit c433c4
	}*/
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * check_rgrps_integrity - verify rgrp consistency
Packit c433c4
 * Note: We consider an rgrp "cleaned" if the unlinked meta blocks are
Packit c433c4
 *       cleaned, so not quite "bad" and not quite "good" but rewritten anyway.
Packit c433c4
 *
Packit c433c4
 * Returns: 0 on success, 1 if errors were detected
Packit c433c4
 */
Packit c433c4
static void check_rgrps_integrity(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	struct osi_node *n, *next = NULL;
Packit c433c4
	int rgs_good = 0, rgs_bad = 0, rgs_fixed = 0, rgs_cleaned = 0;
Packit c433c4
	int was_bad = 0, was_fixed = 0, was_cleaned = 0;
Packit c433c4
	struct rgrp_tree *rgd;
Packit c433c4
	int reclaim_unlinked = 0;
Packit c433c4
Packit c433c4
	log_info( _("Checking the integrity of all resource groups.\n"));
Packit c433c4
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit c433c4
		next = osi_next(n);
Packit c433c4
		rgd = (struct rgrp_tree *)n;
Packit c433c4
		if (fsck_abort)
Packit c433c4
			return;
Packit c433c4
		check_rgrp_integrity(sdp, rgd, &reclaim_unlinked,
Packit c433c4
				     &was_fixed, &was_bad, &was_cleaned);
Packit c433c4
		if (was_fixed)
Packit c433c4
			rgs_fixed++;
Packit c433c4
		if (was_cleaned)
Packit c433c4
			rgs_cleaned++;
Packit c433c4
		else if (was_bad)
Packit c433c4
			rgs_bad++;
Packit c433c4
		else
Packit c433c4
			rgs_good++;
Packit c433c4
	}
Packit c433c4
	if (rgs_bad || rgs_cleaned) {
Packit c433c4
		log_err( _("RGs: Consistent: %d   Cleaned: %d   Inconsistent: "
Packit c433c4
			   "%d   Fixed: %d   Total: %d\n"),
Packit c433c4
			 rgs_good, rgs_cleaned, rgs_bad, rgs_fixed,
Packit c433c4
			 rgs_good + rgs_bad + rgs_cleaned);
Packit c433c4
		if (rgs_cleaned && blks_2free)
Packit c433c4
			log_err(_("%lld blocks may need to be freed in pass 5 "
Packit c433c4
				  "due to the cleaned resource groups.\n"),
Packit c433c4
				blks_2free);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * rebuild_master - rebuild a destroyed master directory
Packit c433c4
 */
Packit c433c4
static int rebuild_master(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	struct gfs2_inum inum;
Packit c433c4
	struct gfs2_buffer_head *bh = NULL;
Packit c433c4
	int err = 0;
Packit c433c4
Packit c433c4
	log_err(_("The system master directory seems to be destroyed.\n"));
Packit c433c4
	if (!query(_("Okay to rebuild it? (y/n)"))) {
Packit c433c4
		log_err(_("System master not rebuilt; aborting.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	log_err(_("Trying to rebuild the master directory.\n"));
Packit c433c4
	inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
	inum.no_addr = sdp->sd_sb.sb_master_dir.no_addr;
Packit c433c4
	err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum);
Packit c433c4
	if (err != 0)
Packit c433c4
		return -1;
Packit c433c4
	sdp->master_dir = lgfs2_inode_get(sdp, bh);
Packit c433c4
	if (sdp->master_dir == NULL) {
Packit c433c4
		log_crit(_("Error reading master: %s\n"), strerror(errno));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	sdp->master_dir->bh_owned = 1;
Packit c433c4
Packit c433c4
	if (fix_md.jiinode) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.jiinode->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "jindex", 6, &inum,
Packit c433c4
		              IF2DT(S_IFDIR | 0700));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding jindex directory\n"), errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		sdp->master_dir->i_di.di_nlink++;
Packit c433c4
	} else {
Packit c433c4
		err = build_jindex(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building jindex\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (fix_md.pinode) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.pinode->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "per_node", 8, &inum,
Packit c433c4
			IF2DT(S_IFDIR | 0700));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding per_node directory\n"),
Packit c433c4
				 errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		sdp->master_dir->i_di.di_nlink++;
Packit c433c4
	} else {
Packit c433c4
		err = build_per_node(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building per_node directory\n"),
Packit c433c4
			         err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (fix_md.inum) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.inum->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "inum", 4, &inum,
Packit c433c4
			IF2DT(S_IFREG | 0600));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding inum inode\n"), errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	} else {
Packit c433c4
		err = build_inum(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building inum inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (fix_md.statfs) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.statfs->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "statfs", 6, &inum,
Packit c433c4
			      IF2DT(S_IFREG | 0600));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding statfs inode\n"), errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	} else {
Packit c433c4
		err = build_statfs(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building statfs inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (fix_md.riinode) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.riinode->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "rindex", 6, &inum,
Packit c433c4
			IF2DT(S_IFREG | 0600));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding rindex inode\n"), errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	} else {
Packit c433c4
		err = build_rindex(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building rindex inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (fix_md.qinode) {
Packit c433c4
		inum.no_formal_ino = sdp->md.next_inum++;
Packit c433c4
		inum.no_addr = fix_md.qinode->i_di.di_num.no_addr;
Packit c433c4
		err = dir_add(sdp->master_dir, "quota", 5, &inum,
Packit c433c4
			IF2DT(S_IFREG | 0600));
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d adding quota inode\n"), errno);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	} else {
Packit c433c4
		err = build_quota(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d building quota inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	log_err(_("Master directory rebuilt.\n"));
Packit c433c4
	inode_put(&sdp->md.inum);
Packit c433c4
	inode_put(&sdp->md.statfs);
Packit c433c4
	inode_put(&sdp->master_dir);
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * lookup_per_node - Make sure the per_node directory is read in
Packit c433c4
 *
Packit c433c4
 * This function is used to read in the per_node directory.  It is called
Packit c433c4
 * twice.  The first call tries to read in the dinode early on.  That ensures
Packit c433c4
 * that if any journals are missing, we can figure out the number of journals
Packit c433c4
 * from per_node.  However, we unfortunately can't rebuild per_node at that
Packit c433c4
 * point in time because our resource groups aren't read in yet.
Packit c433c4
 * The second time it's called is much later when we can rebuild it.
Packit c433c4
 *
Packit c433c4
 * allow_rebuild: 0 if rebuilds are not allowed
Packit c433c4
 *                1 if rebuilds are allowed
Packit c433c4
 */
Packit c433c4
static void lookup_per_node(struct gfs2_sbd *sdp, int allow_rebuild)
Packit c433c4
{
Packit c433c4
	if (sdp->md.pinode)
Packit c433c4
		return;
Packit c433c4
Packit c433c4
	gfs2_lookupi(sdp->master_dir, "per_node", 8, &sdp->md.pinode);
Packit c433c4
	if (sdp->md.pinode)
Packit c433c4
		return;
Packit c433c4
	if (!allow_rebuild) {
Packit c433c4
		log_err( _("The gfs2 system per_node directory "
Packit c433c4
			   "inode is missing, so we might not be \nable to "
Packit c433c4
			   "rebuild missing journals this run.\n"));
Packit c433c4
		return;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (query( _("The gfs2 system per_node directory "
Packit c433c4
		     "inode is missing. Okay to rebuild it? (y/n) "))) {
Packit c433c4
		int err;
Packit c433c4
Packit c433c4
		err = build_per_node(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d rebuilding per_node directory\n"),
Packit c433c4
				 err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
	gfs2_lookupi(sdp->master_dir, "per_node", 8, &sdp->md.pinode);
Packit c433c4
	if (!sdp->md.pinode) {
Packit c433c4
		log_err( _("Unable to rebuild per_node; aborting.\n"));
Packit c433c4
		exit(FSCK_ERROR);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * fetch_rgrps - fetch the resource groups from disk, and check their integrity
Packit c433c4
 */
Packit c433c4
static int fetch_rgrps(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	enum rgindex_trust_level trust_lvl;
Packit c433c4
	int rgcount, sane = 1;
Packit c433c4
Packit c433c4
	const char *level_desc[] = {
Packit c433c4
		_("Checking if all rgrp and rindex values are good"),
Packit c433c4
		_("Checking if rindex values may be easily repaired"),
Packit c433c4
		_("Calculating where the rgrps should be if evenly spaced"),
Packit c433c4
		_("Trying to rebuild rindex assuming evenly spaced rgrps"),
Packit c433c4
		_("Trying to rebuild rindex assuming unevenly spaced rgrps"),
Packit c433c4
	};
Packit c433c4
	const char *fail_desc[] = {
Packit c433c4
		_("Some damage was found; we need to take remedial measures"),
Packit c433c4
		_("rindex is unevenly spaced: either gfs1-style or corrupt"),
Packit c433c4
		_("rindex calculations don't match: uneven rgrp boundaries"),
Packit c433c4
		_("Too many rgrp misses: rgrps must be unevenly spaced"),
Packit c433c4
		_("Too much damage found: we cannot rebuild this rindex"),
Packit c433c4
	};
Packit c433c4
	/*******************************************************************
Packit c433c4
	 ********  Validate and read in resource group information  ********
Packit c433c4
	 *******************************************************************/
Packit c433c4
	log_notice(_("Validating resource group index.\n"));
Packit c433c4
	for (trust_lvl = blind_faith; trust_lvl <= indignation; trust_lvl++) {
Packit c433c4
		int ret = 0;
Packit c433c4
Packit c433c4
		log_notice(_("Level %d resource group check: %s.\n"), trust_lvl + 1,
Packit c433c4
			  level_desc[trust_lvl]);
Packit c433c4
		if ((rg_repair(sdp, trust_lvl, &rgcount, &sane) == 0) &&
Packit c433c4
		    ((ret = ri_update(sdp, 0, &rgcount, &sane)) == 0)) {
Packit c433c4
			log_notice(_("(level %d passed)\n"), trust_lvl + 1);
Packit c433c4
			break;
Packit c433c4
		} else {
Packit c433c4
			if (ret == -1)
Packit c433c4
				log_err( _("(level %d failed: %s)\n"),
Packit c433c4
					 trust_lvl + 1, fail_desc[trust_lvl]);
Packit c433c4
			else
Packit c433c4
				log_err( _("(level %d failed at block %lld "
Packit c433c4
					   "(0x%llx): %s)\n"), trust_lvl + 1,
Packit c433c4
					 (unsigned long long)ret,
Packit c433c4
					 (unsigned long long)ret,
Packit c433c4
					 fail_desc[trust_lvl]);
Packit c433c4
		}
Packit c433c4
		if (fsck_abort)
Packit c433c4
			break;
Packit c433c4
	}
Packit c433c4
	if (trust_lvl > indignation) {
Packit c433c4
		log_err( _("Resource group recovery impossible; I can't fix "
Packit c433c4
			   "this file system.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	log_info( _("%u resource groups found.\n"), rgcount);
Packit c433c4
Packit c433c4
	check_rgrps_integrity(sdp);
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * init_system_inodes
Packit c433c4
 *
Packit c433c4
 * Returns: 0 on success, -1 on failure
Packit c433c4
 */
Packit c433c4
static int init_system_inodes(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	uint64_t inumbuf = 0;
Packit c433c4
	char *buf;
Packit c433c4
	struct gfs2_statfs_change sc;
Packit c433c4
	int err;
Packit c433c4
Packit c433c4
	/*******************************************************************
Packit c433c4
	 ******************  Initialize important inodes  ******************
Packit c433c4
	 *******************************************************************/
Packit c433c4
Packit c433c4
	log_info( _("Initializing special inodes...\n"));
Packit c433c4
Packit c433c4
	/* Get root dinode */
Packit c433c4
	sdp->md.rooti = lgfs2_inode_read(sdp, sdp->sd_sb.sb_root_dir.no_addr);
Packit c433c4
	if (sdp->md.rooti == NULL)
Packit c433c4
		return -1;
Packit c433c4
Packit c433c4
	/*******************************************************************
Packit c433c4
	 *****************  Initialize more system inodes  *****************
Packit c433c4
	 *******************************************************************/
Packit c433c4
	if (!sdp->gfs1) {
Packit c433c4
		/* Look for "inum" entry in master dinode */
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
Packit c433c4
		if (!sdp->md.inum) {
Packit c433c4
			if (!query( _("The gfs2 system inum inode is missing. "
Packit c433c4
				      "Okay to rebuild it? (y/n) "))) {
Packit c433c4
				log_err( _("fsck.gfs2 cannot continue without "
Packit c433c4
					   "a valid inum file; aborting.\n"));
Packit c433c4
				goto fail;
Packit c433c4
			}
Packit c433c4
			err = build_inum(sdp);
Packit c433c4
			if (err) {
Packit c433c4
				log_crit(_("Error %d rebuilding inum inode\n"),
Packit c433c4
					 err);
Packit c433c4
				exit(FSCK_ERROR);
Packit c433c4
			}
Packit c433c4
			gfs2_lookupi(sdp->master_dir, "inum", 4,
Packit c433c4
				     &sdp->md.inum);
Packit c433c4
			if (!sdp->md.inum) {
Packit c433c4
				log_crit(_("System inum inode was not rebuilt."
Packit c433c4
					   " Aborting.\n"));
Packit c433c4
				goto fail;
Packit c433c4
			}
Packit c433c4
		}
Packit c433c4
		/* Read inum entry into buffer */
Packit c433c4
		err = gfs2_readi(sdp->md.inum, &inumbuf, 0,
Packit c433c4
				 sdp->md.inum->i_di.di_size);
Packit c433c4
		if (err != sdp->md.inum->i_di.di_size) {
Packit c433c4
			log_crit(_("Error %d reading system inum inode. "
Packit c433c4
				   "Aborting.\n"), err);
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
		/* call gfs2_inum_range_in() to retrieve range */
Packit c433c4
		sdp->md.next_inum = be64_to_cpu(inumbuf);
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (sdp->gfs1) {
Packit c433c4
		/* In gfs1, the license_di is always 3 blocks after the jindex_di */
Packit c433c4
		if ((sbd1->sb_license_di.no_addr != sbd1->sb_jindex_di.no_addr + 3) ||
Packit c433c4
		    (sbd1->sb_license_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 3)) {
Packit c433c4
			if (!query( _("The gfs system statfs inode pointer is incorrect. "
Packit c433c4
				      "Okay to correct? (y/n) "))) {
Packit c433c4
				log_err( _("fsck.gfs2 cannot continue without a valid "
Packit c433c4
					   "statfs file; aborting.\n"));
Packit c433c4
				goto fail;
Packit c433c4
			}
Packit c433c4
			sbd1->sb_license_di.no_addr = sbd1->sb_license_di.no_formal_ino
Packit c433c4
				= sbd1->sb_jindex_di.no_addr + 3;
Packit c433c4
		}
Packit c433c4
Packit c433c4
		sdp->md.statfs = lgfs2_inode_read(sdp, sbd1->sb_license_di.no_addr);
Packit c433c4
		if (sdp->md.statfs == NULL) {
Packit c433c4
			log_crit(_("Error reading statfs inode: %s\n"), strerror(errno));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
	} else
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
Packit c433c4
	if (!sdp->gfs1 && !sdp->md.statfs) {
Packit c433c4
		if (!query( _("The gfs2 system statfs inode is missing. "
Packit c433c4
			      "Okay to rebuild it? (y/n) "))) {
Packit c433c4
			log_err( _("fsck.gfs2 cannot continue without a valid "
Packit c433c4
				   "statfs file; aborting.\n"));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
		err = build_statfs(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d rebuilding statfs inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
Packit c433c4
		if (!sdp->md.statfs) {
Packit c433c4
			log_err( _("Rebuild of statfs system file failed."));
Packit c433c4
			log_err( _("fsck.gfs2 cannot continue without "
Packit c433c4
				   "a valid statfs file; aborting.\n"));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
		do_init_statfs(sdp);
Packit c433c4
	}
Packit c433c4
	if (sdp->md.statfs->i_di.di_size) {
Packit c433c4
		buf = malloc(sdp->md.statfs->i_di.di_size);
Packit c433c4
		if (buf) {
Packit c433c4
			err = gfs2_readi(sdp->md.statfs, buf, 0,
Packit c433c4
					 sdp->md.statfs->i_di.di_size);
Packit c433c4
			if (err != sdp->md.statfs->i_di.di_size) {
Packit c433c4
				log_crit(_("Error %d reading statfs file. "
Packit c433c4
					   "Aborting.\n"), err);
Packit c433c4
				free(buf);
Packit c433c4
				goto fail;
Packit c433c4
			}
Packit c433c4
			/* call gfs2_inum_range_in() to retrieve range */
Packit c433c4
			gfs2_statfs_change_in(&sc, buf);
Packit c433c4
			free(buf);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (sdp->gfs1) {
Packit c433c4
		/* In gfs1, the quota_di is always 2 blocks after the jindex_di */
Packit c433c4
		if ((sbd1->sb_quota_di.no_addr != sbd1->sb_jindex_di.no_addr + 2) ||
Packit c433c4
		    (sbd1->sb_quota_di.no_formal_ino != sbd1->sb_jindex_di.no_addr + 2)) {
Packit c433c4
			if (!query( _("The gfs system quota inode pointer is incorrect. "
Packit c433c4
				      " Okay to correct? (y/n) "))) {
Packit c433c4
				log_err( _("fsck.gfs2 cannot continue without a valid "
Packit c433c4
					   "quota file; aborting.\n"));
Packit c433c4
				goto fail;
Packit c433c4
			}
Packit c433c4
			sbd1->sb_quota_di.no_addr = sbd1->sb_quota_di.no_formal_ino
Packit c433c4
				= sbd1->sb_jindex_di.no_addr + 2;
Packit c433c4
		}
Packit c433c4
Packit c433c4
		sdp->md.qinode = lgfs2_inode_read(sdp, sbd1->sb_quota_di.no_addr);
Packit c433c4
		if (sdp->md.qinode == NULL) {
Packit c433c4
			log_crit(_("Error reading quota inode: %s\n"), strerror(errno));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
	} else
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
Packit c433c4
	if (!sdp->gfs1 && !sdp->md.qinode) {
Packit c433c4
		if (!query( _("The gfs2 system quota inode is missing. "
Packit c433c4
			      "Okay to rebuild it? (y/n) "))) {
Packit c433c4
			log_crit(_("System quota inode was not "
Packit c433c4
				   "rebuilt.  Aborting.\n"));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
		err = build_quota(sdp);
Packit c433c4
		if (err) {
Packit c433c4
			log_crit(_("Error %d rebuilding quota inode\n"), err);
Packit c433c4
			exit(FSCK_ERROR);
Packit c433c4
		}
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "quota", 5, &sdp->md.qinode);
Packit c433c4
		if (!sdp->md.qinode) {
Packit c433c4
			log_crit(_("Unable to rebuild system quota file "
Packit c433c4
				   "inode.  Aborting.\n"));
Packit c433c4
			goto fail;
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	/* Try to lookup the per_node inode.  If it was missing, it is now
Packit c433c4
	   safe to rebuild it. */
Packit c433c4
	if (!sdp->gfs1)
Packit c433c4
		lookup_per_node(sdp, 1);
Packit c433c4
Packit c433c4
	/*******************************************************************
Packit c433c4
	 *******  Now, set boundary fields in the super block  *************
Packit c433c4
	 *******************************************************************/
Packit c433c4
	if (set_block_ranges(sdp)){
Packit c433c4
		log_err( _("Unable to determine the boundaries of the"
Packit c433c4
			" file system.\n"));
Packit c433c4
		goto fail;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	return 0;
Packit c433c4
 fail:
Packit c433c4
	empty_super_block(sdp);
Packit c433c4
Packit c433c4
	return -1;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * is_journal_copy - Is this a "real" dinode or a copy inside a journal?
Packit c433c4
 * A real dinode will be located at the block number in its no_addr.
Packit c433c4
 * A journal-copy will be at a different block (inside the journal).
Packit c433c4
 */
Packit c433c4
static int is_journal_copy(struct gfs2_inode *ip, struct gfs2_buffer_head *bh)
Packit c433c4
{
Packit c433c4
	if (ip->i_di.di_num.no_addr == bh->b_blocknr)
Packit c433c4
		return 0;
Packit c433c4
	return 1; /* journal copy */
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * peruse_system_dinode - process a system dinode
Packit c433c4
 *
Packit c433c4
 * This function looks at a system dinode and tries to figure out which
Packit c433c4
 * dinode it is: statfs, inum, per_node, master, etc.  Some of them we
Packit c433c4
 * can deduce from the contents.  For example, di_size will be a multiple
Packit c433c4
 * of 96 for the rindex.  di_size will be 8 for inum, 24 for statfs, etc.
Packit c433c4
 * the per_node directory will have a ".." entry that will lead us to
Packit c433c4
 * the master dinode if it's been destroyed.
Packit c433c4
 */
Packit c433c4
static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
Packit c433c4
				 struct gfs2_buffer_head *bh)
Packit c433c4
{
Packit c433c4
	struct gfs2_inode *ip, *child_ip;
Packit c433c4
	struct gfs2_inum inum;
Packit c433c4
	int error;
Packit c433c4
Packit c433c4
	if (di->di_num.no_formal_ino == 2) {
Packit c433c4
		if (sdp->sd_sb.sb_master_dir.no_addr)
Packit c433c4
			return;
Packit c433c4
		log_warn(_("Found system master directory at: 0x%llx.\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
		sdp->sd_sb.sb_master_dir.no_addr = di->di_num.no_addr;
Packit c433c4
		return;
Packit c433c4
	}
Packit c433c4
	ip = lgfs2_inode_read(sdp, di->di_num.no_addr);
Packit c433c4
	if (ip == NULL) {
Packit c433c4
		log_crit(_("Error reading inode: %s\n"), strerror(errno));
Packit c433c4
		return;
Packit c433c4
	}
Packit c433c4
	if ((!sdp->gfs1 && di->di_num.no_formal_ino == 3) ||
Packit c433c4
	    (sdp->gfs1 && (di->di_flags & GFS2_DIF_JDATA) &&
Packit c433c4
	     (di->di_size % sizeof(struct gfs_jindex) == 0))) {
Packit c433c4
		if (fix_md.jiinode || is_journal_copy(ip, bh))
Packit c433c4
			goto out_discard_ip;
Packit c433c4
		log_warn(_("Found system jindex file at: 0x%llx\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
		fix_md.jiinode = ip;
Packit c433c4
	} else if (!sdp->gfs1 && is_dir(di, sdp->gfs1)) {
Packit c433c4
		/* Check for a jindex dir entry. Only one system dir has a
Packit c433c4
		   jindex: master */
Packit c433c4
		gfs2_lookupi(ip, "jindex", 6, &child_ip);
Packit c433c4
		if (child_ip) {
Packit c433c4
			if (fix_md.jiinode || is_journal_copy(ip, bh)) {
Packit c433c4
				inode_put(&child_ip);
Packit c433c4
				goto out_discard_ip;
Packit c433c4
			}
Packit c433c4
			fix_md.jiinode = child_ip;
Packit c433c4
			sdp->sd_sb.sb_master_dir.no_addr = di->di_num.no_addr;
Packit c433c4
			log_warn(_("Found system master directory at: "
Packit c433c4
				   "0x%llx\n"), di->di_num.no_addr);
Packit c433c4
			return;
Packit c433c4
		}
Packit c433c4
Packit c433c4
		/* Check for a statfs_change0 dir entry. Only one system dir
Packit c433c4
		   has a statfs_change: per_node, and its .. will be master. */
Packit c433c4
		gfs2_lookupi(ip, "statfs_change0", 14, &child_ip);
Packit c433c4
		if (child_ip) {
Packit c433c4
			inode_put(&child_ip);
Packit c433c4
			if (fix_md.pinode || is_journal_copy(ip, bh))
Packit c433c4
				goto out_discard_ip;
Packit c433c4
			log_warn(_("Found system per_node directory at: "
Packit c433c4
				   "0x%llx\n"), ip->i_di.di_num.no_addr);
Packit c433c4
			fix_md.pinode = ip;
Packit c433c4
			error = dir_search(ip, "..", 2, NULL, &inum);
Packit c433c4
			if (!error && inum.no_addr) {
Packit c433c4
				sdp->sd_sb.sb_master_dir.no_addr =
Packit c433c4
					inum.no_addr;
Packit c433c4
				log_warn(_("From per_node\'s \'..\' I "
Packit c433c4
					   "backtracked the master directory "
Packit c433c4
					   "to: 0x%llx\n"), inum.no_addr);
Packit c433c4
			}
Packit c433c4
			return;
Packit c433c4
		}
Packit c433c4
		log_debug(_("Unknown system directory at block 0x%llx\n"),
Packit c433c4
			  di->di_num.no_addr);
Packit c433c4
		goto out_discard_ip;
Packit c433c4
	} else if (!sdp->gfs1 && di->di_size == 8) {
Packit c433c4
		if (fix_md.inum || is_journal_copy(ip, bh))
Packit c433c4
			goto out_discard_ip;
Packit c433c4
		fix_md.inum = ip;
Packit c433c4
		log_warn(_("Found system inum file at: 0x%llx\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
	} else if (di->di_size == 24) {
Packit c433c4
		if (fix_md.statfs || is_journal_copy(ip, bh))
Packit c433c4
			goto out_discard_ip;
Packit c433c4
		fix_md.statfs = ip;
Packit c433c4
		log_warn(_("Found system statfs file at: 0x%llx\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
	} else if ((di->di_size % 96) == 0) {
Packit c433c4
		if (fix_md.riinode || is_journal_copy(ip, bh))
Packit c433c4
			goto out_discard_ip;
Packit c433c4
		fix_md.riinode = ip;
Packit c433c4
		log_warn(_("Found system rindex file at: 0x%llx\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
	} else if (!fix_md.qinode && di->di_size >= 176 &&
Packit c433c4
		   di->di_num.no_formal_ino >= 12 &&
Packit c433c4
		   di->di_num.no_formal_ino <= 100) {
Packit c433c4
		if (is_journal_copy(ip, bh))
Packit c433c4
			goto out_discard_ip;
Packit c433c4
		fix_md.qinode = ip;
Packit c433c4
		log_warn(_("Found system quota file at: 0x%llx\n"),
Packit c433c4
			 di->di_num.no_addr);
Packit c433c4
	} else {
Packit c433c4
out_discard_ip:
Packit c433c4
		inode_put(&ip);
Packit c433c4
	}
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * peruse_user_dinode - process a user dinode trying to find the root directory
Packit c433c4
 *
Packit c433c4
 */
Packit c433c4
static void peruse_user_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
Packit c433c4
			       struct gfs2_buffer_head *bh)
Packit c433c4
{
Packit c433c4
	struct gfs2_inode *ip, *parent_ip;
Packit c433c4
	struct gfs2_inum inum;
Packit c433c4
	int error;
Packit c433c4
Packit c433c4
	if (sdp->sd_sb.sb_root_dir.no_addr) /* if we know the root dinode */
Packit c433c4
		return;             /* we don't need to find the root */
Packit c433c4
	if (!is_dir(di, sdp->gfs1))  /* if this isn't a directory */
Packit c433c4
		return;             /* it can't lead us to the root anyway */
Packit c433c4
Packit c433c4
	if (di->di_num.no_formal_ino == 1) {
Packit c433c4
		struct gfs2_buffer_head *root_bh;
Packit c433c4
Packit c433c4
		if (di->di_num.no_addr == bh->b_blocknr) {
Packit c433c4
			log_warn(_("Found the root directory at: 0x%llx.\n"),
Packit c433c4
				 di->di_num.no_addr);
Packit c433c4
			sdp->sd_sb.sb_root_dir.no_addr = di->di_num.no_addr;
Packit c433c4
			return;
Packit c433c4
		}
Packit c433c4
		log_warn(_("The root dinode should be at block 0x%llx but it "
Packit c433c4
			   "seems to be destroyed.\n"),
Packit c433c4
			 (unsigned long long)di->di_num.no_addr);
Packit c433c4
		log_warn(_("Found a copy of the root directory in a journal "
Packit c433c4
			   "at block: 0x%llx.\n"),
Packit c433c4
			 (unsigned long long)bh->b_blocknr);
Packit c433c4
		if (!query(_("Do you want to replace the root dinode from the "
Packit c433c4
			     "copy? (y/n)"))) {
Packit c433c4
			log_err(_("Damaged root dinode not fixed.\n"));
Packit c433c4
			return;
Packit c433c4
		}
Packit c433c4
		root_bh = bread(sdp, di->di_num.no_addr);
Packit c433c4
		memcpy(root_bh->b_data, bh->b_data, sdp->bsize);
Packit c433c4
		bmodified(root_bh);
Packit c433c4
		brelse(root_bh);
Packit c433c4
		log_warn(_("Root directory copied from the journal.\n"));
Packit c433c4
		return;
Packit c433c4
	}
Packit c433c4
	ip = lgfs2_inode_read(sdp, di->di_num.no_addr);
Packit c433c4
	if (ip == NULL) {
Packit c433c4
		log_crit(_("Error reading inode: %s\n"), strerror(errno));
Packit c433c4
		return;
Packit c433c4
	}
Packit c433c4
	while (ip) {
Packit c433c4
		gfs2_lookupi(ip, "..", 2, &parent_ip);
Packit c433c4
		if (parent_ip && parent_ip->i_di.di_num.no_addr ==
Packit c433c4
		    ip->i_di.di_num.no_addr) {
Packit c433c4
			log_warn(_("Found the root directory at: 0x%llx\n"),
Packit c433c4
				 ip->i_di.di_num.no_addr);
Packit c433c4
			sdp->sd_sb.sb_root_dir.no_addr =
Packit c433c4
				ip->i_di.di_num.no_addr;
Packit c433c4
			inode_put(&parent_ip);
Packit c433c4
			inode_put(&ip);
Packit c433c4
			return;
Packit c433c4
		}
Packit c433c4
		if (!parent_ip)
Packit c433c4
			break;
Packit c433c4
		inode_put(&ip);
Packit c433c4
		ip = parent_ip;
Packit c433c4
	}
Packit c433c4
	error = dir_search(ip, "..", 2, NULL, &inum);
Packit c433c4
	if (!error && inum.no_addr && inum.no_addr < possible_root) {
Packit c433c4
			possible_root = inum.no_addr;
Packit c433c4
			log_debug(_("Found a possible root at: 0x%llx\n"),
Packit c433c4
				  (unsigned long long)possible_root);
Packit c433c4
	}
Packit c433c4
	inode_put(&ip);
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * find_rgs_for_bsize - check a range of blocks for rgrps to determine bsize.
Packit c433c4
 * Assumes: device is open.
Packit c433c4
 */
Packit c433c4
static int find_rgs_for_bsize(struct gfs2_sbd *sdp, uint64_t startblock,
Packit c433c4
			      uint32_t *known_bsize)
Packit c433c4
{
Packit c433c4
	uint64_t blk, max_rg_size, rb_addr;
Packit c433c4
	struct gfs2_buffer_head *bh, *rb_bh;
Packit c433c4
	uint32_t bsize, bsize2;
Packit c433c4
	uint32_t chk;
Packit c433c4
	char *p;
Packit c433c4
	int found_rg;
Packit c433c4
	struct gfs2_meta_header mh;
Packit c433c4
Packit c433c4
	sdp->bsize = GFS2_DEFAULT_BSIZE;
Packit c433c4
	max_rg_size = 524288;
Packit c433c4
	/* Max RG size is 2GB. Max block size is 4K. 2G / 4K blks = 524288,
Packit c433c4
	   So this is traversing 2GB in 4K block increments. */
Packit c433c4
	for (blk = startblock; blk < startblock + max_rg_size; blk++) {
Packit c433c4
		bh = bread(sdp, blk);
Packit c433c4
		found_rg = 0;
Packit c433c4
		for (bsize = 0; bsize < GFS2_DEFAULT_BSIZE;
Packit c433c4
		     bsize += GFS2_BASIC_BLOCK) {
Packit c433c4
			p = bh->b_data + bsize;
Packit c433c4
			chk = ((struct gfs2_meta_header *)p)->mh_magic;
Packit c433c4
			if (be32_to_cpu(chk) != GFS2_MAGIC)
Packit c433c4
				continue;
Packit c433c4
			chk = ((struct gfs2_meta_header *)p)->mh_type;
Packit c433c4
			if (be32_to_cpu(chk) == GFS2_METATYPE_RG) {
Packit c433c4
				found_rg = 1;
Packit c433c4
				break;
Packit c433c4
			}
Packit c433c4
		}
Packit c433c4
		if (!found_rg)
Packit c433c4
			continue;
Packit c433c4
		/* Try all the block sizes in 512 byte multiples */
Packit c433c4
		for (bsize2 = GFS2_BASIC_BLOCK; bsize2 <= GFS2_DEFAULT_BSIZE;
Packit c433c4
		     bsize2 += GFS2_BASIC_BLOCK) {
Packit c433c4
			rb_addr = (bh->b_blocknr *
Packit c433c4
				   (GFS2_DEFAULT_BSIZE / bsize2)) +
Packit c433c4
				(bsize / bsize2) + 1;
Packit c433c4
			sdp->bsize = bsize2; /* temporarily */
Packit c433c4
			rb_bh = bread(sdp, rb_addr);
Packit c433c4
			gfs2_meta_header_in(&mh, rb_bh->b_data);
Packit c433c4
			brelse(rb_bh);
Packit c433c4
			if (mh.mh_magic == GFS2_MAGIC &&
Packit c433c4
			    mh.mh_type == GFS2_METATYPE_RB) {
Packit c433c4
				log_debug(_("boff:%d bsize2:%d rg:0x%llx, "
Packit c433c4
					    "rb:0x%llx\n"), bsize, bsize2,
Packit c433c4
					  (unsigned long long)blk,
Packit c433c4
					  (unsigned long long)rb_addr);
Packit c433c4
				*known_bsize = bsize2;
Packit c433c4
				break;
Packit c433c4
			}
Packit c433c4
		}
Packit c433c4
		brelse(bh);
Packit c433c4
		if (!(*known_bsize)) {
Packit c433c4
			sdp->bsize = GFS2_DEFAULT_BSIZE;
Packit c433c4
			continue;
Packit c433c4
		}
Packit c433c4
Packit c433c4
		sdp->bsize = *known_bsize;
Packit c433c4
		log_warn(_("Block size determined to be: %d\n"), *known_bsize);
Packit c433c4
		return 0;
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * peruse_metadata - check a range of blocks for metadata
Packit c433c4
 * Assumes: device is open.
Packit c433c4
 */
Packit c433c4
static int peruse_metadata(struct gfs2_sbd *sdp, uint64_t startblock)
Packit c433c4
{
Packit c433c4
	uint64_t blk, max_rg_size;
Packit c433c4
	struct gfs2_buffer_head *bh;
Packit c433c4
	struct gfs2_dinode di;
Packit c433c4
Packit c433c4
	max_rg_size = 2147483648ull / sdp->bsize;
Packit c433c4
	/* Max RG size is 2GB. 2G / bsize. */
Packit c433c4
	for (blk = startblock; blk < startblock + max_rg_size; blk++) {
Packit c433c4
		bh = bread(sdp, blk);
Packit c433c4
		if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
Packit c433c4
			brelse(bh);
Packit c433c4
			continue;
Packit c433c4
		}
Packit c433c4
		gfs2_dinode_in(&di, bh->b_data);
Packit c433c4
		if (di.di_flags & GFS2_DIF_SYSTEM)
Packit c433c4
			peruse_system_dinode(sdp, &di, bh);
Packit c433c4
		else
Packit c433c4
			peruse_user_dinode(sdp, &di, bh);
Packit c433c4
		brelse(bh);
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * sb_repair - repair a damaged superblock
Packit c433c4
 * Assumes: device is open.
Packit c433c4
 *          The biggest RG size is 2GB
Packit c433c4
 */
Packit c433c4
static int sb_repair(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	uint64_t half;
Packit c433c4
	uint32_t known_bsize = 0;
Packit c433c4
	int error = 0;
Packit c433c4
Packit c433c4
	memset(&fix_md, 0, sizeof(fix_md));
Packit c433c4
	/* Step 1 - First we need to determine the correct block size. */
Packit c433c4
	sdp->bsize = GFS2_DEFAULT_BSIZE;
Packit c433c4
	log_warn(_("Gathering information to repair the gfs2 superblock.  "
Packit c433c4
		   "This may take some time.\n"));
Packit c433c4
	error = find_rgs_for_bsize(sdp, (GFS2_SB_ADDR * GFS2_BASIC_BLOCK) /
Packit c433c4
				   GFS2_DEFAULT_BSIZE, &known_bsize);
Packit c433c4
	if (error)
Packit c433c4
		return error;
Packit c433c4
	if (!known_bsize) {
Packit c433c4
		log_warn(_("Block size not apparent; checking elsewhere.\n"));
Packit c433c4
		/* First, figure out the device size.  We need that so we can
Packit c433c4
		   find a suitable start point to determine what's what. */
Packit c433c4
		half = sdp->dinfo.size / 2; /* in bytes */
Packit c433c4
		half /= sdp->bsize;
Packit c433c4
		/* Start looking halfway through the device for gfs2
Packit c433c4
		   structures.  If there aren't any at all, forget it. */
Packit c433c4
		error = find_rgs_for_bsize(sdp, half, &known_bsize);
Packit c433c4
		if (error)
Packit c433c4
			return error;
Packit c433c4
	}
Packit c433c4
	if (!known_bsize) {
Packit c433c4
		log_err(_("Unable to determine the block size; this "
Packit c433c4
			  "does not look like a gfs2 file system.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	/* Step 2 - look for the sytem dinodes */
Packit c433c4
	error = peruse_metadata(sdp, (GFS2_SB_ADDR * GFS2_BASIC_BLOCK) /
Packit c433c4
				GFS2_DEFAULT_BSIZE);
Packit c433c4
	if (error)
Packit c433c4
		return error;
Packit c433c4
	if (!sdp->sd_sb.sb_master_dir.no_addr) {
Packit c433c4
		log_err(_("Unable to locate the system master  directory.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	if (!sdp->sd_sb.sb_root_dir.no_addr) {
Packit c433c4
		struct gfs2_inum inum;
Packit c433c4
Packit c433c4
		log_err(_("Unable to locate the root directory.\n"));
Packit c433c4
		if (possible_root == HIGHEST_BLOCK) {
Packit c433c4
			/* Take advantage of the fact that mkfs.gfs2
Packit c433c4
			   creates master immediately after root. */
Packit c433c4
			log_err(_("Can't find any dinodes that might "
Packit c433c4
				  "be the root; using master - 1.\n"));
Packit c433c4
			possible_root = sdp->sd_sb.sb_master_dir.no_addr - 1;
Packit c433c4
		}
Packit c433c4
		log_err(_("Found a possible root at: 0x%llx\n"),
Packit c433c4
			(unsigned long long)possible_root);
Packit c433c4
		sdp->sd_sb.sb_root_dir.no_addr = possible_root;
Packit c433c4
		sdp->md.rooti = lgfs2_inode_read(sdp, possible_root);
Packit c433c4
		if (!sdp->md.rooti ||
Packit c433c4
		    sdp->md.rooti->i_di.di_header.mh_magic != GFS2_MAGIC) {
Packit c433c4
			struct gfs2_buffer_head *bh = NULL;
Packit c433c4
Packit c433c4
			log_err(_("The root dinode block is destroyed.\n"));
Packit c433c4
			log_err(_("At this point I recommend "
Packit c433c4
				  "reinitializing it.\n"
Packit c433c4
				  "Hopefully everything will later "
Packit c433c4
				  "be put into lost+found.\n"));
Packit c433c4
			if (!query(_("Okay to reinitialize the root "
Packit c433c4
				     "dinode? (y/n)"))) {
Packit c433c4
				log_err(_("The root dinode was not "
Packit c433c4
					  "reinitialized; aborting.\n"));
Packit c433c4
				return -1;
Packit c433c4
			}
Packit c433c4
			inum.no_formal_ino = 1;
Packit c433c4
			inum.no_addr = possible_root;
Packit c433c4
			error = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, 0, &inum);
Packit c433c4
			if (error != 0)
Packit c433c4
				return -1;
Packit c433c4
			brelse(bh);
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
	/* Step 3 - Rebuild the lock protocol and file system table name */
Packit c433c4
	if (query(_("Okay to fix the GFS2 superblock? (y/n)"))) {
Packit c433c4
		struct gfs2_sb sb;
Packit c433c4
		log_info(_("Found system master directory at: 0x%llx\n"),
Packit c433c4
			 sdp->sd_sb.sb_master_dir.no_addr);
Packit c433c4
		sdp->master_dir = lgfs2_inode_read(sdp,
Packit c433c4
					     sdp->sd_sb.sb_master_dir.no_addr);
Packit c433c4
		if (sdp->master_dir == NULL) {
Packit c433c4
			log_crit(_("Error reading master inode: %s\n"), strerror(errno));
Packit c433c4
			return -1;
Packit c433c4
		}
Packit c433c4
		sdp->master_dir->i_di.di_num.no_addr =
Packit c433c4
			sdp->sd_sb.sb_master_dir.no_addr;
Packit c433c4
		log_info(_("Found the root directory at: 0x%llx\n"),
Packit c433c4
			 sdp->sd_sb.sb_root_dir.no_addr);
Packit c433c4
		sdp->md.rooti = lgfs2_inode_read(sdp,
Packit c433c4
					   sdp->sd_sb.sb_root_dir.no_addr);
Packit c433c4
		if (sdp->md.rooti == NULL) {
Packit c433c4
			log_crit(_("Error reading root inode: %s\n"), strerror(errno));
Packit c433c4
			return -1;
Packit c433c4
		}
Packit c433c4
		lgfs2_sb_init(&sb, sdp->bsize);
Packit c433c4
		strcpy(sb.sb_lockproto, GFS2_DEFAULT_LOCKPROTO);
Packit c433c4
		strcpy(sb.sb_locktable, "unknown");
Packit c433c4
		sb.sb_master_dir = sdp->master_dir->i_di.di_num;
Packit c433c4
		sb.sb_root_dir = sdp->md.rooti->i_di.di_num;
Packit c433c4
		lgfs2_sb_write(&sb, sdp->device_fd, sdp->bsize);
Packit c433c4
		inode_put(&sdp->md.rooti);
Packit c433c4
		inode_put(&sdp->master_dir);
Packit c433c4
		sb_fixed = 1;
Packit c433c4
	} else {
Packit c433c4
		log_crit(_("GFS2 superblock not fixed; fsck cannot proceed "
Packit c433c4
			   "without a valid superblock.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * fill_super_block
Packit c433c4
 * @sdp:
Packit c433c4
 *
Packit c433c4
 * Returns: 0 on success, -1 on failure
Packit c433c4
 */
Packit c433c4
static int fill_super_block(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	int ret;
Packit c433c4
Packit c433c4
	sync();
Packit c433c4
Packit c433c4
	/********************************************************************
Packit c433c4
	 ***************** First, initialize all lists **********************
Packit c433c4
	 ********************************************************************/
Packit c433c4
	log_info( _("Initializing lists...\n"));
Packit c433c4
	sdp->rgtree.osi_node = NULL;
Packit c433c4
Packit c433c4
	/********************************************************************
Packit c433c4
	 ************  next, read in on-disk SB and set constants  **********
Packit c433c4
	 ********************************************************************/
Packit c433c4
	sdp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
Packit c433c4
	sdp->bsize = sdp->sd_sb.sb_bsize;
Packit c433c4
Packit c433c4
	if (sizeof(struct gfs2_sb) > sdp->sd_sb.sb_bsize){
Packit c433c4
		log_crit( _("GFS superblock is larger than the blocksize!\n"));
Packit c433c4
		log_debug("sizeof(struct gfs2_sb) > sdp->sd_sb.sb_bsize\n");
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (compute_constants(sdp)) {
Packit c433c4
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit c433c4
		exit(FSCK_ERROR);
Packit c433c4
	}
Packit c433c4
	ret = read_sb(sdp);
Packit c433c4
	if (ret < 0) {
Packit c433c4
		if (sb_repair(sdp) != 0)
Packit c433c4
			return -1; /* unrepairable, so exit */
Packit c433c4
		/* Now that we've tried to repair it, re-read it. */
Packit c433c4
		ret = read_sb(sdp);
Packit c433c4
		if (ret < 0)
Packit c433c4
			return -1;
Packit c433c4
	}
Packit c433c4
	if (sdp->gfs1)
Packit c433c4
		sbd1 = (struct gfs_sb *)&sdp->sd_sb;
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
static void gfs_log_header_out(struct gfs_log_header *head, char *buf)
Packit c433c4
{
Packit c433c4
        struct gfs_log_header *str = (struct gfs_log_header *) buf;
Packit c433c4
Packit c433c4
	str->lh_header.mh_magic = cpu_to_be32(head->lh_header.mh_magic);
Packit c433c4
	str->lh_header.mh_type = cpu_to_be32(head->lh_header.mh_type);
Packit c433c4
	str->lh_header.mh_format = cpu_to_be32(head->lh_header.mh_format);
Packit c433c4
	str->lh_header.__pad0 = cpu_to_be32(head->lh_header.__pad0);
Packit c433c4
Packit c433c4
	str->lh_flags = cpu_to_be32(head->lh_flags);
Packit c433c4
	str->lh_pad = cpu_to_be32(head->lh_pad);
Packit c433c4
	str->lh_first = cpu_to_be64(head->lh_first);
Packit c433c4
	str->lh_sequence = cpu_to_be64(head->lh_sequence);
Packit c433c4
	str->lh_tail = cpu_to_be64(head->lh_tail);
Packit c433c4
	str->lh_last_dump = cpu_to_be64(head->lh_last_dump);
Packit c433c4
}
Packit c433c4
Packit c433c4
/*
Packit c433c4
 * reconstruct_single_journal - write a fresh GFS1 journal
Packit c433c4
 * @sdp: superblock
Packit c433c4
 * @jnum: journal number
Packit c433c4
 *
Packit c433c4
 * This function will write a fresh journal over the top of
Packit c433c4
 * the previous journal.  All journal information is lost.  This
Packit c433c4
 * process is basically stolen from write_journals() in the mkfs code.
Packit c433c4
 *
Packit c433c4
 * Returns: -1 on error, 0 otherwise
Packit c433c4
 */
Packit c433c4
static int reconstruct_single_journal(struct gfs2_sbd *sdp, int jnum,
Packit c433c4
				      uint32_t ji_nsegment)
Packit c433c4
{
Packit c433c4
	struct gfs_log_header lh;
Packit c433c4
	uint32_t seg, sequence;
Packit c433c4
	struct gfs2_buffer_head *bh;
Packit c433c4
Packit c433c4
	srandom(time(NULL));
Packit c433c4
	sequence = ji_nsegment / (RAND_MAX + 1.0) * random();
Packit c433c4
Packit c433c4
	log_info(_("Clearing journal %d\n"), jnum);
Packit c433c4
Packit c433c4
	for (seg = 0; seg < ji_nsegment; seg++){
Packit c433c4
		memset(&lh, 0, sizeof(struct gfs_log_header));
Packit c433c4
Packit c433c4
		lh.lh_header.mh_magic = GFS2_MAGIC;
Packit c433c4
		lh.lh_header.mh_type = GFS2_METATYPE_LH;
Packit c433c4
		lh.lh_header.mh_format = GFS2_FORMAT_LH;
Packit c433c4
		lh.lh_header.__pad0 = 0x101674; /* mh_generation */
Packit c433c4
		lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
Packit c433c4
		lh.lh_first = sdp->md.journal[jnum]->i_di.di_num.no_addr +
Packit c433c4
			(seg * sbd1->sb_seg_size);
Packit c433c4
		lh.lh_sequence = sequence;
Packit c433c4
Packit c433c4
		bh = bget(sdp, lh.lh_first * sdp->bsize);
Packit c433c4
		memset(bh->b_data, 0, sdp->bsize);
Packit c433c4
		gfs_log_header_out(&lh, bh->b_data);
Packit c433c4
		gfs_log_header_out(&lh, bh->b_data + GFS2_BASIC_BLOCK -
Packit c433c4
				   sizeof(struct gfs_log_header));
Packit c433c4
		brelse(bh);
Packit c433c4
Packit c433c4
		if (++sequence == ji_nsegment)
Packit c433c4
			sequence = 0;
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
static int reset_journal_seg_size(unsigned int jsize, unsigned int nsegs,
Packit c433c4
					     unsigned int bsize)
Packit c433c4
{
Packit c433c4
	unsigned int seg_size = jsize / (nsegs * bsize);
Packit c433c4
	if (!seg_size)
Packit c433c4
		seg_size = 16; /* The default with 128MB journal and 4K bsize */
Packit c433c4
	if (seg_size != sbd1->sb_seg_size) {
Packit c433c4
		sbd1->sb_seg_size = seg_size;
Packit c433c4
		if (!query(_("Computed correct journal segment size to %u."
Packit c433c4
			     " Reset it? (y/n) "), seg_size)) {
Packit c433c4
			log_crit(_("Error: Cannot proceed without a valid journal"
Packit c433c4
				   " segment size value.\n"));
Packit c433c4
			return -1;
Packit c433c4
		}
Packit c433c4
		log_err(_("Resetting journal segment size to %u\n"), sbd1->sb_seg_size);
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
static int correct_journal_seg_size(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	int count;
Packit c433c4
	struct gfs_jindex ji_0, ji_1;
Packit c433c4
	char buf[sizeof(struct gfs_jindex)];
Packit c433c4
	unsigned int jsize = GFS2_DEFAULT_JSIZE * 1024 * 1024;
Packit c433c4
Packit c433c4
	count = gfs2_readi(sdp->md.jiinode, buf, 0, sizeof(struct gfs_jindex));
Packit c433c4
	if (count != sizeof(struct gfs_jindex)) {
Packit c433c4
		log_crit(_("Error %d reading system journal index inode. "
Packit c433c4
			   "Aborting\n"), count);
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	gfs_jindex_in(&ji_0, buf);
Packit c433c4
Packit c433c4
	if (sdp->md.journals == 1) {
Packit c433c4
		if (sbd1->sb_seg_size == 0) {
Packit c433c4
			if (!query(_("The gfs2 journal segment size is 0 and a"
Packit c433c4
				     " correct value cannot be determined in a"
Packit c433c4
				     " single-journal filesystem.\n"
Packit c433c4
				     "Continue with default? (y/n) "))) {
Packit c433c4
				log_crit(_("Error: Cannot proceed without a valid"
Packit c433c4
					   " sb_seg_size value.\n"));
Packit c433c4
				return -1;
Packit c433c4
			}
Packit c433c4
			goto out;
Packit c433c4
		}
Packit c433c4
		/* Don't mess with sb_seg_size because we don't know what
Packit c433c4
		 * it needs to be
Packit c433c4
		 */
Packit c433c4
		return 0;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	count = gfs2_readi(sdp->md.jiinode, buf, sizeof(struct gfs_jindex),
Packit c433c4
			   sizeof(struct gfs_jindex));
Packit c433c4
	if (count != sizeof(struct gfs_jindex)) {
Packit c433c4
		log_crit(_("Error %d reading system journal index inode. "
Packit c433c4
			   "Aborting\n"), count);
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	gfs_jindex_in(&ji_1, buf);
Packit c433c4
Packit c433c4
	jsize = (ji_1.ji_addr - ji_0.ji_addr) * sbd1->sb_bsize;
Packit c433c4
out:
Packit c433c4
	return reset_journal_seg_size(jsize, ji_0.ji_nsegment, sbd1->sb_bsize);
Packit c433c4
}
Packit c433c4
Packit c433c4
/*
Packit c433c4
 * reconstruct_journals - write fresh journals for GFS1 only
Packit c433c4
 * sdp: the super block
Packit c433c4
 *
Packit c433c4
 * Returns: 0 on success, -1 on failure
Packit c433c4
 */
Packit c433c4
static int reconstruct_journals(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	int i, count;
Packit c433c4
	struct gfs_jindex ji;
Packit c433c4
	char buf[sizeof(struct gfs_jindex)];
Packit c433c4
Packit c433c4
	/* Ensure that sb_seg_size is valid */
Packit c433c4
	if (correct_journal_seg_size(sdp)) {
Packit c433c4
		log_crit(_("Failed to set correct journal segment size. Cannot continue\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	log_err(_("Clearing GFS journals (this may take a while)\n"));
Packit c433c4
	for (i = 0; i < sdp->md.journals; i++) {
Packit c433c4
		count = gfs2_readi(sdp->md.jiinode, buf,
Packit c433c4
				   i * sizeof(struct gfs_jindex),
Packit c433c4
				   sizeof(struct gfs_jindex));
Packit c433c4
		if (count != sizeof(struct gfs_jindex))
Packit c433c4
			return 0;
Packit c433c4
		gfs_jindex_in(&ji, buf);
Packit c433c4
		if ((i % 2) == 0)
Packit c433c4
			log_err(".");
Packit c433c4
		if (reconstruct_single_journal(sdp, i, ji.ji_nsegment))
Packit c433c4
			return -1;
Packit c433c4
	}
Packit c433c4
	log_err(_("\nJournals cleared.\n"));
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * init_rindex - read in the rindex file
Packit c433c4
 */
Packit c433c4
static int init_rindex(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	int err;
Packit c433c4
Packit c433c4
	if (sdp->gfs1)
Packit c433c4
		sdp->md.riinode = lgfs2_inode_read(sdp, sbd1->sb_rindex_di.no_addr);
Packit c433c4
	else
Packit c433c4
		gfs2_lookupi(sdp->master_dir, "rindex", 6, &sdp->md.riinode);
Packit c433c4
Packit c433c4
	if (sdp->md.riinode)
Packit c433c4
		return 0;
Packit c433c4
Packit c433c4
	if (!query( _("The gfs2 system rindex inode is missing. "
Packit c433c4
		      "Okay to rebuild it? (y/n) "))) {
Packit c433c4
		log_crit(_("Error: Cannot proceed without a valid rindex.\n"));
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	if ((err = build_rindex(sdp))) {
Packit c433c4
		log_crit(_("Error %d rebuilding rindex\n"), err);
Packit c433c4
		return -1;
Packit c433c4
	}
Packit c433c4
	return 0;
Packit c433c4
}
Packit c433c4
Packit c433c4
/**
Packit c433c4
 * initialize - initialize superblock pointer
Packit c433c4
 *
Packit c433c4
 */
Packit c433c4
int initialize(struct gfs2_sbd *sdp, int force_check, int preen,
Packit c433c4
	       int *all_clean)
Packit c433c4
{
Packit c433c4
	int clean_journals = 0, open_flag;
Packit c433c4
Packit c433c4
	*all_clean = 0;
Packit c433c4
Packit c433c4
	if (opts.no)
Packit c433c4
		open_flag = O_RDONLY;
Packit c433c4
	else
Packit c433c4
		open_flag = O_RDWR | O_EXCL;
Packit c433c4
Packit c433c4
	sdp->device_fd = open(opts.device, open_flag);
Packit c433c4
	if (sdp->device_fd < 0) {
Packit c433c4
		struct mntent *mnt;
Packit c433c4
		if (open_flag == O_RDONLY || errno != EBUSY) {
Packit c433c4
			log_crit( _("Unable to open device: %s\n"),
Packit c433c4
				  opts.device);
Packit c433c4
			return FSCK_USAGE;
Packit c433c4
		}
Packit c433c4
		/* We can't open it EXCL.  It may be already open rw (in which
Packit c433c4
		   case we want to deny them access) or it may be mounted as
Packit c433c4
		   the root file system at boot time (in which case we need to
Packit c433c4
		   allow it.)
Packit c433c4
		   If the device is busy, but not because it's mounted, fail.
Packit c433c4
		   This protects against cases where the file system is LVM
Packit c433c4
		   and perhaps mounted on a different node.
Packit c433c4
		   Try opening without O_EXCL. */
Packit c433c4
		sdp->device_fd = lgfs2_open_mnt_dev(opts.device, O_RDWR, &mnt;;
Packit c433c4
		if (sdp->device_fd < 0)
Packit c433c4
			goto mount_fail;
Packit c433c4
		/* If the device is mounted, but not mounted RO, fail.  This
Packit c433c4
		   protects them against cases where the file system is
Packit c433c4
		   mounted RW, but still allows us to check our own root
Packit c433c4
		   file system. */
Packit c433c4
		if (!hasmntopt(mnt, MNTOPT_RO))
Packit c433c4
			goto close_fail;
Packit c433c4
		/* The device is mounted RO, so it's likely our own root
Packit c433c4
		   file system.  We can only do so much to protect the users
Packit c433c4
		   from themselves. */
Packit c433c4
		was_mounted_ro = 1;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo)) {
Packit c433c4
		perror(opts.device);
Packit c433c4
		return FSCK_ERROR;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	/* read in sb from disk */
Packit c433c4
	if (fill_super_block(sdp))
Packit c433c4
		return FSCK_ERROR;
Packit c433c4
Packit c433c4
	/* Change lock protocol to be fsck_* instead of lock_* */
Packit c433c4
	if (!opts.no && preen_is_safe(sdp, preen, force_check)) {
Packit c433c4
		if (block_mounters(sdp, 1)) {
Packit c433c4
			log_err( _("Unable to block other mounters\n"));
Packit c433c4
			return FSCK_USAGE;
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	/* Get master dinode */
Packit c433c4
	if (sdp->gfs1)
Packit c433c4
		sdp->master_dir = NULL;
Packit c433c4
	else
Packit c433c4
		sdp->master_dir = lgfs2_inode_read(sdp,
Packit c433c4
					     sdp->sd_sb.sb_master_dir.no_addr);
Packit c433c4
	if (!sdp->gfs1 &&
Packit c433c4
	    (sdp->master_dir->i_di.di_header.mh_magic != GFS2_MAGIC ||
Packit c433c4
	     sdp->master_dir->i_di.di_header.mh_type != GFS2_METATYPE_DI ||
Packit c433c4
	     !sdp->master_dir->i_di.di_size)) {
Packit c433c4
		inode_put(&sdp->master_dir);
Packit c433c4
		rebuild_master(sdp);
Packit c433c4
		sdp->master_dir = lgfs2_inode_read(sdp,
Packit c433c4
					     sdp->sd_sb.sb_master_dir.no_addr);
Packit c433c4
		if (sdp->master_dir == NULL) {
Packit c433c4
			log_crit(_("Error reading master directory: %s\n"), strerror(errno));
Packit c433c4
			return FSCK_ERROR;
Packit c433c4
		}
Packit c433c4
	}
Packit c433c4
Packit c433c4
	/* Look up the "per_node" inode.  If there are journals missing, we
Packit c433c4
	   need to figure out what's missing from per_node. And we need all
Packit c433c4
	   our journals to be there before we can replay them. */
Packit c433c4
	if (!sdp->gfs1)
Packit c433c4
		lookup_per_node(sdp, 0);
Packit c433c4
Packit c433c4
	/* We need rindex first in case jindex is missing and needs to read
Packit c433c4
	   in the rgrps before rebuilding it. However, note that if the rindex
Packit c433c4
	   is damaged, we need the journals to repair it. That's because the
Packit c433c4
	   journals likely contain rgrps and bitmaps, which we need to ignore
Packit c433c4
	   when we're trying to find the rgrps. */
Packit c433c4
	if (init_rindex(sdp))
Packit c433c4
		return FSCK_ERROR;
Packit c433c4
Packit c433c4
	if (fetch_rgrps(sdp))
Packit c433c4
		return FSCK_ERROR;
Packit c433c4
Packit c433c4
	/* We need to read in jindex in order to replay the journals. If
Packit c433c4
	   there's an error, we may proceed and let init_system_inodes
Packit c433c4
	   try to rebuild it. */
Packit c433c4
	if (init_jindex(sdp, 1) == 0) {
Packit c433c4
		/* If GFS, rebuild the journals. If GFS2, replay them. We don't
Packit c433c4
		   have the smarts to replay GFS1 journals (neither did
Packit c433c4
		   gfs_fsck). */
Packit c433c4
		if (sdp->gfs1) {
Packit c433c4
			if (reconstruct_journals(sdp))
Packit c433c4
				return FSCK_ERROR;
Packit c433c4
		} else if (replay_journals(sdp, preen, force_check,
Packit c433c4
					   &clean_journals)) {
Packit c433c4
			if (!opts.no && preen_is_safe(sdp, preen, force_check))
Packit c433c4
				block_mounters(sdp, 0);
Packit c433c4
			stack;
Packit c433c4
			return FSCK_ERROR;
Packit c433c4
		}
Packit c433c4
		if (sdp->md.journals == clean_journals)
Packit c433c4
			*all_clean = 1;
Packit c433c4
		else if (force_check || !preen)
Packit c433c4
			log_notice( _("\nJournal recovery complete.\n"));
Packit c433c4
Packit c433c4
		if (!force_check && *all_clean && preen)
Packit c433c4
			return FSCK_OK;
Packit c433c4
	}
Packit c433c4
Packit c433c4
	if (init_system_inodes(sdp))
Packit c433c4
		return FSCK_ERROR;
Packit c433c4
Packit c433c4
	return FSCK_OK;
Packit c433c4
Packit c433c4
close_fail:
Packit c433c4
	close(sdp->device_fd);
Packit c433c4
mount_fail:
Packit c433c4
	log_crit( _("Device %s is busy.\n"), opts.device);
Packit c433c4
	return FSCK_USAGE;
Packit c433c4
}
Packit c433c4
Packit c433c4
void destroy(struct gfs2_sbd *sdp)
Packit c433c4
{
Packit c433c4
	if (!opts.no) {
Packit c433c4
		if (block_mounters(sdp, 0)) {
Packit c433c4
			log_warn( _("Unable to unblock other mounters - manual intervention required\n"));
Packit c433c4
			log_warn( _("Use 'gfs2_tool sb <device> proto' to fix\n"));
Packit c433c4
		}
Packit c433c4
		log_info( _("Syncing the device.\n"));
Packit c433c4
		fsync(sdp->device_fd);
Packit c433c4
	}
Packit c433c4
	empty_super_block(sdp);
Packit c433c4
	close(sdp->device_fd);
Packit c433c4
	if (was_mounted_ro && errors_corrected) {
Packit c433c4
		sdp->device_fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
Packit c433c4
		if (sdp->device_fd >= 0) {
Packit c433c4
			if (write(sdp->device_fd, "2", 1) == 2) {
Packit c433c4
				close(sdp->device_fd);
Packit c433c4
				return;
Packit c433c4
			}
Packit c433c4
			close(sdp->device_fd);
Packit c433c4
		}
Packit c433c4
		log_warn(_("fsck.gfs2: Could not flush caches (non-fatal).\n"));
Packit c433c4
	}
Packit c433c4
}