Blame gfs2/fsck/pass2.c

Packit 6ef888
#include "clusterautoconfig.h"
Packit 6ef888
Packit 6ef888
#include <dirent.h>
Packit 6ef888
#include <stdio.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include <sys/stat.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "fsck.h"
Packit 6ef888
#include "util.h"
Packit 6ef888
#include "metawalk.h"
Packit 6ef888
#include "link.h"
Packit 6ef888
#include "lost_n_found.h"
Packit 6ef888
#include "inode_hash.h"
Packit 6ef888
#include "afterpass1_common.h"
Packit 6ef888
Packit 6ef888
#define MAX_FILENAME 256
Packit 6ef888
Packit 6ef888
struct metawalk_fxns pass2_fxns;
Packit 6ef888
Packit 6ef888
struct metawalk_fxns delete_eattrs = {
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
Packit 6ef888
/* Set children's parent inode in dir_info structure - ext2 does not set
Packit 6ef888
 * dotdot inode here, but instead in pass3 - should we? */
Packit 6ef888
static int set_parent_dir(struct gfs2_sbd *sdp, struct gfs2_inum child,
Packit 6ef888
			  struct gfs2_inum parent)
Packit 6ef888
{
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
Packit 6ef888
	di = dirtree_find(child.no_addr);
Packit 6ef888
	if (!di) {
Packit 6ef888
		log_err( _("Unable to find block %llu (0x%llx"
Packit 6ef888
			   ") in dir_info list\n"),
Packit 6ef888
			(unsigned long long)child.no_addr,
Packit 6ef888
			(unsigned long long)child.no_addr);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (di->dinode.no_addr == child.no_addr &&
Packit 6ef888
	    di->dinode.no_formal_ino == child.no_formal_ino) {
Packit 6ef888
		if (di->treewalk_parent) {
Packit 6ef888
			log_err( _("Another directory at block %lld (0x%llx) "
Packit 6ef888
				   "already contains this child %lld (0x%llx)"
Packit 6ef888
				   " - checking parent %lld (0x%llx)\n"),
Packit 6ef888
				 (unsigned long long)di->treewalk_parent,
Packit 6ef888
				 (unsigned long long)di->treewalk_parent,
Packit 6ef888
				 (unsigned long long)child.no_addr,
Packit 6ef888
				 (unsigned long long)child.no_addr,
Packit 6ef888
				 (unsigned long long)parent.no_addr,
Packit 6ef888
				 (unsigned long long)parent.no_addr);
Packit 6ef888
			return 1;
Packit 6ef888
		}
Packit 6ef888
		log_debug( _("Child %lld (0x%llx) has parent %lld (0x%llx)\n"),
Packit 6ef888
			   (unsigned long long)child.no_addr,
Packit 6ef888
			   (unsigned long long)child.no_addr,
Packit 6ef888
			   (unsigned long long)parent.no_addr,
Packit 6ef888
			   (unsigned long long)parent.no_addr);
Packit 6ef888
		di->treewalk_parent = parent.no_addr;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Set's the child's '..' directory inode number in dir_info structure */
Packit 6ef888
static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
Packit 6ef888
			  struct gfs2_inum parent)
Packit 6ef888
{
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
Packit 6ef888
	di = dirtree_find(childblock);
Packit 6ef888
	if (!di) {
Packit 6ef888
		log_err( _("Unable to find block %"PRIu64" (0x%" PRIx64
Packit 6ef888
			   ") in dir_info tree\n"), childblock, childblock);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (di->dinode.no_addr != childblock) {
Packit 6ef888
		log_debug("'..' doesn't point to what we found: childblock "
Packit 6ef888
			  "(0x%llx) != dinode (0x%llx)\n",
Packit 6ef888
			  (unsigned long long)childblock,
Packit 6ef888
			  (unsigned long long)di->dinode.no_addr);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	/* Special case for root inode because we set it earlier */
Packit 6ef888
	if (di->dotdot_parent.no_addr &&
Packit 6ef888
	    sdp->md.rooti->i_di.di_num.no_addr != di->dinode.no_addr) {
Packit 6ef888
		/* This should never happen */
Packit 6ef888
		log_crit( _("Dotdot parent already set for block %llu (0x%llx)"
Packit 6ef888
			    "-> %llu (0x%llx)\n"),
Packit 6ef888
			  (unsigned long long)childblock,
Packit 6ef888
			  (unsigned long long)childblock,
Packit 6ef888
			  (unsigned long long)di->dotdot_parent.no_addr,
Packit 6ef888
			  (unsigned long long)di->dotdot_parent.no_addr);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	log_debug("Setting '..' for directory block (0x%llx) to parent "
Packit 6ef888
		  "(0x%llx)\n", (unsigned long long)childblock,
Packit 6ef888
		  (unsigned long long)parent.no_addr);
Packit 6ef888
	di->dotdot_parent.no_addr = parent.no_addr;
Packit 6ef888
	di->dotdot_parent.no_formal_ino = parent.no_formal_ino;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_eattr_indir(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
	*bh = bread(ip->i_sbd, block);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit 6ef888
			    uint64_t parent, struct gfs2_buffer_head **bh,
Packit 6ef888
			    void *private)
Packit 6ef888
{
Packit 6ef888
	*bh = bread(ip->i_sbd, block);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static const char *de_type_string(uint8_t de_type)
Packit 6ef888
{
Packit 6ef888
	const char *de_types[15] = {"unknown", "fifo", "chrdev", "invalid",
Packit 6ef888
				    "directory", "invalid", "blkdev", "invalid",
Packit 6ef888
				    "file", "invalid", "symlink", "invalid",
Packit 6ef888
				    "socket", "invalid", "wht"};
Packit 6ef888
	if (de_type < 15)
Packit 6ef888
		return de_types[de_type];
Packit 6ef888
	return de_types[3]; /* invalid */
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_file_type(uint64_t block, uint8_t de_type, int q,
Packit 6ef888
			   int gfs1, int *isdir)
Packit 6ef888
{
Packit 6ef888
	struct dir_info *dt;
Packit 6ef888
Packit 6ef888
	*isdir = 0;
Packit 6ef888
	if (q != GFS2_BLKST_DINODE) {
Packit 6ef888
		log_err( _("Invalid block type\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (de_type == (gfs1 ? GFS_FILE_DIR : DT_DIR))
Packit 6ef888
		*isdir = 1;
Packit 6ef888
	/* Check if the dinode is in the dir tree */
Packit 6ef888
	dt = dirtree_find(block);
Packit 6ef888
	/* This is a bit confusing, so let me explain:
Packit 6ef888
	   If the dirent says the inode supposed to be for a directory,
Packit 6ef888
	   it should be in the dir tree. If it is, no problem, return 0.
Packit 6ef888
	   If it's not, return 1 (wrong type). If it's not supposed to be
Packit 6ef888
	   a directory, it shouldn't be in the dir tree. */
Packit 6ef888
	if (dt)
Packit 6ef888
		return !(*isdir);
Packit 6ef888
	return *isdir;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns pass2_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
Packit 6ef888
/* bad_formal_ino - handle mismatches in formal inode number
Packit 6ef888
 * Returns: 0 if the dirent was repaired
Packit 6ef888
 *          1 if the caller should delete the dirent
Packit 6ef888
 */
Packit 6ef888
static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
			  struct gfs2_inum entry, const char *tmp_name,
Packit 6ef888
			  int q, struct gfs2_dirent *de,
Packit 6ef888
			  struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	struct inode_info *ii;
Packit 6ef888
	struct dir_info *di = NULL;
Packit 6ef888
	struct gfs2_inode *child_ip;
Packit 6ef888
	struct gfs2_inum childs_dotdot;
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int error;
Packit 6ef888
	struct gfs2_inum inum = { 0 };
Packit 6ef888
Packit 6ef888
	ii = inodetree_find(entry.no_addr);
Packit 6ef888
	if (ii)
Packit 6ef888
		inum = ii->di_num;
Packit 6ef888
	else {
Packit 6ef888
		di = dirtree_find(entry.no_addr);
Packit 6ef888
		if (di)
Packit 6ef888
			inum = di->dinode;
Packit 6ef888
		else if (link1_type(&clink1map, entry.no_addr) == 1) {
Packit 6ef888
			struct gfs2_inode *dent_ip;
Packit 6ef888
Packit 6ef888
			dent_ip = fsck_load_inode(ip->i_sbd, entry.no_addr);
Packit 6ef888
			inum = dent_ip->i_di.di_num;
Packit 6ef888
			fsck_inode_put(&dent_ip);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	log_err( _("Directory entry '%s' pointing to block %llu (0x%llx) in "
Packit 6ef888
		   "directory %llu (0x%llx) has the wrong 'formal' inode "
Packit 6ef888
		   "number.\n"), tmp_name, (unsigned long long)entry.no_addr,
Packit 6ef888
		 (unsigned long long)entry.no_addr,
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
	log_err( _("The directory entry has %llu (0x%llx) but the inode has "
Packit 6ef888
		   "%llu (0x%llx)\n"), (unsigned long long)entry.no_formal_ino,
Packit 6ef888
		 (unsigned long long)entry.no_formal_ino,
Packit 6ef888
		 (unsigned long long)inum.no_formal_ino,
Packit 6ef888
		 (unsigned long long)inum.no_formal_ino);
Packit 6ef888
	if (q != GFS2_BLKST_DINODE || !strcmp("..", tmp_name)) {
Packit 6ef888
		if (query( _("Remove the corrupt directory entry? (y/n) ")))
Packit 6ef888
			return 1;
Packit 6ef888
		log_err( _("Corrupt directory entry not removed.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	/* We have a directory pointing to another directory, but the
Packit 6ef888
	   formal inode number still doesn't match. If that directory
Packit 6ef888
	   has a '..' pointing back, just fix up the no_formal_ino. */
Packit 6ef888
	child_ip = lgfs2_inode_read(sdp, entry.no_addr);
Packit 6ef888
	error = dir_search(child_ip, "..", 2, NULL, &childs_dotdot);
Packit 6ef888
	if (!error && childs_dotdot.no_addr == ip->i_di.di_num.no_addr) {
Packit 6ef888
		log_err( _("The entry points to another directory with intact "
Packit 6ef888
			   "linkage.\n"));
Packit 6ef888
		if (query( _("Fix the bad directory entry? (y/n) "))) {
Packit 6ef888
			log_err( _("Fixing the corrupt directory entry.\n"));
Packit 6ef888
			entry.no_formal_ino = inum.no_formal_ino;
Packit 6ef888
			de->de_inum.no_formal_ino = entry.no_formal_ino;
Packit 6ef888
			gfs2_dirent_out(de, (char *)dent);
Packit 6ef888
			bmodified(bh);
Packit 6ef888
			incr_link_count(entry, ip, _("fixed reference"));
Packit 6ef888
			set_parent_dir(sdp, entry, ip->i_di.di_num);
Packit 6ef888
		} else {
Packit 6ef888
			log_err( _("Directory entry not fixed.\n"));
Packit 6ef888
		}
Packit 6ef888
	} else {
Packit 6ef888
		if (query( _("Remove the corrupt directory entry? (y/n) "))) {
Packit 6ef888
			inode_put(&child_ip);
Packit 6ef888
			return 1;
Packit 6ef888
		}
Packit 6ef888
		log_err( _("Corrupt directory entry not removed.\n"));
Packit 6ef888
	}
Packit 6ef888
	inode_put(&child_ip);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int hash_table_index(uint32_t hash, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	return hash >> (32 - ip->i_di.di_depth);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int hash_table_max(int lindex, struct gfs2_inode *ip,
Packit 6ef888
		   struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
	return (1 << (ip->i_di.di_depth - be16_to_cpu(leaf->lf_depth))) +
Packit 6ef888
		lindex - 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_leaf_depth(struct gfs2_inode *ip, uint64_t leaf_no,
Packit 6ef888
			    int ref_count, struct gfs2_buffer_head *lbh)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_leaf *leaf = (struct gfs2_leaf *)lbh->b_data;
Packit 6ef888
	int cur_depth = be16_to_cpu(leaf->lf_depth);
Packit 6ef888
	int exp_count = 1 << (ip->i_di.di_depth - cur_depth);
Packit 6ef888
	int divisor;
Packit 6ef888
	int factor, correct_depth;
Packit 6ef888
Packit 6ef888
	if (exp_count == ref_count)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	factor = 0;
Packit 6ef888
	divisor = ref_count;
Packit 6ef888
	while (divisor > 1) {
Packit 6ef888
		factor++;
Packit 6ef888
		divisor >>= 1;
Packit 6ef888
	}
Packit 6ef888
	if (ip->i_di.di_depth < factor) /* can't be fixed--leaf must be on the
Packit 6ef888
					   wrong dinode. */
Packit 6ef888
		return -1;
Packit 6ef888
	correct_depth = ip->i_di.di_depth - factor;
Packit 6ef888
	if (cur_depth == correct_depth)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	log_err(_("Leaf block %llu (0x%llx) in dinode %llu (0x%llx) has the "
Packit 6ef888
		  "wrong depth: is %d (length %d), should be %d (length "
Packit 6ef888
		  "%d).\n"),
Packit 6ef888
		(unsigned long long)leaf_no, (unsigned long long)leaf_no,
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
		cur_depth, ref_count, correct_depth, exp_count);
Packit 6ef888
	if (!query( _("Fix the leaf block? (y/n)"))) {
Packit 6ef888
		log_err( _("The leaf block was not fixed.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	leaf->lf_depth = cpu_to_be16(correct_depth);
Packit 6ef888
	bmodified(lbh);
Packit 6ef888
	log_err( _("The leaf block depth was fixed.\n"));
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* wrong_leaf: Deal with a dirent discovered to be on the wrong leaf block
Packit 6ef888
 *
Packit 6ef888
 * Returns: 1 if the dirent is to be removed, 0 if it needs to be kept,
Packit 6ef888
 *          or -1 on error
Packit 6ef888
 */
Packit 6ef888
static int wrong_leaf(struct gfs2_inode *ip, struct gfs2_inum *entry,
Packit 6ef888
		      const char *tmp_name, int *lindex, int lindex_max,
Packit 6ef888
		      int hash_index, struct gfs2_buffer_head *bh,
Packit 6ef888
		      struct dir_status *ds, struct gfs2_dirent *dent,
Packit 6ef888
		      struct gfs2_dirent *de, struct gfs2_dirent *prev_de,
Packit 6ef888
		      uint32_t *count, int q)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *dest_lbh;
Packit 6ef888
	uint64_t planned_leaf, real_leaf;
Packit 6ef888
	int li, dest_ref, error;
Packit 6ef888
	uint64_t *tbl;
Packit 6ef888
	int di_depth;
Packit 6ef888
Packit 6ef888
	log_err(_("Directory entry '%s' at block %lld (0x%llx) is on the "
Packit 6ef888
		  "wrong leaf block.\n"), tmp_name,
Packit 6ef888
		(unsigned long long)entry->no_addr,
Packit 6ef888
		(unsigned long long)entry->no_addr);
Packit 6ef888
	log_err(_("Leaf index is: 0x%x. The range for this leaf block is "
Packit 6ef888
		  "0x%x - 0x%x\n"), hash_index, *lindex, lindex_max);
Packit 6ef888
	if (!query( _("Move the misplaced directory entry to "
Packit 6ef888
		      "a valid leaf block? (y/n) "))) {
Packit 6ef888
		log_err( _("Misplaced directory entry not moved.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* check the destination leaf block's depth */
Packit 6ef888
	tbl = get_dir_hash(ip);
Packit 6ef888
	if (tbl == NULL) {
Packit 6ef888
		perror("get_dir_hash");
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	planned_leaf = be64_to_cpu(tbl[hash_index]);
Packit 6ef888
	log_err(_("Moving it from leaf %llu (0x%llx) to %llu (0x%llx)\n"),
Packit 6ef888
		(unsigned long long)be64_to_cpu(tbl[*lindex]),
Packit 6ef888
		(unsigned long long)be64_to_cpu(tbl[*lindex]),
Packit 6ef888
		(unsigned long long)planned_leaf,
Packit 6ef888
		(unsigned long long)planned_leaf);
Packit 6ef888
	/* Can't trust lf_depth; we have to count */
Packit 6ef888
	dest_ref = 0;
Packit 6ef888
	for (li = 0; li < (1 << ip->i_di.di_depth); li++) {
Packit 6ef888
		if (be64_to_cpu(tbl[li]) == planned_leaf)
Packit 6ef888
			dest_ref++;
Packit 6ef888
		else if (dest_ref)
Packit 6ef888
			break;
Packit 6ef888
	}
Packit 6ef888
	dest_lbh = bread(sdp, planned_leaf);
Packit 6ef888
	check_leaf_depth(ip, planned_leaf, dest_ref, dest_lbh);
Packit 6ef888
	brelse(dest_lbh);
Packit 6ef888
	free(tbl);
Packit 6ef888
Packit 6ef888
	/* check if it's already on the correct leaf block */
Packit 6ef888
	error = dir_search(ip, tmp_name, de->de_name_len, NULL, &de->de_inum);
Packit 6ef888
	if (!error) {
Packit 6ef888
		log_err(_("The misplaced directory entry already appears on "
Packit 6ef888
			  "the correct leaf block.\n"));
Packit 6ef888
		log_err( _("The bad duplicate directory entry "
Packit 6ef888
			   "'%s' was cleared.\n"), tmp_name);
Packit 6ef888
		return 1; /* nuke the dent upon return */
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	di_depth = ip->i_di.di_depth;
Packit 6ef888
	if (dir_add(ip, tmp_name, de->de_name_len, &de->de_inum,
Packit 6ef888
		    de->de_type) == 0) {
Packit 6ef888
		log_err(_("The misplaced directory entry was moved to a "
Packit 6ef888
			  "valid leaf block.\n"));
Packit 6ef888
		if (ip->i_di.di_depth > di_depth) {
Packit 6ef888
			log_err(_("Directory hash table was doubled.\n"));
Packit 6ef888
			hash_index <<= (ip->i_di.di_depth - di_depth);
Packit 6ef888
			(*lindex) <<= (ip->i_di.di_depth - di_depth);
Packit 6ef888
		}
Packit 6ef888
		if (lgfs2_get_leaf_ptr(ip, hash_index, &real_leaf)) {
Packit 6ef888
			log_err(_("Could not read leaf %d in dinode %"PRIu64": %s\n"), hash_index,
Packit 6ef888
			        (uint64_t)ip->i_di.di_num.no_addr, strerror(errno));
Packit 6ef888
		}
Packit 6ef888
		if (real_leaf != planned_leaf) {
Packit 6ef888
			log_err(_("The planned leaf was split. The new leaf "
Packit 6ef888
				  "is: %llu (0x%llx). di_blocks=%llu\n"),
Packit 6ef888
				(unsigned long long)real_leaf,
Packit 6ef888
				(unsigned long long)real_leaf,
Packit 6ef888
				(unsigned long long)ip->i_di.di_blocks);
Packit 6ef888
			fsck_bitmap_set(ip, real_leaf, _("split leaf"),
Packit 6ef888
					sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
					GFS2_BLKST_USED);
Packit 6ef888
		}
Packit 6ef888
		/* If the misplaced dirent was supposed to be earlier in the
Packit 6ef888
		   hash table, we need to adjust our counts for the blocks
Packit 6ef888
		   that have already been processed. If it's supposed to
Packit 6ef888
		   appear later, we'll count it has part of our normal
Packit 6ef888
		   processing when we get to that leaf block later on in the
Packit 6ef888
		   hash table. */
Packit 6ef888
		if (hash_index > *lindex) {
Packit 6ef888
			log_err(_("Accounting deferred.\n"));
Packit 6ef888
			return 1; /* nuke the dent upon return */
Packit 6ef888
		}
Packit 6ef888
		/* If we get here, it's because we moved a dent to another
Packit 6ef888
		   leaf, but that leaf has already been processed. So we have
Packit 6ef888
		   to nuke the dent from this leaf when we return, but we
Packit 6ef888
		   still need to do the "good dent" accounting. */
Packit 6ef888
		if (de->de_type == (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR)) {
Packit 6ef888
			error = set_parent_dir(sdp, de->de_inum,
Packit 6ef888
					       ip->i_di.di_num);
Packit 6ef888
			if (error > 0)
Packit 6ef888
				/* This is a bit of a kludge, but returning 0
Packit 6ef888
				   in this case causes the caller to go through
Packit 6ef888
				   function set_parent_dir a second time and
Packit 6ef888
				   deal properly with the hard link. */
Packit 6ef888
				return 0;
Packit 6ef888
		}
Packit 6ef888
		error = incr_link_count(*entry, ip,
Packit 6ef888
					_("moved valid reference"));
Packit 6ef888
		if (error > 0 &&
Packit 6ef888
		    bad_formal_ino(ip, dent, *entry, tmp_name, q, de, bh) == 1)
Packit 6ef888
			return 1; /* nuke it */
Packit 6ef888
Packit 6ef888
		/* You cannot do this:
Packit 6ef888
		   (*count)++;
Packit 6ef888
		   The reason is: *count is the count of dentries on the leaf,
Packit 6ef888
		   and we moved the dentry to a previous leaf within the same
Packit 6ef888
		   directory dinode. So the directory counts still get
Packit 6ef888
		   incremented, but not leaf entries. When we called dir_add
Packit 6ef888
		   above, it should have fixed that prev leaf's lf_entries. */
Packit 6ef888
		ds->entry_count++;
Packit 6ef888
		return 1;
Packit 6ef888
	} else {
Packit 6ef888
		log_err(_("Error moving directory entry.\n"));
Packit 6ef888
		return 1; /* nuke it */
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* basic_dentry_checks - fundamental checks for directory entries
Packit 6ef888
 *
Packit 6ef888
 * @ip: pointer to the incode inode structure
Packit 6ef888
 * @entry: pointer to the inum info
Packit 6ef888
 * @tmp_name: user-friendly file name
Packit 6ef888
 * @count: pointer to the entry count
Packit 6ef888
 * @de: pointer to the directory entry
Packit 6ef888
 *
Packit 6ef888
 * Returns: 1 means corruption, nuke the dentry, 0 means checks pass
Packit 6ef888
 */
Packit 6ef888
static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
			       struct gfs2_inum *entry, const char *tmp_name,
Packit 6ef888
			       uint32_t *count, struct gfs2_dirent *de,
Packit 6ef888
			       struct dir_status *ds, int *q,
Packit 6ef888
			       struct gfs2_buffer_head *bh, int *isdir)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	uint32_t calculated_hash;
Packit 6ef888
	struct gfs2_inode *entry_ip = NULL;
Packit 6ef888
	int error;
Packit 6ef888
	struct inode_info *ii;
Packit 6ef888
	struct dir_info *di = NULL;
Packit 6ef888
	struct gfs2_inum inum = { 0 };
Packit 6ef888
Packit 6ef888
	*isdir = 0;
Packit 6ef888
	if (!valid_block_ip(ip, entry->no_addr)) {
Packit 6ef888
		log_err( _("Block # referenced by directory entry %s in inode "
Packit 6ef888
			   "%lld (0x%llx) is invalid\n"),
Packit 6ef888
			 tmp_name, (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			 (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if (query( _("Clear directory entry to out of range block? "
Packit 6ef888
			    "(y/n) "))) {
Packit 6ef888
			return 1;
Packit 6ef888
		} else {
Packit 6ef888
			log_err( _("Directory entry to out of range block remains\n"));
Packit 6ef888
			(*count)++;
Packit 6ef888
			ds->entry_count++;
Packit 6ef888
			/* can't do this because the block is out of range:
Packit 6ef888
			   incr_link_count(entry); */
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (de->de_rec_len < GFS2_DIRENT_SIZE(de->de_name_len) ||
Packit 6ef888
	    de->de_name_len > GFS2_FNAMESIZE) {
Packit 6ef888
		log_err( _("Dir entry with bad record or name length\n"
Packit 6ef888
			"\tRecord length = %u\n\tName length = %u\n"),
Packit 6ef888
			de->de_rec_len, de->de_name_len);
Packit 6ef888
		if (!query( _("Clear the directory entry? (y/n) "))) {
Packit 6ef888
			log_err( _("Directory entry not fixed.\n"));
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		/* Don't be tempted to do this:
Packit 6ef888
		fsck_bitmap_set(ip, ip->i_di.di_num.no_addr,
Packit 6ef888
				_("corrupt directory entry"),
Packit 6ef888
				GFS2_BLKST_FREE);
Packit 6ef888
		We can't free it because another dir may have a valid reference
Packit 6ef888
		to it. Just return 1 so we can delete the bad dirent. */
Packit 6ef888
		log_err( _("Bad directory entry deleted.\n"));
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	calculated_hash = gfs2_disk_hash(tmp_name, de->de_name_len);
Packit 6ef888
	if (de->de_hash != calculated_hash){
Packit 6ef888
	        log_err( _("Dir entry with bad hash or name length\n"
Packit 6ef888
			   "\tHash found         = %u (0x%x)\n"
Packit 6ef888
			   "\tFilename           = %s\n"),
Packit 6ef888
			 de->de_hash, de->de_hash, tmp_name);
Packit 6ef888
		log_err( _("\tName length found  = %u\n"
Packit 6ef888
			   "\tHash expected      = %u (0x%x)\n"),
Packit 6ef888
			 de->de_name_len, calculated_hash, calculated_hash);
Packit 6ef888
		if (!query( _("Fix directory hash for %s? (y/n) "),
Packit 6ef888
			   tmp_name)) {
Packit 6ef888
			log_err( _("Directory entry hash for %s not "
Packit 6ef888
				   "fixed.\n"), tmp_name);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		de->de_hash = calculated_hash;
Packit 6ef888
		gfs2_dirent_out(de, (char *)dent);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		log_err( _("Directory entry hash for %s fixed.\n"),
Packit 6ef888
			 tmp_name);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	*q = bitmap_type(sdp, entry->no_addr);
Packit 6ef888
	/* Get the status of the directory inode */
Packit 6ef888
	/**
Packit 6ef888
	 * 1. Blocks marked "invalid" were invalidated due to duplicate
Packit 6ef888
	 * block references.  Pass1b should have already taken care of deleting
Packit 6ef888
	 * their metadata, so here we only need to delete the directory entries
Packit 6ef888
	 * pointing to them.  We delete the metadata in pass1b because we need
Packit 6ef888
	 * to eliminate the inode referencing the duplicate-referenced block
Packit 6ef888
	 * from the list of candidates to keep.  So we have a delete-as-we-go
Packit 6ef888
	 * policy.
Packit 6ef888
	 *
Packit 6ef888
	 * 2. Blocks marked "bad" need to have their entire
Packit 6ef888
	 * metadata tree deleted.
Packit 6ef888
	*/
Packit 6ef888
	if (*q != GFS2_BLKST_DINODE) {
Packit 6ef888
		log_err( _("Directory entry '%s' referencing inode %llu "
Packit 6ef888
			   "(0x%llx) in dir inode %llu (0x%llx) block type "
Packit 6ef888
			   "%d: %s.\n"), tmp_name,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
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
			 *q, *q == GFS2_BLKST_FREE ?
Packit 6ef888
			 _("was previously marked invalid") :
Packit 6ef888
			 _("was deleted or is not an inode"));
Packit 6ef888
Packit 6ef888
		if (!query( _("Clear directory entry to non-inode block? "
Packit 6ef888
			     "(y/n) "))) {
Packit 6ef888
			log_err( _("Directory entry to non-inode block remains\n"));
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* Don't decrement the link here: Here in pass2, we increment
Packit 6ef888
		   only when we know it's okay.
Packit 6ef888
		   decr_link_count(ip->i_di.di_num.no_addr, blah); */
Packit 6ef888
		/* If it was previously marked invalid (i.e. known
Packit 6ef888
		   to be bad, not just a free block, etc.) then the temptation
Packit 6ef888
		   would be to delete any metadata it holds.  The trouble is:
Packit 6ef888
		   if it's invalid, we may or _may_not_ have traversed its
Packit 6ef888
		   metadata tree, and therefore may or may not have marked the
Packit 6ef888
		   blocks it points to as a metadata type, or as a duplicate.
Packit 6ef888
		   If there is really a duplicate reference, but we didn't
Packit 6ef888
		   process the metadata tree because it's invalid, some other
Packit 6ef888
		   inode has a reference to the metadata block, in which case
Packit 6ef888
		   freeing it would do more harm than good.  IOW we cannot
Packit 6ef888
		   count on "delete_block_if_notdup" knowing whether it's
Packit 6ef888
		   really a duplicate block if we never traversed the metadata
Packit 6ef888
		   tree for the invalid inode. */
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	error = check_file_type(entry->no_addr, de->de_type, *q, sdp->gfs1,
Packit 6ef888
				isdir);
Packit 6ef888
	if (error < 0) {
Packit 6ef888
		log_err( _("Error: directory entry type is "
Packit 6ef888
			   "incompatible with block type at block %lld "
Packit 6ef888
			   "(0x%llx) in directory inode %llu (0x%llx).\n"),
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
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
		log_err( _("Directory entry type is %d, block type is %d.\n"),
Packit 6ef888
			 de->de_type, *q);
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (error > 0) {
Packit 6ef888
		log_err( _("Type '%s' in dir entry (%s, %llu/0x%llx) conflicts"
Packit 6ef888
			 " with type '%s' in dinode. (Dir entry is stale.)\n"),
Packit 6ef888
			 de_type_string(de->de_type), tmp_name,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 block_type_string(*q));
Packit 6ef888
		if (!query( _("Clear stale directory entry? (y/n) "))) {
Packit 6ef888
			log_err( _("Stale directory entry remains\n"));
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		if (ip->i_di.di_num.no_addr == entry->no_addr)
Packit 6ef888
			entry_ip = ip;
Packit 6ef888
		else
Packit 6ef888
			entry_ip = fsck_load_inode(sdp, entry->no_addr);
Packit 6ef888
		check_inode_eattr(entry_ip, &delete_eattrs);
Packit 6ef888
		if (entry_ip != ip)
Packit 6ef888
			fsck_inode_put(&entry_ip);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	/* We need to verify the formal inode number matches. If it doesn't,
Packit 6ef888
	   it needs to be deleted. */
Packit 6ef888
	ii = inodetree_find(entry->no_addr);
Packit 6ef888
	if (ii)
Packit 6ef888
		inum = ii->di_num;
Packit 6ef888
	else {
Packit 6ef888
		di = dirtree_find(entry->no_addr);
Packit 6ef888
		if (di)
Packit 6ef888
			inum = di->dinode;
Packit 6ef888
		else if (link1_type(&nlink1map, entry->no_addr) == 1) {
Packit 6ef888
			/* Since we don't have ii or di, the only way to
Packit 6ef888
			   validate formal_ino is to read in the inode, which
Packit 6ef888
			   would kill performance. So skip it for now. */
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	if (inum.no_formal_ino != entry->no_formal_ino) {
Packit 6ef888
		log_err( _("Directory entry '%s' pointing to block %llu "
Packit 6ef888
			   "(0x%llx) in directory %llu (0x%llx) has the "
Packit 6ef888
			   "wrong 'formal' inode number.\n"), tmp_name,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
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
		log_err( _("The directory entry has %llu (0x%llx) but the "
Packit 6ef888
			   "inode has %llu (0x%llx)\n"),
Packit 6ef888
			 (unsigned long long)entry->no_formal_ino,
Packit 6ef888
			 (unsigned long long)entry->no_formal_ino,
Packit 6ef888
			 (unsigned long long)inum.no_formal_ino,
Packit 6ef888
			 (unsigned long long)inum.no_formal_ino);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	/* Check for a special case where a (bad) GFS1 dirent points to what
Packit 6ef888
	 * is not a known inode. It could be other GFS1 metadata, such as an
Packit 6ef888
	 * eattr or indirect block, but marked "dinode" in the bitmap because
Packit 6ef888
	 * gfs1 marked all gfs1 metadata that way. */
Packit 6ef888
	if (ii == NULL && di == NULL && sdp->gfs1) {
Packit 6ef888
		struct gfs2_buffer_head *tbh;
Packit 6ef888
Packit 6ef888
		tbh = bread(sdp, entry->no_addr);
Packit 6ef888
		if (gfs2_check_meta(tbh, GFS2_METATYPE_DI)) { /* not dinode */
Packit 6ef888
			log_err( _("Directory entry '%s' pointing to block "
Packit 6ef888
				   "%llu (0x%llx) in directory %llu (0x%llx) "
Packit 6ef888
				   "is not really a GFS1 dinode.\n"), tmp_name,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
Packit 6ef888
			 (unsigned long long)entry->no_addr,
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
			brelse(tbh);
Packit 6ef888
			return 1;
Packit 6ef888
		}
Packit 6ef888
		brelse(tbh);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int dirref_find(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
		       struct gfs2_dirent *prev, struct gfs2_buffer_head *bh,
Packit 6ef888
		       char *filename, uint32_t *count, int *lindex,
Packit 6ef888
		       void *private)
Packit 6ef888
{
Packit 6ef888
	/* the metawalk_fxn's private field must be set to the dentry
Packit 6ef888
	 * block we want to clear */
Packit 6ef888
	struct gfs2_inum *entry = (struct gfs2_inum *)private;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	char fn[MAX_FILENAME];
Packit 6ef888
Packit 6ef888
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
	gfs2_dirent_in(&dentry, (char *)dent);
Packit 6ef888
	de = &dentry;
Packit 6ef888
Packit 6ef888
	if (de->de_inum.no_addr != entry->no_addr) {
Packit 6ef888
		(*count)++;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	if (de->de_inum.no_formal_ino == dent->de_inum.no_formal_ino) {
Packit 6ef888
		log_debug("Formal inode number matches; must be a hard "
Packit 6ef888
			  "link.\n");
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
	log_err(_("The original reference to inode %lld (0x%llx) from "
Packit 6ef888
		  "directory %lld (0x%llx) has the wrong 'formal' inode "
Packit 6ef888
		  "number.\n"), (unsigned long long)entry->no_addr,
Packit 6ef888
		(unsigned long long)entry->no_addr,
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
	memset(fn, 0, sizeof(fn));
Packit 6ef888
	if (de->de_name_len < MAX_FILENAME)
Packit 6ef888
		strncpy(fn, filename, de->de_name_len);
Packit 6ef888
	else
Packit 6ef888
		strncpy(fn, filename, MAX_FILENAME - 1);
Packit 6ef888
	log_err(_("The bad reference '%s' had formal inode number: %lld "
Packit 6ef888
		  "(0x%llx) but the correct value is: %lld (0x%llx)\n"),
Packit 6ef888
		fn, (unsigned long long)de->de_inum.no_formal_ino,
Packit 6ef888
		(unsigned long long)de->de_inum.no_formal_ino,
Packit 6ef888
		(unsigned long long)entry->no_formal_ino,
Packit 6ef888
		(unsigned long long)entry->no_formal_ino);
Packit 6ef888
	if (!query(_("Delete the bad directory entry? (y/n) "))) {
Packit 6ef888
		log_err(_("The corrupt directory entry was not fixed.\n"));
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
	decr_link_count(entry->no_addr, ip->i_di.di_num.no_addr,
Packit 6ef888
			ip->i_sbd->gfs1, _("bad original reference"));
Packit 6ef888
	dirent2_del(ip, bh, prev, dent);
Packit 6ef888
	log_err(_("The corrupt directory entry '%s' was deleted.\n"), fn);
Packit 6ef888
out:
Packit 6ef888
	return -1; /* force check_dir to stop; don't waste time. */
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * check_suspicious_dirref - double-check a questionable first dentry ref
Packit 6ef888
 *
Packit 6ef888
 * This function is called when a dentry has caused us to increment the
Packit 6ef888
 * link count to a file from 1 to 2, and we know the object pointed to is
Packit 6ef888
 * not a directory. (Most likely, it'a a file). The second directory to
Packit 6ef888
 * reference the dinode has the correct formal inode number, but when we
Packit 6ef888
 * created the original reference in the counted links bitmap (clink1map),
Packit 6ef888
 * we had no way to check the formal inode number. (Well, we could have read
Packit 6ef888
 * in the dinode, but that would kill fsck.gfs2 performance.)
Packit 6ef888
 * So now we have to walk through the directory tree and find that original
Packit 6ef888
 * reference so make sure it's a valid reference. If the formal inode number
Packit 6ef888
 * is the same, it's a hard link (which is unlikely for gfs2). If it's not
Packit 6ef888
 * the same, that's an error, and we need to delete the damaged original
Packit 6ef888
 * dentry, since we failed to detect the problem earlier.
Packit 6ef888
 */
Packit 6ef888
static int check_suspicious_dirref(struct gfs2_sbd *sdp,
Packit 6ef888
				   struct gfs2_inum *entry)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *tmp, *next = NULL;
Packit 6ef888
	struct dir_info *dt;
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	uint64_t dirblk;
Packit 6ef888
	int error = FSCK_OK;
Packit 6ef888
	struct metawalk_fxns dirref_hunt = {
Packit 6ef888
		.private = (void *)entry,
Packit 6ef888
		.check_dentry = dirref_find,
Packit 6ef888
	};
Packit 6ef888
Packit 6ef888
	log_debug("This dentry is good, but since this is a second "
Packit 6ef888
		  "reference to block 0x%llx, we need to check the "
Packit 6ef888
		  "original.\n", (unsigned long long)entry->no_addr);
Packit 6ef888
	for (tmp = osi_first(&dirtree); tmp; tmp = next) {
Packit 6ef888
		next = osi_next(tmp);
Packit 6ef888
		dt = (struct dir_info *)tmp;
Packit 6ef888
		dirblk = dt->dinode.no_addr;
Packit 6ef888
		if (skip_this_pass || fsck_abort) /* asked to skip the rest */
Packit 6ef888
			break;
Packit 6ef888
		ip = fsck_load_inode(sdp, dirblk);
Packit 6ef888
		if (ip == NULL) {
Packit 6ef888
			stack;
Packit 6ef888
			return FSCK_ERROR;
Packit 6ef888
		}
Packit 6ef888
		error = check_dir(sdp, ip, &dirref_hunt);
Packit 6ef888
		fsck_inode_put(&ip);
Packit 6ef888
		/* Error just means we found the dentry and dealt with it. */
Packit 6ef888
		if (error)
Packit 6ef888
			break;
Packit 6ef888
	}
Packit 6ef888
	log_debug("Original reference check complete. Found = %d.\n",
Packit 6ef888
		  error ? 1 : 0);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* FIXME: should maybe refactor this a bit - but need to deal with
Packit 6ef888
 * FIXMEs internally first */
Packit 6ef888
static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
			struct gfs2_dirent *prev_de,
Packit 6ef888
			struct gfs2_buffer_head *bh, char *filename,
Packit 6ef888
			uint32_t *count, int *lindex, void *priv)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	int q = 0;
Packit 6ef888
	char tmp_name[MAX_FILENAME];
Packit 6ef888
	struct gfs2_inum entry;
Packit 6ef888
	struct dir_status *ds = (struct dir_status *) priv;
Packit 6ef888
	int error;
Packit 6ef888
	struct gfs2_inode *entry_ip = NULL;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	int hash_index; /* index into the hash table based on the hash */
Packit 6ef888
	int lindex_max; /* largest acceptable hash table index for hash */
Packit 6ef888
	int isdir;
Packit 6ef888
Packit 6ef888
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
	gfs2_dirent_in(&dentry, (char *)dent);
Packit 6ef888
	de = &dentry;
Packit 6ef888
Packit 6ef888
	entry.no_addr = de->de_inum.no_addr;
Packit 6ef888
	entry.no_formal_ino = de->de_inum.no_formal_ino;
Packit 6ef888
Packit 6ef888
	/* Start of checks */
Packit 6ef888
	memset(tmp_name, 0, MAX_FILENAME);
Packit 6ef888
	if (de->de_name_len < MAX_FILENAME)
Packit 6ef888
		strncpy(tmp_name, filename, de->de_name_len);
Packit 6ef888
	else
Packit 6ef888
		strncpy(tmp_name, filename, MAX_FILENAME - 1);
Packit 6ef888
Packit 6ef888
	error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de,
Packit 6ef888
				    ds, &q, bh, &isdir);
Packit 6ef888
	if (error)
Packit 6ef888
		goto nuke_dentry;
Packit 6ef888
Packit 6ef888
	if (!strcmp(".", tmp_name)) {
Packit 6ef888
		log_debug( _("Found . dentry in directory %lld (0x%llx)\n"),
Packit 6ef888
			     (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			     (unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
Packit 6ef888
		if (ds->dotdir) {
Packit 6ef888
			log_err( _("Already found '.' entry in directory %llu"
Packit 6ef888
				" (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
			if (!query( _("Clear duplicate '.' entry? (y/n) "))) {
Packit 6ef888
				log_err( _("Duplicate '.' entry remains\n"));
Packit 6ef888
				/* FIXME: Should we continue on here
Packit 6ef888
				 * and check the rest of the '.' entry? */
Packit 6ef888
				goto dentry_is_valid;
Packit 6ef888
			}
Packit 6ef888
			if (ip->i_di.di_num.no_addr == entry.no_addr)
Packit 6ef888
				entry_ip = ip;
Packit 6ef888
			else
Packit 6ef888
				entry_ip = fsck_load_inode(sdp, entry.no_addr);
Packit 6ef888
			check_inode_eattr(entry_ip, &delete_eattrs);
Packit 6ef888
			if (entry_ip != ip)
Packit 6ef888
				fsck_inode_put(&entry_ip);
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* GFS2 does not rely on '.' being in a certain
Packit 6ef888
		 * location */
Packit 6ef888
Packit 6ef888
		/* check that '.' refers to this inode */
Packit 6ef888
		if (entry.no_addr != ip->i_di.di_num.no_addr) {
Packit 6ef888
			log_err( _("'.' entry's value incorrect in directory %llu"
Packit 6ef888
				" (0x%llx).  Points to %llu"
Packit 6ef888
				" (0x%llx) when it should point to %llu"
Packit 6ef888
				" (0x%llx).\n"),
Packit 6ef888
				(unsigned long long)entry.no_addr,
Packit 6ef888
				(unsigned long long)entry.no_addr,
Packit 6ef888
				(unsigned long long)entry.no_addr,
Packit 6ef888
				(unsigned long long)entry.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
			if (!query( _("Remove '.' reference? (y/n) "))) {
Packit 6ef888
				log_err( _("Invalid '.' reference remains\n"));
Packit 6ef888
				/* Not setting ds->dotdir here since
Packit 6ef888
				 * this '.' entry is invalid */
Packit 6ef888
				goto dentry_is_valid;
Packit 6ef888
			}
Packit 6ef888
			if (ip->i_di.di_num.no_addr == entry.no_addr)
Packit 6ef888
				entry_ip = ip;
Packit 6ef888
			else
Packit 6ef888
				entry_ip = fsck_load_inode(sdp, entry.no_addr);
Packit 6ef888
			check_inode_eattr(entry_ip, &delete_eattrs);
Packit 6ef888
			if (entry_ip != ip)
Packit 6ef888
				fsck_inode_put(&entry_ip);
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		ds->dotdir = 1;
Packit 6ef888
		goto dentry_is_valid;
Packit 6ef888
	}
Packit 6ef888
	if (!strcmp("..", tmp_name)) {
Packit 6ef888
		log_debug( _("Found '..' dentry in directory %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
		if (ds->dotdotdir) {
Packit 6ef888
			log_err( _("Already had a '..' entry in directory %llu"
Packit 6ef888
				"(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
			if (!query( _("Clear duplicate '..' entry? (y/n) "))) {
Packit 6ef888
				log_err( _("Duplicate '..' entry remains\n"));
Packit 6ef888
				/* FIXME: Should we continue on here
Packit 6ef888
				 * and check the rest of the '..'
Packit 6ef888
				 * entry? */
Packit 6ef888
				goto dentry_is_valid;
Packit 6ef888
			}
Packit 6ef888
Packit 6ef888
			if (ip->i_di.di_num.no_addr == entry.no_addr)
Packit 6ef888
				entry_ip = ip;
Packit 6ef888
			else
Packit 6ef888
				entry_ip = fsck_load_inode(sdp, entry.no_addr);
Packit 6ef888
			check_inode_eattr(entry_ip, &delete_eattrs);
Packit 6ef888
			if (entry_ip != ip)
Packit 6ef888
				fsck_inode_put(&entry_ip);
Packit 6ef888
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
		}
Packit 6ef888
		if (!isdir) {
Packit 6ef888
			log_err( _("Found '..' entry in directory %llu (0x%llx) "
Packit 6ef888
				"pointing to something that's not a directory"),
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
			if (!query( _("Clear bad '..' directory entry? (y/n) "))) {
Packit 6ef888
				log_err( _("Bad '..' directory entry remains\n"));
Packit 6ef888
				goto dentry_is_valid;
Packit 6ef888
			}
Packit 6ef888
			if (ip->i_di.di_num.no_addr == entry.no_addr)
Packit 6ef888
				entry_ip = ip;
Packit 6ef888
			else
Packit 6ef888
				entry_ip = fsck_load_inode(sdp, entry.no_addr);
Packit 6ef888
			check_inode_eattr(entry_ip, &delete_eattrs);
Packit 6ef888
			if (entry_ip != ip)
Packit 6ef888
				fsck_inode_put(&entry_ip);
Packit 6ef888
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
		}
Packit 6ef888
		/* GFS2 does not rely on '..' being in a certain location */
Packit 6ef888
Packit 6ef888
		/* Add the address this entry is pointing to
Packit 6ef888
		 * to this inode's dotdot_parent in
Packit 6ef888
		 * dir_info */
Packit 6ef888
		if (set_dotdot_dir(sdp, ip->i_di.di_num.no_addr, entry)) {
Packit 6ef888
			stack;
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		ds->dotdotdir = 1;
Packit 6ef888
		goto dentry_is_valid;
Packit 6ef888
	}
Packit 6ef888
	/* If this is an exhash directory, make sure the dentries in the leaf
Packit 6ef888
	   block have a hash table index that fits */
Packit 6ef888
	if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
Packit 6ef888
		hash_index = hash_table_index(de->de_hash, ip);
Packit 6ef888
		lindex_max = hash_table_max(*lindex, ip, bh);
Packit 6ef888
		if (hash_index < *lindex || hash_index > lindex_max) {
Packit 6ef888
			int nuke_dent;
Packit 6ef888
Packit 6ef888
			nuke_dent = wrong_leaf(ip, &entry, tmp_name, lindex,
Packit 6ef888
					       lindex_max, hash_index, bh, ds,
Packit 6ef888
					       dent, de, prev_de, count, q);
Packit 6ef888
			if (nuke_dent)
Packit 6ef888
				goto nuke_dentry;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* After this point we're only concerned with directories */
Packit 6ef888
	if (!isdir) {
Packit 6ef888
		log_debug( _("Found non-dir inode dentry pointing to %lld "
Packit 6ef888
			     "(0x%llx)\n"),
Packit 6ef888
			   (unsigned long long)entry.no_addr,
Packit 6ef888
			   (unsigned long long)entry.no_addr);
Packit 6ef888
		goto dentry_is_valid;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/*log_debug( _("Found plain directory dentry\n"));*/
Packit 6ef888
	error = set_parent_dir(sdp, entry, ip->i_di.di_num);
Packit 6ef888
	if (error > 0) {
Packit 6ef888
		log_err( _("%s: Hard link to block %llu (0x%llx"
Packit 6ef888
			   ") detected.\n"), tmp_name,
Packit 6ef888
			(unsigned long long)entry.no_addr,
Packit 6ef888
			(unsigned long long)entry.no_addr);
Packit 6ef888
Packit 6ef888
		if (query( _("Clear hard link to directory? (y/n) ")))
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
		else {
Packit 6ef888
			log_err( _("Hard link to directory remains\n"));
Packit 6ef888
			goto dentry_is_valid;
Packit 6ef888
		}
Packit 6ef888
	} else if (error < 0) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
dentry_is_valid:
Packit 6ef888
	/* This directory inode links to this inode via this dentry */
Packit 6ef888
	error = incr_link_count(entry, ip, _("valid reference"));
Packit 6ef888
	if (error == incr_link_check_orig) {
Packit 6ef888
		error = check_suspicious_dirref(sdp, &entry);
Packit 6ef888
	} else if (error == incr_link_ino_mismatch) {
Packit 6ef888
		log_err("incr_link_count err=%d.\n", error);
Packit 6ef888
		if (bad_formal_ino(ip, dent, entry, tmp_name, q, de, bh) == 1)
Packit 6ef888
			goto nuke_dentry;
Packit 6ef888
	}
Packit 6ef888
	(*count)++;
Packit 6ef888
	ds->entry_count++;
Packit 6ef888
	/* End of checks */
Packit 6ef888
	return 0;
Packit 6ef888
Packit 6ef888
nuke_dentry:
Packit 6ef888
	dirent2_del(ip, bh, prev_de, dent);
Packit 6ef888
	log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * write_new_leaf - allocate and write a new leaf to cover a gap in hash table
Packit 6ef888
 * @dip: the directory inode
Packit 6ef888
 * @start_lindex: where in the hash table to start writing
Packit 6ef888
 * @num_copies: number of copies of the pointer to write into hash table
Packit 6ef888
 * @before_or_after: desc. of whether this is being added before/after/etc.
Packit 6ef888
 * @bn: pointer to return the newly allocated leaf's block number
Packit 6ef888
 */
Packit 6ef888
static int write_new_leaf(struct gfs2_inode *dip, int start_lindex,
Packit 6ef888
			  int num_copies, const char *before_or_after,
Packit 6ef888
			  uint64_t *bn)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *nbh;
Packit 6ef888
	struct gfs2_leaf *leaf;
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	int count, i;
Packit 6ef888
	int factor = 0, pad_size;
Packit 6ef888
	uint64_t *cpyptr;
Packit 6ef888
	char *padbuf;
Packit 6ef888
	int divisor = num_copies;
Packit 6ef888
	int end_lindex = start_lindex + num_copies;
Packit 6ef888
Packit 6ef888
	padbuf = malloc(num_copies * sizeof(uint64_t));
Packit 6ef888
	/* calculate the depth needed for the new leaf */
Packit 6ef888
	while (divisor > 1) {
Packit 6ef888
		factor++;
Packit 6ef888
		divisor /= 2;
Packit 6ef888
	}
Packit 6ef888
	/* Make sure the number of copies is properly a factor of 2 */
Packit 6ef888
	if ((1 << factor) != num_copies) {
Packit 6ef888
		log_err(_("Program error: num_copies not a factor of 2.\n"));
Packit 6ef888
		log_err(_("num_copies=%d, dinode = %lld (0x%llx)\n"),
Packit 6ef888
			num_copies,
Packit 6ef888
			(unsigned long long)dip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)dip->i_di.di_num.no_addr);
Packit 6ef888
		log_err(_("lindex = %d (0x%x)\n"), start_lindex, start_lindex);
Packit 6ef888
		stack;
Packit 6ef888
		free(padbuf);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* allocate and write out a new leaf block */
Packit 6ef888
	if (lgfs2_meta_alloc(dip, bn)) {
Packit 6ef888
		log_err( _("Error: allocation failed while fixing directory leaf "
Packit 6ef888
			   "pointers.\n"));
Packit 6ef888
		free(padbuf);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	fsck_bitmap_set(dip, *bn, _("directory leaf"), dip->i_sbd->gfs1 ?
Packit 6ef888
			GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
	log_err(_("A new directory leaf was allocated at block %lld "
Packit 6ef888
		  "(0x%llx) to fill the %d (0x%x) pointer gap %s the existing "
Packit 6ef888
		  "pointer at index %d (0x%x).\n"), (unsigned long long)*bn,
Packit 6ef888
		(unsigned long long)*bn, num_copies, num_copies,
Packit 6ef888
		before_or_after, start_lindex, start_lindex);
Packit 6ef888
	dip->i_di.di_blocks++;
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
	nbh = bget(dip->i_sbd, *bn);
Packit 6ef888
	memset(nbh->b_data, 0, dip->i_sbd->bsize);
Packit 6ef888
	leaf = (struct gfs2_leaf *)nbh->b_data;
Packit 6ef888
	leaf->lf_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
Packit 6ef888
	leaf->lf_header.mh_type = cpu_to_be32(GFS2_METATYPE_LF);
Packit 6ef888
	leaf->lf_header.mh_format = cpu_to_be32(GFS2_FORMAT_LF);
Packit 6ef888
	leaf->lf_depth = cpu_to_be16(dip->i_di.di_depth - factor);
Packit 6ef888
Packit 6ef888
	/* initialize the first dirent on the new leaf block */
Packit 6ef888
	dent = (struct gfs2_dirent *)(nbh->b_data + sizeof(struct gfs2_leaf));
Packit 6ef888
	dent->de_rec_len = cpu_to_be16(dip->i_sbd->bsize -
Packit 6ef888
				       sizeof(struct gfs2_leaf));
Packit 6ef888
	bmodified(nbh);
Packit 6ef888
	brelse(nbh);
Packit 6ef888
Packit 6ef888
	/* pad the hash table with the new leaf block */
Packit 6ef888
	cpyptr = (uint64_t *)padbuf;
Packit 6ef888
	for (i = start_lindex; i < end_lindex; i++) {
Packit 6ef888
		*cpyptr = cpu_to_be64(*bn);
Packit 6ef888
		cpyptr++;
Packit 6ef888
	}
Packit 6ef888
	pad_size = num_copies * sizeof(uint64_t);
Packit 6ef888
	log_err(_("Writing to the hash table of directory %lld "
Packit 6ef888
		  "(0x%llx) at index: 0x%x for 0x%lx pointers.\n"),
Packit 6ef888
		(unsigned long long)dip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)dip->i_di.di_num.no_addr,
Packit 6ef888
		start_lindex, (unsigned long)pad_size / sizeof(uint64_t));
Packit 6ef888
	if (dip->i_sbd->gfs1)
Packit 6ef888
		count = gfs1_writei(dip, padbuf, start_lindex *
Packit 6ef888
				    sizeof(uint64_t), pad_size);
Packit 6ef888
	else
Packit 6ef888
		count = gfs2_writei(dip, padbuf, start_lindex *
Packit 6ef888
				    sizeof(uint64_t), pad_size);
Packit 6ef888
	free(padbuf);
Packit 6ef888
	if (count != pad_size) {
Packit 6ef888
		log_err( _("Error: bad write while fixing directory leaf "
Packit 6ef888
			   "pointers.\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* pad_with_leafblks - pad a hash table with pointers to new leaf blocks
Packit 6ef888
 *
Packit 6ef888
 * @ip: pointer to the dinode structure
Packit 6ef888
 * @tbl: pointer to the hash table in memory
Packit 6ef888
 * @lindex: index location within the hash table to pad
Packit 6ef888
 * @len: number of pointers to be padded
Packit 6ef888
 */
Packit 6ef888
static void pad_with_leafblks(struct gfs2_inode *ip, uint64_t *tbl,
Packit 6ef888
			      int lindex, int len)
Packit 6ef888
{
Packit 6ef888
	int new_len, i;
Packit 6ef888
	uint32_t proper_start = lindex;
Packit 6ef888
	uint64_t new_leaf_blk;
Packit 6ef888
Packit 6ef888
	log_err(_("Padding inode %llu (0x%llx) hash table at offset %d (0x%x) "
Packit 6ef888
		  "for %d pointers.\n"),
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr, lindex, lindex,
Packit 6ef888
		len);
Packit 6ef888
	while (len) {
Packit 6ef888
		new_len = 1;
Packit 6ef888
		/* Determine the next factor of 2 down from extras. We can't
Packit 6ef888
		   just write out a leaf block on a power-of-two boundary.
Packit 6ef888
		   We also need to make sure it has a length that will
Packit 6ef888
		   ensure a "proper start" block as well. */
Packit 6ef888
		while ((new_len << 1) <= len) {
Packit 6ef888
			/* Translation: If doubling the size of the new leaf
Packit 6ef888
			   will make its start boundary wrong, we have to
Packit 6ef888
			   settle for a smaller length (and iterate more). */
Packit 6ef888
			proper_start = (lindex & ~((new_len << 1) - 1));
Packit 6ef888
			if (lindex != proper_start)
Packit 6ef888
				break;
Packit 6ef888
			new_len <<= 1;
Packit 6ef888
		}
Packit 6ef888
		write_new_leaf(ip, lindex, new_len, "after", &new_leaf_blk);
Packit 6ef888
		log_err(_("New leaf block was allocated at %llu (0x%llx) for "
Packit 6ef888
			  "index %d (0x%x), length %d\n"),
Packit 6ef888
			(unsigned long long)new_leaf_blk,
Packit 6ef888
			(unsigned long long)new_leaf_blk,
Packit 6ef888
			lindex, lindex, new_len);
Packit 6ef888
		fsck_bitmap_set(ip, new_leaf_blk, _("pad leaf"),
Packit 6ef888
				ip->i_sbd->gfs1 ?
Packit 6ef888
				GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
		/* Fix the hash table in memory to have the new leaf */
Packit 6ef888
		for (i = 0; i < new_len; i++)
Packit 6ef888
			tbl[lindex + i] = cpu_to_be64(new_leaf_blk);
Packit 6ef888
		len -= new_len;
Packit 6ef888
		lindex += new_len;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* lost_leaf - repair a leaf block that's on the wrong directory inode
Packit 6ef888
 *
Packit 6ef888
 * If the correct index is less than the starting index, we have a problem.
Packit 6ef888
 * Since we process the index sequentially, the previous index has already
Packit 6ef888
 * been processed, fixed, and is now correct. But this leaf wants to overwrite
Packit 6ef888
 * a previously written good leaf. The only thing we can do is move all the
Packit 6ef888
 * directory entries to lost+found so we don't overwrite the good leaf. Then
Packit 6ef888
 * we need to pad the gap we leave.
Packit 6ef888
 */
Packit 6ef888
static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno,
Packit 6ef888
		     int ref_count, int lindex, struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	char *filename;
Packit 6ef888
	char *bh_end = bh->b_data + ip->i_sbd->bsize;
Packit 6ef888
	struct gfs2_dirent de, *dent;
Packit 6ef888
	int error;
Packit 6ef888
	int isdir = 0;
Packit 6ef888
Packit 6ef888
	log_err(_("Leaf block %llu (0x%llx) seems to be out of place and its "
Packit 6ef888
		  "contents need to be moved to lost+found.\n"),
Packit 6ef888
		(unsigned long long)leafno, (unsigned long long)leafno);
Packit 6ef888
	if (!query( _("Attempt to fix it? (y/n) "))) {
Packit 6ef888
		log_err( _("Directory leaf was not fixed.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	make_sure_lf_exists(ip);
Packit 6ef888
Packit 6ef888
	dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
Packit 6ef888
	while (1) {
Packit 6ef888
		char tmp_name[PATH_MAX];
Packit 6ef888
Packit 6ef888
		memset(&de, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
		gfs2_dirent_in(&de, (char *)dent);
Packit 6ef888
		filename = (char *)dent + sizeof(struct gfs2_dirent);
Packit 6ef888
		memset(tmp_name, 0, sizeof(tmp_name));
Packit 6ef888
		if (de.de_name_len > sizeof(filename)) {
Packit 6ef888
			log_debug(_("Encountered bad filename length; "
Packit 6ef888
				    "stopped processing.\n"));
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		memcpy(tmp_name, filename, de.de_name_len);
Packit 6ef888
		if ((de.de_name_len == 1 && filename[0] == '.')) {
Packit 6ef888
			log_debug(_("Skipping entry '.'\n"));
Packit 6ef888
		} else if (de.de_name_len == 2 && filename[0] == '.' &&
Packit 6ef888
			   filename[1] == '.') {
Packit 6ef888
			log_debug(_("Skipping entry '..'\n"));
Packit 6ef888
		} else if (!de.de_inum.no_formal_ino) { /* sentinel */
Packit 6ef888
			log_debug(_("Skipping sentinel '%s'\n"), tmp_name);
Packit 6ef888
		} else {
Packit 6ef888
			uint32_t count;
Packit 6ef888
			struct dir_status ds = {0};
Packit 6ef888
			int q = 0;
Packit 6ef888
Packit 6ef888
			error = basic_dentry_checks(ip, dent, &de.de_inum,
Packit 6ef888
						    tmp_name, &count, &de,
Packit 6ef888
						    &ds, &q, bh, &isdir);
Packit 6ef888
			if (error) {
Packit 6ef888
				log_err(_("Not relocating corrupt entry "
Packit 6ef888
					  "\"%s\".\n"), tmp_name);
Packit 6ef888
			} else {
Packit 6ef888
				error = dir_add(lf_dip, filename,
Packit 6ef888
						de.de_name_len, &de.de_inum,
Packit 6ef888
						de.de_type);
Packit 6ef888
				if (error && error != -EEXIST) {
Packit 6ef888
					log_err(_("Error %d encountered while "
Packit 6ef888
						  "trying to relocate \"%s\" "
Packit 6ef888
						  "to lost+found.\n"), error,
Packit 6ef888
						tmp_name);
Packit 6ef888
					return error;
Packit 6ef888
				}
Packit 6ef888
				/* This inode is linked from lost+found */
Packit 6ef888
				incr_link_count(de.de_inum, lf_dip,
Packit 6ef888
						_("from lost+found"));
Packit 6ef888
				/* If it's a directory, lost+found is
Packit 6ef888
				   back-linked to it via .. */
Packit 6ef888
				if (isdir)
Packit 6ef888
					incr_link_count(lf_dip->i_di.di_num,
Packit 6ef888
							NULL,
Packit 6ef888
							_("to lost+found"));
Packit 6ef888
				log_err(_("Relocated \"%s\", block %llu "
Packit 6ef888
					  "(0x%llx) to lost+found.\n"),
Packit 6ef888
					tmp_name,
Packit 6ef888
					(unsigned long long)de.de_inum.no_addr,
Packit 6ef888
					(unsigned long long)de.de_inum.no_addr);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		if ((char *)dent + de.de_rec_len >= bh_end)
Packit 6ef888
			break;
Packit 6ef888
		dent = (struct gfs2_dirent *)((char *)dent + de.de_rec_len);
Packit 6ef888
	}
Packit 6ef888
	log_err(_("Directory entries from misplaced leaf block were relocated "
Packit 6ef888
		  "to lost+found.\n"));
Packit 6ef888
	/* Free the lost leaf. */
Packit 6ef888
	fsck_bitmap_set(ip, leafno, _("lost leaf"), GFS2_BLKST_FREE);
Packit 6ef888
	ip->i_di.di_blocks--;
Packit 6ef888
	bmodified(ip->i_bh);
Packit 6ef888
	/* Now we have to deal with the bad hash table entries pointing to the
Packit 6ef888
	   misplaced leaf block. But we can't just fill the gap with a single
Packit 6ef888
	   leaf. We have to write on nice power-of-two boundaries, and we have
Packit 6ef888
	   to pad out any extra pointers. */
Packit 6ef888
	pad_with_leafblks(ip, tbl, lindex, ref_count);
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit 6ef888
			      struct gfs2_dirent *prev_de,
Packit 6ef888
			      struct gfs2_buffer_head *bh, char *filename,
Packit 6ef888
			      uint32_t *count, int *lindex, void *priv)
Packit 6ef888
{
Packit 6ef888
	int q = 0;
Packit 6ef888
	char tmp_name[MAX_FILENAME];
Packit 6ef888
	struct gfs2_inum entry;
Packit 6ef888
	struct dir_status *ds = (struct dir_status *) priv;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	int error;
Packit 6ef888
	int isdir;
Packit 6ef888
Packit 6ef888
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
	gfs2_dirent_in(&dentry, (char *)dent);
Packit 6ef888
	de = &dentry;
Packit 6ef888
Packit 6ef888
	entry.no_addr = de->de_inum.no_addr;
Packit 6ef888
	entry.no_formal_ino = de->de_inum.no_formal_ino;
Packit 6ef888
Packit 6ef888
	/* Start of checks */
Packit 6ef888
	memset(tmp_name, 0, MAX_FILENAME);
Packit 6ef888
	if (de->de_name_len < MAX_FILENAME)
Packit 6ef888
		strncpy(tmp_name, filename, de->de_name_len);
Packit 6ef888
	else
Packit 6ef888
		strncpy(tmp_name, filename, MAX_FILENAME - 1);
Packit 6ef888
Packit 6ef888
	error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de,
Packit 6ef888
				    ds, &q, bh, &isdir);
Packit 6ef888
	if (error) {
Packit 6ef888
		dirent2_del(ip, bh, prev_de, dent);
Packit 6ef888
		log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
Packit 6ef888
		return 1;
Packit 6ef888
	} else {
Packit 6ef888
		(*count)++;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* pass2_repair_leaf - Warn the user of an error and ask permission to fix it
Packit 6ef888
 * Process a bad leaf pointer and ask to repair the first time.
Packit 6ef888
 * The repair process involves extending the previous leaf's entries
Packit 6ef888
 * so that they replace the bad ones.  We have to hack up the old
Packit 6ef888
 * leaf a bit, but it's better than deleting the whole directory,
Packit 6ef888
 * which is what used to happen before. */
Packit 6ef888
static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
Packit 6ef888
			     int lindex, int ref_count, const char *msg)
Packit 6ef888
{
Packit 6ef888
	int new_leaf_blks = 0, error, refs;
Packit 6ef888
	uint64_t bn = 0;
Packit 6ef888
Packit 6ef888
	log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
Packit 6ef888
		   " (0x%llx) %s.\n"),
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		 (unsigned long long)*leaf_no,
Packit 6ef888
		 (unsigned long long)*leaf_no, msg);
Packit 6ef888
	if (!query( _("Attempt to patch around it? (y/n) "))) {
Packit 6ef888
		log_err( _("Bad leaf left in place.\n"));
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
	/* We can only write leafs in quantities that are factors of
Packit 6ef888
	   two, since leaves are doubled, not added sequentially.
Packit 6ef888
	   So if we have a hole that's not a factor of 2, we have to
Packit 6ef888
	   break it down into separate leaf blocks that are. */
Packit 6ef888
	while (ref_count) {
Packit 6ef888
		refs = 1;
Packit 6ef888
		while (refs <= ref_count) {
Packit 6ef888
			if (refs * 2 > ref_count)
Packit 6ef888
				break;
Packit 6ef888
			refs *= 2;
Packit 6ef888
		}
Packit 6ef888
		error = write_new_leaf(ip, lindex, refs, _("replacing"), &bn);
Packit 6ef888
		if (error)
Packit 6ef888
			return error;
Packit 6ef888
Packit 6ef888
		new_leaf_blks++;
Packit 6ef888
		lindex += refs;
Packit 6ef888
		ref_count -= refs;
Packit 6ef888
	}
Packit 6ef888
	log_err( _("Directory Inode %llu (0x%llx) repaired.\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
out:
Packit 6ef888
	*leaf_no = bn;
Packit 6ef888
	return new_leaf_blks;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* The purpose of leafck_fxns is to provide a means for function fix_hashtable
Packit 6ef888
 * to do basic sanity checks on leaf blocks before manipulating them, for
Packit 6ef888
 * example, splitting them. If they're corrupt, splitting them or trying to
Packit 6ef888
 * move their contents can cause a segfault. We can't really use the standard
Packit 6ef888
 * pass2_fxns because that will do things we don't want. For example, it will
Packit 6ef888
 * find '.' and '..' and increment the directory link count, which would be
Packit 6ef888
 * done a second time when the dirent is really checked in pass2_fxns.
Packit 6ef888
 * We don't want it to do the "wrong leaf" thing, or set_parent_dir either.
Packit 6ef888
 * We just want a basic sanity check on pointers and lengths.
Packit 6ef888
 */
Packit 6ef888
struct metawalk_fxns leafck_fxns = {
Packit 6ef888
	.check_leaf_depth = check_leaf_depth,
Packit 6ef888
	.check_dentry = basic_check_dentry,
Packit 6ef888
	.repair_leaf = pass2_repair_leaf,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
/* fix_hashtable - fix a corrupt hash table
Packit 6ef888
 *
Packit 6ef888
 * The main intent of this function is to sort out hash table problems.
Packit 6ef888
 * That is, it needs to determine if leaf blocks are in the wrong place,
Packit 6ef888
 * if the count of pointers is wrong, and if there are extra pointers.
Packit 6ef888
 * Everything should be placed on correct power-of-two boundaries appropriate
Packit 6ef888
 * to their leaf depth, and extra pointers should be correctly padded with new
Packit 6ef888
 * leaf blocks.
Packit 6ef888
 *
Packit 6ef888
 * @ip: the directory dinode structure pointer
Packit 6ef888
 * @tbl: hash table that's already read into memory
Packit 6ef888
 * @hsize: hash table size, as dictated by the dinode's di_depth
Packit 6ef888
 * @leafblk: the leaf block number that appears at this lindex in the tbl
Packit 6ef888
 * @lindex: leaf index that has a problem
Packit 6ef888
 * @proper_start: where this leaf's pointers should start, as far as the
Packit 6ef888
 *                hash table is concerned (sight unseen; trusting the leaf
Packit 6ef888
 *                really belongs here).
Packit 6ef888
 * @len: count of pointers in the hash table to this leafblk
Packit 6ef888
 * @proper_len: pointer to return the proper number of pointers, as the kernel
Packit 6ef888
 *              calculates it, based on the leaf depth.
Packit 6ef888
 * @factor: the proper depth, given this number of pointers (rounded down).
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 - no changes made, or X if changes were made
Packit 6ef888
 */
Packit 6ef888
static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
Packit 6ef888
			 uint64_t leafblk, int lindex, uint32_t proper_start,
Packit 6ef888
			 int len, int *proper_len, int factor)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *lbh;
Packit 6ef888
	struct gfs2_leaf leaf;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	int changes = 0, error, i, extras, hash_index;
Packit 6ef888
	uint64_t new_leaf_blk;
Packit 6ef888
	uint64_t leaf_no;
Packit 6ef888
	uint32_t leaf_proper_start;
Packit 6ef888
Packit 6ef888
	*proper_len = len;
Packit 6ef888
	log_err(_("Dinode %llu (0x%llx) has a hash table error at index "
Packit 6ef888
		  "0x%x, length 0x%x: leaf block %llu (0x%llx)\n"),
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
		(unsigned long long)ip->i_di.di_num.no_addr, lindex, len,
Packit 6ef888
		(unsigned long long)leafblk, (unsigned long long)leafblk);
Packit 6ef888
	if (!query( _("Fix the hash table? (y/n) "))) {
Packit 6ef888
		log_err(_("Hash table not fixed.\n"));
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	memset(&leaf, 0, sizeof(leaf));
Packit 6ef888
	leaf_no = leafblk;
Packit 6ef888
	error = check_leaf(ip, lindex, &leafck_fxns, &leaf_no, &leaf, &len;;
Packit 6ef888
	if (error) {
Packit 6ef888
		log_debug("Leaf repaired while fixing the hash table.\n");
Packit 6ef888
		error = 0;
Packit 6ef888
	}
Packit 6ef888
	lbh = bread(ip->i_sbd, leafblk);
Packit 6ef888
	/* If the leaf's depth is out of range for this dinode, it's obviously
Packit 6ef888
	   attached to the wrong dinode. Move the dirents to lost+found. */
Packit 6ef888
	if (leaf.lf_depth > ip->i_di.di_depth) {
Packit 6ef888
		log_err(_("This leaf block's depth (%d) is too big for this "
Packit 6ef888
			  "dinode's depth (%d)\n"),
Packit 6ef888
			leaf.lf_depth, ip->i_di.di_depth);
Packit 6ef888
		error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		return error;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
	de = (struct gfs2_dirent *)(lbh->b_data + sizeof(struct gfs2_leaf));
Packit 6ef888
	gfs2_dirent_in(&dentry, (char *)de);
Packit 6ef888
Packit 6ef888
	/* If this is an empty leaf, we can just delete it and pad. */
Packit 6ef888
	if ((dentry.de_rec_len == cpu_to_be16(ip->i_sbd->bsize -
Packit 6ef888
					      sizeof(struct gfs2_leaf))) &&
Packit 6ef888
	    (dentry.de_inum.no_formal_ino == 0)) {
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		gfs2_free_block(ip->i_sbd, leafblk);
Packit 6ef888
		log_err(_("Out of place leaf block %llu (0x%llx) had no "
Packit 6ef888
			"entries, so it was deleted.\n"),
Packit 6ef888
			(unsigned long long)leafblk,
Packit 6ef888
			(unsigned long long)leafblk);
Packit 6ef888
		pad_with_leafblks(ip, tbl, lindex, len);
Packit 6ef888
		log_err(_("Reprocessing index 0x%x (case 1).\n"), lindex);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* Calculate the proper number of pointers based on the leaf depth. */
Packit 6ef888
	*proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
Packit 6ef888
Packit 6ef888
	/* Look at the first dirent and check its hash value to see if it's
Packit 6ef888
	   at the proper starting offset. */
Packit 6ef888
	hash_index = hash_table_index(dentry.de_hash, ip);
Packit 6ef888
	/* Need to use len here, not *proper_len because the leaf block may
Packit 6ef888
	   be valid within the range, but starts too soon in the hash table. */
Packit 6ef888
	if (hash_index < lindex ||  hash_index > lindex + len) {
Packit 6ef888
		log_err(_("This leaf block has hash index %d, which is out of "
Packit 6ef888
			  "bounds for where it appears in the hash table "
Packit 6ef888
			  "(%d - %d)\n"),
Packit 6ef888
			hash_index, lindex, lindex + *proper_len);
Packit 6ef888
		error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		return error;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* Now figure out where this leaf should start, and pad any pointers
Packit 6ef888
	   up to that point with new leaf blocks. */
Packit 6ef888
	leaf_proper_start = (hash_index & ~(*proper_len - 1));
Packit 6ef888
	if (lindex < leaf_proper_start) {
Packit 6ef888
		log_err(_("Leaf pointers start at %d (0x%x), should be %d "
Packit 6ef888
			  "(%x).\n"), lindex, lindex,
Packit 6ef888
			leaf_proper_start, leaf_proper_start);
Packit 6ef888
		pad_with_leafblks(ip, tbl, lindex, leaf_proper_start - lindex);
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		return 1; /* reprocess the starting lindex */
Packit 6ef888
	}
Packit 6ef888
	/* If the proper start according to the leaf's hash index is later
Packit 6ef888
	   than the proper start according to the hash table, it's once
Packit 6ef888
	   again lost and we have to relocate it. The same applies if the
Packit 6ef888
	   leaf's hash index is prior to the proper state, but the leaf is
Packit 6ef888
	   already at its maximum depth. */
Packit 6ef888
	if ((leaf_proper_start < proper_start) ||
Packit 6ef888
	    ((*proper_len > len || lindex > leaf_proper_start) &&
Packit 6ef888
	     leaf.lf_depth == ip->i_di.di_depth)) {
Packit 6ef888
		log_err(_("Leaf block should start at 0x%x, but it appears at "
Packit 6ef888
			  "0x%x in the hash table.\n"), leaf_proper_start,
Packit 6ef888
			proper_start);
Packit 6ef888
		error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		return error;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* If we SHOULD have more pointers than we do, we can solve the
Packit 6ef888
	   problem by splitting the block to a lower depth. Then we may have
Packit 6ef888
	   the right number of pointers. If the leaf block pointers start
Packit 6ef888
	   later than they should, we can split the leaf to give it a smaller
Packit 6ef888
	   footprint in the hash table. */
Packit 6ef888
	if ((*proper_len > len || lindex > leaf_proper_start) &&
Packit 6ef888
	    ip->i_di.di_depth > leaf.lf_depth) {
Packit 6ef888
		log_err(_("For depth %d, length %d, the proper start is: "
Packit 6ef888
			  "0x%x.\n"), factor, len, proper_start);
Packit 6ef888
		changes++;
Packit 6ef888
		new_leaf_blk = find_free_blk(ip->i_sbd);
Packit 6ef888
		dir_split_leaf(ip, lindex, leafblk, lbh);
Packit 6ef888
		/* re-read the leaf to pick up dir_split_leaf's changes */
Packit 6ef888
		gfs2_leaf_in(&leaf, lbh->b_data);
Packit 6ef888
		*proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
Packit 6ef888
		log_err(_("Leaf block %llu (0x%llx) was split from length "
Packit 6ef888
			  "%d to %d\n"), (unsigned long long)leafblk,
Packit 6ef888
			(unsigned long long)leafblk, len, *proper_len);
Packit 6ef888
		if (*proper_len < 0) {
Packit 6ef888
			log_err(_("Programming error: proper_len=%d, "
Packit 6ef888
				  "di_depth = %d, lf_depth = %d.\n"),
Packit 6ef888
				*proper_len, ip->i_di.di_depth, leaf.lf_depth);
Packit 6ef888
			exit(FSCK_ERROR);
Packit 6ef888
		}
Packit 6ef888
		log_err(_("New split-off leaf block was allocated at %lld "
Packit 6ef888
			  "(0x%llx) for index %d (0x%x)\n"),
Packit 6ef888
			(unsigned long long)new_leaf_blk,
Packit 6ef888
			(unsigned long long)new_leaf_blk, lindex, lindex);
Packit 6ef888
		fsck_bitmap_set(ip, new_leaf_blk, _("split leaf"),
Packit 6ef888
				ip->i_sbd->gfs1 ?
Packit 6ef888
				GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit 6ef888
		log_err(_("Hash table repaired.\n"));
Packit 6ef888
		/* Fix up the hash table in memory to include the new leaf */
Packit 6ef888
		for (i = 0; i < *proper_len; i++)
Packit 6ef888
			tbl[lindex + i] = cpu_to_be64(new_leaf_blk);
Packit 6ef888
		if (*proper_len < (len >> 1)) {
Packit 6ef888
			log_err(_("One leaf split is not enough. The hash "
Packit 6ef888
				  "table will need to be reprocessed.\n"));
Packit 6ef888
			brelse(lbh);
Packit 6ef888
			return changes;
Packit 6ef888
		}
Packit 6ef888
		lindex += (*proper_len); /* skip the new leaf from the split */
Packit 6ef888
		len -= (*proper_len);
Packit 6ef888
	}
Packit 6ef888
	if (*proper_len < len) {
Packit 6ef888
		log_err(_("There are %d pointers, but leaf 0x%llx's "
Packit 6ef888
			  "depth, %d, only allows %d\n"),
Packit 6ef888
			len, (unsigned long long)leafblk, leaf.lf_depth,
Packit 6ef888
			*proper_len);
Packit 6ef888
	}
Packit 6ef888
	brelse(lbh);
Packit 6ef888
	/* At this point, lindex should be at the proper end of the pointers.
Packit 6ef888
	   Now we need to replace any extra duplicate pointers to the old
Packit 6ef888
	   (original) leafblk (that ran off the end) with new leaf blocks. */
Packit 6ef888
	lindex += (*proper_len); /* Skip past the normal good pointers */
Packit 6ef888
	len -= (*proper_len);
Packit 6ef888
	extras = 0;
Packit 6ef888
	for (i = 0; i < len; i++) {
Packit 6ef888
		if (be64_to_cpu(tbl[lindex + i]) == leafblk)
Packit 6ef888
			extras++;
Packit 6ef888
		else
Packit 6ef888
			break;
Packit 6ef888
	}
Packit 6ef888
	if (extras) {
Packit 6ef888
		log_err(_("Found %d extra pointers to leaf %llu (0x%llx)\n"),
Packit 6ef888
			extras, (unsigned long long)leafblk,
Packit 6ef888
			(unsigned long long)leafblk);
Packit 6ef888
		pad_with_leafblks(ip, tbl, lindex, extras);
Packit 6ef888
		log_err(_("Reprocessing index 0x%x (case 2).\n"), lindex);
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
	return changes;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* check_hash_tbl_dups - check for the same leaf in multiple places */
Packit 6ef888
static int check_hash_tbl_dups(struct gfs2_inode *ip, uint64_t *tbl,
Packit 6ef888
			       unsigned hsize, int lindex, int len)
Packit 6ef888
{
Packit 6ef888
	int l, len2;
Packit 6ef888
	uint64_t leafblk, leaf_no;
Packit 6ef888
	struct gfs2_buffer_head *lbh;
Packit 6ef888
	struct gfs2_leaf leaf;
Packit 6ef888
	struct gfs2_dirent dentry, *de;
Packit 6ef888
	int hash_index; /* index into the hash table based on the hash */
Packit 6ef888
Packit 6ef888
	leafblk = be64_to_cpu(tbl[lindex]);
Packit 6ef888
	for (l = 0; l < hsize; l++) {
Packit 6ef888
		if (l == lindex) { /* skip the valid reference */
Packit 6ef888
			l += len - 1;
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
		if (be64_to_cpu(tbl[l]) != leafblk)
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		for (len2 = 0; l + len2 < hsize; len2++) {
Packit 6ef888
			if (l + len2 == lindex)
Packit 6ef888
				break;
Packit 6ef888
			if (be64_to_cpu(tbl[l + len2]) != leafblk)
Packit 6ef888
				break;
Packit 6ef888
		}
Packit 6ef888
		log_err(_("Dinode %llu (0x%llx) has duplicate leaf pointers "
Packit 6ef888
			  "to block %llu (0x%llx) at offsets %u (0x%x) "
Packit 6ef888
			  "(for 0x%x) and %u (0x%x) (for 0x%x)\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)leafblk,
Packit 6ef888
			(unsigned long long)leafblk, lindex, lindex, len,
Packit 6ef888
			l, l, len2);
Packit 6ef888
Packit 6ef888
		/* See which set of references is valid: the one passed in
Packit 6ef888
		   or the duplicate we found. */
Packit 6ef888
		memset(&leaf, 0, sizeof(leaf));
Packit 6ef888
		leaf_no = leafblk;
Packit 6ef888
		if (!valid_block_ip(ip, leaf_no)) /* Checked later */
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		lbh = bread(ip->i_sbd, leafblk);
Packit 6ef888
		if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) { /* Chked later */
Packit 6ef888
			brelse(lbh);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
		de = (struct gfs2_dirent *)(lbh->b_data +
Packit 6ef888
					    sizeof(struct gfs2_leaf));
Packit 6ef888
		gfs2_dirent_in(&dentry, (char *)de);
Packit 6ef888
		hash_index = hash_table_index(dentry.de_hash, ip);
Packit 6ef888
		brelse(lbh);
Packit 6ef888
		/* check the duplicate ref first */
Packit 6ef888
		if (hash_index < l ||  hash_index > l + len2) {
Packit 6ef888
			log_err(_("This leaf block has hash index %d, which "
Packit 6ef888
				  "is out of bounds for lindex (%d - %d)\n"),
Packit 6ef888
				hash_index, l, l + len2);
Packit 6ef888
			if (!query( _("Fix the hash table? (y/n) "))) {
Packit 6ef888
				log_err(_("Hash table not fixed.\n"));
Packit 6ef888
				return 0;
Packit 6ef888
			}
Packit 6ef888
			/* Adjust the ondisk block count. The original value
Packit 6ef888
			   may have been correct without the duplicates but
Packit 6ef888
			   pass1 would have counted them and adjusted the
Packit 6ef888
			   count to include them. So we must subtract them. */
Packit 6ef888
			ip->i_di.di_blocks--;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
			pad_with_leafblks(ip, tbl, l, len2);
Packit 6ef888
		} else {
Packit 6ef888
			log_debug(_("Hash index 0x%x is the proper "
Packit 6ef888
				    "reference to leaf 0x%llx.\n"),
Packit 6ef888
				  l, (unsigned long long)leafblk);
Packit 6ef888
		}
Packit 6ef888
		/* Check the original ref: both references might be bad.
Packit 6ef888
		   If both were bad, just return and if we encounter it
Packit 6ef888
		   again, we'll treat it as new. If the original ref is not
Packit 6ef888
		   bad, keep looking for (and fixing) other instances. */
Packit 6ef888
		if (hash_index < lindex ||  hash_index > lindex + len) {
Packit 6ef888
			log_err(_("This leaf block has hash index %d, which "
Packit 6ef888
				  "is out of bounds for lindex (%d - %d).\n"),
Packit 6ef888
				hash_index, lindex, lindex + len);
Packit 6ef888
			if (!query( _("Fix the hash table? (y/n) "))) {
Packit 6ef888
				log_err(_("Hash table not fixed.\n"));
Packit 6ef888
				return 0;
Packit 6ef888
			}
Packit 6ef888
			ip->i_di.di_blocks--;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
			pad_with_leafblks(ip, tbl, lindex, len);
Packit 6ef888
			/* At this point we know both copies are bad, so we
Packit 6ef888
			   return to start fresh */
Packit 6ef888
			return -EFAULT;
Packit 6ef888
		} else {
Packit 6ef888
			log_debug(_("Hash index 0x%x is the proper "
Packit 6ef888
				    "reference to leaf 0x%llx.\n"),
Packit 6ef888
				  lindex, (unsigned long long)leafblk);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* check_hash_tbl - check that the hash table is sane
Packit 6ef888
 *
Packit 6ef888
 * We've got to make sure the hash table is sane. Each leaf needs to
Packit 6ef888
 * be counted a proper power of 2. We can't just have 3 pointers to a leaf.
Packit 6ef888
 * The number of pointers must correspond to the proper leaf depth, and they
Packit 6ef888
 * must all fall on power-of-two boundaries. The leaf block pointers all need
Packit 6ef888
 * to fall properly on these boundaries, otherwise the kernel code's
Packit 6ef888
 * calculations will land it on the wrong leaf block while it's searching,
Packit 6ef888
 * and the result will be files you can see with ls, but can't open, delete
Packit 6ef888
 * or use them.
Packit 6ef888
 *
Packit 6ef888
 * The goal of this function is to check the hash table to make sure the
Packit 6ef888
 * boundaries and lengths all line up properly, and if not, to fix it.
Packit 6ef888
 *
Packit 6ef888
 * Note: There's a delicate balance here, because this function gets called
Packit 6ef888
 *       BEFORE leaf blocks are checked by function check_leaf from function
Packit 6ef888
 *       check_leaf_blks: the hash table has to be sane before we can start
Packit 6ef888
 *       checking all the leaf blocks. And yet if there's hash table corruption
Packit 6ef888
 *       we may need to reference leaf blocks to fix it, which means we need
Packit 6ef888
 *       to check and/or fix a leaf block along the way.
Packit 6ef888
 */
Packit 6ef888
static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
Packit 6ef888
			  unsigned hsize, void *private)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
	int lindex, len, proper_len, i, changes = 0;
Packit 6ef888
	uint64_t leafblk;
Packit 6ef888
	struct gfs2_leaf leaf;
Packit 6ef888
	struct gfs2_buffer_head *lbh;
Packit 6ef888
	int factor;
Packit 6ef888
	uint32_t proper_start;
Packit 6ef888
	int anomaly;
Packit 6ef888
Packit 6ef888
	lindex = 0;
Packit 6ef888
	while (lindex < hsize) {
Packit 6ef888
		if (fsck_abort)
Packit 6ef888
			return changes;
Packit 6ef888
		len = 1;
Packit 6ef888
		factor = 0;
Packit 6ef888
		leafblk = be64_to_cpu(tbl[lindex]);
Packit 6ef888
		anomaly = 0;
Packit 6ef888
		while (lindex + (len << 1) - 1 < hsize) {
Packit 6ef888
			uint32_t next_proper_start;
Packit 6ef888
			if (be64_to_cpu(tbl[lindex + (len << 1) - 1]) !=
Packit 6ef888
			    leafblk)
Packit 6ef888
				break;
Packit 6ef888
			next_proper_start = (lindex & ~((len << 1) - 1));
Packit 6ef888
			if (lindex != next_proper_start)
Packit 6ef888
				anomaly = 1;
Packit 6ef888
			/* Check if there are other values written between
Packit 6ef888
			   here and the next factor. */
Packit 6ef888
			for (i = len; !anomaly && i + lindex < hsize &&
Packit 6ef888
				     i < (len << 1); i++)
Packit 6ef888
				if (be64_to_cpu(tbl[lindex + i]) != leafblk)
Packit 6ef888
					anomaly = 1;
Packit 6ef888
			if (anomaly)
Packit 6ef888
				break;
Packit 6ef888
			len <<= 1;
Packit 6ef888
			factor++;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* Check for leftover pointers after the factor of two: */
Packit 6ef888
		proper_len = len; /* A factor of 2 that fits nicely */
Packit 6ef888
		while (lindex + len < hsize &&
Packit 6ef888
		       be64_to_cpu(tbl[lindex + len]) == leafblk)
Packit 6ef888
			len++;
Packit 6ef888
Packit 6ef888
		/* See if that leaf block is valid. If not, write a new one
Packit 6ef888
		   that falls on a proper boundary. If it doesn't naturally,
Packit 6ef888
		   we may need more. */
Packit 6ef888
		if (!valid_block_ip(ip, leafblk)) {
Packit 6ef888
			uint64_t new_leafblk;
Packit 6ef888
Packit 6ef888
			log_err(_("Dinode %llu (0x%llx) has bad leaf pointers "
Packit 6ef888
				  "at offset %d for %d\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
				lindex, len);
Packit 6ef888
			if (!query( _("Fix the hash table? (y/n) "))) {
Packit 6ef888
				log_err(_("Hash table not fixed.\n"));
Packit 6ef888
				lindex += len;
Packit 6ef888
				continue;
Packit 6ef888
			}
Packit 6ef888
			error = write_new_leaf(ip, lindex, proper_len,
Packit 6ef888
					       _("replacing"), &new_leafblk);
Packit 6ef888
			if (error)
Packit 6ef888
				return error;
Packit 6ef888
Packit 6ef888
			for (i = lindex; i < lindex + proper_len; i++)
Packit 6ef888
				tbl[i] = cpu_to_be64(new_leafblk);
Packit 6ef888
			lindex += proper_len;
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (check_hash_tbl_dups(ip, tbl, hsize, lindex, len))
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		/* Make sure they call on proper leaf-split boundaries. This
Packit 6ef888
		   is the calculation used by the kernel, and dir_split_leaf */
Packit 6ef888
		proper_start = (lindex & ~(proper_len - 1));
Packit 6ef888
		if (lindex != proper_start) {
Packit 6ef888
			log_debug(_("lindex 0x%llx is not a proper starting "
Packit 6ef888
				    "point for leaf %llu (0x%llx): 0x%llx\n"),
Packit 6ef888
				  (unsigned long long)lindex,
Packit 6ef888
				  (unsigned long long)leafblk,
Packit 6ef888
				  (unsigned long long)leafblk,
Packit 6ef888
				  (unsigned long long)proper_start);
Packit 6ef888
			changes = fix_hashtable(ip, tbl, hsize, leafblk,
Packit 6ef888
						lindex, proper_start, len,
Packit 6ef888
						&proper_len, factor);
Packit 6ef888
			/* Check if we need to split more leaf blocks */
Packit 6ef888
			if (changes) {
Packit 6ef888
				if (proper_len < (len >> 1))
Packit 6ef888
					log_err(_("More leaf splits are "
Packit 6ef888
						  "needed; "));
Packit 6ef888
				log_err(_("Reprocessing index 0x%x (case 3).\n"),
Packit 6ef888
					lindex);
Packit 6ef888
				continue; /* Make it reprocess the lindex */
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		/* Check for extra pointers to this leaf. At this point, len
Packit 6ef888
		   is the number of pointers we have. proper_len is the proper
Packit 6ef888
		   number of pointers if the hash table is assumed correct.
Packit 6ef888
		   Function fix_hashtable will read in the leaf block and
Packit 6ef888
		   determine the "actual" proper length based on the leaf
Packit 6ef888
		   depth, and adjust the hash table accordingly. */
Packit 6ef888
		if (len != proper_len) {
Packit 6ef888
			log_err(_("Length %d (0x%x) is not a proper length "
Packit 6ef888
				  "for leaf %llu (0x%llx). Valid boundary "
Packit 6ef888
				  "assumed to be %d (0x%x).\n"), len, len,
Packit 6ef888
				(unsigned long long)leafblk,
Packit 6ef888
				(unsigned long long)leafblk,
Packit 6ef888
				proper_len, proper_len);
Packit 6ef888
			lbh = bread(ip->i_sbd, leafblk);
Packit 6ef888
			gfs2_leaf_in(&leaf, lbh->b_data);
Packit 6ef888
			if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) ||
Packit 6ef888
			    leaf.lf_depth > ip->i_di.di_depth)
Packit 6ef888
				leaf.lf_depth = factor;
Packit 6ef888
			brelse(lbh);
Packit 6ef888
			changes = fix_hashtable(ip, tbl, hsize, leafblk,
Packit 6ef888
						lindex, lindex, len,
Packit 6ef888
						&proper_len, leaf.lf_depth);
Packit 6ef888
			/* If fixing the hash table made changes, we can no
Packit 6ef888
			   longer count on the leaf block pointers all pointing
Packit 6ef888
			   to the same leaf (which is checked below). To avoid
Packit 6ef888
			   flagging another error, reprocess the offset. */
Packit 6ef888
			if (changes) {
Packit 6ef888
				log_err(_("Reprocessing index 0x%x (case 4).\n"),
Packit 6ef888
					lindex);
Packit 6ef888
				continue; /* Make it reprocess the lindex */
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* Now make sure they're all the same pointer */
Packit 6ef888
		for (i = lindex; i < lindex + proper_len; i++) {
Packit 6ef888
			if (fsck_abort)
Packit 6ef888
				return changes;
Packit 6ef888
Packit 6ef888
			if (be64_to_cpu(tbl[i]) == leafblk) /* No problem */
Packit 6ef888
				continue;
Packit 6ef888
Packit 6ef888
			log_err(_("Dinode %llu (0x%llx) has a hash table "
Packit 6ef888
				  "inconsistency at index %d (0x%x) for %d\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
				i, i, len);
Packit 6ef888
			if (!query( _("Fix the hash table? (y/n) "))) {
Packit 6ef888
				log_err(_("Hash table not fixed.\n"));
Packit 6ef888
				continue;
Packit 6ef888
			}
Packit 6ef888
			changes++;
Packit 6ef888
			/* Now we have to determine if the hash table is
Packit 6ef888
			   corrupt, or if the leaf has the wrong depth. */
Packit 6ef888
			lbh = bread(ip->i_sbd, leafblk);
Packit 6ef888
			gfs2_leaf_in(&leaf, lbh->b_data);
Packit 6ef888
			brelse(lbh);
Packit 6ef888
			/* Calculate the expected pointer count based on the
Packit 6ef888
			   leaf depth. */
Packit 6ef888
			proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
Packit 6ef888
			if (proper_len != len) {
Packit 6ef888
				log_debug(_("Length 0x%x is not proper for "
Packit 6ef888
					    "leaf %llu (0x%llx): 0x%x\n"),
Packit 6ef888
					  len, (unsigned long long)leafblk,
Packit 6ef888
					  (unsigned long long)leafblk,
Packit 6ef888
					  proper_len);
Packit 6ef888
				changes = fix_hashtable(ip, tbl, hsize,
Packit 6ef888
							leafblk, lindex,
Packit 6ef888
							lindex, len,
Packit 6ef888
							&proper_len,
Packit 6ef888
							leaf.lf_depth);
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		lindex += proper_len;
Packit 6ef888
	}
Packit 6ef888
	if (!error && changes)
Packit 6ef888
		error = 1;
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns pass2_fxns = {
Packit 6ef888
	.private = NULL,
Packit 6ef888
	.check_leaf_depth = check_leaf_depth,
Packit 6ef888
	.check_leaf = NULL,
Packit 6ef888
	.check_metalist = NULL,
Packit 6ef888
	.check_data = NULL,
Packit 6ef888
	.check_eattr_indir = check_eattr_indir,
Packit 6ef888
	.check_eattr_leaf = check_eattr_leaf,
Packit 6ef888
	.check_dentry = check_dentry,
Packit 6ef888
	.check_eattr_entry = NULL,
Packit 6ef888
	.check_hash_tbl = check_hash_tbl,
Packit 6ef888
	.repair_leaf = pass2_repair_leaf,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
static int check_metalist_qc(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 meta_is_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock,
Packit 6ef888
			 uint64_t block, void *private,
Packit 6ef888
			 struct gfs2_buffer_head *bbh, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
Packit 6ef888
	/* At this point, basic data block checks have already been done,
Packit 6ef888
	   so we only need to make sure they're QC blocks. */
Packit 6ef888
	if (!valid_block_ip(ip, block))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	bh = bread(ip->i_sbd, block);
Packit 6ef888
	if (gfs2_check_meta(bh, GFS2_METATYPE_QC) != 0) {
Packit 6ef888
		log_crit(_("Error: quota_change block at %lld (0x%llx) is "
Packit 6ef888
			   "the wrong metadata type.\n"),
Packit 6ef888
			 (unsigned long long)block, (unsigned long long)block);
Packit 6ef888
		brelse(bh);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	brelse(bh);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct metawalk_fxns quota_change_fxns = {
Packit 6ef888
	.check_metalist = check_metalist_qc,
Packit 6ef888
	.check_data = check_data_qc,
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
/* check_pernode_for - verify a file within the system per_node directory
Packit 6ef888
 * @x - index number X
Packit 6ef888
 * @per_node - pointer to the per_node inode
Packit 6ef888
 * @fn - system file name
Packit 6ef888
 * @filelen - the file length the system file needs to be
Packit 6ef888
 * @multiple - the file length must be a multiple (versus the exact value)
Packit 6ef888
 * @pass - a metawalk function for checking the data blocks (if any)
Packit 6ef888
 * @builder - a rebuild function for the file
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 if all went well, else error. */
Packit 6ef888
static int check_pernode_for(int x, struct gfs2_inode *pernode, const char *fn,
Packit 6ef888
			     unsigned long long filelen, int multiple,
Packit 6ef888
			     struct metawalk_fxns *pass,
Packit 6ef888
			     int builder(struct gfs2_inode *per_node,
Packit 6ef888
					 unsigned int j))
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	int error, valid_size = 1;
Packit 6ef888
Packit 6ef888
	log_debug(_("Checking system file %s\n"), fn);
Packit 6ef888
	error = gfs2_lookupi(pernode, fn, strlen(fn), &ip);
Packit 6ef888
	if (error) {
Packit 6ef888
		log_err(_("System file %s is missing.\n"), fn);
Packit 6ef888
		if (!query( _("Rebuild the system file? (y/n) ")))
Packit 6ef888
			return 0;
Packit 6ef888
		goto build_it;
Packit 6ef888
	}
Packit 6ef888
	if (!ip->i_di.di_size)
Packit 6ef888
		valid_size = 0;
Packit 6ef888
	else if (!multiple && ip->i_di.di_size != filelen)
Packit 6ef888
		valid_size = 0;
Packit 6ef888
	else if (multiple && (ip->i_di.di_size % filelen))
Packit 6ef888
		valid_size = 0;
Packit 6ef888
	if (!valid_size) {
Packit 6ef888
		log_err(_("System file %s has an invalid size. Is %llu, "
Packit 6ef888
			  "should be %llu.\n"), fn, ip->i_di.di_size, filelen);
Packit 6ef888
		if (!query( _("Rebuild the system file? (y/n) ")))
Packit 6ef888
			goto out_good;
Packit 6ef888
		fsck_inode_put(&ip);
Packit 6ef888
		goto build_it;
Packit 6ef888
	}
Packit 6ef888
	if (pass) {
Packit 6ef888
		error = check_metatree(ip, pass);
Packit 6ef888
		if (!error)
Packit 6ef888
			goto out_good;
Packit 6ef888
		log_err(_("System file %s has bad contents.\n"), fn);
Packit 6ef888
		if (!query( _("Delete and rebuild the system file? (y/n) ")))
Packit 6ef888
			goto out_good;
Packit 6ef888
		check_metatree(ip, &pass2_fxns_delete);
Packit 6ef888
		fsck_inode_put(&ip);
Packit 6ef888
		gfs2_dirent_del(pernode, fn, strlen(fn));
Packit 6ef888
		goto build_it;
Packit 6ef888
	}
Packit 6ef888
out_good:
Packit 6ef888
	fsck_inode_put(&ip);
Packit 6ef888
	return 0;
Packit 6ef888
Packit 6ef888
build_it:
Packit 6ef888
	if (builder(pernode, x)) {
Packit 6ef888
		log_err(_("Error building %s\n"), fn);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	error = gfs2_lookupi(pernode, fn, strlen(fn), &ip);
Packit 6ef888
	if (error) {
Packit 6ef888
		log_err(_("Error rebuilding %s.\n"), fn);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	fsck_bitmap_set(ip, ip->i_di.di_num.no_addr, fn, GFS2_BLKST_DINODE);
Packit 6ef888
	log_err(_("System file %s rebuilt.\n"), fn);
Packit 6ef888
	goto out_good;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Check system directory inode                                           */
Packit 6ef888
/* Should work for all system directories: root, master, jindex, per_node */
Packit 6ef888
static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
Packit 6ef888
		     int builder(struct gfs2_sbd *sdp))
Packit 6ef888
{
Packit 6ef888
	uint64_t iblock = 0;
Packit 6ef888
	struct dir_status ds = {0};
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	log_info( _("Checking system directory inode '%s'\n"), dirname);
Packit 6ef888
Packit 6ef888
	if (!sysinode) {
Packit 6ef888
		log_err( _("Failed to check '%s': sysinode is null\n"), dirname);
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	iblock = sysinode->i_di.di_num.no_addr;
Packit 6ef888
	ds.q = bitmap_type(sysinode->i_sbd, iblock);
Packit 6ef888
Packit 6ef888
	pass2_fxns.private = (void *) &ds;
Packit 6ef888
	if (ds.q == GFS2_BLKST_FREE) {
Packit 6ef888
		/* First check that the directory's metatree is valid */
Packit 6ef888
		error = check_metatree(sysinode, &pass2_fxns);
Packit 6ef888
		if (error < 0) {
Packit 6ef888
			stack;
Packit 6ef888
			return error;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	error = check_dir(sysinode->i_sbd, sysinode, &pass2_fxns);
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	if (error < 0) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (error > 0)
Packit 6ef888
		fsck_bitmap_set(sysinode, iblock, dirname, GFS2_BLKST_FREE);
Packit 6ef888
Packit 6ef888
	if (check_inode_eattr(sysinode, &pass2_fxns)) {
Packit 6ef888
		stack;
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if (!ds.dotdir) {
Packit 6ef888
		log_err( _("No '.' entry found for %s directory.\n"), dirname);
Packit 6ef888
		if (query( _("Is it okay to add '.' entry? (y/n) "))) {
Packit 6ef888
			log_warn( _("Adding '.' entry\n"));
Packit 6ef888
			error = dir_add(sysinode, ".", 1, &(sysinode->i_di.di_num),
Packit 6ef888
			                (sysinode->i_sbd->gfs1 ? GFS_FILE_DIR : DT_DIR));
Packit 6ef888
			if (error) {
Packit 6ef888
				log_err(_("Error adding directory %s: %s\n"), "'.'",
Packit 6ef888
				         strerror(errno));
Packit 6ef888
				return -errno;
Packit 6ef888
			}
Packit 6ef888
			/* This system inode is linked to itself via '.' */
Packit 6ef888
			incr_link_count(sysinode->i_di.di_num, sysinode,
Packit 6ef888
					"sysinode \".\"");
Packit 6ef888
			ds.entry_count++;
Packit 6ef888
		} else
Packit 6ef888
			log_err( _("The directory was not fixed.\n"));
Packit 6ef888
	}
Packit 6ef888
	if (sysinode->i_di.di_entries != ds.entry_count) {
Packit 6ef888
		log_err( _("%s inode %llu (0x%llx"
Packit 6ef888
			"): Entries is %d - should be %d\n"), dirname,
Packit 6ef888
			(unsigned long long)sysinode->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)sysinode->i_di.di_num.no_addr,
Packit 6ef888
			sysinode->i_di.di_entries, ds.entry_count);
Packit 6ef888
		if (query( _("Fix entries for %s inode %llu (0x%llx)? (y/n) "),
Packit 6ef888
			  dirname,
Packit 6ef888
			  (unsigned long long)sysinode->i_di.di_num.no_addr,
Packit 6ef888
			  (unsigned long long)sysinode->i_di.di_num.no_addr)) {
Packit 6ef888
			sysinode->i_di.di_entries = ds.entry_count;
Packit 6ef888
			bmodified(sysinode->i_bh);
Packit 6ef888
			log_warn( _("Entries updated\n"));
Packit 6ef888
		} else {
Packit 6ef888
			log_err( _("Entries for inode %llu (0x%llx"
Packit 6ef888
				") left out of sync\n"),
Packit 6ef888
				(unsigned long long)
Packit 6ef888
				sysinode->i_di.di_num.no_addr,
Packit 6ef888
				(unsigned long long)
Packit 6ef888
				sysinode->i_di.di_num.no_addr);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	error = 0;
Packit 6ef888
	if (sysinode == sysinode->i_sbd->md.pinode) {
Packit 6ef888
		int j;
Packit 6ef888
		char fn[64];
Packit 6ef888
Packit 6ef888
		/* Make sure all the per_node files are there, and valid */
Packit 6ef888
		for (j = 0; j < sysinode->i_sbd->md.journals; j++) {
Packit 6ef888
			sprintf(fn, "inum_range%d", j);
Packit 6ef888
			error += check_pernode_for(j, sysinode, fn, 16, 0,
Packit 6ef888
						   NULL, build_inum_range);
Packit 6ef888
			sprintf(fn, "statfs_change%d", j);
Packit 6ef888
			error += check_pernode_for(j, sysinode, fn, 24, 0,
Packit 6ef888
						   NULL, build_statfs_change);
Packit 6ef888
			sprintf(fn, "quota_change%d", j);
Packit 6ef888
			error += check_pernode_for(j, sysinode, fn, 1048576, 1,
Packit 6ef888
						   &quota_change_fxns,
Packit 6ef888
						   build_quota_change);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * is_system_dir - determine if a given block is for a system directory.
Packit 6ef888
 */
Packit 6ef888
static inline int is_system_dir(struct gfs2_sbd *sdp, uint64_t block)
Packit 6ef888
{
Packit 6ef888
	if (block == sdp->md.rooti->i_di.di_num.no_addr)
Packit 6ef888
		return TRUE;
Packit 6ef888
	if (sdp->gfs1)
Packit 6ef888
		return FALSE;
Packit 6ef888
	if (block == sdp->md.jiinode->i_di.di_num.no_addr ||
Packit 6ef888
	    block == sdp->md.pinode->i_di.di_num.no_addr ||
Packit 6ef888
	    block == sdp->master_dir->i_di.di_num.no_addr)
Packit 6ef888
		return TRUE;
Packit 6ef888
	return FALSE;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int pass2_check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	uint64_t dirblk = ip->i_di.di_num.no_addr;
Packit 6ef888
	struct dir_status ds = {0};
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	pass2_fxns.private = &ds;
Packit 6ef888
	error = check_dir(sdp, ip, &pass2_fxns);
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	if (error < 0) {
Packit 6ef888
		stack;
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	if (error > 0) {
Packit 6ef888
		struct dir_info *di;
Packit 6ef888
Packit 6ef888
		di = dirtree_find(dirblk);
Packit 6ef888
		if (!di) {
Packit 6ef888
			stack;
Packit 6ef888
			return FSCK_ERROR;
Packit 6ef888
		}
Packit 6ef888
		if (query(_("Remove directory entry for bad inode "
Packit 6ef888
		            "%llu (0x%llx) in %llu (0x%llx)? (y/n)"),
Packit 6ef888
			  (unsigned long long)dirblk,
Packit 6ef888
			  (unsigned long long)dirblk,
Packit 6ef888
			  (unsigned long long)di->treewalk_parent,
Packit 6ef888
			  (unsigned long long)di->treewalk_parent)) {
Packit 6ef888
			error = remove_dentry_from_dir(sdp, di->treewalk_parent, dirblk);
Packit 6ef888
			if (error < 0) {
Packit 6ef888
				stack;
Packit 6ef888
				return FSCK_ERROR;
Packit 6ef888
			}
Packit 6ef888
			if (error > 0) {
Packit 6ef888
				log_warn(_("Unable to find dentry for %llu (0x%llx) "
Packit 6ef888
				           "in %llu (0x%llx)\n"),
Packit 6ef888
					  (unsigned long long)dirblk,
Packit 6ef888
					  (unsigned long long)dirblk,
Packit 6ef888
					  (unsigned long long)di->treewalk_parent,
Packit 6ef888
					  (unsigned long long)di->treewalk_parent);
Packit 6ef888
			}
Packit 6ef888
			log_warn(_("Directory entry removed\n"));
Packit 6ef888
		} else
Packit 6ef888
			log_err(_("Directory entry to invalid inode remains.\n"));
Packit 6ef888
Packit 6ef888
		log_debug(_("Directory block %lld (0x%llx) is now marked as 'invalid'\n"),
Packit 6ef888
			   (unsigned long long)dirblk, (unsigned long long)dirblk);
Packit 6ef888
		check_n_fix_bitmap(sdp, ip->i_rgd, dirblk, 0, GFS2_BLKST_FREE);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!ds.dotdir) {
Packit 6ef888
		log_err(_("No '.' entry found for directory inode at block %llu (0x%llx)\n"),
Packit 6ef888
			(unsigned long long)dirblk, (unsigned long long)dirblk);
Packit 6ef888
Packit 6ef888
		if (query( _("Is it okay to add '.' entry? (y/n) "))) {
Packit 6ef888
			error = dir_add(ip, ".", 1, &(ip->i_di.di_num),
Packit 6ef888
					(sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
Packit 6ef888
			if (error) {
Packit 6ef888
				log_err(_("Error adding directory %s: %s\n"), "'.'",
Packit 6ef888
					strerror(errno));
Packit 6ef888
				return -errno;
Packit 6ef888
			}
Packit 6ef888
			/* directory links to itself via '.' */
Packit 6ef888
			incr_link_count(ip->i_di.di_num, ip, _("\". (itself)\""));
Packit 6ef888
			ds.entry_count++;
Packit 6ef888
			log_err(_("The directory was fixed.\n"));
Packit 6ef888
		} else {
Packit 6ef888
			log_err(_("The directory was not fixed.\n"));
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!fsck_abort && ip->i_di.di_entries != ds.entry_count) {
Packit 6ef888
		log_err(_("Entries is %d - should be %d for inode block %llu (0x%llx)\n"),
Packit 6ef888
			ip->i_di.di_entries, ds.entry_count,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr,
Packit 6ef888
			(unsigned long long)ip->i_di.di_num.no_addr);
Packit 6ef888
		if (query(_("Fix the entry count? (y/n) "))) {
Packit 6ef888
			ip->i_di.di_entries = ds.entry_count;
Packit 6ef888
			bmodified(ip->i_bh);
Packit 6ef888
		} else {
Packit 6ef888
			log_err(_("The entry count was not fixed.\n"));
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return FSCK_OK;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* What i need to do in this pass is check that the dentries aren't
Packit 6ef888
 * pointing to invalid blocks...and verify the contents of each
Packit 6ef888
 * directory. and start filling in the directory info structure*/
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * pass2 - check pathnames
Packit 6ef888
 *
Packit 6ef888
 * verify root inode
Packit 6ef888
 * directory name length
Packit 6ef888
 * entries in range
Packit 6ef888
 */
Packit 6ef888
int pass2(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct osi_node *tmp, *next = NULL;
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct dir_info *dt;
Packit 6ef888
	uint64_t dirblk;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	/* Check all the system directory inodes. */
Packit 6ef888
	if (!sdp->gfs1 &&
Packit 6ef888
	    check_system_dir(sdp->md.jiinode, "jindex", build_jindex)) {
Packit 6ef888
		stack;
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	if (!sdp->gfs1 &&
Packit 6ef888
	    check_system_dir(sdp->md.pinode, "per_node", build_per_node)) {
Packit 6ef888
		stack;
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	if (!sdp->gfs1 &&
Packit 6ef888
	    check_system_dir(sdp->master_dir, "master", build_master)) {
Packit 6ef888
		stack;
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	if (check_system_dir(sdp->md.rooti, "root", build_root)) {
Packit 6ef888
		stack;
Packit 6ef888
		return FSCK_ERROR;
Packit 6ef888
	}
Packit 6ef888
	if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
		return FSCK_OK;
Packit 6ef888
	log_info( _("Checking directory inodes.\n"));
Packit 6ef888
	/* Grab each directory inode, and run checks on it */
Packit 6ef888
	for (tmp = osi_first(&dirtree); tmp; tmp = next) {
Packit 6ef888
		next = osi_next(tmp);
Packit 6ef888
Packit 6ef888
		dt = (struct dir_info *)tmp;
Packit 6ef888
		dirblk = dt->dinode.no_addr;
Packit 6ef888
		warm_fuzzy_stuff(dirblk);
Packit 6ef888
		if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
Packit 6ef888
			return FSCK_OK;
Packit 6ef888
Packit 6ef888
		/* Skip the system inodes - they're checked above */
Packit 6ef888
		if (is_system_dir(sdp, dirblk))
Packit 6ef888
			continue;
Packit 6ef888
Packit 6ef888
		/* If we created lost+found, its links should have been
Packit 6ef888
		   properly adjusted, so don't check it. */
Packit 6ef888
		if (lf_was_created &&
Packit 6ef888
		    (dirblk == lf_dip->i_di.di_num.no_addr)) {
Packit 6ef888
			log_debug(_("Pass2 skipping the new lost+found.\n"));
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		log_debug(_("Checking directory inode at block %llu (0x%llx)\n"),
Packit 6ef888
			  (unsigned long long)dirblk, (unsigned long long)dirblk);
Packit 6ef888
Packit 6ef888
		ip = fsck_load_inode(sdp, dirblk);
Packit 6ef888
		if (ip == NULL) {
Packit 6ef888
			stack;
Packit 6ef888
			return FSCK_ERROR;
Packit 6ef888
		}
Packit 6ef888
		error = pass2_check_dir(sdp, ip);
Packit 6ef888
		fsck_inode_put(&ip);
Packit 6ef888
Packit 6ef888
		if (skip_this_pass || fsck_abort)
Packit 6ef888
			return FSCK_OK;
Packit 6ef888
Packit 6ef888
		if (error != FSCK_OK) {
Packit 6ef888
			stack;
Packit 6ef888
			return error;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return FSCK_OK;
Packit 6ef888
}