Blame gfs2/fsck/util.c

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