Blame gfs2/fsck/pass1b.c

Packit 6ef888
#include "clusterautoconfig.h"
Packit 6ef888
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <unistd.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#include <sys/stat.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "link.h"
Packit 6ef888
#include "fsck.h"
Packit 6ef888
#include "osi_list.h"
Packit 6ef888
#include "util.h"
Packit 6ef888
#include "metawalk.h"
Packit 6ef888
#include "inode_hash.h"
Packit 6ef888
#include "afterpass1_common.h"
Packit 6ef888
Packit 6ef888
struct fxn_info {
Packit 6ef888
	uint64_t block;
Packit 6ef888
	int found;
Packit 6ef888
	int ea_only;    /* The only dups were found in EAs */
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct dup_handler {
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
	int ref_inode_count;
Packit 6ef888
	int ref_count;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct clone_target {
Packit 6ef888
	uint64_t dup_block;
Packit 6ef888
	int first;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct meta_blk_ref {
Packit 6ef888
	uint64_t block; /* block to locate */
Packit 6ef888
	uint64_t metablock; /* returned metadata block addr containing ref */
Packit 6ef888
	int off; /* offset to the reference within the buffer */
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
static int clone_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
static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
Packit 6ef888
{
Packit 6ef888
	char reftypestring[32];
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
Packit 6ef888
	id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
	if (id->dup_count == 1)
Packit 6ef888
		sprintf(reftypestring, "as %s", reftypes[get_ref_type(id)]);
Packit 6ef888
	else
Packit 6ef888
		sprintf(reftypestring, "%d/%d/%d/%d",
Packit 6ef888
			id->reftypecount[ref_is_inode],
Packit 6ef888
			id->reftypecount[ref_as_data],
Packit 6ef888
			id->reftypecount[ref_as_meta],
Packit 6ef888
			id->reftypecount[ref_as_ea]);
Packit 6ef888
	if (inval)
Packit 6ef888
		log_warn( _("Invalid "));
Packit 6ef888
	log_warn( _("Inode %s (%lld/0x%llx) has %d reference(s) to "
Packit 6ef888
		    "block %llu (0x%llx) (%s)\n"), id->name,
Packit 6ef888
		  (unsigned long long)id->block_no,
Packit 6ef888
		  (unsigned long long)id->block_no, id->dup_count,
Packit 6ef888
		  (unsigned long long)dt->block,
Packit 6ef888
		  (unsigned long long)dt->block, reftypestring);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int findref_meta(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			struct gfs2_buffer_head **bh, int h,
Packit 6ef888
			int *is_valid, int *was_duplicate, void *private)
Packit 6ef888
{
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int findref_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
	struct meta_blk_ref *mbr = (struct meta_blk_ref *)private;
Packit 6ef888
Packit 6ef888
	if (block == mbr->block) {
Packit 6ef888
		mbr->metablock = bh->b_blocknr;
Packit 6ef888
		mbr->off = (ptr - (uint64_t *)bh->b_data);
Packit 6ef888
		log_debug("Duplicate data reference located on metadata "
Packit 6ef888
			  "block 0x%llx, offset 0x%x\n",
Packit 6ef888
			  (unsigned long long)mbr->metablock, mbr->off);
Packit 6ef888
	}
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void clone_data_block(struct gfs2_sbd *sdp, struct duptree *dt,
Packit 6ef888
			     struct inode_with_dups *id)
Packit 6ef888
{
Packit 6ef888
	struct meta_blk_ref metaref = { .block = dt->block, };
Packit 6ef888
	struct metawalk_fxns find1ref_fxns = {
Packit 6ef888
		.private = &metaref,
Packit 6ef888
		.check_metalist = findref_meta,
Packit 6ef888
		.check_data = findref_data,
Packit 6ef888
	};
Packit 6ef888
	struct clone_target clone = {.dup_block = dt->block,};
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint64_t *ptr;
Packit 6ef888
Packit 6ef888
	if (!(query(_("Okay to clone data block %lld (0x%llx) for inode "
Packit 6ef888
		      "%lld (0x%llx)? (y/n) "),
Packit 6ef888
		    (unsigned long long)dt->block,
Packit 6ef888
		    (unsigned long long)dt->block,
Packit 6ef888
		    (unsigned long long)id->block_no,
Packit 6ef888
		    (unsigned long long)id->block_no))) {
Packit 6ef888
		log_warn(_("The duplicate reference was not cloned.\n"));
Packit 6ef888
		return;
Packit 6ef888
	}
Packit 6ef888
	ip = fsck_load_inode(sdp, id->block_no);
Packit 6ef888
	check_metatree(ip, &find1ref_fxns);
Packit 6ef888
	if (metaref.metablock == 0) {
Packit 6ef888
		log_err(_("Unable to clone data block.\n"));
Packit 6ef888
	} else {
Packit 6ef888
		if (metaref.metablock != id->block_no)
Packit 6ef888
			bh = bread(sdp, metaref.metablock);
Packit 6ef888
		else
Packit 6ef888
			bh = ip->i_bh;
Packit 6ef888
		ptr = (uint64_t *)bh->b_data + metaref.off;
Packit 6ef888
		clone_data(ip, 0, dt->block, &clone, bh, ptr);
Packit 6ef888
		if (metaref.metablock != id->block_no)
Packit 6ef888
			brelse(bh);
Packit 6ef888
		else
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
	}
Packit 6ef888
	fsck_inode_put(&ip); /* out, brelse, free */
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* revise_dup_handler - get current information about a duplicate reference
Packit 6ef888
 *
Packit 6ef888
 * Function resolve_dup_references can delete dinodes that reference blocks
Packit 6ef888
 * which may have duplicate references. Therefore, the duplicate tree is
Packit 6ef888
 * constantly being changed. This function revises the duplicate handler so
Packit 6ef888
 * that it accurately matches what's in the duplicate tree regarding this block
Packit 6ef888
 */
Packit 6ef888
static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *tmp;
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
Packit 6ef888
	dh->ref_inode_count = 0;
Packit 6ef888
	dh->ref_count = 0;
Packit 6ef888
	dh->dt = NULL;
Packit 6ef888
Packit 6ef888
	dt = dupfind(dup_blk);
Packit 6ef888
	if (!dt)
Packit 6ef888
		return;
Packit 6ef888
Packit 6ef888
	dh->dt = dt;
Packit 6ef888
	/* Count the duplicate references, both valid and invalid */
Packit 6ef888
	osi_list_foreach(tmp, &dt->ref_invinode_list) {
Packit 6ef888
		id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
		dh->ref_inode_count++;
Packit 6ef888
		dh->ref_count += id->dup_count;
Packit 6ef888
	}
Packit 6ef888
	osi_list_foreach(tmp, &dt->ref_inode_list) {
Packit 6ef888
		id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
		dh->ref_inode_count++;
Packit 6ef888
		dh->ref_count += id->dup_count;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * resolve_dup_references - resolve all but the last dinode that has a
Packit 6ef888
 *                          duplicate reference to a given block.
Packit 6ef888
 *
Packit 6ef888
 * @sdp - pointer to the superblock structure
Packit 6ef888
 * @dt - pointer to the duplicate reference rbtree to use
Packit 6ef888
 * @ref_list - list of duplicate references to be resolved (invalid or valid)
Packit 6ef888
 * @dh - duplicate handler
Packit 6ef888
 * inval - The references on this ref_list are invalid.  We prefer to delete
Packit 6ef888
 *         these first before resorting to deleting valid dinodes.
Packit 6ef888
 * acceptable_ref - Delete dinodes that reference the given block as anything
Packit 6ef888
 *                  _but_ this type.  Try to save references as this type.
Packit 6ef888
 */
Packit 6ef888
static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
Packit 6ef888
				   osi_list_t *ref_list,
Packit 6ef888
				   struct dup_handler *dh,
Packit 6ef888
				   int inval, int acceptable_ref)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	osi_list_t *tmp, *x;
Packit 6ef888
	struct metawalk_fxns pass1b_fxns_delete = {
Packit 6ef888
		.private = NULL,
Packit 6ef888
		.check_metalist = delete_metadata,
Packit 6ef888
		.check_data = delete_data,
Packit 6ef888
		.check_leaf = delete_leaf,
Packit 6ef888
		.check_eattr_indir = delete_eattr_indir,
Packit 6ef888
		.check_eattr_leaf = delete_eattr_leaf,
Packit 6ef888
		.check_eattr_entry = delete_eattr_entry,
Packit 6ef888
		.check_eattr_extentry = delete_eattr_extentry,
Packit 6ef888
	};
Packit 6ef888
	enum dup_ref_type this_ref;
Packit 6ef888
	struct inode_info *ii;
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
	int found_good_ref = 0;
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	osi_list_foreach_safe(tmp, ref_list, x) {
Packit 6ef888
		if (skip_this_pass || fsck_abort)
Packit 6ef888
			return;
Packit 6ef888
Packit 6ef888
		id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
		dh->dt = dt;
Packit 6ef888
Packit 6ef888
		if (dh->ref_inode_count == 1) /* down to the last reference */
Packit 6ef888
			return;
Packit 6ef888
Packit 6ef888
		this_ref = get_ref_type(id);
Packit 6ef888
		q = bitmap_type(sdp, id->block_no);
Packit 6ef888
		if (inval)
Packit 6ef888
			log_warn( _("Invalid "));
Packit 6ef888
		/* FIXME: If we already found an acceptable reference to this
Packit 6ef888
		 * block, we should really duplicate the block and fix all
Packit 6ef888
		 * references to it in this inode.  Unfortunately, we would
Packit 6ef888
		 * have to traverse the entire metadata tree to do that. */
Packit 6ef888
		if (acceptable_ref != ref_types && /* If we're nuking all but
Packit 6ef888
						      an acceptable reference
Packit 6ef888
						      type and */
Packit 6ef888
		    this_ref == acceptable_ref) { /* this ref is acceptable */
Packit 6ef888
			/* If this is an invalid inode, but not on the invalid
Packit 6ef888
			   list, it's better to delete it. */
Packit 6ef888
			if (q == GFS2_BLKST_DINODE) {
Packit 6ef888
				found_good_ref = 1;
Packit 6ef888
				log_warn( _("Inode %s (%lld/0x%llx)'s "
Packit 6ef888
					    "reference to block %llu (0x%llx) "
Packit 6ef888
					    "as '%s' is acceptable.\n"),
Packit 6ef888
					  id->name,
Packit 6ef888
					  (unsigned long long)id->block_no,
Packit 6ef888
					  (unsigned long long)id->block_no,
Packit 6ef888
					  (unsigned long long)dt->block,
Packit 6ef888
					  (unsigned long long)dt->block,
Packit 6ef888
					  reftypes[this_ref]);
Packit 6ef888
				continue; /* don't delete the dinode */
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		/* If this reference is from a system inode, for example, if
Packit 6ef888
		   it's data or metadata inside a journal, the reference
Packit 6ef888
		   should take priority over user dinodes that reference the
Packit 6ef888
		   block. */
Packit 6ef888
		if (!found_good_ref && fsck_system_inode(sdp, id->block_no)) {
Packit 6ef888
			found_good_ref = 1;
Packit 6ef888
			continue; /* don't delete the dinode */
Packit 6ef888
		}
Packit 6ef888
		log_warn( _("Inode %s (%lld/0x%llx) references block "
Packit 6ef888
			    "%llu (0x%llx) as '%s', but the block is "
Packit 6ef888
			    "really %s.\n"),
Packit 6ef888
			  id->name, (unsigned long long)id->block_no,
Packit 6ef888
			  (unsigned long long)id->block_no,
Packit 6ef888
			  (unsigned long long)dt->block,
Packit 6ef888
			  (unsigned long long)dt->block,
Packit 6ef888
			  reftypes[this_ref], reftypes[acceptable_ref]);
Packit 6ef888
		if (this_ref == ref_as_ea) {
Packit 6ef888
			if (!(query( _("Okay to remove extended attributes "
Packit 6ef888
				       "from %s inode %lld (0x%llx)? (y/n) "),
Packit 6ef888
				     (inval ? _("invalidated") : ""),
Packit 6ef888
				     (unsigned long long)id->block_no,
Packit 6ef888
				     (unsigned long long)id->block_no))) {
Packit 6ef888
				log_warn( _("The bad EA reference was not "
Packit 6ef888
					    "cleared."));
Packit 6ef888
				/* delete the list entry so we don't leak
Packit 6ef888
				   memory but leave the reference count. If we
Packit 6ef888
				   decrement the ref count, we could get down
Packit 6ef888
				   to 1 and the dinode would be changed
Packit 6ef888
				   without a 'Yes' answer. */
Packit 6ef888
				/* (dh->ref_inode_count)--;*/
Packit 6ef888
				dup_listent_delete(dt, id);
Packit 6ef888
				continue;
Packit 6ef888
			}
Packit 6ef888
		} else if (acceptable_ref == ref_types &&
Packit 6ef888
			   this_ref == ref_as_data) {
Packit 6ef888
			clone_data_block(sdp, dt, id);
Packit 6ef888
			dup_listent_delete(dt, id);
Packit 6ef888
			revise_dup_handler(dt->block, dh);
Packit 6ef888
			continue;
Packit 6ef888
		} else if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
Packit 6ef888
				      "(y/n) "),
Packit 6ef888
				    (inval ? _("invalidated") : ""),
Packit 6ef888
				    (unsigned long long)id->block_no,
Packit 6ef888
				    (unsigned long long)id->block_no))) {
Packit 6ef888
			log_warn( _("The bad inode was not cleared."));
Packit 6ef888
			/* delete the list entry so we don't leak memory but
Packit 6ef888
			   leave the reference count. If we decrement the
Packit 6ef888
			   ref count, we could get down to 1 and the dinode
Packit 6ef888
			   would be changed without a 'Yes' answer. */
Packit 6ef888
			/* (dh->ref_inode_count)--;*/
Packit 6ef888
			dup_listent_delete(dt, id);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
		if (q == GFS2_BLKST_FREE)
Packit 6ef888
			log_warn( _("Inode %lld (0x%llx) was previously "
Packit 6ef888
				    "deleted.\n"),
Packit 6ef888
				  (unsigned long long)id->block_no,
Packit 6ef888
				  (unsigned long long)id->block_no);
Packit 6ef888
		else if (this_ref == ref_as_ea)
Packit 6ef888
			log_warn(_("Pass1b is removing extended attributes "
Packit 6ef888
				   "from inode %lld (0x%llx).\n"),
Packit 6ef888
				 (unsigned long long)id->block_no,
Packit 6ef888
				 (unsigned long long)id->block_no);
Packit 6ef888
		else
Packit 6ef888
			log_warn(_("Pass1b is deleting inode %lld (0x%llx).\n"),
Packit 6ef888
				 (unsigned long long)id->block_no,
Packit 6ef888
				 (unsigned long long)id->block_no);
Packit 6ef888
Packit 6ef888
		ip = fsck_load_inode(sdp, id->block_no);
Packit 6ef888
		/* If we've already deleted this dinode, don't try to delete
Packit 6ef888
		   it again. That could free blocks that used to be duplicate
Packit 6ef888
		   references that are now resolved (and gone). */
Packit 6ef888
		if (q != GFS2_BLKST_FREE) {
Packit 6ef888
			/* If the inode's eattr pointer is to the duplicate
Packit 6ef888
			   ref block, we don't want to call check_inode_eattr
Packit 6ef888
			   because that would traverse the structure, and it's
Packit 6ef888
			   not ours to do anymore; it rightly belongs to a
Packit 6ef888
			   different dinode. On the other hand, if the dup
Packit 6ef888
			   block is buried deep within the eattr structure
Packit 6ef888
			   of this dinode, we need to traverse the structure
Packit 6ef888
			   because it IS ours, and we need to remove all the
Packit 6ef888
			   eattr leaf blocks: they do belong to us (except for
Packit 6ef888
			   the duplicate referenced one, which is handled). */
Packit 6ef888
			if (ip->i_di.di_eattr == dt->block) {
Packit 6ef888
				ip->i_di.di_eattr = 0;
Packit 6ef888
				if (ip->i_di.di_blocks > 0)
Packit 6ef888
					ip->i_di.di_blocks--;
Packit 6ef888
				ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
Packit 6ef888
				bmodified(ip->i_bh);
Packit 6ef888
				dup_listent_delete(dt, id);
Packit 6ef888
				(dh->ref_inode_count)--;
Packit 6ef888
			} else {
Packit 6ef888
				/* Clear the EAs for the inode first */
Packit 6ef888
				check_inode_eattr(ip, &pass1b_fxns_delete);
Packit 6ef888
				(dh->ref_inode_count)--;
Packit 6ef888
			}
Packit 6ef888
			/* If the reference was as metadata or data, we've got
Packit 6ef888
			   a corrupt dinode that will be deleted. */
Packit 6ef888
			if ((this_ref != ref_as_ea) &&
Packit 6ef888
			    (inval || id->reftypecount[ref_as_data] ||
Packit 6ef888
			     id->reftypecount[ref_as_meta])) {
Packit 6ef888
				/* Fix the bitmap first, while the inodetree
Packit 6ef888
				   and dirtree entries exist. That way, the
Packit 6ef888
				   bitmap_set will do proper accounting for
Packit 6ef888
				   the rgrp dinode count. */
Packit 6ef888
				fsck_bitmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
						_("duplicate referencing bad"),
Packit 6ef888
						GFS2_BLKST_FREE);
Packit 6ef888
				/* Remove the inode from the inode tree */
Packit 6ef888
				ii = inodetree_find(ip->i_di.di_num.no_addr);
Packit 6ef888
				if (ii)
Packit 6ef888
					inodetree_delete(ii);
Packit 6ef888
				di = dirtree_find(ip->i_di.di_num.no_addr);
Packit 6ef888
				if (di)
Packit 6ef888
					dirtree_delete(di);
Packit 6ef888
				link1_set(&nlink1map, ip->i_di.di_num.no_addr,
Packit 6ef888
					  0);
Packit 6ef888
				/* We delete the dup_handler inode count and
Packit 6ef888
				   duplicate id BEFORE clearing the metadata,
Packit 6ef888
				   because if this is the last reference to
Packit 6ef888
				   this metadata block, we need to traverse the
Packit 6ef888
				   tree and free the data blocks it references.
Packit 6ef888
				   However, we don't want to delete other
Packit 6ef888
				   duplicates that may be used by other
Packit 6ef888
				   dinodes. */
Packit 6ef888
				(dh->ref_inode_count)--;
Packit 6ef888
				/* FIXME: other option should be to duplicate
Packit 6ef888
				   the block for each duplicate and point the
Packit 6ef888
				   metadata at the cloned blocks */
Packit 6ef888
				check_metatree(ip, &pass1b_fxns_delete);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		/* Now we've got to go through and delete any other duplicate
Packit 6ef888
		   references from this dinode we're deleting. If we don't,
Packit 6ef888
		   pass1b will discover the other duplicate record, try to
Packit 6ef888
		   delete this dinode a second time, and this time its earlier
Packit 6ef888
		   duplicate references won't be seen as duplicates anymore
Packit 6ef888
		   (because they were eliminated earlier in pass1b). And so
Packit 6ef888
		   the blocks will be mistakenly freed, when, in fact, they're
Packit 6ef888
		   still being referenced by a valid dinode. */
Packit 6ef888
		if (this_ref != ref_as_ea)
Packit 6ef888
			delete_all_dups(ip);
Packit 6ef888
		fsck_inode_put(&ip); /* out, brelse, free */
Packit 6ef888
	}
Packit 6ef888
	return;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int clone_check_meta(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			    struct gfs2_buffer_head **bh, int h,
Packit 6ef888
			    int *is_valid, int *was_duplicate, void *private)
Packit 6ef888
{
Packit 6ef888
	*was_duplicate = 0;
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	*bh = bread(ip->i_sbd, block);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* clone_data - clone a duplicate reference
Packit 6ef888
 *
Packit 6ef888
 * This function remembers the first reference to the specified block, and
Packit 6ef888
 * clones all subsequent references to it (with permission).
Packit 6ef888
 */
Packit 6ef888
static int clone_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
	struct clone_target *clonet = (struct clone_target *)private;
Packit 6ef888
	struct gfs2_buffer_head *clone_bh;
Packit 6ef888
	uint64_t cloneblock;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	if (block != clonet->dup_block)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	if (clonet->first) {
Packit 6ef888
		log_debug(_("Inode %lld (0x%llx)'s first reference to "
Packit 6ef888
			    "block %lld (0x%llx) is targeted for cloning.\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);
Packit 6ef888
		clonet->first = 0;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	log_err(_("Error: Inode %lld (0x%llx)'s reference to block %lld "
Packit 6ef888
		  "(0x%llx) should be replaced with a clone.\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
	if (query( _("Okay to clone the duplicated reference? (y/n) "))) {
Packit 6ef888
		error = lgfs2_meta_alloc(ip, &cloneblock);
Packit 6ef888
		if (!error) {
Packit 6ef888
			clone_bh = bread(ip->i_sbd, clonet->dup_block);
Packit 6ef888
			if (clone_bh) {
Packit 6ef888
				fsck_bitmap_set(ip, cloneblock, _("data"),
Packit 6ef888
						GFS2_BLKST_USED);
Packit 6ef888
				clone_bh->b_blocknr = cloneblock;
Packit 6ef888
				bmodified(clone_bh);
Packit 6ef888
				brelse(clone_bh);
Packit 6ef888
				/* Now fix the reference: */
Packit 6ef888
				*ptr = cpu_to_be64(cloneblock);
Packit 6ef888
				bmodified(bh);
Packit 6ef888
				log_err(_("Duplicate reference to block %lld "
Packit 6ef888
					  "(0x%llx) was cloned to block %lld "
Packit 6ef888
					  "(0x%llx).\n"),
Packit 6ef888
					(unsigned long long)block,
Packit 6ef888
					(unsigned long long)block,
Packit 6ef888
					(unsigned long long)cloneblock,
Packit 6ef888
					(unsigned long long)cloneblock);
Packit 6ef888
				return 0;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		log_err(_("Error: Unable to allocate a new data block.\n"));
Packit 6ef888
		if (!query("Should I zero the reference instead? (y/n)")) {
Packit 6ef888
			log_err(_("Duplicate reference to block %lld "
Packit 6ef888
				  "(0x%llx) was not fixed.\n"),
Packit 6ef888
				(unsigned long long)block,
Packit 6ef888
				(unsigned long long)block);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		*ptr = 0;
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		log_err(_("Duplicate reference to block %lld (0x%llx) was "
Packit 6ef888
			  "zeroed.\n"),
Packit 6ef888
			(unsigned long long)block,
Packit 6ef888
			(unsigned long long)block);
Packit 6ef888
	} else {
Packit 6ef888
		log_err(_("Duplicate reference to block %lld (0x%llx) "
Packit 6ef888
			  "was not fixed.\n"), (unsigned long long)block,
Packit 6ef888
			(unsigned long long)block);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* clone_dup_ref_in_inode - clone a duplicate reference within a single inode
Packit 6ef888
 *
Packit 6ef888
 * This function traverses the metadata tree of an inode, cloning all
Packit 6ef888
 * but the first reference to a duplicate block reference.
Packit 6ef888
 */
Packit 6ef888
static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
	struct clone_target clonet = {.dup_block = dt->block, .first = 1};
Packit 6ef888
	struct metawalk_fxns pass1b_fxns_clone = {
Packit 6ef888
		.private = &clonet,
Packit 6ef888
		.check_metalist = clone_check_meta,
Packit 6ef888
		.check_data = clone_data,
Packit 6ef888
	};
Packit 6ef888
Packit 6ef888
	log_err(_("There are multiple references to block %lld (0x%llx) 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
		(unsigned long long)dt->block, (unsigned long long)dt->block);
Packit 6ef888
	error = check_metatree(ip, &pass1b_fxns_clone);
Packit 6ef888
	if (error) {
Packit 6ef888
		log_err(_("Error cloning duplicate reference(s) to block %lld "
Packit 6ef888
			  "(0x%llx).\n"), (unsigned long long)dt->block,
Packit 6ef888
			(unsigned long long)dt->block);
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int set_ip_bitmap(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
	fsck_bitmap_set(ip, block, ty, GFS2_BLKST_DINODE);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void resolve_last_reference(struct gfs2_sbd *sdp, struct duptree *dt,
Packit 6ef888
				   enum dup_ref_type acceptable_ref)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	osi_list_t *tmp;
Packit 6ef888
	int q;
Packit 6ef888
Packit 6ef888
	log_notice( _("Block %llu (0x%llx) has only one remaining "
Packit 6ef888
		      "valid inode referencing it.\n"),
Packit 6ef888
		    (unsigned long long)dt->block,
Packit 6ef888
		    (unsigned long long)dt->block);
Packit 6ef888
	/* If we're down to a single reference (and not all references
Packit 6ef888
	   deleted, which may be the case of an inode that has only
Packit 6ef888
	   itself and a reference), we need to reset the block type
Packit 6ef888
	   from invalid to data or metadata. Start at the first one
Packit 6ef888
	   in the list, not the structure's place holder. */
Packit 6ef888
	tmp = dt->ref_inode_list.next;
Packit 6ef888
	id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
	log_debug( _("----------------------------------------------\n"
Packit 6ef888
		     "Step 4. Set block type based on the remaining "
Packit 6ef888
		     "reference in inode %lld (0x%llx).\n"),
Packit 6ef888
		   (unsigned long long)id->block_no,
Packit 6ef888
		   (unsigned long long)id->block_no);
Packit 6ef888
	ip = fsck_load_inode(sdp, id->block_no);
Packit 6ef888
Packit 6ef888
	if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
Packit 6ef888
		clone_dup_ref_in_inode(ip, dt);
Packit 6ef888
Packit 6ef888
	q = bitmap_type(sdp, id->block_no);
Packit 6ef888
	if (q == GFS2_BLKST_FREE) {
Packit 6ef888
		log_debug( _("The remaining reference inode %lld (0x%llx) was "
Packit 6ef888
			     "already marked free.\n"),
Packit 6ef888
			   (unsigned long long)id->block_no,
Packit 6ef888
			   (unsigned long long)id->block_no);
Packit 6ef888
	} else if (id->reftypecount[ref_is_inode]) {
Packit 6ef888
		set_ip_bitmap(ip);
Packit 6ef888
	} else if (id->reftypecount[ref_as_data]) {
Packit 6ef888
		fsck_bitmap_set(ip, dt->block,  _("reference-repaired data"),
Packit 6ef888
				GFS2_BLKST_USED);
Packit 6ef888
	} else if (id->reftypecount[ref_as_meta]) {
Packit 6ef888
		if (is_dir(&ip->i_di, sdp->gfs1))
Packit 6ef888
			fsck_bitmap_set(ip, dt->block,
Packit 6ef888
					_("reference-repaired leaf"),
Packit 6ef888
					sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
					GFS2_BLKST_USED);
Packit 6ef888
		else
Packit 6ef888
			fsck_bitmap_set(ip, dt->block,
Packit 6ef888
					_("reference-repaired indirect"),
Packit 6ef888
					sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
					GFS2_BLKST_USED);
Packit 6ef888
	} else {
Packit 6ef888
		if (acceptable_ref == ref_as_ea)
Packit 6ef888
			fsck_bitmap_set(ip, dt->block,
Packit 6ef888
					_("reference-repaired extended "
Packit 6ef888
					  "attribute"),
Packit 6ef888
					sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
					GFS2_BLKST_USED);
Packit 6ef888
		else {
Packit 6ef888
			log_err(_("Error: The remaining reference to block "
Packit 6ef888
				  " %lld (0x%llx) is as extended attribute, "
Packit 6ef888
				  "in inode %lld (0x%llx) but the block is "
Packit 6ef888
				  "not an EA.\n"),
Packit 6ef888
				(unsigned long long)dt->block,
Packit 6ef888
				(unsigned long long)dt->block,
Packit 6ef888
				(unsigned long long)id->block_no,
Packit 6ef888
				(unsigned long long)id->block_no);
Packit 6ef888
			if (query(_("Okay to remove the bad extended "
Packit 6ef888
				    "attribute from inode %lld (0x%llx)? "
Packit 6ef888
				    "(y/n) "),
Packit 6ef888
				  (unsigned long long)id->block_no,
Packit 6ef888
				  (unsigned long long)id->block_no)) {
Packit 6ef888
				ip->i_di.di_eattr = 0;
Packit 6ef888
				ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
Packit 6ef888
				ip->i_di.di_blocks--;
Packit 6ef888
				bmodified(ip->i_bh);
Packit 6ef888
				fsck_bitmap_set(ip, dt->block,
Packit 6ef888
						_("reference-repaired EA"),
Packit 6ef888
						GFS2_BLKST_FREE);
Packit 6ef888
				log_err(_("The bad extended attribute was "
Packit 6ef888
					  "removed.\n"));
Packit 6ef888
			} else {
Packit 6ef888
				log_err(_("The bad extended attribute was not "
Packit 6ef888
					  "removed.\n"));
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	fsck_inode_put(&ip); /* out, brelse, free */
Packit 6ef888
	log_debug(_("Done with duplicate reference to block 0x%llx\n"),
Packit 6ef888
		  (unsigned long long)dt->block);
Packit 6ef888
	dup_delete(dt);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* handle_dup_blk - handle a duplicate block reference.
Packit 6ef888
 *
Packit 6ef888
 * This function should resolve and delete the duplicate block reference given,
Packit 6ef888
 * iow dt.
Packit 6ef888
 */
Packit 6ef888
static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *tmp;
Packit 6ef888
	struct dup_handler dh = {0};
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint32_t cmagic, ctype;
Packit 6ef888
	enum dup_ref_type acceptable_ref;
Packit 6ef888
	uint64_t dup_blk;
Packit 6ef888
Packit 6ef888
	dup_blk = dt->block;
Packit 6ef888
	revise_dup_handler(dup_blk, &dh);
Packit 6ef888
Packit 6ef888
	/* Log the duplicate references */
Packit 6ef888
	log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
Packit 6ef888
		   " for a total of %d duplicate references:\n"),
Packit 6ef888
		    (unsigned long long)dt->block,
Packit 6ef888
		    (unsigned long long)dt->block,
Packit 6ef888
		    dh.ref_inode_count, dh.ref_count);
Packit 6ef888
Packit 6ef888
	osi_list_foreach(tmp, &dt->ref_invinode_list)
Packit 6ef888
		log_inode_reference(dt, tmp, 1);
Packit 6ef888
	osi_list_foreach(tmp, &dt->ref_inode_list)
Packit 6ef888
		log_inode_reference(dt, tmp, 0);
Packit 6ef888
Packit 6ef888
	/* Figure out the block type to see if we can eliminate references
Packit 6ef888
	   to a different type. In other words, if the duplicate block looks
Packit 6ef888
	   like metadata, we can delete dinodes that reference it as data.
Packit 6ef888
	   If the block doesn't look like metadata, we can eliminate any
Packit 6ef888
	   references to it as metadata.  Dinodes with such references are
Packit 6ef888
	   clearly corrupt and need to be deleted.
Packit 6ef888
	   And if we're left with a single reference, problem solved. */
Packit 6ef888
	bh = bread(sdp, dt->block);
Packit 6ef888
	cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
Packit 6ef888
	ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
Packit 6ef888
	brelse(bh);
Packit 6ef888
Packit 6ef888
	/* If this is a dinode, any references to it (except in directory
Packit 6ef888
	   entries) are invalid and should be deleted. */
Packit 6ef888
	if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
Packit 6ef888
	    be32_to_cpu(ctype) == GFS2_METATYPE_DI)
Packit 6ef888
		acceptable_ref = ref_is_inode;
Packit 6ef888
	else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
Packit 6ef888
	    (be32_to_cpu(ctype) == GFS2_METATYPE_EA ||
Packit 6ef888
	     be32_to_cpu(ctype) == GFS2_METATYPE_ED))
Packit 6ef888
		acceptable_ref = ref_as_ea;
Packit 6ef888
	else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
Packit 6ef888
		 be32_to_cpu(ctype) <= GFS2_METATYPE_QC)
Packit 6ef888
		acceptable_ref = ref_as_meta;
Packit 6ef888
	else
Packit 6ef888
		acceptable_ref = ref_as_data;
Packit 6ef888
Packit 6ef888
	/* A single reference to the block implies a possible situation where
Packit 6ef888
	   a data pointer points to a metadata block.  In other words, the
Packit 6ef888
	   duplicate reference in the file system is (1) Metadata block X and
Packit 6ef888
	   (2) A dinode reference such as a data pointer pointing to block X.
Packit 6ef888
	   We can't really check for that in pass1 because user data might
Packit 6ef888
	   just _look_ like metadata by coincidence, and at the time we're
Packit 6ef888
	   checking, we might not have processed the referenced block.
Packit 6ef888
	   Here in pass1b we're sure. */
Packit 6ef888
	/* Another possibility here is that there is a single reference
Packit 6ef888
	   because all the other metadata references were in inodes that got
Packit 6ef888
	   invalidated for other reasons, such as bad pointers.  So we need to
Packit 6ef888
	   make sure at this point that any inode deletes reverse out any
Packit 6ef888
	   duplicate reference before we get to this point. */
Packit 6ef888
Packit 6ef888
	/* Step 1 - eliminate references from inodes that are not valid.
Packit 6ef888
	 *          This may be because they were deleted due to corruption.
Packit 6ef888
	 *          All block types are unacceptable, so we use ref_types.
Packit 6ef888
	 */
Packit 6ef888
	if (dh.ref_count > 1) {
Packit 6ef888
		log_debug( _("----------------------------------------------\n"
Packit 6ef888
			     "Step 1: Eliminate references to block %llu "
Packit 6ef888
			     "(0x%llx) that were previously marked "
Packit 6ef888
			     "invalid.\n"),
Packit 6ef888
			   (unsigned long long)dt->block,
Packit 6ef888
			   (unsigned long long)dt->block);
Packit 6ef888
		resolve_dup_references(sdp, dt, &dt->ref_invinode_list,
Packit 6ef888
				       &dh, 1, ref_types);
Packit 6ef888
		revise_dup_handler(dup_blk, &dh);
Packit 6ef888
	}
Packit 6ef888
	/* Step 2 - eliminate reference from inodes that reference it as the
Packit 6ef888
	 *          wrong type.  For example, a data file referencing it as
Packit 6ef888
	 *          a data block, but it's really a metadata block.  Or a
Packit 6ef888
	 *          directory inode referencing a data block as a leaf block.
Packit 6ef888
	 */
Packit 6ef888
	if (dh.ref_count > 1) {
Packit 6ef888
		log_debug( _("----------------------------------------------\n"
Packit 6ef888
			     "Step 2: Eliminate references to block %llu "
Packit 6ef888
			     "(0x%llx) that need the wrong block type.\n"),
Packit 6ef888
			   (unsigned long long)dt->block,
Packit 6ef888
			   (unsigned long long)dt->block);
Packit 6ef888
		resolve_dup_references(sdp, dt, &dt->ref_inode_list, &dh, 0,
Packit 6ef888
				       acceptable_ref);
Packit 6ef888
		revise_dup_handler(dup_blk, &dh);
Packit 6ef888
	}
Packit 6ef888
	/* Step 3 - We have multiple dinodes referencing it as the correct
Packit 6ef888
	 *          type.  Just blast one of them.
Packit 6ef888
	 *          All block types are fair game, so we use ref_types.
Packit 6ef888
	 */
Packit 6ef888
	if (dh.ref_count > 1) {
Packit 6ef888
		log_debug( _("----------------------------------------------\n"
Packit 6ef888
			     "Step 3: Choose one reference to block %llu "
Packit 6ef888
			     "(0x%llx) to keep.\n"),
Packit 6ef888
			   (unsigned long long)dt->block,
Packit 6ef888
			   (unsigned long long)dt->block);
Packit 6ef888
		resolve_dup_references(sdp, dt, &dt->ref_inode_list, &dh, 0,
Packit 6ef888
				       ref_types);
Packit 6ef888
		revise_dup_handler(dup_blk, &dh);
Packit 6ef888
	}
Packit 6ef888
	/* If there's still a last remaining reference, and it's a valid
Packit 6ef888
	   reference, use it to determine the correct block type for our
Packit 6ef888
	   blockmap and bitmap. */
Packit 6ef888
	if (dh.ref_inode_count == 1 && !osi_list_empty(&dt->ref_inode_list)) {
Packit 6ef888
		resolve_last_reference(sdp, dt, acceptable_ref);
Packit 6ef888
	} else {
Packit 6ef888
		/* They may have answered no and not fixed all references. */
Packit 6ef888
		log_debug( _("All duplicate references to block 0x%llx were "
Packit 6ef888
			     "processed.\n"), (unsigned long long)dup_blk);
Packit 6ef888
		if (dh.ref_count) {
Packit 6ef888
			log_debug(_("Done with duplicate reference to block "
Packit 6ef888
				    "0x%llx, but %d references remain.\n"),
Packit 6ef888
				  (unsigned long long)dup_blk, dh.ref_count);
Packit 6ef888
		} else {
Packit 6ef888
			log_notice( _("Block %llu (0x%llx) has no more "
Packit 6ef888
				      "references; Marking as 'free'.\n"),
Packit 6ef888
				    (unsigned long long)dup_blk,
Packit 6ef888
				    (unsigned long long)dup_blk);
Packit 6ef888
			if (dh.dt)
Packit 6ef888
				dup_delete(dh.dt);
Packit 6ef888
			check_n_fix_bitmap(sdp, NULL, dup_blk, 0,
Packit 6ef888
					   GFS2_BLKST_FREE);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			   void *private)
Packit 6ef888
{
Packit 6ef888
	return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_metalist_refs(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
	*was_duplicate = 0;
Packit 6ef888
	*is_valid = 1;
Packit 6ef888
	return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_data_refs(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 add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_indir_refs(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
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
Packit 6ef888
	if (!error)
Packit 6ef888
		*bh = bread(sdp, block);
Packit 6ef888
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_leaf_refs(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
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
Packit 6ef888
	if (!error)
Packit 6ef888
		*bh = bread(sdp, block);
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_entry_refs(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
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_extentry_refs(struct gfs2_inode *ip, int i,
Packit 6ef888
				     uint64_t *ea_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 block = be64_to_cpu(*ea_data_ptr);
Packit 6ef888
Packit 6ef888
	/* This is a case where a bad return code may be sent back, and
Packit 6ef888
	   behavior has changed. Before, if add_duplicate_ref returned a
Packit 6ef888
	   non-zero return code, the caller would delete the eattr from
Packit 6ef888
	   the blockmap. In this case, we should be okay because the only
Packit 6ef888
	   error possible is a malloc that fails, in which case we don't
Packit 6ef888
	   want to delete the eattr anyway. */
Packit 6ef888
	return add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Finds all references to duplicate blocks in the metadata */
Packit 6ef888
/* Finds all references to duplicate blocks in the metadata */
Packit 6ef888
static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	int error = 0;
Packit 6ef888
	struct metawalk_fxns find_refs = {
Packit 6ef888
		.private = NULL,
Packit 6ef888
		.check_leaf = check_leaf_refs,
Packit 6ef888
		.check_metalist = check_metalist_refs,
Packit 6ef888
		.check_data = check_data_refs,
Packit 6ef888
		.check_eattr_indir = check_eattr_indir_refs,
Packit 6ef888
		.check_eattr_leaf = check_eattr_leaf_refs,
Packit 6ef888
		.check_eattr_entry = check_eattr_entry_refs,
Packit 6ef888
		.check_eattr_extentry = check_eattr_extentry_refs,
Packit 6ef888
	};
Packit 6ef888
Packit 6ef888
	ip = fsck_load_inode(sdp, inode); /* bread, inode_get */
Packit 6ef888
Packit 6ef888
	/* double-check the meta header just to be sure it's metadata */
Packit 6ef888
	if (ip->i_di.di_header.mh_magic != GFS2_MAGIC ||
Packit 6ef888
	    ip->i_di.di_header.mh_type != GFS2_METATYPE_DI) {
Packit 6ef888
		if (!sdp->gfs1)
Packit 6ef888
			log_debug( _("Block %lld (0x%llx) is not a dinode.\n"),
Packit 6ef888
				   (unsigned long long)inode,
Packit 6ef888
				   (unsigned long long)inode);
Packit 6ef888
		error = 1;
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
	/* Check to see if this inode was referenced by another by mistake */
Packit 6ef888
	add_duplicate_ref(ip, inode, ref_is_inode, 1, INODE_VALID);
Packit 6ef888
Packit 6ef888
	/* Check this dinode's metadata for references to known duplicates */
Packit 6ef888
	error = check_metatree(ip, &find_refs);
Packit 6ef888
	if (error < 0)
Packit 6ef888
		stack;
Packit 6ef888
Packit 6ef888
	/* Check for ea references in the inode */
Packit 6ef888
	if (!error)
Packit 6ef888
		error = check_inode_eattr(ip, &find_refs);
Packit 6ef888
Packit 6ef888
out:
Packit 6ef888
	fsck_inode_put(&ip); /* out, brelse, free */
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Pass 1b handles finding the previous inode for a duplicate block
Packit 6ef888
 * When found, store the inodes pointing to the duplicate block for
Packit 6ef888
 * use in pass2 */
Packit 6ef888
int pass1b(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
	uint64_t i;
Packit 6ef888
	int q;
Packit 6ef888
	struct osi_node *n;
Packit 6ef888
	int rc = FSCK_OK;
Packit 6ef888
Packit 6ef888
	log_info( _("Looking for duplicate blocks...\n"));
Packit 6ef888
Packit 6ef888
	/* If there were no dups in the bitmap, we don't need to do anymore */
Packit 6ef888
	if (dup_blocks.osi_node == NULL) {
Packit 6ef888
		log_info( _("No duplicate blocks found\n"));
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* Rescan the fs looking for pointers to blocks that are in
Packit 6ef888
	 * the duplicate block map */
Packit 6ef888
	log_info( _("Scanning filesystem for inodes containing duplicate blocks...\n"));
Packit 6ef888
	log_debug( _("Filesystem has %llu (0x%llx) blocks total\n"),
Packit 6ef888
		  (unsigned long long)last_fs_block,
Packit 6ef888
		  (unsigned long long)last_fs_block);
Packit 6ef888
	for (i = 0; i < last_fs_block; i++) {
Packit 6ef888
		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
			goto out;
Packit 6ef888
Packit 6ef888
		if (dups_found_first == dups_found) {
Packit 6ef888
			log_debug(_("Found all %d original references to "
Packit 6ef888
				    "duplicates.\n"), dups_found);
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		q = bitmap_type(sdp, i);
Packit 6ef888
Packit 6ef888
		if (q == GFS2_BLKST_FREE || q == GFS2_BLKST_USED || q < 0)
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		if (q == GFS2_BLKST_UNLINKED) {
Packit 6ef888
			log_debug( _("Error: block %lld (0x%llx) is still "
Packit 6ef888
				     "marked UNLINKED.\n"),
Packit 6ef888
				   (unsigned long long)i,
Packit 6ef888
				   (unsigned long long)i);
Packit 6ef888
			return FSCK_ERROR;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		warm_fuzzy_stuff(i);
Packit 6ef888
		if (find_block_ref(sdp, i) < 0) {
Packit 6ef888
			stack;
Packit 6ef888
			rc = FSCK_ERROR;
Packit 6ef888
			goto out;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* Fix dups here - it's going to slow things down a lot to fix
Packit 6ef888
	 * it later */
Packit 6ef888
	log_info( _("Handling duplicate blocks\n"));
Packit 6ef888
out:
Packit 6ef888
	/* Resolve all duplicates by clearing out the dup tree */
Packit 6ef888
        while ((n = osi_first(&dup_blocks))) {
Packit 6ef888
                dt = (struct duptree *)n;
Packit 6ef888
		if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
Packit 6ef888
			handle_dup_blk(sdp, dt);
Packit 6ef888
	}
Packit 6ef888
	return rc;
Packit 6ef888
}