Blame gfs2/fsck/pass1.c

Packit 6ef888
/* pass1 checks inodes for format & type, duplicate blocks, & incorrect
Packit 6ef888
 * block count.
Packit 6ef888
 *
Packit 6ef888
 * It builds up tables that contains the state of each block (free,
Packit 6ef888
 * block in use, metadata type, etc), as well as bad blocks and
Packit 6ef888
 * duplicate blocks.  (See block_list.[ch] for more info)
Packit 6ef888
 *
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
#include <stdio.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <sys/time.h>
Packit 6ef888
#include <sys/stat.h>
Packit 6ef888
#include <unistd.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <time.h>
Packit 6ef888
#include <fcntl.h>
Packit 6ef888
#include <sys/ioctl.h>
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "fsck.h"
Packit 6ef888
#include "inode_hash.h"
Packit 6ef888
#include "util.h"
Packit 6ef888
#include "link.h"
Packit 6ef888
#include "metawalk.h"
Packit 6ef888
#include "fs_recovery.h"
Packit 6ef888
Packit 6ef888
struct special_blocks gfs1_rindex_blks;
Packit 6ef888
struct gfs2_bmap *bl = NULL;
Packit 6ef888
Packit 6ef888
struct block_count {
Packit 6ef888
	uint64_t indir_count;
Packit 6ef888
	uint64_t data_count;
Packit 6ef888
	uint64_t ea_count;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
Packit 6ef888
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit 6ef888
			  int *was_duplicate, void *private);
Packit 6ef888
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			       int h, void *private);
Packit 6ef888
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
		      uint64_t block, void *private,
Packit 6ef888
		      struct gfs2_buffer_head *bh, uint64_t *ptr);
Packit 6ef888
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private);
Packit 6ef888
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
Packit 6ef888
			     uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
			     void *private);
Packit 6ef888
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			    uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
			    void *private);
Packit 6ef888
static int check_eattr_entries(struct gfs2_inode *ip,
Packit 6ef888
			       struct gfs2_buffer_head *leaf_bh,
Packit 6ef888
			       struct gfs2_ea_header *ea_hdr,
Packit 6ef888
			       struct gfs2_ea_header *ea_hdr_prev,
Packit 6ef888
			       void *private);
Packit 6ef888
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
Packit 6ef888
				     uint64_t *data_ptr,
Packit 6ef888
				     struct gfs2_buffer_head *leaf_bh,
Packit 6ef888
				     uint32_t tot_ealen,
Packit 6ef888
				     struct gfs2_ea_header *ea_hdr,
Packit 6ef888
				     struct gfs2_ea_header *ea_hdr_prev,
Packit 6ef888
				     void *private);
Packit 6ef888
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
Packit 6ef888
			      int leaf_pointer_errors, void *private);
Packit 6ef888
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			       struct gfs2_buffer_head **bh, int h,
Packit 6ef888
			       int *is_valid, int *was_duplicate,
Packit 6ef888
			       void *private);
Packit 6ef888
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private);
Packit 6ef888
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
			   uint64_t block, void *private,
Packit 6ef888
			   struct gfs2_buffer_head *bh, uint64_t *ptr);
Packit 6ef888
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				  uint64_t parent,
Packit 6ef888
				  struct gfs2_buffer_head **bh,
Packit 6ef888
				  void *private);
Packit 6ef888
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
				 void *private);
Packit 6ef888
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip);
Packit 6ef888
static int delete_block(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			struct gfs2_buffer_head **bh, const char *btype,
Packit 6ef888
			void *private);
Packit 6ef888
Packit 6ef888
static int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark)
Packit 6ef888
{
Packit 6ef888
	static unsigned char *byte;
Packit 6ef888
	static uint64_t b;
Packit 6ef888
Packit 6ef888
	if (!bmap)
Packit 6ef888
		return 0;
Packit 6ef888
	if (bblock > bmap->size)
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	byte = bmap->map + BLOCKMAP_SIZE2(bblock);
Packit 6ef888
	b = BLOCKMAP_BYTE_OFFSET2(bblock);
Packit 6ef888
	*byte &= ~(BLOCKMAP_MASK2 << b);
Packit 6ef888
	*byte |= (mark & BLOCKMAP_MASK2) << b;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * _fsck_blockmap_set - Mark a block in the 4-bit blockmap and the 2-bit
Packit 6ef888
 *                      bitmap, and adjust free space accordingly.
Packit 6ef888
 */
Packit 6ef888
static int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
Packit 6ef888
			      const char *btype, int mark, int error_on_dinode,
Packit 6ef888
			      const char *caller, int fline)
Packit 6ef888
{
Packit 6ef888
	int error = _fsck_bitmap_set(ip, bblock, btype, mark, error_on_dinode,
Packit 6ef888
				     caller, fline);
Packit 6ef888
	if (error)
Packit 6ef888
		return error;
Packit 6ef888
Packit 6ef888
	return gfs2_blockmap_set(bl, bblock, mark);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
#define fsck_blockmap_set(ip, b, bt, m) \
Packit 6ef888
	_fsck_blockmap_set(ip, b, bt, m, 0, __FUNCTION__, __LINE__)
Packit 6ef888
#define fsck_blkmap_set_noino(ip, b, bt, m) \
Packit 6ef888
	_fsck_blockmap_set(ip, b, bt, m, 1, __FUNCTION__, __LINE__)
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * delete_block - delete a block associated with an inode
Packit 6ef888
 */
Packit 6ef888
static int delete_block(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			struct gfs2_buffer_head **bh, const char *btype,
Packit 6ef888
			void *private)
Packit 6ef888
{
Packit 6ef888
	if (valid_block_ip(ip, block)) {
Packit 6ef888
		fsck_blockmap_set(ip, block, btype, GFS2_BLKST_FREE);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	return -1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* This is a pass1-specific leaf repair. Since we are not allowed to do
Packit 6ef888
 * block allocations, we do what we can. */
Packit 6ef888
static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
Packit 6ef888
			     int lindex, int ref_count, const char *msg)
Packit 6ef888
{
Packit 6ef888
	uint64_t *cpyptr;
Packit 6ef888
	char *padbuf;
Packit 6ef888
	int pad_size, i;
Packit 6ef888
Packit 6ef888
	log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
Packit 6ef888
		   " (0x%llx) %s.\n"),
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)*leaf_no,
Packit 6ef888
		 (unsigned long long)*leaf_no, msg);
Packit 6ef888
	if (!query( _("Attempt to patch around it? (y/n) "))) {
Packit 6ef888
		log_err( _("Bad leaf left in place.\n"));
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	padbuf = malloc(ref_count * sizeof(uint64_t));
Packit 6ef888
	cpyptr = (uint64_t *)padbuf;
Packit 6ef888
	for (i = 0; i < ref_count; i++) {
Packit 6ef888
		*cpyptr = 0;
Packit 6ef888
		cpyptr++;
Packit 6ef888
	}
Packit 6ef888
	pad_size = ref_count * sizeof(uint64_t);
Packit 6ef888
	log_err(_("Writing zeros to the hash table of directory %lld "
Packit 6ef888
		  "(0x%llx) at index: 0x%x for 0x%x pointers.\n"),
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr, lindex,
Packit 6ef888
		ref_count);
Packit 6ef888
	if (ip->i_sbd->gfs1)
Packit 6ef888
		gfs1_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
Packit 6ef888
	else
Packit 6ef888
		gfs2_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
Packit 6ef888
	free(padbuf);
Packit 6ef888
	log_err( _("Directory Inode %llu (0x%llx) patched.\n"),
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
Packit 6ef888
out:
Packit 6ef888
	*leaf_no = 0;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns pass1_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_leaf = p1check_leaf,
Packit 6ef888
	.check_metalist = check_metalist,
Packit 6ef888
	.check_data = check_data,
Packit 6ef888
	.check_eattr_indir = check_eattr_indir,
Packit 6ef888
	.check_eattr_leaf = check_eattr_leaf,
Packit 6ef888
	.check_dentry = NULL,
Packit 6ef888
	.check_eattr_entry = check_eattr_entries,
Packit 6ef888
	.check_eattr_extentry = check_extended_leaf_eattr,
Packit 6ef888
	.big_file_msg = big_file_comfort,
Packit 6ef888
	.repair_leaf = pass1_repair_leaf,
Packit 6ef888
	.undo_check_meta = undo_check_metalist,
Packit 6ef888
	.undo_check_data = undo_check_data,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct metawalk_fxns invalidate_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_metalist = invalidate_metadata,
Packit 6ef888
	.check_data = invalidate_data,
Packit 6ef888
	.check_leaf = invalidate_leaf,
Packit 6ef888
	.check_eattr_indir = invalidate_eattr_indir,
Packit 6ef888
	.check_eattr_leaf = invalidate_eattr_leaf,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * resuscitate_metalist - make sure a system directory entry's metadata blocks
Packit 6ef888
 *                        are marked "in use" in the bitmap.
Packit 6ef888
 *
Packit 6ef888
 * This function makes sure metadata blocks for system and root directories are
Packit 6ef888
 * marked "in use" by the bitmap.  You don't want root's indirect blocks
Packit 6ef888
 * deleted, do you? Or worse, reused for lost+found.
Packit 6ef888
 */
Packit 6ef888
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				struct gfs2_buffer_head **bh, int h,
Packit 6ef888
				int *is_valid, int *was_duplicate,
Packit 6ef888
				void *private)
Packit 6ef888
{
Packit 6ef888
	struct block_count *bc = (struct block_count *)private;
Packit 6ef888
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	*bh = NULL;
Packit 6ef888
	if (!valid_block_ip(ip, block)){ /* blk outside of FS */
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("itself"), GFS2_BLKST_UNLINKED);
Packit 6ef888
		log_err( _("Bad indirect block pointer (invalid or out of "
Packit 6ef888
			   "range) found in system inode %lld (0x%llx).\n"),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		*is_valid = 0;
Packit 6ef888
		return meta_is_good;
Packit 6ef888
	}
Packit 6ef888
	if (fsck_system_inode(ip->i_sbd, block))
Packit 6ef888
		fsck_blockmap_set(ip, block, _("system file"),
Packit 6ef888
				  ip->i_sbd->gfs1 ?
Packit 6ef888
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	else
Packit 6ef888
		check_n_fix_bitmap(ip->i_sbd, ip->i_rgd, block, 0,
Packit 6ef888
				   ip->i_sbd->gfs1 ?
Packit 6ef888
				   GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	bc->indir_count++;
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * resuscitate_dentry - make sure a system directory entry is alive
Packit 6ef888
 *
Packit 6ef888
 * This function makes sure directory entries in system directories are
Packit 6ef888
 * kept alive.  You don't want journal0 deleted from jindex, do you?
Packit 6ef888
 */
Packit 6ef888
static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
			      struct gfs2_dirent *prev_de,
Packit 6ef888
			      struct gfs2_buffer_head *bh, char *filename,
Packit 6ef888
			      uint32_t *count, int *lindex, void *priv)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	char tmp_name[PATH_MAX];
Packit 6ef888
	uint64_t block;
Packit 6ef888
Packit 6ef888
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
	gfs2_dirent_in(&dentry, (char *)dent);
Packit 6ef888
	de = &dentry;
Packit 6ef888
	block = de->de_inum.no_addr;
Packit 6ef888
	/* Start of checks */
Packit 6ef888
	memset(tmp_name, 0, sizeof(tmp_name));
Packit 6ef888
	if (de->de_name_len < sizeof(tmp_name))
Packit 6ef888
		strncpy(tmp_name, filename, de->de_name_len);
Packit 6ef888
	else
Packit 6ef888
		strncpy(tmp_name, filename, sizeof(tmp_name) - 1);
Packit 6ef888
	if (!valid_block_ip(ip, block)) {
Packit 6ef888
		log_err( _("Block # referenced by system directory entry %s "
Packit 6ef888
			   "in inode %lld (0x%llx) is invalid or out of range;"
Packit 6ef888
			   " ignored.\n"),
Packit 6ef888
			 tmp_name, (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	/* If this is a system dinode, we'll handle it later in
Packit 6ef888
	   check_system_inodes.  If not, it'll be handled by pass1 but
Packit 6ef888
	   since it's in a system directory we need to make sure it's
Packit 6ef888
	   represented in the rgrp bitmap. */
Packit 6ef888
	if (fsck_system_inode(sdp, block))
Packit 6ef888
		fsck_blockmap_set(ip, block, _("system file"),
Packit 6ef888
				  GFS2_BLKST_DINODE);
Packit 6ef888
	else
Packit 6ef888
		check_n_fix_bitmap(sdp, ip->i_rgd, block, 0,
Packit 6ef888
				   GFS2_BLKST_DINODE);
Packit 6ef888
	/* Return the number of leaf entries so metawalk doesn't flag this
Packit 6ef888
	   leaf as having none. */
Packit 6ef888
	*count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns sysdir_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_metalist = resuscitate_metalist,
Packit 6ef888
	.check_dentry = resuscitate_dentry,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
Packit 6ef888
{
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	/* Note if we've gotten this far, the block has already passed the
Packit 6ef888
	   check in metawalk: gfs2_check_meta(lbh, GFS2_METATYPE_LF).
Packit 6ef888
	   So we know it's a leaf block. */
Packit 6ef888
	bc->indir_count++;
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	if (q != GFS2_BLKST_FREE) {
Packit 6ef888
		log_err( _("Found duplicate block #%llu (0x%llx) referenced "
Packit 6ef888
			   "as a directory leaf in dinode "
Packit 6ef888
			   "%llu (0x%llx) - was marked %d (%s)\n"),
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr, q,
Packit 6ef888
			 block_type_string(q));
Packit 6ef888
		add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
Packit 6ef888
		if (q == (ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
			  GFS2_BLKST_USED))
Packit 6ef888
			/* If the previous reference also saw this as a leaf,
Packit 6ef888
			   it was already checked, so don't check again. */
Packit 6ef888
			return EEXIST; /* non-fatal */
Packit 6ef888
	}
Packit 6ef888
	fsck_blockmap_set(ip, block, _("directory leaf"),
Packit 6ef888
			  ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
			  GFS2_BLKST_USED);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit 6ef888
			  int *was_duplicate, void *private)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
	int iblk_type;
Packit 6ef888
	struct gfs2_buffer_head *nbh;
Packit 6ef888
	struct block_count *bc = (struct block_count *)private;
Packit 6ef888
	const char *blktypedesc;
Packit 6ef888
Packit 6ef888
	*bh = NULL;
Packit 6ef888
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	*is_valid = 0;
Packit 6ef888
	if (!valid_block_ip(ip, block)) { /* blk outside of FS */
Packit 6ef888
		/* The bad dinode should be invalidated later due to
Packit 6ef888
		   "unrecoverable" errors.  The inode itself should be
Packit 6ef888
		   set "free" and removed from the inodetree by
Packit 6ef888
		   undo_check_metalist. */
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("bad block referencing"), GFS2_BLKST_UNLINKED);
Packit 6ef888
		log_debug( _("Bad indirect block (invalid/out of range) "
Packit 6ef888
			     "found in inode %lld (0x%llx).\n"),
Packit 6ef888
			   (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			   (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
Packit 6ef888
		return meta_skip_further;
Packit 6ef888
	}
Packit 6ef888
	if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
Packit 6ef888
		iblk_type = GFS2_METATYPE_JD;
Packit 6ef888
		blktypedesc = _("a directory hash table block");
Packit 6ef888
	} else {
Packit 6ef888
		iblk_type = GFS2_METATYPE_IN;
Packit 6ef888
		blktypedesc = _("a journaled data block");
Packit 6ef888
	}
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	if (q != GFS2_BLKST_FREE) {
Packit 6ef888
		log_err( _("Found duplicate block #%llu (0x%llx) referenced "
Packit 6ef888
			   "as metadata in indirect block for dinode "
Packit 6ef888
			   "%llu (0x%llx) - was marked %d (%s)\n"),
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr, q,
Packit 6ef888
			 block_type_string(q));
Packit 6ef888
		*was_duplicate = 1;
Packit 6ef888
	}
Packit 6ef888
	nbh = bread(ip->i_sbd, block);
Packit 6ef888
Packit 6ef888
	*is_valid = (gfs2_check_meta(nbh, iblk_type) == 0);
Packit 6ef888
Packit 6ef888
	if (!(*is_valid)) {
Packit 6ef888
		log_err( _("Inode %lld (0x%llx) has a bad indirect block "
Packit 6ef888
			   "pointer %lld (0x%llx) (points to something "
Packit 6ef888
			   "that is not %s).\n"),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)block, blktypedesc);
Packit 6ef888
		brelse(nbh);
Packit 6ef888
		return meta_skip_further;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bc->indir_count++;
Packit 6ef888
	if (*was_duplicate) {
Packit 6ef888
		add_duplicate_ref(ip, block, ref_as_meta, 0,
Packit 6ef888
				  *is_valid ? INODE_VALID : INODE_INVALID);
Packit 6ef888
		brelse(nbh);
Packit 6ef888
	} else {
Packit 6ef888
		*bh = nbh;
Packit 6ef888
		fsck_blockmap_set(ip, block, _("indirect"), ip->i_sbd->gfs1 ?
Packit 6ef888
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (*is_valid)
Packit 6ef888
		return meta_is_good;
Packit 6ef888
	return meta_skip_further;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* undo_reference - undo previously processed data or metadata
Packit 6ef888
 * We've treated the metadata for this dinode as good so far, but not we
Packit 6ef888
 * realize it's bad. So we need to undo what we've done.
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 - We need to process the block as metadata. In other words,
Packit 6ef888
 *              we need to undo any blocks it refers to.
Packit 6ef888
 *          1 - We can't process the block as metadata.
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
Packit 6ef888
			  void *private)
Packit 6ef888
{
Packit 6ef888
	struct block_count *bc = (struct block_count *)private;
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	int old_bitmap_state = 0;
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, block)) { /* blk outside of FS */
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("bad block referencing"), GFS2_BLKST_FREE);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (meta)
Packit 6ef888
		bc->indir_count--;
Packit 6ef888
	dt = dupfind(block);
Packit 6ef888
	if (dt) {
Packit 6ef888
		/* remove all duplicate reference structures from this inode */
Packit 6ef888
		do {
Packit 6ef888
			id = find_dup_ref_inode(dt, ip);
Packit 6ef888
			if (!id)
Packit 6ef888
				break;
Packit 6ef888
Packit 6ef888
			dup_listent_delete(dt, id);
Packit 6ef888
		} while (id);
Packit 6ef888
Packit 6ef888
		if (dt->refs) {
Packit 6ef888
			log_err(_("Block %llu (0x%llx) is still referenced "
Packit 6ef888
				  "from another inode; not freeing.\n"),
Packit 6ef888
				(unsigned long long)block,
Packit 6ef888
				(unsigned long long)block);
Packit 6ef888
			if (dt->refs == 1) {
Packit 6ef888
				log_err(_("This was the only duplicate "
Packit 6ef888
					  "reference so far; removing it.\n"));
Packit 6ef888
				dup_delete(dt);
Packit 6ef888
			}
Packit 6ef888
			return 1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	if (!meta) {
Packit 6ef888
		rgd = gfs2_blk2rgrpd(ip->i_sbd, block);
Packit 6ef888
		old_bitmap_state = lgfs2_get_bitmap(ip->i_sbd, block, rgd);
Packit 6ef888
		if (old_bitmap_state == GFS2_BLKST_DINODE)
Packit 6ef888
			return -1;
Packit 6ef888
	}
Packit 6ef888
	fsck_blockmap_set(ip, block,
Packit 6ef888
			  meta ? _("bad indirect") : _("referenced data"),
Packit 6ef888
			  GFS2_BLKST_FREE);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			       int h, void *private)
Packit 6ef888
{
Packit 6ef888
	return undo_reference(ip, block, 1, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private)
Packit 6ef888
{
Packit 6ef888
	return undo_reference(ip, block, 0, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* blockmap_set_as_data - set block as 'data' in the blockmap, if not dinode
Packit 6ef888
 *
Packit 6ef888
 * This function tries to set a block that's referenced as data as 'data'
Packit 6ef888
 * in the fsck blockmap. But if that block is marked as 'dinode' in the
Packit 6ef888
 * rgrp bitmap, it does additional checks to see if it looks like a dinode.
Packit 6ef888
 * Note that previous checks were done for duplicate references, so this
Packit 6ef888
 * is checking for dinodes that we haven't processed yet.
Packit 6ef888
 */
Packit 6ef888
static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	struct gfs2_dinode *di;
Packit 6ef888
Packit 6ef888
	error = fsck_blkmap_set_noino(ip, block, _("data"), GFS2_BLKST_USED);
Packit 6ef888
	if (!error)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	error = 0;
Packit 6ef888
	/* The bitmap says it's a dinode, but a block reference begs to differ.
Packit 6ef888
	   So which is it? */
Packit 6ef888
	bh = bread(ip->i_sbd, block);
Packit 6ef888
	if (gfs2_check_meta(bh, GFS2_METATYPE_DI) != 0)
Packit 6ef888
		goto out;
Packit 6ef888
Packit 6ef888
	/* The meta header agrees it's a dinode. But it might be data in
Packit 6ef888
	   disguise, so do some extra checks. */
Packit 6ef888
	di = (struct gfs2_dinode *)bh->b_data;
Packit 6ef888
	if (be64_to_cpu(di->di_num.no_addr) != block)
Packit 6ef888
		goto out;
Packit 6ef888
Packit 6ef888
	log_err(_("Inode %lld (0x%llx) has a reference to block %lld (0x%llx) "
Packit 6ef888
		  "as a data block, but it appears to be a dinode we "
Packit 6ef888
		  "haven't checked yet.\n"),
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)block, (unsigned long long)block);
Packit 6ef888
	error = -1;
Packit 6ef888
out:
Packit 6ef888
	if (!error)
Packit 6ef888
		fsck_blockmap_set(ip, block, _("data"),  GFS2_BLKST_USED);
Packit 6ef888
	brelse(bh);
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
		      uint64_t block, void *private,
Packit 6ef888
		      struct gfs2_buffer_head *bbh, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, block)) {
Packit 6ef888
		log_err( _("inode %lld (0x%llx) has a bad data block pointer "
Packit 6ef888
			   "%lld (0x%llx) (invalid or out of range) "),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
		if (metablock == ip->i_di.di_num.no_addr)
Packit 6ef888
			log_err("\n");
Packit 6ef888
		else
Packit 6ef888
			log_err(_("from metadata block %llu (0x%llx)\n"),
Packit 6ef888
				(unsigned long long)metablock,
Packit 6ef888
				(unsigned long long)metablock);
Packit 6ef888
		/* Mark the owner of this block with the bad_block
Packit 6ef888
		 * designator so we know to check it for out of range
Packit 6ef888
		 * blocks later */
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("bad (out of range) data"),
Packit 6ef888
				  GFS2_BLKST_UNLINKED);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	bc->data_count++; /* keep the count sane anyway */
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	if (q != GFS2_BLKST_FREE) {
Packit 6ef888
		struct gfs2_buffer_head *bh;
Packit 6ef888
		struct gfs2_meta_header mh;
Packit 6ef888
Packit 6ef888
		log_err( _("Found duplicate %s block %llu (0x%llx) "
Packit 6ef888
			   "referenced as data by dinode %llu (0x%llx) "),
Packit 6ef888
			 block_type_string(q),
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if (metablock == ip->i_di.di_num.no_addr)
Packit 6ef888
			log_err("\n");
Packit 6ef888
		else
Packit 6ef888
			log_err(_("from metadata block %llu (0x%llx)\n"),
Packit 6ef888
				(unsigned long long)metablock,
Packit 6ef888
				(unsigned long long)metablock);
Packit 6ef888
Packit 6ef888
		switch (q) {
Packit 6ef888
		case GFS2_BLKST_DINODE:
Packit 6ef888
			log_info(_("The block was processed earlier as an "
Packit 6ef888
				   "inode, so it can't possibly be data.\n"));
Packit 6ef888
			/* We still need to add a duplicate record here because
Packit 6ef888
			   when check_metatree tries to delete the inode, we
Packit 6ef888
			   can't have the "undo" functions freeing the block
Packit 6ef888
			   out from other the original referencing inode. */
Packit 6ef888
			add_duplicate_ref(ip, block, ref_as_data, 0,
Packit 6ef888
					  INODE_VALID);
Packit 6ef888
			return 1;
Packit 6ef888
		case GFS2_BLKST_USED: /* tough decision: May be data or meta */
Packit 6ef888
			bh = bread(ip->i_sbd, block);
Packit 6ef888
			gfs2_meta_header_in(&mh, bh->b_data);
Packit 6ef888
			brelse(bh);
Packit 6ef888
			if (mh.mh_magic == GFS2_MAGIC &&
Packit 6ef888
			    mh.mh_type >= GFS2_METATYPE_RG &&
Packit 6ef888
			    mh.mh_type <= GFS2_METATYPE_QC &&
Packit 6ef888
			    mh.mh_type != GFS2_METATYPE_DI &&
Packit 6ef888
			    mh.mh_format % 100 == 0) {
Packit 6ef888
				log_info(_("The block was processed earlier "
Packit 6ef888
					   "as valid metadata, so it can't "
Packit 6ef888
					   "possibly be data.\n"));
Packit 6ef888
				/* We still need to add a duplicate record here
Packit 6ef888
				   because when check_metatree tries to delete
Packit 6ef888
				   the inode, we can't have the "undo"
Packit 6ef888
				   functions freeing the block out from other
Packit 6ef888
				   the original referencing inode. */
Packit 6ef888
				add_duplicate_ref(ip, block, ref_as_data, 0,
Packit 6ef888
						  INODE_VALID);
Packit 6ef888
				return 1;
Packit 6ef888
			}
Packit 6ef888
			log_info( _("Seems to be a normal duplicate; I'll "
Packit 6ef888
				    "sort it out in pass1b.\n"));
Packit 6ef888
			add_duplicate_ref(ip, block, ref_as_data, 0,
Packit 6ef888
					  INODE_VALID);
Packit 6ef888
			/* This inode references the block as data. So if this
Packit 6ef888
			   all is validated, we want to keep this count. */
Packit 6ef888
			return 0;
Packit 6ef888
		case GFS2_BLKST_UNLINKED:
Packit 6ef888
			log_info( _("The block was invalid as metadata but might be "
Packit 6ef888
				    "okay as data.  I'll sort it out in pass1b.\n"));
Packit 6ef888
			add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
Packit 6ef888
	   In gfs2, "meta" is only for dinodes. So here we dummy up the
Packit 6ef888
	   blocks so that the bitmap isn't changed improperly. */
Packit 6ef888
	if (ip->i_sbd->gfs1 && ip == ip->i_sbd->md.riinode) {
Packit 6ef888
		log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"),
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
		gfs2_special_set(&gfs1_rindex_blks, block);
Packit 6ef888
		fsck_blockmap_set(ip, block, _("rgrp"), GFS2_BLKST_DINODE);
Packit 6ef888
		/*gfs2_meta_rgrp);*/
Packit 6ef888
	} else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) {
Packit 6ef888
		log_info(_("Block %lld (0x%llx) is a GFS1 journaled data "
Packit 6ef888
			   "block\n"),
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
		fsck_blockmap_set(ip, block, _("jdata"), GFS2_BLKST_DINODE);
Packit 6ef888
	} else
Packit 6ef888
		return blockmap_set_as_data(ip, block);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int ask_remove_inode_eattr(struct gfs2_inode *ip,
Packit 6ef888
				  struct block_count *bc)
Packit 6ef888
{
Packit 6ef888
	if (ip->i_di.di_eattr == 0)
Packit 6ef888
		return 0; /* eattr was removed prior to this call */
Packit 6ef888
	log_err( _("Inode %lld (0x%llx) has unrecoverable Extended Attribute "
Packit 6ef888
		   "errors.\n"), (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
	if (query( _("Clear all Extended Attributes from the inode? (y/n) "))){
Packit 6ef888
		undo_reference(ip, ip->i_di.di_eattr, 0, bc);
Packit 6ef888
		ip->i_di.di_eattr = 0;
Packit 6ef888
		bc->ea_count = 0;
Packit 6ef888
		ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
Packit 6ef888
		ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
Packit 6ef888
		bmodified(ip->i_bh);
Packit 6ef888
		log_err( _("Extended attributes were removed.\n"));
Packit 6ef888
	} else {
Packit 6ef888
		log_err( _("Extended attributes were not removed.\n"));
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int undo_eattr_indir_or_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				    uint64_t parent,
Packit 6ef888
				    struct gfs2_buffer_head **bh,
Packit 6ef888
				    void *private)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int q;
Packit 6ef888
	int error;
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, block))
Packit 6ef888
		return meta_error;
Packit 6ef888
Packit 6ef888
	/* Need to check block_type before undoing the reference, which can
Packit 6ef888
	   set it to free, which would cause the test below to fail. */
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
Packit 6ef888
	error = undo_reference(ip, block, 0, private);
Packit 6ef888
	if (error)
Packit 6ef888
		return error;
Packit 6ef888
Packit 6ef888
	bc->ea_count--;
Packit 6ef888
Packit 6ef888
	if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED))
Packit 6ef888
		return 1;
Packit 6ef888
Packit 6ef888
	*bh = bread(sdp, block);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* complain_eas - complain about extended attribute errors for an inode
Packit 6ef888
 *
Packit 6ef888
 * @ip       - in core inode pointer
Packit 6ef888
 * block     - the block that had the problem
Packit 6ef888
 * duplicate - if this is a duplicate block, don't set it "free"
Packit 6ef888
 * emsg      - what to tell the user about the eas being checked
Packit 6ef888
 * Returns: 1 if the EA is fixed, else 0 if it was not fixed.
Packit 6ef888
 */
Packit 6ef888
static void complain_eas(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			 const char *emsg)
Packit 6ef888
{
Packit 6ef888
	log_err(_("Inode #%llu (0x%llx): %s"),
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr, emsg);
Packit 6ef888
	log_err(_(" at block #%lld (0x%llx).\n"),
Packit 6ef888
		 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
Packit 6ef888
			     uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
			     void *private)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int ret = 0;
Packit 6ef888
	int q;
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
Packit 6ef888
	/* This inode contains an eattr - it may be invalid, but the
Packit 6ef888
	 * eattr attributes points to a non-zero block */
Packit 6ef888
	if (!valid_block_ip(ip, indirect)) {
Packit 6ef888
		/* Doesn't help to mark this here - this gets checked
Packit 6ef888
		 * in pass1c */
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	q = block_type(bl, indirect);
Packit 6ef888
Packit 6ef888
	/* Special duplicate processing:  If we have an EA block,
Packit 6ef888
	   check if it really is an EA.  If it is, let duplicate
Packit 6ef888
	   handling sort it out.  If it isn't, clear it but don't
Packit 6ef888
	   count it as a duplicate. */
Packit 6ef888
	*bh = bread(sdp, indirect);
Packit 6ef888
	if (gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
Packit 6ef888
		bc->ea_count++;
Packit 6ef888
		if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit 6ef888
			add_duplicate_ref(ip, indirect, ref_as_ea, 0,
Packit 6ef888
					  INODE_VALID);
Packit 6ef888
			complain_eas(ip, indirect,
Packit 6ef888
				     _("Bad indirect Extended Attribute "
Packit 6ef888
				       "duplicate found"));
Packit 6ef888
			/* Return 0 here because if all that's wrong is a
Packit 6ef888
			   duplicate block reference, we want pass1b to figure
Packit 6ef888
			   it out. We don't want to delete all the extended
Packit 6ef888
			   attributes as if they are in error. */
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		complain_eas(ip, indirect,
Packit 6ef888
			     _("Extended Attribute indirect block has "
Packit 6ef888
			       "incorrect type"));
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit 6ef888
		add_duplicate_ref(ip, indirect, ref_as_ea, 0, INODE_VALID);
Packit 6ef888
		complain_eas(ip, indirect,
Packit 6ef888
			     _("Duplicate Extended Attribute indirect block"));
Packit 6ef888
		bc->ea_count++;
Packit 6ef888
		ret = 0; /* For the same reason stated above. */
Packit 6ef888
	} else {
Packit 6ef888
		fsck_blockmap_set(ip, indirect,
Packit 6ef888
				  _("indirect Extended Attribute"), sdp->gfs1 ?
Packit 6ef888
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
		bc->ea_count++;
Packit 6ef888
	}
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
Packit 6ef888
			      int leaf_pointer_errors, void *private)
Packit 6ef888
{
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
Packit 6ef888
	if (leaf_pointer_errors == leaf_pointers) /* All eas were bad */
Packit 6ef888
		return ask_remove_inode_eattr(ip, bc);
Packit 6ef888
	log_debug( _("Marking inode #%llu (0x%llx) with extended "
Packit 6ef888
		     "attribute block\n"),
Packit 6ef888
		   (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		   (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
	if (!leaf_pointer_errors)
Packit 6ef888
		return 0;
Packit 6ef888
	log_err( _("Inode %lld (0x%llx) has recoverable indirect "
Packit 6ef888
		   "Extended Attribute errors.\n"),
Packit 6ef888
		   (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		   (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
	if (query( _("Okay to fix the block count for the inode? (y/n) "))) {
Packit 6ef888
		ip->i_di.di_blocks = 1 + bc->indir_count +
Packit 6ef888
			bc->data_count + bc->ea_count;
Packit 6ef888
		bmodified(ip->i_bh);
Packit 6ef888
		log_err(_("Block count fixed: 1+%lld+%lld+%lld = %lld.\n"),
Packit 6ef888
			(unsigned long long)bc->indir_count,
Packit 6ef888
			(unsigned long long)bc->data_count,
Packit 6ef888
			(unsigned long long)bc->ea_count,
Packit 6ef888
			(unsigned long long)ip->i_di.di_blocks);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	log_err( _("Block count not fixed.\n"));
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* check_ealeaf_block
Packit 6ef888
 *      checks an extended attribute (not directory) leaf block
Packit 6ef888
 */
Packit 6ef888
static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
Packit 6ef888
			      struct gfs2_buffer_head **bh, void *private)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *leaf_bh = NULL;
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int q;
Packit 6ef888
	struct block_count *bc = (struct block_count *) private;
Packit 6ef888
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	/* Special duplicate processing:  If we have an EA block, check if it
Packit 6ef888
	   really is an EA.  If it is, let duplicate handling sort it out.
Packit 6ef888
	   If it isn't, clear it but don't count it as a duplicate. */
Packit 6ef888
	leaf_bh = bread(sdp, block);
Packit 6ef888
	if (gfs2_check_meta(leaf_bh, btype)) {
Packit 6ef888
		bc->ea_count++;
Packit 6ef888
		if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit 6ef888
			add_duplicate_ref(ip, block, ref_as_ea, 0,
Packit 6ef888
					  INODE_VALID);
Packit 6ef888
			complain_eas(ip, block, _("Extended attribute leaf "
Packit 6ef888
						  "duplicate found"));
Packit 6ef888
			/* Return 0 here because if all that's wrong is a
Packit 6ef888
			   duplicate block reference, we want pass1b to figure
Packit 6ef888
			   it out. We don't want to delete all the extended
Packit 6ef888
			   attributes as if they are in error. */
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		complain_eas(ip, block, _("Extended Attribute leaf block has "
Packit 6ef888
					  "incorrect type"));
Packit 6ef888
		brelse(leaf_bh);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit 6ef888
		complain_eas(ip, block, _("Extended Attribute leaf "
Packit 6ef888
					  "duplicate found"));
Packit 6ef888
		add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
Packit 6ef888
		bc->ea_count++;
Packit 6ef888
		brelse(leaf_bh);
Packit 6ef888
		/* Return 0 here because if all that's wrong is a duplicate
Packit 6ef888
		   block reference, we want pass1b to figure it out. We don't
Packit 6ef888
		   want to delete all the extended attributes as if they are
Packit 6ef888
		   in error. */
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	/* Point of confusion: We've got to set the ea block itself to
Packit 6ef888
	   GFS2_BLKST_USED here.  Elsewhere we mark the inode with
Packit 6ef888
	   gfs2_eattr_block meaning it contains an eattr. */
Packit 6ef888
	fsck_blockmap_set(ip, block, _("Extended Attribute"),
Packit 6ef888
			  sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	bc->ea_count++;
Packit 6ef888
	*bh = leaf_bh;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * check_extended_leaf_eattr
Packit 6ef888
 * @ip
Packit 6ef888
 * @el_blk: block number of the extended leaf
Packit 6ef888
 *
Packit 6ef888
 * An EA leaf block can contain EA's with pointers to blocks
Packit 6ef888
 * where the data for that EA is kept.  Those blocks still
Packit 6ef888
 * have the gfs2 meta header of type GFS2_METATYPE_EA
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 if correct[able], -1 if removal is needed
Packit 6ef888
 */
Packit 6ef888
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
Packit 6ef888
				     uint64_t *data_ptr,
Packit 6ef888
				     struct gfs2_buffer_head *leaf_bh,
Packit 6ef888
				     uint32_t tot_ealen,
Packit 6ef888
				     struct gfs2_ea_header *ea_hdr,
Packit 6ef888
				     struct gfs2_ea_header *ea_hdr_prev,
Packit 6ef888
				     void *private)
Packit 6ef888
{
Packit 6ef888
	uint64_t el_blk = be64_to_cpu(*data_ptr);
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, el_blk)) {
Packit 6ef888
		log_err( _("Inode #%llu (0x%llx): Extended Attribute block "
Packit 6ef888
			   "%llu (0x%llx) has an extended leaf block #%llu "
Packit 6ef888
			   "(0x%llx) that is invalid or out of range.\n"),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_eattr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_eattr,
Packit 6ef888
			 (unsigned long long)el_blk,
Packit 6ef888
			 (unsigned long long)el_blk);
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit 6ef888
				  _("bad (out of range) Extended Attribute "),
Packit 6ef888
				  GFS2_BLKST_UNLINKED);
Packit 6ef888
		error = 1;
Packit 6ef888
	} else {
Packit 6ef888
		error = check_ealeaf_block(ip, el_blk, GFS2_METATYPE_ED, &bh,
Packit 6ef888
					   private);
Packit 6ef888
	}
Packit 6ef888
	if (bh)
Packit 6ef888
		brelse(bh);
Packit 6ef888
	if (error) {
Packit 6ef888
		log_err(_("Bad extended attribute found at block %lld "
Packit 6ef888
			  "(0x%llx)"),
Packit 6ef888
			(unsigned long long)be64_to_cpu(*data_ptr),
Packit 6ef888
			(unsigned long long)be64_to_cpu(*data_ptr));
Packit 6ef888
		if (query( _("Repair the bad Extended Attribute? (y/n) "))) {
Packit 6ef888
			ea_hdr->ea_num_ptrs = i;
Packit 6ef888
			ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
Packit 6ef888
			*data_ptr = 0;
Packit 6ef888
			bmodified(leaf_bh);
Packit 6ef888
			/* Endianness doesn't matter in this case because it's
Packit 6ef888
			   a single byte. */
Packit 6ef888
			fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit 6ef888
					  _("extended attribute"),
Packit 6ef888
					  sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
					  GFS2_BLKST_USED);
Packit 6ef888
			log_err( _("The EA was fixed.\n"));
Packit 6ef888
			error = 0;
Packit 6ef888
		} else {
Packit 6ef888
			error = 1;
Packit 6ef888
			log_err( _("The bad EA was not fixed.\n"));
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			    uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
			    void *private)
Packit 6ef888
{
Packit 6ef888
	if (!valid_block_ip(ip, block)) {
Packit 6ef888
		log_warn( _("Inode #%llu (0x%llx): Extended Attribute leaf "
Packit 6ef888
			    "block #%llu (0x%llx) is invalid or out of "
Packit 6ef888
			    "range.\n"),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit 6ef888
				  _("bad (out of range) Extended "
Packit 6ef888
				    "Attribute leaf"), GFS2_BLKST_UNLINKED);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	return check_ealeaf_block(ip, block, GFS2_METATYPE_EA, bh, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int ask_remove_eattr_entry(struct gfs2_sbd *sdp,
Packit 6ef888
				  struct gfs2_buffer_head *leaf_bh,
Packit 6ef888
				  struct gfs2_ea_header *curr,
Packit 6ef888
				  struct gfs2_ea_header *prev,
Packit 6ef888
				  int fix_curr, int fix_curr_len)
Packit 6ef888
{
Packit 6ef888
	if (!query( _("Remove the bad Extended Attribute entry? (y/n) "))) {
Packit 6ef888
		log_err( _("Bad Extended Attribute not removed.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	if (fix_curr)
Packit 6ef888
		curr->ea_flags |= GFS2_EAFLAG_LAST;
Packit 6ef888
	if (fix_curr_len) {
Packit 6ef888
		uint32_t max_size = sdp->sd_sb.sb_bsize;
Packit 6ef888
		uint32_t offset = (uint32_t)(((unsigned long)curr) -
Packit 6ef888
					     ((unsigned long)leaf_bh->b_data));
Packit 6ef888
		curr->ea_rec_len = cpu_to_be32(max_size - offset);
Packit 6ef888
	}
Packit 6ef888
	if (!prev)
Packit 6ef888
		curr->ea_type = GFS2_EATYPE_UNUSED;
Packit 6ef888
	else {
Packit 6ef888
		uint32_t tmp32 = be32_to_cpu(curr->ea_rec_len) +
Packit 6ef888
			be32_to_cpu(prev->ea_rec_len);
Packit 6ef888
		prev->ea_rec_len = cpu_to_be32(tmp32);
Packit 6ef888
		if (curr->ea_flags & GFS2_EAFLAG_LAST)
Packit 6ef888
			prev->ea_flags |= GFS2_EAFLAG_LAST;	
Packit 6ef888
	}
Packit 6ef888
	log_err( _("Bad Extended Attribute at block #%llu"
Packit 6ef888
		   " (0x%llx) removed.\n"),
Packit 6ef888
		 (unsigned long long)leaf_bh->b_blocknr,
Packit 6ef888
		 (unsigned long long)leaf_bh->b_blocknr);
Packit 6ef888
	bmodified(leaf_bh);
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_entries(struct gfs2_inode *ip,
Packit 6ef888
			       struct gfs2_buffer_head *leaf_bh,
Packit 6ef888
			       struct gfs2_ea_header *ea_hdr,
Packit 6ef888
			       struct gfs2_ea_header *ea_hdr_prev,
Packit 6ef888
			       void *private)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	char ea_name[256];
Packit 6ef888
	uint32_t offset = (uint32_t)(((unsigned long)ea_hdr) -
Packit 6ef888
				     ((unsigned long)leaf_bh->b_data));
Packit 6ef888
	uint32_t max_size = sdp->sd_sb.sb_bsize;
Packit 6ef888
	uint32_t avail_size;
Packit 6ef888
	int max_ptrs;
Packit 6ef888
Packit 6ef888
	if (!ea_hdr->ea_name_len){
Packit 6ef888
		log_err( _("EA has name length of zero\n"));
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 1, 1);
Packit 6ef888
	}
Packit 6ef888
	if (offset + be32_to_cpu(ea_hdr->ea_rec_len) > max_size){
Packit 6ef888
		log_err( _("EA rec length too long\n"));
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 1, 1);
Packit 6ef888
	}
Packit 6ef888
	if (offset + be32_to_cpu(ea_hdr->ea_rec_len) == max_size &&
Packit 6ef888
	   (ea_hdr->ea_flags & GFS2_EAFLAG_LAST) == 0){
Packit 6ef888
		log_err( _("last EA has no last entry flag\n"));
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 0, 0);
Packit 6ef888
	}
Packit 6ef888
	if (!ea_hdr->ea_name_len){
Packit 6ef888
		log_err( _("EA has name length of zero\n"));
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 0, 0);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	memset(ea_name, 0, sizeof(ea_name));
Packit 6ef888
	strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
Packit 6ef888
		ea_hdr->ea_name_len);
Packit 6ef888
Packit 6ef888
	if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
Packit 6ef888
	   ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
Packit 6ef888
		/* Skip invalid entry */
Packit 6ef888
		log_err(_("EA (%s) type is invalid (%d > %d).\n"),
Packit 6ef888
			ea_name, ea_hdr->ea_type, GFS2_EATYPE_LAST);
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 0, 0);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!ea_hdr->ea_num_ptrs)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
Packit 6ef888
	max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len)+avail_size-1)/avail_size;
Packit 6ef888
Packit 6ef888
	if (max_ptrs > ea_hdr->ea_num_ptrs) {
Packit 6ef888
		log_err(_("EA (%s) has incorrect number of pointers.\n"),
Packit 6ef888
			ea_name);
Packit 6ef888
		log_err(_("  Required:  %d\n  Reported:  %d\n"),
Packit 6ef888
			max_ptrs, ea_hdr->ea_num_ptrs);
Packit 6ef888
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit 6ef888
					      ea_hdr_prev, 0, 0);
Packit 6ef888
	} else {
Packit 6ef888
		log_debug( _("  Pointers Required: %d\n  Pointers Reported: %d\n"),
Packit 6ef888
			   max_ptrs, ea_hdr->ea_num_ptrs);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * mark_block_invalid - mark blocks associated with an inode as invalid
Packit 6ef888
 *                      unless the block is a duplicate.
Packit 6ef888
 *
Packit 6ef888
 * An "invalid" block is now considered free in the bitmap, and pass2 will
Packit 6ef888
 * delete any invalid blocks.  This is nearly identical to function
Packit 6ef888
 * delete_block_if_notdup.
Packit 6ef888
 */
Packit 6ef888
static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			      enum dup_ref_type reftype, const char *btype,
Packit 6ef888
			      int *is_valid, int *was_duplicate)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	/* If the block isn't valid, we obviously can't invalidate it.
Packit 6ef888
	 * However, if we return an error, invalidating will stop, and
Packit 6ef888
	 * we want it to continue to invalidate the valid blocks.  If we
Packit 6ef888
	 * don't do this, block references that follow that are also
Packit 6ef888
	 * referenced elsewhere (duplicates) won't be flagged as such,
Packit 6ef888
	 * and as a result, they'll be freed when this dinode is deleted,
Packit 6ef888
	 * despite being used by another dinode as a valid block. */
Packit 6ef888
	if (is_valid)
Packit 6ef888
		*is_valid = 1;
Packit 6ef888
	if (was_duplicate)
Packit 6ef888
		*was_duplicate = 0;
Packit 6ef888
	if (!valid_block_ip(ip, block)) {
Packit 6ef888
		if (is_valid)
Packit 6ef888
			*is_valid = 0;
Packit 6ef888
		return meta_is_good;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	if (q != GFS2_BLKST_FREE) {
Packit 6ef888
		if (was_duplicate)
Packit 6ef888
			*was_duplicate = 1;
Packit 6ef888
		add_duplicate_ref(ip, block, reftype, 0, INODE_INVALID);
Packit 6ef888
		log_info( _("%s block %lld (0x%llx), part of inode "
Packit 6ef888
			    "%lld (0x%llx), was previously referenced so "
Packit 6ef888
			    "the invalid reference is ignored.\n"),
Packit 6ef888
			  btype, (unsigned long long)block,
Packit 6ef888
			  (unsigned long long)block,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		return meta_is_good;
Packit 6ef888
	}
Packit 6ef888
	fsck_blockmap_set(ip, block, btype, GFS2_BLKST_UNLINKED);
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			       struct gfs2_buffer_head **bh, int h,
Packit 6ef888
			       int *is_valid, int *was_duplicate,
Packit 6ef888
			       void *private)
Packit 6ef888
{
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	return mark_block_invalid(ip, block, ref_as_meta, _("metadata"),
Packit 6ef888
				  is_valid, was_duplicate);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private)
Packit 6ef888
{
Packit 6ef888
	return mark_block_invalid(ip, block, ref_as_meta, _("leaf"),
Packit 6ef888
				  NULL, NULL);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
			   uint64_t block, void *private,
Packit 6ef888
			   struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	return mark_block_invalid(ip, block, ref_as_data, _("data"),
Packit 6ef888
				  NULL, NULL);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				  uint64_t parent,
Packit 6ef888
				  struct gfs2_buffer_head **bh, void *private)
Packit 6ef888
{
Packit 6ef888
	return mark_block_invalid(ip, block, ref_as_ea,
Packit 6ef888
				  _("indirect extended attribute"),
Packit 6ef888
				  NULL, NULL);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
				 void *private)
Packit 6ef888
{
Packit 6ef888
	return mark_block_invalid(ip, block, ref_as_ea,
Packit 6ef888
				  _("extended attribute"),
Packit 6ef888
				  NULL, NULL);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Check for massive amounts of pointer corruption.  If the block has
Packit 6ef888
 * lots of out-of-range pointers, we can't trust any of the pointers.
Packit 6ef888
 * For example, a stray pointer with a value of 0x1d might be
Packit 6ef888
 * corruption/nonsense, and if so, we don't want to delete an
Packit 6ef888
 * important file (like master or the root directory) because of it.
Packit 6ef888
 * We need to check for a large number of bad pointers BEFORE we start
Packit 6ef888
 * messing with them because we don't want to mark a block as a
Packit 6ef888
 * duplicate (for example) until we know if the pointers in general can
Packit 6ef888
 * be trusted. Thus it needs to be in a separate loop.
Packit 6ef888
 * Returns: 0 if good range, otherwise != 0
Packit 6ef888
 */
Packit 6ef888
enum b_types { btype_meta, btype_leaf, btype_data, btype_ieattr, btype_eattr};
Packit 6ef888
const char *btypes[5] = {
Packit 6ef888
	"metadata", "leaf", "data", "indirect extended attribute",
Packit 6ef888
	"extended attribute" };
Packit 6ef888
Packit 6ef888
static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			    struct gfs2_buffer_head **bh, enum b_types btype,
Packit 6ef888
			    void *private)
Packit 6ef888
{
Packit 6ef888
	long *bad_pointers = (long *)private;
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, block)) {
Packit 6ef888
		(*bad_pointers)++;
Packit 6ef888
		log_info( _("Bad %s block pointer (invalid or out of range "
Packit 6ef888
			    "#%ld) found in inode %lld (0x%llx).\n"),
Packit 6ef888
			  btypes[btype], *bad_pointers,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
Packit 6ef888
			return meta_is_good;
Packit 6ef888
		else
Packit 6ef888
			return meta_error; /* Exits check_metatree quicker */
Packit 6ef888
	}
Packit 6ef888
	/* See how many duplicate blocks it has */
Packit 6ef888
	q = block_type(bl, block);
Packit 6ef888
	if (q != GFS2_BLKST_FREE) {
Packit 6ef888
		(*bad_pointers)++;
Packit 6ef888
		log_info( _("Duplicated %s block pointer (violation %ld, block"
Packit 6ef888
			    " %lld (0x%llx)) found in inode %lld (0x%llx).\n"),
Packit 6ef888
			  btypes[btype], *bad_pointers,
Packit 6ef888
			  (unsigned long long)block, (unsigned long long)block,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			  (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
Packit 6ef888
			return meta_is_good;
Packit 6ef888
		else {
Packit 6ef888
			log_debug(_("Inode 0x%llx bad pointer tolerance "
Packit 6ef888
				    "exceeded: block 0x%llx.\n"),
Packit 6ef888
				  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				  (unsigned long long)block);
Packit 6ef888
			return meta_error; /* Exits check_metatree quicker */
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			       struct gfs2_buffer_head **bh, int h,
Packit 6ef888
			       int *is_valid, int *was_duplicate,
Packit 6ef888
			       void *private)
Packit 6ef888
{
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	return rangecheck_block(ip, block, bh, btype_meta, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private)
Packit 6ef888
{
Packit 6ef888
	return rangecheck_block(ip, block, NULL, btype_leaf, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
			   uint64_t block, void *private,
Packit 6ef888
			   struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	return rangecheck_block(ip, block, NULL, btype_data, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int rangecheck_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				  uint64_t parent,
Packit 6ef888
				  struct gfs2_buffer_head **bh, void *private)
Packit 6ef888
{
Packit 6ef888
	return rangecheck_block(ip, block, NULL, btype_ieattr, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int rangecheck_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
				 void *private)
Packit 6ef888
{
Packit 6ef888
	return rangecheck_block(ip, block, NULL, btype_eattr, private);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns rangecheck_fxns = {
Packit 6ef888
        .private = NULL,
Packit 6ef888
	.readahead = 1,
Packit 6ef888
        .check_metalist = rangecheck_metadata,
Packit 6ef888
        .check_data = rangecheck_data,
Packit 6ef888
        .check_leaf = rangecheck_leaf,
Packit 6ef888
        .check_eattr_indir = rangecheck_eattr_indir,
Packit 6ef888
        .check_eattr_leaf = rangecheck_eattr_leaf,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct metawalk_fxns eattr_undo_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_eattr_indir = undo_eattr_indir_or_leaf,
Packit 6ef888
	.check_eattr_leaf = undo_eattr_indir_or_leaf,
Packit 6ef888
	.finish_eattr_indir = finish_eattr_indir,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
/* set_ip_blockmap - set the blockmap for a dinode
Packit 6ef888
 *
Packit 6ef888
 * returns: 0 if no error, -EINVAL if dinode has a bad mode, -EPERM on error
Packit 6ef888
 */
Packit 6ef888
static int set_ip_blockmap(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	uint64_t block = ip->i_bh->b_blocknr;
Packit 6ef888
	uint32_t mode;
Packit 6ef888
	const char *ty;
Packit 6ef888
Packit 6ef888
	if (ip->i_sbd->gfs1)
Packit 6ef888
		mode = gfs_to_gfs2_mode(ip);
Packit 6ef888
	else
Packit 6ef888
		mode = ip->i_di.di_mode & S_IFMT;
Packit 6ef888
Packit 6ef888
	switch (mode) {
Packit 6ef888
	case S_IFDIR:
Packit 6ef888
		ty = _("directory");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFREG:
Packit 6ef888
		ty = _("file");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFLNK:
Packit 6ef888
		ty = _("symlink");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFBLK:
Packit 6ef888
		ty = _("block device");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFCHR:
Packit 6ef888
		ty = _("character device");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFIFO:
Packit 6ef888
		ty = _("fifo");
Packit 6ef888
		break;
Packit 6ef888
	case S_IFSOCK:
Packit 6ef888
		ty = _("socket");
Packit 6ef888
		break;
Packit 6ef888
	default:
Packit 6ef888
		return -EINVAL;
Packit 6ef888
	}
Packit 6ef888
	if (fsck_blockmap_set(ip, block, ty, GFS2_BLKST_DINODE) ||
Packit 6ef888
	    (mode == S_IFDIR && !dirtree_insert(ip->i_di.di_num))) {
Packit 6ef888
		stack;
Packit 6ef888
		return -EPERM;
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit 6ef888
			  int *was_duplicate, void *private)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
	const char *desc = (const char *)private;
Packit 6ef888
Packit 6ef888
	/* No need to range_check here--if it was added, it's in range. */
Packit 6ef888
	/* We can't check the bitmap here because this function is called
Packit 6ef888
	   after the bitmap has been set but before the blockmap has. */
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	*bh = bread(ip->i_sbd, block);
Packit 6ef888
	q = bitmap_type(ip->i_sbd, block);
Packit 6ef888
	if (q == GFS2_BLKST_FREE) {
Packit 6ef888
		log_debug(_("%s reference to new metadata block "
Packit 6ef888
			    "%lld (0x%llx) is now marked as indirect.\n"),
Packit 6ef888
			  desc, (unsigned long long)block,
Packit 6ef888
			  (unsigned long long)block);
Packit 6ef888
		gfs2_blockmap_set(bl, block, ip->i_sbd->gfs1 ?
Packit 6ef888
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	}
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
		      uint64_t block, void *private,
Packit 6ef888
		      struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
	const char *desc = (const char *)private;
Packit 6ef888
Packit 6ef888
	/* No need to range_check here--if it was added, it's in range. */
Packit 6ef888
	/* We can't check the bitmap here because this function is called
Packit 6ef888
	   after the bitmap has been set but before the blockmap has. */
Packit 6ef888
	q = bitmap_type(ip->i_sbd, block);
Packit 6ef888
	if (q == GFS2_BLKST_FREE) {
Packit 6ef888
		log_debug(_("%s reference to new data block "
Packit 6ef888
			    "%lld (0x%llx) is now marked as data.\n"),
Packit 6ef888
			  desc, (unsigned long long)block,
Packit 6ef888
			  (unsigned long long)block);
Packit 6ef888
		gfs2_blockmap_set(bl, block, GFS2_BLKST_USED);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
Packit 6ef888
{
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	/* No need to range_check here--if it was added, it's in range. */
Packit 6ef888
	/* We can't check the bitmap here because this function is called
Packit 6ef888
	   after the bitmap has been set but before the blockmap has. */
Packit 6ef888
	q = bitmap_type(ip->i_sbd, block);
Packit 6ef888
	if (q == GFS2_BLKST_FREE)
Packit 6ef888
		fsck_blockmap_set(ip, block, _("newly allocated leaf"),
Packit 6ef888
				  ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
				  GFS2_BLKST_USED);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns alloc_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_leaf = alloc_leaf,
Packit 6ef888
	.check_metalist = alloc_metalist,
Packit 6ef888
	.check_data = alloc_data,
Packit 6ef888
	.check_eattr_indir = NULL,
Packit 6ef888
	.check_eattr_leaf = NULL,
Packit 6ef888
	.check_dentry = NULL,
Packit 6ef888
	.check_eattr_entry = NULL,
Packit 6ef888
	.check_eattr_extentry = NULL,
Packit 6ef888
	.finish_eattr_indir = NULL,
Packit 6ef888
	.delete_block = delete_block,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * pass1_check_metatree - wrapper function for check_metatree
Packit 6ef888
 *
Packit 6ef888
 * Generic function check_metatree sets the bitmap values, but not the
Packit 6ef888
 * corresponding values in the blockmap. If we get an error, the inode will
Packit 6ef888
 * have been freed in the bitmap. We need to set the inode address as free
Packit 6ef888
 * as well.
Packit 6ef888
 */
Packit 6ef888
static int pass1_check_metatree(struct gfs2_inode *ip,
Packit 6ef888
				struct metawalk_fxns *pass)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	error = check_metatree(ip, pass);
Packit 6ef888
	if (error)
Packit 6ef888
		gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
Packit 6ef888
				  GFS2_BLKST_FREE);		
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * reprocess_inode - fixes the blockmap to match the bitmap due to an
Packit 6ef888
 *                   unexpected block allocation via libgfs2.
Packit 6ef888
 *
Packit 6ef888
 * The problem we're trying to overcome here is when a new block must be
Packit 6ef888
 * added to a dinode because of a write.  This will happen when lost+found
Packit 6ef888
 * needs a new indirect block for its hash table.  In that case, the write
Packit 6ef888
 * causes a new block to be assigned in the bitmap but that block is not yet
Packit 6ef888
 * accurately reflected in the fsck blockmap.  We need to compensate here.
Packit 6ef888
 *
Packit 6ef888
 * We can't really use fsck_blockmap_set here because the new block
Packit 6ef888
 * was already allocated by libgfs2 and therefore it took care of
Packit 6ef888
 * the rgrp free space variable.  fsck_blockmap_set adjusts the free space
Packit 6ef888
 * in the rgrp according to the change, which has already been done.
Packit 6ef888
 * So it's only our blockmap that now disagrees with the rgrp bitmap, so we
Packit 6ef888
 * need to fix only that.
Packit 6ef888
 */
Packit 6ef888
static void reprocess_inode(struct gfs2_inode *ip, const char *desc)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	alloc_fxns.private = (void *)desc;
Packit 6ef888
	log_info( _("%s inode %llu (0x%llx) had blocks added; reprocessing "
Packit 6ef888
		    "its metadata tree at height=%d.\n"), desc,
Packit 6ef888
		  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		  (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		  ip->i_di.di_height);
Packit 6ef888
	error = pass1_check_metatree(ip, &alloc_fxns);
Packit 6ef888
	if (error)
Packit 6ef888
		log_err( _("Error %d reprocessing the %s metadata tree.\n"),
Packit 6ef888
			 error, desc);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * handle_ip - process an incore structure representing a dinode.
Packit 6ef888
 */
Packit 6ef888
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
	struct block_count bc = {0};
Packit 6ef888
	long bad_pointers;
Packit 6ef888
	uint64_t lf_blks = 0;
Packit 6ef888
Packit 6ef888
	bad_pointers = 0L;
Packit 6ef888
Packit 6ef888
	/* First, check the metadata for massive amounts of pointer corruption.
Packit 6ef888
	   Such corruption can only lead us to ruin trying to clean it up,
Packit 6ef888
	   so it's better to check it up front and delete the inode if
Packit 6ef888
	   there is corruption. */
Packit 6ef888
	rangecheck_fxns.private = &bad_pointers;
Packit 6ef888
	error = pass1_check_metatree(ip, &rangecheck_fxns);
Packit 6ef888
	if (bad_pointers > BAD_POINTER_TOLERANCE) {
Packit 6ef888
		log_err( _("Error: inode %llu (0x%llx) has more than "
Packit 6ef888
			   "%d bad pointers.\n"),
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 BAD_POINTER_TOLERANCE);
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("badly corrupt"), GFS2_BLKST_FREE);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	error = set_ip_blockmap(ip);
Packit 6ef888
	if (error == -EINVAL) {
Packit 6ef888
		/* We found a dinode that has an invalid mode. At this point
Packit 6ef888
		   set_ip_blockmap returned an error, which means it never
Packit 6ef888
		   got inserted into the inode tree. Since we haven't even
Packit 6ef888
		   processed its metadata with pass1_fxns, none of its
Packit 6ef888
		   metadata will be flagged as metadata or data blocks yet.
Packit 6ef888
		   Therefore, we don't need to invalidate anything. */
Packit 6ef888
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				  _("invalid mode"), GFS2_BLKST_FREE);
Packit 6ef888
		return 0;
Packit 6ef888
	} else if (error)
Packit 6ef888
		goto bad_dinode;
Packit 6ef888
Packit 6ef888
	if (set_di_nlink(ip))
Packit 6ef888
		goto bad_dinode;
Packit 6ef888
Packit 6ef888
	if (lf_dip)
Packit 6ef888
		lf_blks = lf_dip->i_di.di_blocks;
Packit 6ef888
Packit 6ef888
	pass1_fxns.private = &bc;
Packit 6ef888
	error = pass1_check_metatree(ip, &pass1_fxns);
Packit 6ef888
Packit 6ef888
	/* Pass1 may have added some blocks to lost+found by virtue of leafs
Packit 6ef888
	   that were misplaced. If it did, we need to reprocess lost+found
Packit 6ef888
	   to correctly account for its blocks. */
Packit 6ef888
	if (lf_dip && lf_dip->i_di.di_blocks != lf_blks)
Packit 6ef888
		reprocess_inode(lf_dip, "lost+found");
Packit 6ef888
Packit 6ef888
	/* We there was an error, we return 0 because we want fsck to continue
Packit 6ef888
	   and analyze the other dinodes as well. */
Packit 6ef888
	if (fsck_abort)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	if (!error) {
Packit 6ef888
		error = check_inode_eattr(ip, &pass1_fxns);
Packit 6ef888
Packit 6ef888
		if (error) {
Packit 6ef888
			if (!query(_("Clear the bad Extended Attributes? "
Packit 6ef888
				    "(y/n) "))) {
Packit 6ef888
				log_err( _("The bad Extended Attributes were "
Packit 6ef888
					   "not fixed.\n"));
Packit 6ef888
				return 0;
Packit 6ef888
			}
Packit 6ef888
			log_err(_("Clearing the bad Extended Attributes in "
Packit 6ef888
				  "inode %lld (0x%llx).\n"),
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
			eattr_undo_fxns.private = &bc;
Packit 6ef888
			check_inode_eattr(ip, &eattr_undo_fxns);
Packit 6ef888
			ask_remove_inode_eattr(ip, &bc);
Packit 6ef888
			return 1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_blocks != 
Packit 6ef888
		(1 + bc.indir_count + bc.data_count + bc.ea_count)) {
Packit 6ef888
		log_err( _("Inode #%llu (0x%llx): Ondisk block count (%llu"
Packit 6ef888
			") does not match what fsck found (%llu)\n"),
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_blocks,
Packit 6ef888
			(unsigned long long)1 + bc.indir_count +
Packit 6ef888
			bc.data_count + bc.ea_count);
Packit 6ef888
		log_info( _("inode has: %lld, but fsck counts: Dinode:1 + "
Packit 6ef888
			    "indir:%lld + data: %lld + ea: %lld\n"),
Packit 6ef888
			  (unsigned long long)ip->i_di.di_blocks,
Packit 6ef888
			  (unsigned long long)bc.indir_count,
Packit 6ef888
			  (unsigned long long)bc.data_count,
Packit 6ef888
			  (unsigned long long)bc.ea_count);
Packit 6ef888
		if (query( _("Fix ondisk block count? (y/n) "))) {
Packit 6ef888
			ip->i_di.di_blocks = 1 + bc.indir_count + bc.data_count +
Packit 6ef888
				bc.ea_count;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
			log_err( _("Block count for #%llu (0x%llx) fixed\n"),
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		} else
Packit 6ef888
			log_err( _("Bad block count for #%llu (0x%llx"
Packit 6ef888
				") not fixed\n"),
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
bad_dinode:
Packit 6ef888
	stack;
Packit 6ef888
	return -1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void check_i_goal(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM)
Packit 6ef888
		return;
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_goal_meta <= LGFS2_SB_ADDR(sdp) ||
Packit 6ef888
	    ip->i_di.di_goal_meta > sdp->fssize) {
Packit 6ef888
		log_err(_("Inode #%llu (0x%llx): Bad allocation goal block "
Packit 6ef888
			  "found: %llu (0x%llx)\n"),
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_goal_meta,
Packit 6ef888
			(unsigned long long)ip->i_di.di_goal_meta);
Packit 6ef888
		if (query( _("Fix goal block in inode #%llu (0x%llx)? (y/n) "),
Packit 6ef888
			   (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			   (unsigned long long)ip->i_di.di_num.no_addr)) {
Packit 6ef888
			ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
		} else
Packit 6ef888
			log_err(_("Allocation goal block in inode #%lld "
Packit 6ef888
				  "(0x%llx) not fixed\n"),
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * handle_di - This is now a wrapper function that takes a gfs2_buffer_head
Packit 6ef888
 *             and calls handle_ip, which takes an in-code dinode structure.
Packit 6ef888
 */
Packit 6ef888
static int handle_di(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit 6ef888
		     struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
	uint64_t block = bh->b_blocknr;
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
Packit 6ef888
	ip = fsck_inode_get(sdp, rgd, bh);
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_num.no_addr != block) {
Packit 6ef888
		log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
Packit 6ef888
			"(0x%llx)\n"), (unsigned long long)block,
Packit 6ef888
			(unsigned long long)block,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if (query( _("Fix address in inode at block #%llu"
Packit 6ef888
			    " (0x%llx)? (y/n) "),
Packit 6ef888
			  (unsigned long long)block, (unsigned long long)block)) {
Packit 6ef888
			ip->i_di.di_num.no_addr = ip->i_di.di_num.no_formal_ino = block;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
		} else
Packit 6ef888
			log_err( _("Address in inode at block #%llu"
Packit 6ef888
				 " (0x%llx) not fixed\n"),
Packit 6ef888
				(unsigned long long)block,
Packit 6ef888
				(unsigned long long)block);
Packit 6ef888
	}
Packit 6ef888
	if (sdp->gfs1 && ip->i_di.di_num.no_formal_ino != block) {
Packit 6ef888
		log_err( _("Inode #%llu (0x%llx): GFS1 formal inode number "
Packit 6ef888
			   "mismatch: was %llu (0x%llx)\n"),
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_formal_ino,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_formal_ino);
Packit 6ef888
		if (query( _("Fix formal inode number in inode #%llu"
Packit 6ef888
			    " (0x%llx)? (y/n) "), (unsigned long long)block,
Packit 6ef888
			   (unsigned long long)block)) {
Packit 6ef888
			ip->i_di.di_num.no_formal_ino = block;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
		} else
Packit 6ef888
			log_err( _("Inode number in inode at block #%lld "
Packit 6ef888
				   "(0x%llx) not fixed\n"),
Packit 6ef888
				 (unsigned long long)block,
Packit 6ef888
				 (unsigned long long)block);
Packit 6ef888
	}
Packit 6ef888
	check_i_goal(sdp, ip);
Packit 6ef888
	error = handle_ip(sdp, ip);
Packit 6ef888
	fsck_inode_put(&ip);
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Check system inode and verify it's marked "in use" in the bitmap:       */
Packit 6ef888
/* Should work for all system inodes: root, master, jindex, per_node, etc. */
Packit 6ef888
/* We have to pass the sysinode as ** because the pointer may change out from
Packit 6ef888
   under the reference by way of the builder() function.  */
Packit 6ef888
static int check_system_inode(struct gfs2_sbd *sdp,
Packit 6ef888
			      struct gfs2_inode **sysinode,
Packit 6ef888
			      const char *filename,
Packit 6ef888
			      int builder(struct gfs2_sbd *sdp), int isdir,
Packit 6ef888
			      struct gfs2_inode *sysdir, int needs_sysbit)
Packit 6ef888
{
Packit 6ef888
	uint64_t iblock = 0;
Packit 6ef888
	struct dir_status ds = {0};
Packit 6ef888
	int error, err = 0;
Packit 6ef888
Packit 6ef888
	log_info( _("Checking system inode '%s'\n"), filename);
Packit 6ef888
	if (*sysinode) {
Packit 6ef888
		/* Read in the system inode, look at its dentries, and start
Packit 6ef888
		 * reading through them */
Packit 6ef888
		iblock = (*sysinode)->i_di.di_num.no_addr;
Packit 6ef888
		log_info( _("System inode for '%s' is located at block %llu"
Packit 6ef888
			 " (0x%llx)\n"), filename,
Packit 6ef888
			 (unsigned long long)iblock,
Packit 6ef888
			 (unsigned long long)iblock);
Packit 6ef888
		if (gfs2_check_meta((*sysinode)->i_bh, GFS2_METATYPE_DI)) {
Packit 6ef888
			log_err( _("Found invalid system dinode at block #"
Packit 6ef888
				   "%llu (0x%llx)\n"),
Packit 6ef888
				 (unsigned long long)iblock,
Packit 6ef888
				 (unsigned long long)iblock);
Packit 6ef888
			gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
Packit 6ef888
			check_n_fix_bitmap(sdp, (*sysinode)->i_rgd, iblock, 0,
Packit 6ef888
					   GFS2_BLKST_FREE);
Packit 6ef888
			inode_put(sysinode);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	if (*sysinode) {
Packit 6ef888
		ds.q = block_type(bl, iblock);
Packit 6ef888
		/* If the inode exists but the block is marked free, we might
Packit 6ef888
		   be recovering from a corrupt bitmap.  In that case, don't
Packit 6ef888
		   rebuild the inode.  Just reuse the inode and fix the
Packit 6ef888
		   bitmap. */
Packit 6ef888
		if (ds.q == GFS2_BLKST_FREE) {
Packit 6ef888
			log_info( _("The inode exists but the block is not "
Packit 6ef888
				    "marked 'in use'; fixing it.\n"));
Packit 6ef888
			fsck_blockmap_set(*sysinode,
Packit 6ef888
					  (*sysinode)->i_di.di_num.no_addr,
Packit 6ef888
					  filename, GFS2_BLKST_DINODE);
Packit 6ef888
			ds.q = GFS2_BLKST_DINODE;
Packit 6ef888
			if (isdir)
Packit 6ef888
				dirtree_insert((*sysinode)->i_di.di_num);
Packit 6ef888
		}
Packit 6ef888
		/* Make sure it's marked as a system file/directory */
Packit 6ef888
		if (needs_sysbit &&
Packit 6ef888
		    !((*sysinode)->i_di.di_flags & GFS2_DIF_SYSTEM)) {
Packit 6ef888
			log_err( _("System inode %s is missing the 'system' "
Packit 6ef888
				   "flag. It should be rebuilt.\n"), filename);
Packit 6ef888
			if (sysdir && query(_("Delete the corrupt %s system "
Packit 6ef888
					      "inode? (y/n) "), filename)) {
Packit 6ef888
				inode_put(sysinode);
Packit 6ef888
				gfs2_dirent_del(sysdir, filename,
Packit 6ef888
						strlen(filename));
Packit 6ef888
				/* Set the blockmap (but not bitmap) back to
Packit 6ef888
				   'free' so that it gets checked like any
Packit 6ef888
				   normal dinode. */
Packit 6ef888
				gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
Packit 6ef888
				log_err( _("Removed system inode \"%s\".\n"),
Packit 6ef888
					 filename);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
	} else
Packit 6ef888
		log_info( _("System inode for '%s' is corrupt or missing.\n"),
Packit 6ef888
			  filename);
Packit 6ef888
	/* If there are errors with the inode here, we need to create a new
Packit 6ef888
	   inode and get it all setup - of course, everything will be in
Packit 6ef888
	   lost+found then, but we *need* our system inodes before we can
Packit 6ef888
	   do any of that. */
Packit 6ef888
	if (!(*sysinode) || ds.q != GFS2_BLKST_DINODE) {
Packit 6ef888
		log_err(_("Invalid or missing %s system inode (is '%s', "
Packit 6ef888
			  "should be '%s').\n"), filename,
Packit 6ef888
			block_type_string(ds.q),
Packit 6ef888
			block_type_string(GFS2_BLKST_DINODE));
Packit 6ef888
		if (query(_("Create new %s system inode? (y/n) "), filename)) {
Packit 6ef888
			log_err( _("Rebuilding system file \"%s\"\n"),
Packit 6ef888
				 filename);
Packit 6ef888
			error = builder(sdp);
Packit 6ef888
			if (error) {
Packit 6ef888
				log_err( _("Error rebuilding system "
Packit 6ef888
					   "inode %s: Cannot continue\n"),
Packit 6ef888
					 filename);
Packit 6ef888
				return error;
Packit 6ef888
			}
Packit 6ef888
			if (*sysinode == sdp->md.jiinode)
Packit 6ef888
				ji_update(sdp);
Packit 6ef888
			fsck_blockmap_set(*sysinode,
Packit 6ef888
					  (*sysinode)->i_di.di_num.no_addr,
Packit 6ef888
					  filename, GFS2_BLKST_DINODE);
Packit 6ef888
			ds.q = GFS2_BLKST_DINODE;
Packit 6ef888
			if (isdir)
Packit 6ef888
				dirtree_insert((*sysinode)->i_di.di_num);
Packit 6ef888
		} else {
Packit 6ef888
			log_err( _("Cannot continue without valid %s inode\n"),
Packit 6ef888
				filename);
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	if (is_dir(&(*sysinode)->i_di, sdp->gfs1)) {
Packit 6ef888
		struct block_count bc = {0};
Packit 6ef888
Packit 6ef888
		sysdir_fxns.private = &bc;
Packit 6ef888
		if ((*sysinode)->i_di.di_flags & GFS2_DIF_EXHASH)
Packit 6ef888
			pass1_check_metatree(*sysinode, &sysdir_fxns);
Packit 6ef888
		else {
Packit 6ef888
			err = check_linear_dir(*sysinode, (*sysinode)->i_bh,
Packit 6ef888
					       &sysdir_fxns);
Packit 6ef888
			/* If we encountered an error in our directory check
Packit 6ef888
			   we should still call handle_ip, but return the
Packit 6ef888
			   error later. */
Packit 6ef888
			if (err)
Packit 6ef888
				log_err(_("Error found in %s while checking "
Packit 6ef888
					  "directory entries.\n"), filename);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	check_i_goal(sdp, *sysinode);
Packit 6ef888
	error = handle_ip(sdp, *sysinode);
Packit 6ef888
	return error ? error : err;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int build_a_journal(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	char name[256];
Packit 6ef888
	int err = 0;
Packit 6ef888
Packit 6ef888
	/* First, try to delete the journal if it's in jindex */
Packit 6ef888
	sprintf(name, "journal%u", sdp->md.journals);
Packit 6ef888
	gfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
Packit 6ef888
	/* Now rebuild it */
Packit 6ef888
	err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
Packit 6ef888
	if (err) {
Packit 6ef888
		log_crit(_("Error %d building journal\n"), err);
Packit 6ef888
		exit(FSCK_ERROR);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_system_inodes(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	int journal_count;
Packit 6ef888
Packit 6ef888
	/*******************************************************************
Packit 6ef888
	 *******  Check the system inode integrity             *************
Packit 6ef888
	 *******************************************************************/
Packit 6ef888
	/* Mark the master system dinode as a "dinode" in the block map.
Packit 6ef888
	   All other system dinodes in master will be taken care of by function
Packit 6ef888
	   resuscitate_metalist.  But master won't since it has no parent.*/
Packit 6ef888
	if (!sdp->gfs1) {
Packit 6ef888
		fsck_blockmap_set(sdp->master_dir,
Packit 6ef888
				  sdp->master_dir->i_di.di_num.no_addr,
Packit 6ef888
				  "master", GFS2_BLKST_DINODE);
Packit 6ef888
		if (check_system_inode(sdp, &sdp->master_dir, "master",
Packit 6ef888
				       build_master, 1, NULL, 1)) {
Packit 6ef888
			stack;
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	/* Mark the root dinode as a "dinode" in the block map as we did
Packit 6ef888
	   for master, since it has no parent. */
Packit 6ef888
	fsck_blockmap_set(sdp->md.rooti, sdp->md.rooti->i_di.di_num.no_addr,
Packit 6ef888
			  "root", GFS2_BLKST_DINODE);
Packit 6ef888
	if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root, 1,
Packit 6ef888
			       NULL, 0)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (!sdp->gfs1 &&
Packit 6ef888
	    check_system_inode(sdp, &sdp->md.inum, "inum", build_inum, 0,
Packit 6ef888
			       sdp->master_dir, 1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs, 0,
Packit 6ef888
			       sdp->master_dir, !sdp->gfs1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
Packit 6ef888
			       (sdp->gfs1 ? 0 : 1), sdp->master_dir,
Packit 6ef888
			       !sdp->gfs1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (check_system_inode(sdp, &sdp->md.riinode, "rindex", build_rindex,
Packit 6ef888
			       0, sdp->master_dir, !sdp->gfs1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (check_system_inode(sdp, &sdp->md.qinode, "quota", build_quota,
Packit 6ef888
			       0, sdp->master_dir, !sdp->gfs1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (!sdp->gfs1 &&
Packit 6ef888
	    check_system_inode(sdp, &sdp->md.pinode, "per_node",
Packit 6ef888
			       build_per_node, 1, sdp->master_dir, 1)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	/* We have to play a trick on build_journal:  We swap md.journals
Packit 6ef888
	   in order to keep a count of which journal we need to build. */
Packit 6ef888
	journal_count = sdp->md.journals;
Packit 6ef888
	/* gfs1's journals aren't dinode, they're just a bunch of blocks. */
Packit 6ef888
	if (sdp->gfs1) {
Packit 6ef888
		/* gfs1 has four dinodes that are set in the superblock and
Packit 6ef888
		   therefore not linked to anything else. We need to adjust
Packit 6ef888
		   the link counts so pass4 doesn't get confused. */
Packit 6ef888
		incr_link_count(sdp->md.statfs->i_di.di_num, NULL,
Packit 6ef888
				_("gfs1 statfs inode"));
Packit 6ef888
		incr_link_count(sdp->md.jiinode->i_di.di_num, NULL,
Packit 6ef888
				_("gfs1 jindex inode"));
Packit 6ef888
		incr_link_count(sdp->md.riinode->i_di.di_num, NULL,
Packit 6ef888
				_("gfs1 rindex inode"));
Packit 6ef888
		incr_link_count(sdp->md.qinode->i_di.di_num, NULL,
Packit 6ef888
				_("gfs1 quota inode"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	for (sdp->md.journals = 0; sdp->md.journals < journal_count;
Packit 6ef888
	     sdp->md.journals++) {
Packit 6ef888
		char jname[16];
Packit 6ef888
Packit 6ef888
		sprintf(jname, "journal%d", sdp->md.journals);
Packit 6ef888
		if (check_system_inode(sdp, &sdp->md.journal[sdp->md.journals],
Packit 6ef888
				       jname, build_a_journal, 0,
Packit 6ef888
				       sdp->md.jiinode, 1)) {
Packit 6ef888
			stack;
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uint64_t *ibuf, unsigned n)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	unsigned i;
Packit 6ef888
	uint64_t block;
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	int q;
Packit 6ef888
	/* Readahead numbers arrived at by experiment */
Packit 6ef888
	unsigned rawin = 50;
Packit 6ef888
	unsigned ralen = 100 * sdp->bsize;
Packit 6ef888
	unsigned r = 0;
Packit 6ef888
Packit 6ef888
	for (i = 0; i < n; i++) {
Packit 6ef888
		int is_inode;
Packit 6ef888
		uint32_t check_magic;
Packit 6ef888
Packit 6ef888
		block = ibuf[i];
Packit 6ef888
Packit 6ef888
		if (r++ == rawin) {
Packit 6ef888
			posix_fadvise(sdp->device_fd, block * sdp->bsize, ralen, POSIX_FADV_WILLNEED);
Packit 6ef888
			r = 0;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* skip gfs1 rindex indirect blocks */
Packit 6ef888
		if (sdp->gfs1 && blockfind(&gfs1_rindex_blks, block)) {
Packit 6ef888
			log_debug(_("Skipping rindex indir block "
Packit 6ef888
				    "%lld (0x%llx)\n"),
Packit 6ef888
				  (unsigned long long)block,
Packit 6ef888
				  (unsigned long long)block);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
		warm_fuzzy_stuff(block);
Packit 6ef888
Packit 6ef888
		if (fsck_abort) { /* if asked to abort */
Packit 6ef888
			gfs2_special_free(&gfs1_rindex_blks);
Packit 6ef888
			return FSCK_OK;
Packit 6ef888
		}
Packit 6ef888
		if (skip_this_pass) {
Packit 6ef888
			printf( _("Skipping pass 1 is not a good idea.\n"));
Packit 6ef888
			skip_this_pass = FALSE;
Packit 6ef888
			fflush(stdout);
Packit 6ef888
		}
Packit 6ef888
		if (fsck_system_inode(sdp, block)) {
Packit 6ef888
			log_debug(_("Already processed system inode "
Packit 6ef888
				    "%lld (0x%llx)\n"),
Packit 6ef888
				  (unsigned long long)block,
Packit 6ef888
				  (unsigned long long)block);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		bh = bread(sdp, block);
Packit 6ef888
Packit 6ef888
		is_inode = 0;
Packit 6ef888
		if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
Packit 6ef888
			is_inode = 1;
Packit 6ef888
Packit 6ef888
		check_magic = ((struct gfs2_meta_header *)
Packit 6ef888
			       (bh->b_data))->mh_magic;
Packit 6ef888
Packit 6ef888
		q = block_type(bl, block);
Packit 6ef888
		if (q != GFS2_BLKST_FREE) {
Packit 6ef888
			if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
Packit 6ef888
			    sdp->gfs1 && !is_inode) {
Packit 6ef888
				log_debug(_("Block 0x%llx assumed to be "
Packit 6ef888
					    "previously processed GFS1 "
Packit 6ef888
					    "non-dinode metadata.\n"),
Packit 6ef888
					  (unsigned long long)block);
Packit 6ef888
				brelse(bh);
Packit 6ef888
				continue;
Packit 6ef888
			}
Packit 6ef888
			log_err( _("Found a duplicate inode block at #%llu "
Packit 6ef888
				   "(0x%llx) previously marked as a %s\n"),
Packit 6ef888
				 (unsigned long long)block,
Packit 6ef888
				 (unsigned long long)block,
Packit 6ef888
				 block_type_string(q));
Packit 6ef888
			ip = fsck_inode_get(sdp, rgd, bh);
Packit 6ef888
			if (is_inode && ip->i_di.di_num.no_addr == block)
Packit 6ef888
				add_duplicate_ref(ip, block, ref_is_inode, 0,
Packit 6ef888
						  INODE_VALID);
Packit 6ef888
			else
Packit 6ef888
				log_info(_("dinum.no_addr is wrong, so I "
Packit 6ef888
					   "assume the bitmap is just "
Packit 6ef888
					   "wrong.\n"));
Packit 6ef888
			fsck_inode_put(&ip);
Packit 6ef888
			brelse(bh);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (!is_inode) {
Packit 6ef888
			if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
Packit 6ef888
			/* In gfs2, a bitmap mark of 2 means an inode,
Packit 6ef888
			   but in gfs1 it means any metadata.  So if
Packit 6ef888
			   this is gfs1 and not an inode, it may be
Packit 6ef888
			   okay.  If it's non-dinode metadata, it will
Packit 6ef888
			   be referenced by an inode, so we need to
Packit 6ef888
			   skip it here and it will be sorted out
Packit 6ef888
			   when the referencing inode is checked. */
Packit 6ef888
				if (sdp->gfs1) {
Packit 6ef888
					log_debug( _("Deferring GFS1 "
Packit 6ef888
						     "metadata block #"
Packit 6ef888
						     "%" PRIu64" (0x%"
Packit 6ef888
						     PRIx64 ")\n"),
Packit 6ef888
						   block, block);
Packit 6ef888
					brelse(bh);
Packit 6ef888
					continue;
Packit 6ef888
				}
Packit 6ef888
			}
Packit 6ef888
			log_err( _("Found invalid inode at block #"
Packit 6ef888
				   "%llu (0x%llx)\n"),
Packit 6ef888
				 (unsigned long long)block,
Packit 6ef888
				 (unsigned long long)block);
Packit 6ef888
			check_n_fix_bitmap(sdp, rgd, block, 0,
Packit 6ef888
					   GFS2_BLKST_FREE);
Packit 6ef888
		} else if (handle_di(sdp, rgd, bh) < 0) {
Packit 6ef888
			stack;
Packit 6ef888
			brelse(bh);
Packit 6ef888
			gfs2_special_free(&gfs1_rindex_blks);
Packit 6ef888
			return FSCK_ERROR;
Packit 6ef888
		}
Packit 6ef888
		/* Ignore everything else - they should be hit by the
Packit 6ef888
		   handle_di step.  Don't check NONE either, because
Packit 6ef888
		   check_meta passes everything if GFS2_METATYPE_NONE
Packit 6ef888
		   is specified.  Hopefully, other metadata types such
Packit 6ef888
		   as indirect blocks will be handled when the inode
Packit 6ef888
		   itself is processed, and if it's not, it should be
Packit 6ef888
		   caught in pass5. */
Packit 6ef888
		brelse(bh);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int pass1_process_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
Packit 6ef888
{
Packit 6ef888
	unsigned k, n, i;
Packit 6ef888
	uint64_t *ibuf = malloc(sdp->bsize * GFS2_NBBY * sizeof(uint64_t));
Packit 6ef888
	int ret = 0;
Packit 6ef888
Packit 6ef888
	if (ibuf == NULL)
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
Packit 6ef888
	for (k = 0; k < rgd->ri.ri_length; k++) {
Packit 6ef888
		n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_DINODE);
Packit 6ef888
Packit 6ef888
		if (n) {
Packit 6ef888
			ret = pass1_process_bitmap(sdp, rgd, ibuf, n);
Packit 6ef888
			if (ret)
Packit 6ef888
				goto out;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (fsck_abort)
Packit 6ef888
			goto out;
Packit 6ef888
		/*
Packit 6ef888
		  For GFS1, we have to count the "free meta" blocks in the
Packit 6ef888
		  resource group and mark them specially so we can count them
Packit 6ef888
		  properly in pass5.
Packit 6ef888
		 */
Packit 6ef888
		if (!sdp->gfs1)
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_UNLINKED);
Packit 6ef888
		for (i = 0; i < n; i++) {
Packit 6ef888
			gfs2_blockmap_set(bl, ibuf[i], GFS2_BLKST_UNLINKED);
Packit 6ef888
			if (fsck_abort)
Packit 6ef888
				goto out;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
out:
Packit 6ef888
	free(ibuf);
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int gfs2_blockmap_create(struct gfs2_bmap *bmap, uint64_t size)
Packit 6ef888
{
Packit 6ef888
	bmap->size = size;
Packit 6ef888
Packit 6ef888
	/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
Packit 6ef888
	 * must be 1-based */
Packit 6ef888
	bmap->mapsize = BLOCKMAP_SIZE2(size) + 1;
Packit 6ef888
Packit 6ef888
	if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
Packit 6ef888
		return -ENOMEM;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
Packit 6ef888
static int link1_create(struct gfs2_bmap *bmap, uint64_t size)
Packit 6ef888
{
Packit 6ef888
	bmap->size = size;
Packit 6ef888
Packit 6ef888
	/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
Packit 6ef888
	 * must be 1-based */
Packit 6ef888
	bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
Packit 6ef888
Packit 6ef888
	if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
Packit 6ef888
		return -ENOMEM;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
Packit 6ef888
					  uint64_t *addl_mem_needed)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_bmap *il;
Packit 6ef888
Packit 6ef888
	*addl_mem_needed = 0L;
Packit 6ef888
	il = calloc(1, sizeof(*il));
Packit 6ef888
	if (!il)
Packit 6ef888
		return NULL;
Packit 6ef888
Packit 6ef888
	if (gfs2_blockmap_create(il, size)) {
Packit 6ef888
		*addl_mem_needed = il->mapsize;
Packit 6ef888
		free(il);
Packit 6ef888
		il = NULL;
Packit 6ef888
	}
Packit 6ef888
	return il;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void gfs2_blockmap_destroy(struct gfs2_bmap *bmap)
Packit 6ef888
{
Packit 6ef888
	if (bmap->map)
Packit 6ef888
		free(bmap->map);
Packit 6ef888
	bmap->size = 0;
Packit 6ef888
	bmap->mapsize = 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il)
Packit 6ef888
{
Packit 6ef888
	if (il) {
Packit 6ef888
		gfs2_blockmap_destroy(il);
Packit 6ef888
		free(il);
Packit 6ef888
		il = NULL;
Packit 6ef888
	}
Packit 6ef888
	return il;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void enomem(uint64_t addl_mem_needed)
Packit 6ef888
{
Packit 6ef888
	log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
Packit 6ef888
	log_crit( _("Additional memory needed is approximately: %lluMB\n"),
Packit 6ef888
		  (unsigned long long)(addl_mem_needed / 1048576ULL));
Packit 6ef888
	log_crit( _("Please increase your swap space by that amount and run fsck.gfs2 again.\n"));
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * pass1 - walk through inodes and check inode state
Packit 6ef888
 *
Packit 6ef888
 * this walk can be done using root inode and depth first search,
Packit 6ef888
 * watching for repeat inode numbers
Packit 6ef888
 *
Packit 6ef888
 * format & type
Packit 6ef888
 * link count
Packit 6ef888
 * duplicate blocks
Packit 6ef888
 * bad blocks
Packit 6ef888
 * inodes size
Packit 6ef888
 * dir info
Packit 6ef888
 */
Packit 6ef888
int pass1(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *n, *next = NULL;
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
	uint64_t i;
Packit 6ef888
	uint64_t rg_count = 0;
Packit 6ef888
	struct timeval timer;
Packit 6ef888
	int ret = FSCK_OK;
Packit 6ef888
	uint64_t addl_mem_needed;
Packit 6ef888
Packit 6ef888
	bl = gfs2_bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
Packit 6ef888
	if (!bl) {
Packit 6ef888
		enomem(addl_mem_needed);
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
Packit 6ef888
	if (addl_mem_needed) {
Packit 6ef888
		enomem(addl_mem_needed);
Packit 6ef888
		gfs2_bmap_destroy(sdp, bl);
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
Packit 6ef888
	if (addl_mem_needed) {
Packit 6ef888
		enomem(addl_mem_needed);
Packit 6ef888
		link1_destroy(&nlink1map);
Packit 6ef888
		gfs2_bmap_destroy(sdp, bl);
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	osi_list_init(&gfs1_rindex_blks.list);
Packit 6ef888
Packit 6ef888
	/* FIXME: In the gfs fsck, we had to mark things like the
Packit 6ef888
	 * journals and indices and such as 'other_meta' - in gfs2,
Packit 6ef888
	 * the journals are files and are found in the normal file
Packit 6ef888
	 * sweep - is there any metadata we need to mark here before
Packit 6ef888
	 * the sweeps start that we won't find otherwise? */
Packit 6ef888
Packit 6ef888
	/* Make sure the system inodes are okay & represented in the bitmap. */
Packit 6ef888
	check_system_inodes(sdp);
Packit 6ef888
Packit 6ef888
	/* So, do we do a depth first search starting at the root
Packit 6ef888
	 * inode, or use the rg bitmaps, or just read every fs block
Packit 6ef888
	 * to find the inodes?  If we use the depth first search, why
Packit 6ef888
	 * have pass3 at all - if we use the rg bitmaps, pass5 is at
Packit 6ef888
	 * least partially invalidated - if we read every fs block,
Packit 6ef888
	 * things will probably be intolerably slow.  The current fsck
Packit 6ef888
	 * uses the rg bitmaps, so maybe that's the best way to start
Packit 6ef888
	 * things - we can change the method later if necessary.
Packit 6ef888
	 */
Packit 6ef888
	for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) {
Packit 6ef888
		if (fsck_abort) {
Packit 6ef888
			ret = FSCK_CANCELED;
Packit 6ef888
			goto out;
Packit 6ef888
		}
Packit 6ef888
		next = osi_next(n);
Packit 6ef888
		log_debug( _("Checking metadata in Resource Group #%llu\n"),
Packit 6ef888
				 (unsigned long long)rg_count);
Packit 6ef888
		rgd = (struct rgrp_tree *)n;
Packit 6ef888
		for (i = 0; i < rgd->ri.ri_length; i++) {
Packit 6ef888
			log_debug( _("rgrp block %lld (0x%llx) "
Packit 6ef888
				     "is now marked as 'rgrp data'\n"),
Packit 6ef888
				   rgd->ri.ri_addr + i, rgd->ri.ri_addr + i);
Packit 6ef888
			if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
Packit 6ef888
					      GFS2_BLKST_USED)) {
Packit 6ef888
				stack;
Packit 6ef888
				gfs2_special_free(&gfs1_rindex_blks);
Packit 6ef888
				ret = FSCK_ERROR;
Packit 6ef888
				goto out;
Packit 6ef888
			}
Packit 6ef888
			/* rgrps and bitmaps don't have bits to represent
Packit 6ef888
			   their blocks, so don't do this:
Packit 6ef888
			check_n_fix_bitmap(sdp, rgd, rgd->ri.ri_addr + i, 0,
Packit 6ef888
			gfs2_meta_rgrp);*/
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		ret = pass1_process_rgrp(sdp, rgd);
Packit 6ef888
		if (ret)
Packit 6ef888
			goto out;
Packit 6ef888
	}
Packit 6ef888
	log_notice(_("Reconciling bitmaps.\n"));
Packit 6ef888
	gettimeofday(&timer, NULL);
Packit 6ef888
	pass5(sdp, bl);
Packit 6ef888
	print_pass_duration("reconcile_bitmaps", &timer;;
Packit 6ef888
out:
Packit 6ef888
	gfs2_special_free(&gfs1_rindex_blks);
Packit 6ef888
	if (bl)
Packit 6ef888
		gfs2_bmap_destroy(sdp, bl);
Packit 6ef888
	return ret;
Packit 6ef888
}