Blame gfs2/fsck/util.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 <sys/time.h>
Packit 6ef888
#include <stdio.h>
Packit 6ef888
#include <stdarg.h>
Packit 6ef888
#include <termios.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#include <ctype.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "metawalk.h"
Packit 6ef888
#include "util.h"
Packit 6ef888
Packit 6ef888
const char *reftypes[ref_types + 1] = {"data", "metadata",
Packit 6ef888
				       "an extended attribute", "an inode",
Packit 6ef888
				       "unimportant"};
Packit 6ef888
Packit 6ef888
void big_file_comfort(struct gfs2_inode *ip, uint64_t blks_checked)
Packit 6ef888
{
Packit 6ef888
	static struct timeval tv;
Packit 6ef888
	static uint32_t seconds = 0;
Packit 6ef888
	static uint64_t percent, fsize, chksize;
Packit 6ef888
	uint64_t one_percent = 0;
Packit 6ef888
	int i, cs;
Packit 6ef888
	const char *human_abbrev = " KMGTPE";
Packit 6ef888
Packit 6ef888
	one_percent = ip->i_di.di_blocks / 100;
Packit 6ef888
	if (blks_checked - last_reported_fblock < one_percent)
Packit 6ef888
		return;
Packit 6ef888
Packit 6ef888
	last_reported_fblock = blks_checked;
Packit 6ef888
	gettimeofday(&tv, NULL);
Packit 6ef888
	if (!seconds)
Packit 6ef888
		seconds = tv.tv_sec;
Packit 6ef888
	if (tv.tv_sec == seconds)
Packit 6ef888
		return;
Packit 6ef888
Packit 6ef888
	fsize = ip->i_di.di_size;
Packit 6ef888
	for (i = 0; i < 6 && fsize > 1024; i++)
Packit 6ef888
		fsize /= 1024;
Packit 6ef888
	chksize = blks_checked * ip->i_sbd->bsize;
Packit 6ef888
	for (cs = 0; cs < 6 && chksize > 1024; cs++)
Packit 6ef888
		chksize /= 1024;
Packit 6ef888
	seconds = tv.tv_sec;
Packit 6ef888
	percent = (blks_checked * 100) / ip->i_di.di_blocks;
Packit 6ef888
	log_notice( _("\rChecking %lld%c of %lld%c of file at %lld (0x%llx)"
Packit 6ef888
		      "- %llu percent complete.                   \r"),
Packit 6ef888
		    (long long)chksize, human_abbrev[cs],
Packit 6ef888
		    (unsigned long long)fsize, human_abbrev[i],
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)percent);
Packit 6ef888
	fflush(stdout);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Put out a warm, fuzzy message every second so the user     */
Packit 6ef888
/* doesn't think we hung.  (This may take a long time).       */
Packit 6ef888
void warm_fuzzy_stuff(uint64_t block)
Packit 6ef888
{
Packit 6ef888
	static uint64_t one_percent = 0;
Packit 6ef888
	static struct timeval tv;
Packit 6ef888
	static uint32_t seconds = 0;
Packit 6ef888
Packit 6ef888
	if (!one_percent)
Packit 6ef888
		one_percent = last_fs_block / 100;
Packit 6ef888
	if (!last_reported_block ||
Packit 6ef888
	    block - last_reported_block >= one_percent) {
Packit 6ef888
		last_reported_block = block;
Packit 6ef888
		gettimeofday(&tv, NULL);
Packit 6ef888
		if (!seconds)
Packit 6ef888
			seconds = tv.tv_sec;
Packit 6ef888
		if (tv.tv_sec - seconds) {
Packit 6ef888
			static uint64_t percent;
Packit 6ef888
Packit 6ef888
			seconds = tv.tv_sec;
Packit 6ef888
			if (last_fs_block) {
Packit 6ef888
				percent = (block * 100) / last_fs_block;
Packit 6ef888
				log_notice( _("\r%llu percent complete.\r"),
Packit 6ef888
					   (unsigned long long)percent);
Packit 6ef888
				fflush(stdout);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
char gfs2_getch(void)
Packit 6ef888
{
Packit 6ef888
	struct termios termattr, savetermattr;
Packit 6ef888
	char ch;
Packit 6ef888
	ssize_t size;
Packit 6ef888
Packit 6ef888
	tcgetattr (STDIN_FILENO, &termattr);
Packit 6ef888
	savetermattr = termattr;
Packit 6ef888
	termattr.c_lflag &= ~(ICANON | IEXTEN | ISIG);
Packit 6ef888
	termattr.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
Packit 6ef888
	termattr.c_cflag &= ~(CSIZE | PARENB);
Packit 6ef888
	termattr.c_cflag |= CS8;
Packit 6ef888
	termattr.c_oflag &= ~(OPOST);
Packit 6ef888
   	termattr.c_cc[VMIN] = 0;
Packit 6ef888
	termattr.c_cc[VTIME] = 0;
Packit 6ef888
Packit 6ef888
	tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
Packit 6ef888
	do {
Packit 6ef888
		size = read(STDIN_FILENO, &ch, 1);
Packit 6ef888
		if (size)
Packit 6ef888
			break;
Packit 6ef888
		usleep(50000);
Packit 6ef888
	} while (!size);
Packit 6ef888
Packit 6ef888
	tcsetattr (STDIN_FILENO, TCSANOW, &savetermattr);
Packit 6ef888
	return ch;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
char generic_interrupt(const char *caller, const char *where,
Packit 6ef888
		       const char *progress, const char *question,
Packit 6ef888
		       const char *answers)
Packit 6ef888
{
Packit 6ef888
	fd_set rfds;
Packit 6ef888
	struct timeval tv;
Packit 6ef888
	char response;
Packit 6ef888
	int err, i;
Packit 6ef888
Packit 6ef888
	FD_ZERO(&rfds);
Packit 6ef888
	FD_SET(STDIN_FILENO, &rfds);
Packit 6ef888
Packit 6ef888
	tv.tv_sec = 0;
Packit 6ef888
	tv.tv_usec = 0;
Packit 6ef888
	/* Make sure there isn't extraneous input before asking the
Packit 6ef888
	 * user the question */
Packit 6ef888
	while((err = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv))) {
Packit 6ef888
		if(err < 0) {
Packit 6ef888
			log_debug("Error in select() on stdin\n");
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		if(read(STDIN_FILENO, &response, sizeof(char)) < 0) {
Packit 6ef888
			log_debug("Error in read() on stdin\n");
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	while (TRUE) {
Packit 6ef888
		printf("\n%s interrupted during %s:  ", caller, where);
Packit 6ef888
		if (progress)
Packit 6ef888
			printf("%s.\n", progress);
Packit 6ef888
		printf("%s", question);
Packit 6ef888
Packit 6ef888
		/* Make sure query is printed out */
Packit 6ef888
		fflush(NULL);
Packit 6ef888
		response = gfs2_getch();
Packit 6ef888
		printf("\n");
Packit 6ef888
		fflush(NULL);
Packit 6ef888
		if (strchr(answers, response))
Packit 6ef888
			break;
Packit 6ef888
		printf("Bad response, please type ");
Packit 6ef888
		for (i = 0; i < strlen(answers) - 1; i++)
Packit 6ef888
			printf("'%c', ", answers[i]);
Packit 6ef888
		printf(" or '%c'.\n", answers[i]);
Packit 6ef888
	}
Packit 6ef888
	return response;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* fsck_query: Same as gfs2_query except it adjusts errors_found and
Packit 6ef888
   errors_corrected. */
Packit 6ef888
int fsck_query(const char *format, ...)
Packit 6ef888
{
Packit 6ef888
	va_list args;
Packit 6ef888
	char response;
Packit 6ef888
	int ret = 0;
Packit 6ef888
Packit 6ef888
	errors_found++;
Packit 6ef888
	fsck_abort = 0;
Packit 6ef888
	if (opts.yes) {
Packit 6ef888
		errors_corrected++;
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	if (opts.no)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	opts.query = TRUE;
Packit 6ef888
	while (1) {
Packit 6ef888
		va_start(args, format);
Packit 6ef888
		vprintf(format, args);
Packit 6ef888
		va_end(args);
Packit 6ef888
Packit 6ef888
		/* Make sure query is printed out */
Packit 6ef888
		fflush(NULL);
Packit 6ef888
		response = gfs2_getch();
Packit 6ef888
Packit 6ef888
		printf("\n");
Packit 6ef888
		fflush(NULL);
Packit 6ef888
		if (response == 0x3) { /* if interrupted, by ctrl-c */
Packit 6ef888
			response = generic_interrupt("Question", "response",
Packit 6ef888
						     NULL,
Packit 6ef888
						     "Do you want to abort " \
Packit 6ef888
						     "or continue (a/c)?",
Packit 6ef888
						     "ac");
Packit 6ef888
			if (response == 'a') {
Packit 6ef888
				ret = 0;
Packit 6ef888
				fsck_abort = 1;
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
			printf("Continuing.\n");
Packit 6ef888
		} else if (tolower(response) == 'y') {
Packit 6ef888
			errors_corrected++;
Packit 6ef888
                        ret = 1;
Packit 6ef888
                        break;
Packit 6ef888
		} else if (tolower(response) == 'n') {
Packit 6ef888
			ret = 0;
Packit 6ef888
			break;
Packit 6ef888
		} else {
Packit 6ef888
			printf("Bad response %d, please type 'y' or 'n'.\n",
Packit 6ef888
			       response);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	opts.query = FALSE;
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * gfs2_dup_set - Flag a block as a duplicate
Packit 6ef888
 * We keep the references in a red/black tree.  We can't keep track of every
Packit 6ef888
 * single inode in the file system, so the first time this function is called
Packit 6ef888
 * will actually be for the second reference to the duplicated block.
Packit 6ef888
 * This will return the number of references to the block.
Packit 6ef888
 *
Packit 6ef888
 * create - will be set if the call is supposed to create the reference. */
Packit 6ef888
static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
Packit 6ef888
{
Packit 6ef888
	struct osi_node **newn = &dup_blocks.osi_node, *parent = NULL;
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
Packit 6ef888
	/* Figure out where to put new node */
Packit 6ef888
	while (*newn) {
Packit 6ef888
		struct duptree *cur = (struct duptree *)*newn;
Packit 6ef888
Packit 6ef888
		parent = *newn;
Packit 6ef888
		if (dblock < cur->block)
Packit 6ef888
			newn = &((*newn)->osi_left);
Packit 6ef888
		else if (dblock > cur->block)
Packit 6ef888
			newn = &((*newn)->osi_right);
Packit 6ef888
		else
Packit 6ef888
			return cur;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!create)
Packit 6ef888
		return NULL;
Packit 6ef888
	dt = malloc(sizeof(struct duptree));
Packit 6ef888
	if (dt == NULL) {
Packit 6ef888
		log_crit( _("Unable to allocate duptree structure\n"));
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
	dups_found++;
Packit 6ef888
	memset(dt, 0, sizeof(struct duptree));
Packit 6ef888
	/* Add new node and rebalance tree. */
Packit 6ef888
	dt->block = dblock;
Packit 6ef888
	dt->refs = 1; /* reference 1 is actually the reference we need to
Packit 6ef888
			 discover in pass1b. */
Packit 6ef888
	osi_list_init(&dt->ref_inode_list);
Packit 6ef888
	osi_list_init(&dt->ref_invinode_list);
Packit 6ef888
	osi_link_node(&dt->node, parent, newn);
Packit 6ef888
	osi_insert_color(&dt->node, &dup_blocks);
Packit 6ef888
Packit 6ef888
	return dt;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * find_dup_ref_inode - find a duplicate reference inode entry for an inode
Packit 6ef888
 */
Packit 6ef888
struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
Packit 6ef888
					   struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *ref;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
Packit 6ef888
	osi_list_foreach(ref, &dt->ref_invinode_list) {
Packit 6ef888
		id = osi_list_entry(ref, struct inode_with_dups, list);
Packit 6ef888
Packit 6ef888
		if (id->block_no == ip->i_di.di_num.no_addr)
Packit 6ef888
			return id;
Packit 6ef888
	}
Packit 6ef888
	osi_list_foreach(ref, &dt->ref_inode_list) {
Packit 6ef888
		id = osi_list_entry(ref, struct inode_with_dups, list);
Packit 6ef888
Packit 6ef888
		if (id->block_no == ip->i_di.di_num.no_addr)
Packit 6ef888
			return id;
Packit 6ef888
	}
Packit 6ef888
	return NULL;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * count_dup_meta_refs - count the number of remaining references as metadata
Packit 6ef888
 */
Packit 6ef888
int count_dup_meta_refs(struct duptree *dt)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *ref;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	int metarefs = 0;
Packit 6ef888
Packit 6ef888
	osi_list_foreach(ref, &dt->ref_invinode_list) {
Packit 6ef888
		id = osi_list_entry(ref, struct inode_with_dups, list);
Packit 6ef888
		if (id->reftypecount[ref_as_meta])
Packit 6ef888
			metarefs++;
Packit 6ef888
	}
Packit 6ef888
	osi_list_foreach(ref, &dt->ref_inode_list) {
Packit 6ef888
		id = osi_list_entry(ref, struct inode_with_dups, list);
Packit 6ef888
		if (id->reftypecount[ref_as_meta])
Packit 6ef888
			metarefs++;
Packit 6ef888
	}
Packit 6ef888
	return metarefs;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * add_duplicate_ref - Add a duplicate reference to the duplicates tree list
Packit 6ef888
 * A new element of the tree will be created as needed
Packit 6ef888
 * When the first reference is discovered in pass1, it realizes it's a
Packit 6ef888
 * duplicate but it has already forgotten where the first reference was.
Packit 6ef888
 * So we need to recreate the duplicate reference structure if it's not there.
Packit 6ef888
 * Later, in pass1b, it has to go back through the file system
Packit 6ef888
 * and figure out those original references in order to resolve them.
Packit 6ef888
 *
Packit 6ef888
 * first - if 1, we're being called from pass1b, in which case we're trying
Packit 6ef888
 *         to find the first reference to this block.  If 0, we're being
Packit 6ef888
 *         called from pass1, which is the second reference, which determined
Packit 6ef888
 *         it was a duplicate..
Packit 6ef888
 */
Packit 6ef888
int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
		      enum dup_ref_type reftype, int first, int inode_valid)
Packit 6ef888
{
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
Packit 6ef888
	if (!valid_block_ip(ip, block))
Packit 6ef888
		return meta_is_good;
Packit 6ef888
	/* If this is not the first reference (i.e. all calls from pass1) we
Packit 6ef888
	   need to create the duplicate reference. If this is pass1b, we want
Packit 6ef888
	   to ignore references that aren't found. */
Packit 6ef888
	dt = gfs2_dup_set(block, !first);
Packit 6ef888
	if (!dt)        /* If this isn't a duplicate */
Packit 6ef888
		return meta_is_good;
Packit 6ef888
Packit 6ef888
	/* If we found the duplicate reference but we've already discovered
Packit 6ef888
	   the first reference (in pass1b) and the other references in pass1,
Packit 6ef888
	   we don't need to count it, so just return. */
Packit 6ef888
	if (dt->dup_flags & DUPFLAG_REF1_FOUND)
Packit 6ef888
		return meta_is_good;
Packit 6ef888
Packit 6ef888
	/* Check for a previous reference to this duplicate */
Packit 6ef888
	id = find_dup_ref_inode(dt, ip);
Packit 6ef888
Packit 6ef888
	/* We have to be careful here. The original referencing dinode may have
Packit 6ef888
	   deemed to be bad and deleted/freed in pass1. In that case, pass1b
Packit 6ef888
	   wouldn't discover the correct [deleted] original reference. In
Packit 6ef888
	   that case, we don't want to be confused and consider this second
Packit 6ef888
	   reference the same as the first. If we do, we'll never be able to
Packit 6ef888
	   resolve it. The first reference can't be the second reference. */
Packit 6ef888
	if (id && first && !(dt->dup_flags & DUPFLAG_REF1_FOUND)) {
Packit 6ef888
		log_info(_("Original reference to block %llu (0x%llx) was "
Packit 6ef888
			   "either found to be bad and deleted, or else "
Packit 6ef888
			   "a duplicate within the same inode.\n"),
Packit 6ef888
			 (unsigned long long)block,
Packit 6ef888
			 (unsigned long long)block);
Packit 6ef888
		log_info(_("I'll consider the reference from inode %llu "
Packit 6ef888
			   "(0x%llx) the first reference.\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
		dt->dup_flags |= DUPFLAG_REF1_IS_DUPL;
Packit 6ef888
		dt->refs++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* The first time this is called from pass1 is actually the second
Packit 6ef888
	   reference.  When we go back in pass1b looking for the original
Packit 6ef888
	   reference, we don't want to increment the reference count because
Packit 6ef888
	   it's already accounted for. */
Packit 6ef888
	if (first) {
Packit 6ef888
		dt->dup_flags |= DUPFLAG_REF1_FOUND;
Packit 6ef888
		dups_found_first++; /* We found another first ref. */
Packit 6ef888
	} else {
Packit 6ef888
		dt->refs++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (id == NULL) {
Packit 6ef888
		/* Check for the inode on the invalid inode reference list. */
Packit 6ef888
		int q;
Packit 6ef888
Packit 6ef888
		id = calloc(1, sizeof(*id));
Packit 6ef888
		if (!id) {
Packit 6ef888
			log_crit( _("Unable to allocate inode_with_dups structure\n"));
Packit 6ef888
			return meta_error;
Packit 6ef888
		}
Packit 6ef888
		id->block_no = ip->i_di.di_num.no_addr;
Packit 6ef888
		q = bitmap_type(ip->i_sbd, ip->i_di.di_num.no_addr);
Packit 6ef888
		/* If it's an invalid dinode, put it first on the invalid
Packit 6ef888
		   inode reference list otherwise put it on the normal list. */
Packit 6ef888
		if (!inode_valid || q == GFS2_BLKST_UNLINKED)
Packit 6ef888
			osi_list_add_prev(&id->list, &dt->ref_invinode_list);
Packit 6ef888
		else {
Packit 6ef888
			/* If this is a system dinode, we want the duplicate
Packit 6ef888
			   processing to find it first. That way references
Packit 6ef888
			   from inside journals, et al, will take priority.
Packit 6ef888
			   We don't want to delete journals in favor of dinodes
Packit 6ef888
			   that reference a block inside a journal. */
Packit 6ef888
			if (fsck_system_inode(ip->i_sbd, id->block_no))
Packit 6ef888
				osi_list_add(&id->list, &dt->ref_inode_list);
Packit 6ef888
			else
Packit 6ef888
				osi_list_add_prev(&id->list,
Packit 6ef888
						  &dt->ref_inode_list);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	id->reftypecount[reftype]++;
Packit 6ef888
	id->dup_count++;
Packit 6ef888
	log_info( _("Found %d reference(s) to block %llu"
Packit 6ef888
		    " (0x%llx) as %s in %s inode #%llu (0x%llx)\n"),
Packit 6ef888
		  id->dup_count, (unsigned long long)block,
Packit 6ef888
		  (unsigned long long)block, reftypes[reftype],
Packit 6ef888
		  inode_valid ? _("valid") : _("invalid"),
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 (first)
Packit 6ef888
		log_info( _("This is the original reference.\n"));
Packit 6ef888
	else {
Packit 6ef888
		/* Check for duplicate refs to the same block in one inode. */
Packit 6ef888
		if (id->dup_count > 1)
Packit 6ef888
			dt->dup_flags |= DUPFLAG_REF1_FOUND;
Packit 6ef888
		log_info( _("This brings the total to: %d inode references, "
Packit 6ef888
			    "%d from this inode.\n"),
Packit 6ef888
			  dt->refs, id->dup_count);
Packit 6ef888
	}
Packit 6ef888
	return meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct dir_info *dirtree_insert(struct gfs2_inum inum)
Packit 6ef888
{
Packit 6ef888
	struct osi_node **newn = &dirtree.osi_node, *parent = NULL;
Packit 6ef888
	struct dir_info *data;
Packit 6ef888
Packit 6ef888
	/* Figure out where to put new node */
Packit 6ef888
	while (*newn) {
Packit 6ef888
		struct dir_info *cur = (struct dir_info *)*newn;
Packit 6ef888
Packit 6ef888
		parent = *newn;
Packit 6ef888
		if (inum.no_addr < cur->dinode.no_addr)
Packit 6ef888
			newn = &((*newn)->osi_left);
Packit 6ef888
		else if (inum.no_addr > cur->dinode.no_addr)
Packit 6ef888
			newn = &((*newn)->osi_right);
Packit 6ef888
		else
Packit 6ef888
			return cur;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	data = calloc(1, sizeof(struct dir_info));
Packit 6ef888
	if (!data) {
Packit 6ef888
		log_crit( _("Unable to allocate dir_info structure\n"));
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
	/* Add new node and rebalance tree. */
Packit 6ef888
	data->dinode.no_addr = inum.no_addr;
Packit 6ef888
	data->dinode.no_formal_ino = inum.no_formal_ino;
Packit 6ef888
	osi_link_node(&data->node, parent, newn);
Packit 6ef888
	osi_insert_color(&data->node, &dirtree);
Packit 6ef888
Packit 6ef888
	return data;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct dir_info *dirtree_find(uint64_t block)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *node = dirtree.osi_node;
Packit 6ef888
Packit 6ef888
	while (node) {
Packit 6ef888
		struct dir_info *data = (struct dir_info *)node;
Packit 6ef888
Packit 6ef888
		if (block < data->dinode.no_addr)
Packit 6ef888
			node = node->osi_left;
Packit 6ef888
		else if (block > data->dinode.no_addr)
Packit 6ef888
			node = node->osi_right;
Packit 6ef888
		else
Packit 6ef888
			return data;
Packit 6ef888
	}
Packit 6ef888
	return NULL;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* get_ref_type - figure out if all duplicate references from this inode
Packit 6ef888
   are the same type, and if so, return the type. */
Packit 6ef888
enum dup_ref_type get_ref_type(struct inode_with_dups *id)
Packit 6ef888
{
Packit 6ef888
	enum dup_ref_type t, i;
Packit 6ef888
	int found_type_with_ref;
Packit 6ef888
	int found_other_types;
Packit 6ef888
Packit 6ef888
	for (t = ref_as_data; t < ref_types; t++) {
Packit 6ef888
		found_type_with_ref = 0;
Packit 6ef888
		found_other_types = 0;
Packit 6ef888
		for (i = ref_as_data; i < ref_types; i++) {
Packit 6ef888
			if (id->reftypecount[i]) {
Packit 6ef888
				if (t == i)
Packit 6ef888
					found_type_with_ref = 1;
Packit 6ef888
				else
Packit 6ef888
					found_other_types = 1;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		if (found_type_with_ref)
Packit 6ef888
			return found_other_types ? ref_types : t;
Packit 6ef888
	}
Packit 6ef888
	return ref_types;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id)
Packit 6ef888
{
Packit 6ef888
	log_err( _("Removing duplicate reference to block %llu (0x%llx) "
Packit 6ef888
		   "referenced as %s by dinode %llu (0x%llx)\n"),
Packit 6ef888
		 (unsigned long long)dt->block, (unsigned long long)dt->block,
Packit 6ef888
		 reftypes[get_ref_type(id)], (unsigned long long)id->block_no,
Packit 6ef888
		 (unsigned long long)id->block_no);
Packit 6ef888
	dt->refs--; /* one less reference */
Packit 6ef888
	if (id->name)
Packit 6ef888
		free(id->name);
Packit 6ef888
	osi_list_del(&id->list);
Packit 6ef888
	free(id);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void dup_delete(struct duptree *dt)
Packit 6ef888
{
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	osi_list_t *tmp;
Packit 6ef888
Packit 6ef888
	while (!osi_list_empty(&dt->ref_invinode_list)) {
Packit 6ef888
		tmp = (&dt->ref_invinode_list)->next;
Packit 6ef888
		id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
		dup_listent_delete(dt, id);
Packit 6ef888
	}
Packit 6ef888
	while (!osi_list_empty(&dt->ref_inode_list)) {
Packit 6ef888
		tmp = (&dt->ref_inode_list)->next;
Packit 6ef888
		id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
		dup_listent_delete(dt, id);
Packit 6ef888
	}
Packit 6ef888
	osi_erase(&dt->node, &dup_blocks);
Packit 6ef888
	free(dt);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void dirtree_delete(struct dir_info *b)
Packit 6ef888
{
Packit 6ef888
	osi_erase(&b->node, &dirtree);
Packit 6ef888
	free(b);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
uint64_t find_free_blk(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *n, *next = NULL;
Packit 6ef888
	struct rgrp_tree *rl = NULL;
Packit 6ef888
	struct gfs2_rindex *ri;
Packit 6ef888
	struct gfs2_rgrp *rg;
Packit 6ef888
	unsigned int block, bn = 0, x = 0, y = 0;
Packit 6ef888
	unsigned int state;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
Packit 6ef888
	memset(&rg, 0, sizeof(rg));
Packit 6ef888
	for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit 6ef888
		next = osi_next(n);
Packit 6ef888
		rl = (struct rgrp_tree *)n;
Packit 6ef888
		if (rl->rg.rg_free)
Packit 6ef888
			break;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (n == NULL)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	ri = &rl->ri;
Packit 6ef888
	rg = &rl->rg;
Packit 6ef888
Packit 6ef888
	for (block = 0; block < ri->ri_length; block++) {
Packit 6ef888
		bh = rl->bits[block].bi_bh;
Packit 6ef888
		x = (block) ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp);
Packit 6ef888
Packit 6ef888
		for (; x < sdp->bsize; x++)
Packit 6ef888
			for (y = 0; y < GFS2_NBBY; y++) {
Packit 6ef888
				state = (bh->b_data[x] >> (GFS2_BIT_SIZE * y)) & 0x03;
Packit 6ef888
				if (state == GFS2_BLKST_FREE)
Packit 6ef888
					return ri->ri_data0 + bn;
Packit 6ef888
				bn++;
Packit 6ef888
			}
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
uint64_t *get_dir_hash(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	unsigned hsize = (1 << ip->i_di.di_depth) * sizeof(uint64_t);
Packit 6ef888
	int ret;
Packit 6ef888
	uint64_t *tbl = malloc(hsize);
Packit 6ef888
Packit 6ef888
	if (tbl == NULL)
Packit 6ef888
		return NULL;
Packit 6ef888
Packit 6ef888
	ret = gfs2_readi(ip, tbl, 0, hsize);
Packit 6ef888
	if (ret != hsize) {
Packit 6ef888
		free(tbl);
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return tbl;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void delete_all_dups(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *n, *next;
Packit 6ef888
	struct duptree *dt;
Packit 6ef888
	osi_list_t *tmp, *x;
Packit 6ef888
	struct inode_with_dups *id;
Packit 6ef888
	int found;
Packit 6ef888
Packit 6ef888
	for (n = osi_first(&dup_blocks); n; n = next) {
Packit 6ef888
		next = osi_next(n);
Packit 6ef888
		dt = (struct duptree *)n;
Packit 6ef888
Packit 6ef888
		found = 0;
Packit 6ef888
		id = NULL;
Packit 6ef888
Packit 6ef888
		osi_list_foreach_safe(tmp, &dt->ref_invinode_list, x) {
Packit 6ef888
			id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
			if (id->block_no == ip->i_di.di_num.no_addr) {
Packit 6ef888
				dup_listent_delete(dt, id);
Packit 6ef888
				found = 1;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		osi_list_foreach_safe(tmp, &dt->ref_inode_list, x) {
Packit 6ef888
			id = osi_list_entry(tmp, struct inode_with_dups, list);
Packit 6ef888
			if (id->block_no == ip->i_di.di_num.no_addr) {
Packit 6ef888
				dup_listent_delete(dt, id);
Packit 6ef888
				found = 1;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		if (!found)
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		if (dt->refs == 0) {
Packit 6ef888
			log_debug(_("This was the last reference: 0x%llx is "
Packit 6ef888
				    "no longer a duplicate.\n"),
Packit 6ef888
				  (unsigned long long)dt->block);
Packit 6ef888
			dup_delete(dt); /* not duplicate now */
Packit 6ef888
		} else {
Packit 6ef888
			log_debug(_("%d references remain to 0x%llx\n"),
Packit 6ef888
				  dt->refs, (unsigned long long)dt->block);
Packit 6ef888
			if (dt->refs > 1)
Packit 6ef888
				continue;
Packit 6ef888
Packit 6ef888
			id = NULL;
Packit 6ef888
			osi_list_foreach(tmp, &dt->ref_invinode_list)
Packit 6ef888
				id = osi_list_entry(tmp,
Packit 6ef888
						    struct inode_with_dups,
Packit 6ef888
						    list);
Packit 6ef888
			osi_list_foreach(tmp, &dt->ref_inode_list)
Packit 6ef888
				id = osi_list_entry(tmp,
Packit 6ef888
						    struct inode_with_dups,
Packit 6ef888
						    list);
Packit 6ef888
			if (id)
Packit 6ef888
				log_debug("Last reference is from inode "
Packit 6ef888
					  "0x%llx\n",
Packit 6ef888
					  (unsigned long long)id->block_no);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void print_pass_duration(const char *name, struct timeval *start)
Packit 6ef888
{
Packit 6ef888
	char duration[17] = ""; /* strlen("XXdXXhXXmXX.XXXs") + 1 */
Packit 6ef888
	struct timeval end, diff;
Packit 6ef888
	unsigned d, h, m, s;
Packit 6ef888
	char *p = duration;
Packit 6ef888
Packit 6ef888
	gettimeofday(&end, NULL);
Packit 6ef888
	timersub(&end, start, &diff);
Packit 6ef888
Packit 6ef888
	s = diff.tv_sec % 60;
Packit 6ef888
	diff.tv_sec /= 60;
Packit 6ef888
	m = diff.tv_sec % 60;
Packit 6ef888
	diff.tv_sec /= 60;
Packit 6ef888
	h = diff.tv_sec % 24;
Packit 6ef888
	d = diff.tv_sec / 24;
Packit 6ef888
Packit 6ef888
	if (d)
Packit 6ef888
		p += snprintf(p, 4, "%ud", d > 99 ? 99U : d);
Packit 6ef888
	if (h)
Packit 6ef888
		p += snprintf(p, 4, "%uh", h);
Packit 6ef888
	if (m)
Packit 6ef888
		p += snprintf(p, 4, "%um", m);
Packit 6ef888
Packit 6ef888
	snprintf(p, 8, "%u.%03lus", s, diff.tv_usec / 1000);
Packit 6ef888
	log_notice(_("%s completed in %s\n"), name, duration);
Packit 6ef888
}
Packit 6ef888