Blame gfs2/fsck/metawalk.c

Packit Service 360c39
#include "clusterautoconfig.h"
Packit Service 360c39
Packit Service 360c39
#include <inttypes.h>
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <sys/types.h>
Packit Service 360c39
#include <sys/stat.h>
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <libintl.h>
Packit Service 360c39
#include <ctype.h>
Packit Service 360c39
#include <fcntl.h>
Packit Service 360c39
#define _(String) gettext(String)
Packit Service 360c39
Packit Service 360c39
#include <logging.h>
Packit Service 360c39
#include "libgfs2.h"
Packit Service 360c39
#include "link.h"
Packit Service 360c39
#include "osi_tree.h"
Packit Service 360c39
#include "fsck.h"
Packit Service 360c39
#include "util.h"
Packit Service 360c39
#include "metawalk.h"
Packit Service 360c39
#include "inode_hash.h"
Packit Service 360c39
Packit Service 360c39
#define COMFORTABLE_BLKS 5242880 /* 20GB in 4K blocks */
Packit Service 360c39
Packit Service 360c39
/* There are two bitmaps: (1) The "blockmap" that fsck uses to keep track of
Packit Service 360c39
   what block type has been discovered, and (2) The rgrp bitmap.  Function
Packit Service 360c39
   gfs2_blockmap_set is used to set the former and gfs2_set_bitmap
Packit Service 360c39
   is used to set the latter.  The two must be kept in sync, otherwise
Packit Service 360c39
   you'll get bitmap mismatches.  This function checks the status of the
Packit Service 360c39
   bitmap whenever the blockmap changes, and fixes it accordingly. */
Packit Service 360c39
int check_n_fix_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit Service 360c39
		       uint64_t blk, int error_on_dinode, int new_state)
Packit Service 360c39
{
Packit Service 360c39
	int old_state;
Packit Service 360c39
	int treat_as_inode = 0;
Packit Service 360c39
	int rewrite_rgrp = 0;
Packit Service 360c39
	struct gfs_rgrp *gfs1rg;
Packit Service 360c39
	const char *allocdesc[2][5] = { /* gfs2 descriptions */
Packit Service 360c39
		{"free", "data", "unlinked", "inode", "reserved"},
Packit Service 360c39
		/* gfs1 descriptions: */
Packit Service 360c39
		{"free", "data", "free meta", "metadata", "reserved"}};
Packit Service 360c39
	static struct rgrp_tree *prevrgd = NULL;
Packit Service 360c39
Packit Service 360c39
	if (prevrgd && rgrp_contains_block(prevrgd, blk)) {
Packit Service 360c39
		rgd = prevrgd;
Packit Service 360c39
	} else if (rgd == NULL || !rgrp_contains_block(rgd, blk)) {
Packit Service 360c39
		rgd = gfs2_blk2rgrpd(sdp, blk);
Packit Service 360c39
		prevrgd = rgd;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	gfs1rg = (struct gfs_rgrp *)&rgd->rg;
Packit Service 360c39
Packit Service 360c39
	old_state = lgfs2_get_bitmap(sdp, blk, rgd);
Packit Service 360c39
	if (old_state < 0) {
Packit Service 360c39
		log_err( _("Block %llu (0x%llx) is not represented in the "
Packit Service 360c39
			   "system bitmap; part of an rgrp or superblock.\n"),
Packit Service 360c39
			 (unsigned long long)blk, (unsigned long long)blk);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (old_state == new_state)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	if (error_on_dinode && old_state == GFS2_BLKST_DINODE &&
Packit Service 360c39
	    new_state != GFS2_BLKST_FREE) {
Packit Service 360c39
		log_debug(_("Reference as '%s' to block %llu (0x%llx) which "
Packit Service 360c39
			    "was marked as dinode. Needs further "
Packit Service 360c39
			    "investigation.\n"),
Packit Service 360c39
			  allocdesc[sdp->gfs1][new_state],
Packit Service 360c39
			  (unsigned long long)blk, (unsigned long long)blk);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	/* Keep these messages as short as possible, or the output gets to be
Packit Service 360c39
	   huge and unmanageable. */
Packit Service 360c39
	log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
Packit Service 360c39
		 (unsigned long long)blk, (unsigned long long)blk,
Packit Service 360c39
		 allocdesc[sdp->gfs1][old_state],
Packit Service 360c39
		 allocdesc[sdp->gfs1][new_state]);
Packit Service 360c39
	if (!query( _("Fix the bitmap? (y/n)"))) {
Packit Service 360c39
		log_err( _("The bitmap inconsistency was ignored.\n"));
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	/* If the new bitmap state is free (and therefore the old state was
Packit Service 360c39
	   not) we have to add to the free space in the rgrp. If the old
Packit Service 360c39
	   bitmap state was free (and therefore it no longer is) we have to
Packit Service 360c39
	   subtract to the free space.  If the type changed from dinode to 
Packit Service 360c39
	   data or data to dinode, no change in free space. */
Packit Service 360c39
	gfs2_set_bitmap(rgd, blk, new_state);
Packit Service 360c39
	if (new_state == GFS2_BLKST_FREE) {
Packit Service 360c39
		rgd->rg.rg_free++;
Packit Service 360c39
		rewrite_rgrp = 1;
Packit Service 360c39
	} else if (old_state == GFS2_BLKST_FREE) {
Packit Service 360c39
		rgd->rg.rg_free--;
Packit Service 360c39
		rewrite_rgrp = 1;
Packit Service 360c39
	}
Packit Service 360c39
	/* If we're freeing a dinode, get rid of the data structs for it. */
Packit Service 360c39
	if (old_state == GFS2_BLKST_DINODE ||
Packit Service 360c39
	    old_state == GFS2_BLKST_UNLINKED) {
Packit Service 360c39
		struct dir_info *dt;
Packit Service 360c39
		struct inode_info *ii;
Packit Service 360c39
Packit Service 360c39
		dt = dirtree_find(blk);
Packit Service 360c39
		if (dt) {
Packit Service 360c39
			dirtree_delete(dt);
Packit Service 360c39
			treat_as_inode = 1;
Packit Service 360c39
		}
Packit Service 360c39
		ii = inodetree_find(blk);
Packit Service 360c39
		if (ii) {
Packit Service 360c39
			inodetree_delete(ii);
Packit Service 360c39
			treat_as_inode = 1;
Packit Service 360c39
		} else if (!sdp->gfs1) {
Packit Service 360c39
			treat_as_inode = 1;
Packit Service 360c39
		} else if (link1_type(&nlink1map, blk) == 1) {
Packit Service 360c39
			/* This is a GFS1 fs (so all metadata is marked inode).
Packit Service 360c39
			   We need to verify it is an inode before we can decr
Packit Service 360c39
			   the rgrp inode count. */
Packit Service 360c39
			treat_as_inode = 1;
Packit Service 360c39
		}
Packit Service 360c39
		if (old_state == GFS2_BLKST_DINODE) {
Packit Service 360c39
			if (treat_as_inode && rgd->rg.rg_dinodes > 0)
Packit Service 360c39
				rgd->rg.rg_dinodes--;
Packit Service 360c39
			else if (sdp->gfs1 && gfs1rg->rg_usedmeta > 0)
Packit Service 360c39
				gfs1rg->rg_usedmeta--;
Packit Service 360c39
			rewrite_rgrp = 1;
Packit Service 360c39
		}
Packit Service 360c39
		link1_set(&nlink1map, blk, 0);
Packit Service 360c39
	} else if (new_state == GFS2_BLKST_DINODE) {
Packit Service 360c39
		if (!sdp->gfs1) {
Packit Service 360c39
			treat_as_inode = 1;
Packit Service 360c39
		} else {
Packit Service 360c39
			/* This is GFS1 (so all metadata is marked inode). We
Packit Service 360c39
			   need to verify it is an inode before we can decr
Packit Service 360c39
			   the rgrp inode count. */
Packit Service 360c39
			if (link1_type(&nlink1map, blk) == 1)
Packit Service 360c39
				treat_as_inode = 1;
Packit Service 360c39
			else {
Packit Service 360c39
				struct dir_info *dt;
Packit Service 360c39
				struct inode_info *ii;
Packit Service 360c39
Packit Service 360c39
				dt = dirtree_find(blk);
Packit Service 360c39
				if (dt)
Packit Service 360c39
					treat_as_inode = 1;
Packit Service 360c39
				else {
Packit Service 360c39
					ii = inodetree_find(blk);
Packit Service 360c39
					if (ii)
Packit Service 360c39
						treat_as_inode = 1;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		if (treat_as_inode)
Packit Service 360c39
			rgd->rg.rg_dinodes++;
Packit Service 360c39
		else if (sdp->gfs1)
Packit Service 360c39
			gfs1rg->rg_usedmeta++;
Packit Service 360c39
		rewrite_rgrp = 1;
Packit Service 360c39
	}
Packit Service 360c39
	if (rewrite_rgrp) {
Packit Service 360c39
		if (sdp->gfs1)
Packit Service 360c39
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit Service 360c39
		else
Packit Service 360c39
			gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit Service 360c39
		bmodified(rgd->bits[0].bi_bh);
Packit Service 360c39
	}
Packit Service 360c39
	log_err( _("The bitmap was fixed.\n"));
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * _fsck_bitmap_set - Mark a block in the bitmap, and adjust free space.
Packit Service 360c39
 */
Packit Service 360c39
int _fsck_bitmap_set(struct gfs2_inode *ip, uint64_t bblock,
Packit Service 360c39
		     const char *btype, int mark,
Packit Service 360c39
		     int error_on_dinode, const char *caller, int fline)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
	static int prev_ino_addr = 0;
Packit Service 360c39
	static int prev_mark = 0;
Packit Service 360c39
	static int prevcount = 0;
Packit Service 360c39
	static const char *prev_caller = NULL;
Packit Service 360c39
Packit Service 360c39
	if (print_level >= MSG_DEBUG) {
Packit Service 360c39
		if ((ip->i_di.di_num.no_addr == prev_ino_addr) &&
Packit Service 360c39
		    (mark == prev_mark) && caller == prev_caller) {
Packit Service 360c39
			log_info("(0x%llx) ", (unsigned long long)bblock);
Packit Service 360c39
			prevcount++;
Packit Service 360c39
			if (prevcount > 10) {
Packit Service 360c39
				log_info("\n");
Packit Service 360c39
				prevcount = 0;
Packit Service 360c39
			}
Packit Service 360c39
		/* I'm circumventing the log levels here on purpose to make the
Packit Service 360c39
		   output easier to debug. */
Packit Service 360c39
		} else if (ip->i_di.di_num.no_addr == bblock) {
Packit Service 360c39
			if (prevcount) {
Packit Service 360c39
				log_info("\n");
Packit Service 360c39
				prevcount = 0;
Packit Service 360c39
			}
Packit Service 360c39
			printf( _("(%s:%d) %s inode found at block "
Packit Service 360c39
				  "(0x%llx): marking as '%s'\n"), caller, fline,
Packit Service 360c39
			       btype,
Packit Service 360c39
			       (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			       block_type_string(mark));
Packit Service 360c39
Packit Service 360c39
		} else {
Packit Service 360c39
			if (prevcount) {
Packit Service 360c39
				log_info("\n");
Packit Service 360c39
				prevcount = 0;
Packit Service 360c39
			}
Packit Service 360c39
			printf( _("(%s:%d) inode (0x%llx) references %s block"
Packit Service 360c39
				  " (0x%llx): marking as '%s'\n"),
Packit Service 360c39
			       caller, fline,
Packit Service 360c39
			       (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			       btype, (unsigned long long)bblock,
Packit Service 360c39
			       block_type_string(mark));
Packit Service 360c39
		}
Packit Service 360c39
		prev_ino_addr = ip->i_di.di_num.no_addr;
Packit Service 360c39
		prev_mark = mark;
Packit Service 360c39
		prev_caller = caller;
Packit Service 360c39
	}
Packit Service 360c39
	error = check_n_fix_bitmap(ip->i_sbd, ip->i_rgd, bblock,
Packit Service 360c39
				   error_on_dinode, mark);
Packit Service 360c39
	if (error < 0)
Packit Service 360c39
		log_err(_("This block is not represented in the bitmap.\n"));
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct duptree *dupfind(uint64_t block)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *node = dup_blocks.osi_node;
Packit Service 360c39
Packit Service 360c39
	while (node) {
Packit Service 360c39
		struct duptree *dt = (struct duptree *)node;
Packit Service 360c39
Packit Service 360c39
		if (block < dt->block)
Packit Service 360c39
			node = node->osi_left;
Packit Service 360c39
		else if (block > dt->block)
Packit Service 360c39
			node = node->osi_right;
Packit Service 360c39
		else
Packit Service 360c39
			return dt;
Packit Service 360c39
	}
Packit Service 360c39
	return NULL;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp, uint64_t block)
Packit Service 360c39
{
Packit Service 360c39
	int j;
Packit Service 360c39
Packit Service 360c39
	if (lf_dip && lf_dip->i_di.di_num.no_addr == block)
Packit Service 360c39
		return lf_dip;
Packit Service 360c39
	if (!sdp->gfs1)
Packit Service 360c39
		return is_system_inode(sdp, block);
Packit Service 360c39
Packit Service 360c39
	if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
Packit Service 360c39
		return sdp->md.statfs;
Packit Service 360c39
	if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
Packit Service 360c39
		return sdp->md.jiinode;
Packit Service 360c39
	if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
Packit Service 360c39
		return sdp->md.riinode;
Packit Service 360c39
	if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
Packit Service 360c39
		return sdp->md.qinode;
Packit Service 360c39
	if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
Packit Service 360c39
		return sdp->md.rooti;
Packit Service 360c39
	for (j = 0; j < sdp->md.journals; j++)
Packit Service 360c39
		if (sdp->md.journal && sdp->md.journal[j] &&
Packit Service 360c39
		    block == sdp->md.journal[j]->i_di.di_num.no_addr)
Packit Service 360c39
			return sdp->md.journal[j];
Packit Service 360c39
	return NULL;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* fsck_load_inode - same as gfs2_load_inode() in libgfs2 but system inodes
Packit Service 360c39
   get special treatment. */
Packit Service 360c39
struct gfs2_inode *fsck_load_inode(struct gfs2_sbd *sdp, uint64_t block)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_inode *ip = NULL;
Packit Service 360c39
Packit Service 360c39
	ip = fsck_system_inode(sdp, block);
Packit Service 360c39
	if (ip)
Packit Service 360c39
		return ip;
Packit Service 360c39
	if (sdp->gfs1)
Packit Service 360c39
		return lgfs2_gfs_inode_read(sdp, block);
Packit Service 360c39
	return lgfs2_inode_read(sdp, block);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* fsck_inode_get - same as inode_get() in libgfs2 but system inodes
Packit Service 360c39
   get special treatment. */
Packit Service 360c39
struct gfs2_inode *fsck_inode_get(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit Service 360c39
				  struct gfs2_buffer_head *bh)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_inode *sysip;
Packit Service 360c39
	struct gfs2_inode *ip;
Packit Service 360c39
Packit Service 360c39
	sysip = fsck_system_inode(sdp, bh->b_blocknr);
Packit Service 360c39
	if (sysip)
Packit Service 360c39
		return sysip;
Packit Service 360c39
Packit Service 360c39
	if (sdp->gfs1)
Packit Service 360c39
		ip = lgfs2_gfs_inode_get(sdp, bh);
Packit Service 360c39
	else
Packit Service 360c39
		ip = lgfs2_inode_get(sdp, bh);
Packit Service 360c39
	if (ip)
Packit Service 360c39
		ip->i_rgd = rgd;
Packit Service 360c39
	return ip;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* fsck_inode_put - same as inode_put() in libgfs2 but system inodes
Packit Service 360c39
   get special treatment. */
Packit Service 360c39
void fsck_inode_put(struct gfs2_inode **ip_in)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_inode *ip = *ip_in;
Packit Service 360c39
	struct gfs2_inode *sysip;
Packit Service 360c39
Packit Service 360c39
	sysip = fsck_system_inode(ip->i_sbd, ip->i_di.di_num.no_addr);
Packit Service 360c39
	if (!sysip)
Packit Service 360c39
		inode_put(ip_in);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * dirent_repair - attempt to repair a corrupt directory entry.
Packit Service 360c39
 * @bh - The buffer header that contains the bad dirent
Packit Service 360c39
 * @de - The directory entry in native format
Packit Service 360c39
 * @dent - The directory entry in on-disk format
Packit Service 360c39
 * @type - Type of directory (DIR_LINEAR or DIR_EXHASH)
Packit Service 360c39
 * @first - TRUE if this is the first dirent in the buffer
Packit Service 360c39
 *
Packit Service 360c39
 * This function tries to repair a corrupt directory entry.  All we
Packit Service 360c39
 * know at this point is that the length field is wrong.
Packit Service 360c39
 */
Packit Service 360c39
static int dirent_repair(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
Packit Service 360c39
		  struct gfs2_dirent *de, struct gfs2_dirent *dent,
Packit Service 360c39
		  int type, int first)
Packit Service 360c39
{
Packit Service 360c39
	char *bh_end, *p;
Packit Service 360c39
	int calc_de_name_len = 0;
Packit Service 360c39
	
Packit Service 360c39
	/* If this is a sentinel, just fix the length and move on */
Packit Service 360c39
	if (first && !de->de_inum.no_formal_ino) { /* Is it a sentinel? */
Packit Service 360c39
		if (type == DIR_LINEAR)
Packit Service 360c39
			de->de_rec_len = ip->i_sbd->bsize -
Packit Service 360c39
				sizeof(struct gfs2_dinode);
Packit Service 360c39
		else
Packit Service 360c39
			de->de_rec_len = ip->i_sbd->bsize -
Packit Service 360c39
				sizeof(struct gfs2_leaf);
Packit Service 360c39
	} else {
Packit Service 360c39
		bh_end = bh->b_data + ip->i_sbd->bsize;
Packit Service 360c39
		/* first, figure out a probable name length */
Packit Service 360c39
		p = (char *)dent + sizeof(struct gfs2_dirent);
Packit Service 360c39
		while (*p &&         /* while there's a non-zero char and */
Packit Service 360c39
		       isprint(*p) && /* a printable character and */
Packit Service 360c39
		       p < bh_end) { /* not past end of buffer */
Packit Service 360c39
			calc_de_name_len++;
Packit Service 360c39
			p++;
Packit Service 360c39
		}
Packit Service 360c39
		if (!calc_de_name_len)
Packit Service 360c39
			return 1;
Packit Service 360c39
		/* There can often be noise at the end, so only          */
Packit Service 360c39
		/* Trust the shorter of the two in case we have too much */
Packit Service 360c39
		/* Or rather, only trust ours if it's shorter.           */
Packit Service 360c39
		if (!de->de_name_len || de->de_name_len > NAME_MAX ||
Packit Service 360c39
		    calc_de_name_len < de->de_name_len) /* if dent is hosed */
Packit Service 360c39
			de->de_name_len = calc_de_name_len; /* use ours */
Packit Service 360c39
		de->de_rec_len = GFS2_DIRENT_SIZE(de->de_name_len);
Packit Service 360c39
	}
Packit Service 360c39
	gfs2_dirent_out(de, (char *)dent);
Packit Service 360c39
	bmodified(bh);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * dirblk_truncate - truncate a directory block
Packit Service 360c39
 */
Packit Service 360c39
static void dirblk_truncate(struct gfs2_inode *ip, struct gfs2_dirent *fixb,
Packit Service 360c39
			    struct gfs2_buffer_head *bh)
Packit Service 360c39
{
Packit Service 360c39
	char *bh_end;
Packit Service 360c39
	struct gfs2_dirent de;
Packit Service 360c39
Packit Service 360c39
	bh_end = bh->b_data + ip->i_sbd->sd_sb.sb_bsize;
Packit Service 360c39
	/* truncate the block to save the most dentries.  To do this we
Packit Service 360c39
	   have to patch the previous dent. */
Packit Service 360c39
	gfs2_dirent_in(&de, (char *)fixb);
Packit Service 360c39
	de.de_rec_len = bh_end - (char *)fixb;
Packit Service 360c39
	gfs2_dirent_out(&de, (char *)fixb);
Packit Service 360c39
	bmodified(bh);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * check_entries - check directory entries for a given block
Packit Service 360c39
 *
Packit Service 360c39
 * @ip - dinode associated with this leaf block
Packit Service 360c39
 * bh - buffer for the leaf block
Packit Service 360c39
 * type - type of block this is (linear or exhash)
Packit Service 360c39
 * @count - set to the count entries
Packit Service 360c39
 * @lindex - the last inde
Packit Service 360c39
 * @pass - structure pointing to pass-specific functions
Packit Service 360c39
 *
Packit Service 360c39
 * returns: 0 - good block or it was repaired to be good
Packit Service 360c39
 *         -1 - error occurred
Packit Service 360c39
 */
Packit Service 360c39
static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
Packit Service 360c39
			 int type, uint32_t *count, int lindex,
Packit Service 360c39
			 struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_dirent *dent;
Packit Service 360c39
	struct gfs2_dirent de, *prev;
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	char *bh_end;
Packit Service 360c39
	char *filename;
Packit Service 360c39
	int first = 1;
Packit Service 360c39
Packit Service 360c39
	bh_end = bh->b_data + ip->i_sbd->bsize;
Packit Service 360c39
Packit Service 360c39
	if (type == DIR_LINEAR) {
Packit Service 360c39
		dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
Packit Service 360c39
	} else {
Packit Service 360c39
		dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
Packit Service 360c39
		log_debug( _("Checking leaf %llu (0x%llx)\n"),
Packit Service 360c39
			  (unsigned long long)bh->b_blocknr,
Packit Service 360c39
			  (unsigned long long)bh->b_blocknr);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	prev = NULL;
Packit Service 360c39
	if (!pass->check_dentry)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	while (1) {
Packit Service 360c39
		if (skip_this_pass || fsck_abort)
Packit Service 360c39
			return FSCK_OK;
Packit Service 360c39
		memset(&de, 0, sizeof(struct gfs2_dirent));
Packit Service 360c39
		gfs2_dirent_in(&de, (char *)dent);
Packit Service 360c39
		filename = (char *)dent + sizeof(struct gfs2_dirent);
Packit Service 360c39
Packit Service 360c39
		if (de.de_rec_len < sizeof(struct gfs2_dirent) +
Packit Service 360c39
		    de.de_name_len ||
Packit Service 360c39
		    (de.de_inum.no_formal_ino && !de.de_name_len && !first)) {
Packit Service 360c39
			log_err( _("Directory block %llu (0x%llx"
Packit Service 360c39
				"), entry %d of directory %llu "
Packit Service 360c39
				"(0x%llx) is corrupt.\n"),
Packit Service 360c39
				(unsigned long long)bh->b_blocknr,
Packit Service 360c39
				(unsigned long long)bh->b_blocknr,
Packit Service 360c39
				(*count) + 1,
Packit Service 360c39
				(unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				(unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
			if (query( _("Attempt to repair it? (y/n) "))) {
Packit Service 360c39
				if (dirent_repair(ip, bh, &de, dent, type,
Packit Service 360c39
						  first)) {
Packit Service 360c39
					if (first) /* make a new sentinel */
Packit Service 360c39
						dirblk_truncate(ip, dent, bh);
Packit Service 360c39
					else
Packit Service 360c39
						dirblk_truncate(ip, prev, bh);
Packit Service 360c39
					log_err( _("Unable to repair corrupt "
Packit Service 360c39
						   "directory entry; the "
Packit Service 360c39
						   "entry was removed "
Packit Service 360c39
						   "instead.\n"));
Packit Service 360c39
					return 0;
Packit Service 360c39
				} else {
Packit Service 360c39
					log_err( _("Corrupt directory entry "
Packit Service 360c39
						   "repaired.\n"));
Packit Service 360c39
					/* keep looping through dentries */
Packit Service 360c39
				}
Packit Service 360c39
			} else {
Packit Service 360c39
				log_err( _("Corrupt directory entry ignored, "
Packit Service 360c39
					"stopped after checking %d entries.\n"),
Packit Service 360c39
					*count);
Packit Service 360c39
				return 0;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		if (!de.de_inum.no_formal_ino){
Packit Service 360c39
			if (first){
Packit Service 360c39
				log_debug( _("First dirent is a sentinel (place holder).\n"));
Packit Service 360c39
				first = 0;
Packit Service 360c39
			} else {
Packit Service 360c39
				log_err( _("Directory entry with inode number of "
Packit Service 360c39
					"zero in leaf %llu (0x%llx) of "
Packit Service 360c39
					"directory %llu (0x%llx)!\n"),
Packit Service 360c39
					(unsigned long long)bh->b_blocknr,
Packit Service 360c39
					(unsigned long long)bh->b_blocknr,
Packit Service 360c39
					(unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
					(unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
				if (query(_("Attempt to remove it? (y/n) "))) {
Packit Service 360c39
					dirblk_truncate(ip, prev, bh);
Packit Service 360c39
					log_err(_("The corrupt directory "
Packit Service 360c39
						  "entry was removed.\n"));
Packit Service 360c39
				} else {
Packit Service 360c39
					log_err( _("Corrupt directory entry "
Packit Service 360c39
						   "ignored, stopped after "
Packit Service 360c39
						   "checking %d entries.\n"),
Packit Service 360c39
						 *count);
Packit Service 360c39
				}
Packit Service 360c39
				return 0;
Packit Service 360c39
			}
Packit Service 360c39
		} else {
Packit Service 360c39
			if (!de.de_inum.no_addr && first) { /* reverse sentinel */
Packit Service 360c39
				log_debug( _("First dirent is a Sentinel (place holder).\n"));
Packit Service 360c39
				/* Swap the two to silently make it a proper sentinel */
Packit Service 360c39
				de.de_inum.no_addr = de.de_inum.no_formal_ino;
Packit Service 360c39
				de.de_inum.no_formal_ino = 0;
Packit Service 360c39
				gfs2_dirent_out(&de, (char *)dent);
Packit Service 360c39
				bmodified(bh);
Packit Service 360c39
				/* Mark dirent buffer as modified */
Packit Service 360c39
				first = 0;
Packit Service 360c39
			} else {
Packit Service 360c39
				error = pass->check_dentry(ip, dent, prev, bh,
Packit Service 360c39
							   filename, count,
Packit Service 360c39
							   &lindex,
Packit Service 360c39
							   pass->private);
Packit Service 360c39
				if (error < 0) {
Packit Service 360c39
					stack;
Packit Service 360c39
					return error;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if ((char *)dent + de.de_rec_len >= bh_end){
Packit Service 360c39
			log_debug( _("Last entry processed for %lld->%lld "
Packit Service 360c39
				     "(0x%llx->0x%llx), di_blocks=%llu.\n"),
Packit Service 360c39
				   (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				   (unsigned long long)bh->b_blocknr,
Packit Service 360c39
				   (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				   (unsigned long long)bh->b_blocknr,
Packit Service 360c39
				   (unsigned long long)ip->i_di.di_blocks);
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		/* If we didn't clear the dentry, or if we did, but it
Packit Service 360c39
		 * was the first dentry, set prev  */
Packit Service 360c39
		if (!error || first)
Packit Service 360c39
			prev = dent;
Packit Service 360c39
		first = 0;
Packit Service 360c39
		dent = (struct gfs2_dirent *)((char *)dent + de.de_rec_len);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_leaf - check a leaf block for errors
Packit Service 360c39
 * Reads in the leaf block
Packit Service 360c39
 * Leaves the buffer around for further analysis (caller must brelse)
Packit Service 360c39
 */
Packit Service 360c39
int check_leaf(struct gfs2_inode *ip, int lindex, struct metawalk_fxns *pass,
Packit Service 360c39
	       uint64_t *leaf_no, struct gfs2_leaf *leaf, int *ref_count)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0, fix;
Packit Service 360c39
	struct gfs2_buffer_head *lbh = NULL;
Packit Service 360c39
	uint32_t count = 0;
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	const char *msg;
Packit Service 360c39
	int di_depth = ip->i_di.di_depth;
Packit Service 360c39
Packit Service 360c39
	/* Make sure the block number is in range. */
Packit Service 360c39
	if (!valid_block_ip(ip, *leaf_no)) {
Packit Service 360c39
		log_err( _("Leaf block #%llu (0x%llx) is out of range for "
Packit Service 360c39
			   "directory #%llu (0x%llx) at index %d (0x%x).\n"),
Packit Service 360c39
			 (unsigned long long)*leaf_no,
Packit Service 360c39
			 (unsigned long long)*leaf_no,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			 lindex, lindex);
Packit Service 360c39
		msg = _("that is out of range");
Packit Service 360c39
		goto bad_leaf;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	/* Try to read in the leaf block. */
Packit Service 360c39
	lbh = bread(sdp, *leaf_no);
Packit Service 360c39
	/* Make sure it's really a valid leaf block. */
Packit Service 360c39
	if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) {
Packit Service 360c39
		msg = _("that is not really a leaf");
Packit Service 360c39
		goto bad_leaf;
Packit Service 360c39
	}
Packit Service 360c39
	if (pass->check_leaf_depth)
Packit Service 360c39
		error = pass->check_leaf_depth(ip, *leaf_no, *ref_count, lbh);
Packit Service 360c39
Packit Service 360c39
	if (error >= 0 && pass->check_leaf) {
Packit Service 360c39
		error = pass->check_leaf(ip, *leaf_no, pass->private);
Packit Service 360c39
		if (error == -EEXIST) {
Packit Service 360c39
			log_info(_("Previous reference to leaf %lld (0x%llx) "
Packit Service 360c39
				   "has already checked it; skipping.\n"),
Packit Service 360c39
				 (unsigned long long)*leaf_no,
Packit Service 360c39
				 (unsigned long long)*leaf_no);
Packit Service 360c39
			brelse(lbh);
Packit Service 360c39
			return error;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Early versions of GFS2 had an endianess bug in the kernel that set
Packit Service 360c39
	   lf_dirent_format to cpu_to_be16(GFS2_FORMAT_DE).  This was fixed
Packit Service 360c39
	   to use cpu_to_be32(), but we should check for incorrect values and
Packit Service 360c39
	   replace them with the correct value. */
Packit Service 360c39
Packit Service 360c39
	gfs2_leaf_in(leaf, lbh->b_data);
Packit Service 360c39
	if (leaf->lf_dirent_format == (GFS2_FORMAT_DE << 16)) {
Packit Service 360c39
		log_debug( _("incorrect lf_dirent_format at leaf #%" PRIu64
Packit Service 360c39
			     "\n"), *leaf_no);
Packit Service 360c39
		leaf->lf_dirent_format = GFS2_FORMAT_DE;
Packit Service 360c39
		gfs2_leaf_out(leaf, lbh->b_data);
Packit Service 360c39
		bmodified(lbh);
Packit Service 360c39
		log_debug( _("Fixing lf_dirent_format.\n"));
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	/* Make sure it's really a leaf. */
Packit Service 360c39
	if (leaf->lf_header.mh_type != GFS2_METATYPE_LF) {
Packit Service 360c39
		log_err( _("Inode %llu (0x%llx) points to bad leaf %llu"
Packit Service 360c39
			   " (0x%llx).\n"),
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			 (unsigned long long)*leaf_no,
Packit Service 360c39
			 (unsigned long long)*leaf_no);
Packit Service 360c39
		msg = _("that is not a leaf");
Packit Service 360c39
		goto bad_leaf;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (pass->check_dentry && is_dir(&ip->i_di, sdp->gfs1)) {
Packit Service 360c39
		error = check_entries(ip, lbh, DIR_EXHASH, &count, lindex,
Packit Service 360c39
				      pass);
Packit Service 360c39
Packit Service 360c39
		if (skip_this_pass || fsck_abort)
Packit Service 360c39
			goto out;
Packit Service 360c39
Packit Service 360c39
		if (error < 0) {
Packit Service 360c39
			stack;
Packit Service 360c39
			goto out; /* This seems wrong: needs investigation */
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if (count == leaf->lf_entries)
Packit Service 360c39
			goto out;
Packit Service 360c39
Packit Service 360c39
		/* release and re-read the leaf in case check_entries
Packit Service 360c39
		   changed it. */
Packit Service 360c39
		brelse(lbh);
Packit Service 360c39
		lbh = bread(sdp, *leaf_no);
Packit Service 360c39
		gfs2_leaf_in(leaf, lbh->b_data);
Packit Service 360c39
		if (count != leaf->lf_entries) {
Packit Service 360c39
			log_err( _("Leaf %llu (0x%llx) entry count in "
Packit Service 360c39
				   "directory %llu (0x%llx) does not match "
Packit Service 360c39
				   "number of entries found - is %u, found %u\n"),
Packit Service 360c39
				 (unsigned long long)*leaf_no,
Packit Service 360c39
				 (unsigned long long)*leaf_no,
Packit Service 360c39
				 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				 leaf->lf_entries, count);
Packit Service 360c39
			if (query( _("Update leaf entry count? (y/n) "))) {
Packit Service 360c39
				leaf->lf_entries = count;
Packit Service 360c39
				gfs2_leaf_out(leaf, lbh->b_data);
Packit Service 360c39
				bmodified(lbh);
Packit Service 360c39
				log_warn( _("Leaf entry count updated\n"));
Packit Service 360c39
			} else
Packit Service 360c39
				log_err( _("Leaf entry count left in "
Packit Service 360c39
					   "inconsistent state\n"));
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
out:
Packit Service 360c39
	if (di_depth < ip->i_di.di_depth) {
Packit Service 360c39
		log_debug(_("Depth of directory %lld (0x%llx) changed from "
Packit Service 360c39
			    "%d to %d; adjusting ref_count from %d to %d\n"),
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			  di_depth, ip->i_di.di_depth,
Packit Service 360c39
			  *ref_count,
Packit Service 360c39
			  (*ref_count) << (ip->i_di.di_depth - di_depth));
Packit Service 360c39
		(*ref_count) <<= (ip->i_di.di_depth - di_depth);
Packit Service 360c39
	}
Packit Service 360c39
	brelse(lbh);
Packit Service 360c39
	if (error < 0)
Packit Service 360c39
		return error;
Packit Service 360c39
	return 0;
Packit Service 360c39
Packit Service 360c39
bad_leaf:
Packit Service 360c39
	if (lbh)
Packit Service 360c39
		brelse(lbh);
Packit Service 360c39
	if (pass->repair_leaf) {
Packit Service 360c39
		/* The leaf we read in is bad so we need to repair it. */
Packit Service 360c39
		fix = pass->repair_leaf(ip, leaf_no, lindex, *ref_count, msg);
Packit Service 360c39
		if (fix < 0)
Packit Service 360c39
			return fix;
Packit Service 360c39
Packit Service 360c39
	}
Packit Service 360c39
	if (di_depth < ip->i_di.di_depth) {
Packit Service 360c39
		log_debug(_("Depth of directory %lld (0x%llx) changed from "
Packit Service 360c39
			    "%d to %d. Adjusting ref_count from %d to %d\n"),
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			  di_depth, ip->i_di.di_depth,
Packit Service 360c39
			  *ref_count,
Packit Service 360c39
			  (*ref_count) << (ip->i_di.di_depth - di_depth));
Packit Service 360c39
		(*ref_count) <<= (ip->i_di.di_depth - di_depth);
Packit Service 360c39
	}
Packit Service 360c39
	return 1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int u64cmp(const void *p1, const void *p2)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t a = *(uint64_t *)p1;
Packit Service 360c39
	uint64_t b = *(uint64_t *)p2;
Packit Service 360c39
Packit Service 360c39
	if (a > b)
Packit Service 360c39
		return 1;
Packit Service 360c39
	if (a < b)
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void dir_leaf_reada(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t *t = alloca(hsize * sizeof(uint64_t));
Packit Service 360c39
	uint64_t leaf_no;
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	unsigned n = 0;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < hsize; i++) {
Packit Service 360c39
		leaf_no = be64_to_cpu(tbl[i]);
Packit Service 360c39
		if (valid_block_ip(ip, leaf_no))
Packit Service 360c39
			t[n++] = leaf_no * sdp->bsize;
Packit Service 360c39
	}
Packit Service 360c39
	qsort(t, n, sizeof(uint64_t), u64cmp);
Packit Service 360c39
	for (i = 0; i < n; i++)
Packit Service 360c39
		posix_fadvise(sdp->device_fd, t[i], sdp->bsize, POSIX_FADV_WILLNEED);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* Checks exhash directory entries */
Packit Service 360c39
int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	unsigned hsize = (1 << ip->i_di.di_depth);
Packit Service 360c39
	uint64_t leaf_no, leaf_next;
Packit Service 360c39
	uint64_t first_ok_leaf, orig_di_blocks;
Packit Service 360c39
	struct gfs2_buffer_head *lbh;
Packit Service 360c39
	int lindex;
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	int ref_count, orig_ref_count, orig_di_depth, orig_di_height;
Packit Service 360c39
	uint64_t *tbl;
Packit Service 360c39
	int chained_leaf, tbl_valid;
Packit Service 360c39
Packit Service 360c39
	tbl = get_dir_hash(ip);
Packit Service 360c39
	if (tbl == NULL) {
Packit Service 360c39
		perror("get_dir_hash");
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	tbl_valid = 1;
Packit Service 360c39
	orig_di_depth = ip->i_di.di_depth;
Packit Service 360c39
	orig_di_height = ip->i_di.di_height;
Packit Service 360c39
	orig_di_blocks = ip->i_di.di_blocks;
Packit Service 360c39
Packit Service 360c39
	/* Turn off system readahead */
Packit Service 360c39
	posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_RANDOM);
Packit Service 360c39
Packit Service 360c39
	/* Readahead */
Packit Service 360c39
	dir_leaf_reada(ip, tbl, hsize);
Packit Service 360c39
Packit Service 360c39
	if (pass->check_hash_tbl) {
Packit Service 360c39
		error = pass->check_hash_tbl(ip, tbl, hsize, pass->private);
Packit Service 360c39
		if (error < 0) {
Packit Service 360c39
			free(tbl);
Packit Service 360c39
			posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
Packit Service 360c39
			return error;
Packit Service 360c39
		}
Packit Service 360c39
		/* If hash table changes were made, read it in again. */
Packit Service 360c39
		if (error) {
Packit Service 360c39
			free(tbl);
Packit Service 360c39
			tbl = get_dir_hash(ip);
Packit Service 360c39
			if (tbl == NULL) {
Packit Service 360c39
				perror("get_dir_hash");
Packit Service 360c39
				return -1;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	/* Find the first valid leaf pointer in range and use it as our "old"
Packit Service 360c39
	   leaf. That way, bad blocks at the beginning will be overwritten
Packit Service 360c39
	   with the first valid leaf. */
Packit Service 360c39
	first_ok_leaf = leaf_no = -1;
Packit Service 360c39
	for (lindex = 0; lindex < hsize; lindex++) {
Packit Service 360c39
		leaf_no = be64_to_cpu(tbl[lindex]);
Packit Service 360c39
		if (valid_block_ip(ip, leaf_no)) {
Packit Service 360c39
			lbh = bread(sdp, leaf_no);
Packit Service 360c39
			/* Make sure it's really a valid leaf block. */
Packit Service 360c39
			if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) == 0) {
Packit Service 360c39
				brelse(lbh);
Packit Service 360c39
				first_ok_leaf = leaf_no;
Packit Service 360c39
				break;
Packit Service 360c39
			}
Packit Service 360c39
			brelse(lbh);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (first_ok_leaf == -1) { /* no valid leaf found */
Packit Service 360c39
		log_err( _("Directory #%llu (0x%llx) has no valid leaf "
Packit Service 360c39
			   "blocks\n"),
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
		free(tbl);
Packit Service 360c39
		posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	lindex = 0;
Packit Service 360c39
	leaf_next = -1;
Packit Service 360c39
	while (lindex < hsize) {
Packit Service 360c39
		int l;
Packit Service 360c39
Packit Service 360c39
		if (fsck_abort)
Packit Service 360c39
			break;
Packit Service 360c39
Packit Service 360c39
		if (!tbl_valid) {
Packit Service 360c39
			free(tbl);
Packit Service 360c39
			log_debug(_("Re-reading 0x%llx hash table.\n"),
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
			tbl = get_dir_hash(ip);
Packit Service 360c39
			if (tbl == NULL) {
Packit Service 360c39
				perror("get_dir_hash");
Packit Service 360c39
				return -1;
Packit Service 360c39
			}
Packit Service 360c39
			tbl_valid = 1;
Packit Service 360c39
			orig_di_depth = ip->i_di.di_depth;
Packit Service 360c39
			orig_di_height = ip->i_di.di_height;
Packit Service 360c39
			orig_di_blocks = ip->i_di.di_blocks;
Packit Service 360c39
		}
Packit Service 360c39
		leaf_no = be64_to_cpu(tbl[lindex]);
Packit Service 360c39
Packit Service 360c39
		/* count the number of block pointers to this leaf. We don't
Packit Service 360c39
		   need to count the current lindex, because we already know
Packit Service 360c39
		   it's a reference */
Packit Service 360c39
		ref_count = 1;
Packit Service 360c39
Packit Service 360c39
		for (l = lindex + 1; l < hsize; l++) {
Packit Service 360c39
			leaf_next = be64_to_cpu(tbl[l]);
Packit Service 360c39
			if (leaf_next != leaf_no)
Packit Service 360c39
				break;
Packit Service 360c39
			ref_count++;
Packit Service 360c39
		}
Packit Service 360c39
		orig_ref_count = ref_count;
Packit Service 360c39
Packit Service 360c39
		chained_leaf = 0;
Packit Service 360c39
		do {
Packit Service 360c39
			struct gfs2_leaf leaf;
Packit Service 360c39
			if (fsck_abort) {
Packit Service 360c39
				free(tbl);
Packit Service 360c39
				posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
Packit Service 360c39
				return 0;
Packit Service 360c39
			}
Packit Service 360c39
			error = check_leaf(ip, lindex, pass, &leaf_no, &leaf,
Packit Service 360c39
					   &ref_count);
Packit Service 360c39
			if (ref_count != orig_ref_count) {
Packit Service 360c39
				log_debug(_("Ref count of leaf 0x%llx "
Packit Service 360c39
					    "changed from %d to %d.\n"),
Packit Service 360c39
					  (unsigned long long)leaf_no,
Packit Service 360c39
					  orig_ref_count, ref_count);
Packit Service 360c39
				tbl_valid = 0;
Packit Service 360c39
			}
Packit Service 360c39
			if (error < 0) {
Packit Service 360c39
				free(tbl);
Packit Service 360c39
				return error;
Packit Service 360c39
			}
Packit Service 360c39
			if (!leaf.lf_next || error)
Packit Service 360c39
				break;
Packit Service 360c39
			leaf_no = leaf.lf_next;
Packit Service 360c39
			chained_leaf++;
Packit Service 360c39
			log_debug( _("Leaf chain #%d (0x%llx) detected.\n"),
Packit Service 360c39
				   chained_leaf, (unsigned long long)leaf_no);
Packit Service 360c39
		} while (1); /* while we have chained leaf blocks */
Packit Service 360c39
		if (orig_di_depth != ip->i_di.di_depth) {
Packit Service 360c39
			log_debug(_("Depth of 0x%llx changed from %d to %d\n"),
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				  orig_di_depth, ip->i_di.di_depth);
Packit Service 360c39
			tbl_valid = 0;
Packit Service 360c39
			lindex <<= (ip->i_di.di_depth - orig_di_depth);
Packit Service 360c39
			hsize = (1 << ip->i_di.di_depth);
Packit Service 360c39
		}
Packit Service 360c39
		if (orig_di_height != ip->i_di.di_height) {
Packit Service 360c39
			log_debug(_("Height of 0x%llx changed from %d to "
Packit Service 360c39
				    "%d\n"),
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				  orig_di_height, ip->i_di.di_height);
Packit Service 360c39
			tbl_valid = 0;
Packit Service 360c39
		}
Packit Service 360c39
		if (orig_di_blocks != ip->i_di.di_blocks) {
Packit Service 360c39
			log_debug(_("Block count of 0x%llx changed from %llu "
Packit Service 360c39
				    "to %llu\n"),
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				  (unsigned long long)orig_di_blocks,
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_blocks);
Packit Service 360c39
			tbl_valid = 0;
Packit Service 360c39
		}
Packit Service 360c39
		lindex += ref_count;
Packit Service 360c39
	} /* for every leaf block */
Packit Service 360c39
	free(tbl);
Packit Service 360c39
	posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_eattr_entries(struct gfs2_inode *ip,
Packit Service 360c39
			       struct gfs2_buffer_head *bh,
Packit Service 360c39
			       struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_ea_header *ea_hdr, *ea_hdr_prev = NULL;
Packit Service 360c39
	uint64_t *ea_data_ptr = NULL;
Packit Service 360c39
	int i;
Packit Service 360c39
	int error = 0, err;
Packit Service 360c39
	uint32_t offset = (uint32_t)sizeof(struct gfs2_meta_header);
Packit Service 360c39
Packit Service 360c39
	if (!pass->check_eattr_entry)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	ea_hdr = (struct gfs2_ea_header *)(bh->b_data +
Packit Service 360c39
					  sizeof(struct gfs2_meta_header));
Packit Service 360c39
Packit Service 360c39
	while (1){
Packit Service 360c39
		if (ea_hdr->ea_type == GFS2_EATYPE_UNUSED)
Packit Service 360c39
			error = 0;
Packit Service 360c39
		else
Packit Service 360c39
			error = pass->check_eattr_entry(ip, bh, ea_hdr,
Packit Service 360c39
							ea_hdr_prev,
Packit Service 360c39
							pass->private);
Packit Service 360c39
		if (error < 0) {
Packit Service 360c39
			stack;
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
		if (error == 0 && pass->check_eattr_extentry &&
Packit Service 360c39
		   ea_hdr->ea_num_ptrs) {
Packit Service 360c39
			uint32_t tot_ealen = 0;
Packit Service 360c39
			struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
Packit Service 360c39
			ea_data_ptr = ((uint64_t *)((char *)ea_hdr +
Packit Service 360c39
						    sizeof(struct gfs2_ea_header) +
Packit Service 360c39
						    ((ea_hdr->ea_name_len + 7) & ~7)));
Packit Service 360c39
Packit Service 360c39
			/* It is possible when a EA is shrunk
Packit Service 360c39
			** to have ea_num_ptrs be greater than
Packit Service 360c39
			** the number required for ** data.
Packit Service 360c39
			** In this case, the EA ** code leaves
Packit Service 360c39
			** the blocks ** there for **
Packit Service 360c39
			** reuse...........  */
Packit Service 360c39
Packit Service 360c39
			for(i = 0; i < ea_hdr->ea_num_ptrs; i++){
Packit Service 360c39
				err = pass->check_eattr_extentry(ip, i,
Packit Service 360c39
						ea_data_ptr, bh, tot_ealen,
Packit Service 360c39
						ea_hdr, ea_hdr_prev,
Packit Service 360c39
						pass->private);
Packit Service 360c39
				if (err)
Packit Service 360c39
					error = err;
Packit Service 360c39
				tot_ealen += sdp->sd_sb.sb_bsize -
Packit Service 360c39
					sizeof(struct gfs2_meta_header);
Packit Service 360c39
				ea_data_ptr++;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		offset += be32_to_cpu(ea_hdr->ea_rec_len);
Packit Service 360c39
		if (ea_hdr->ea_flags & GFS2_EAFLAG_LAST ||
Packit Service 360c39
		   offset >= ip->i_sbd->sd_sb.sb_bsize || ea_hdr->ea_rec_len == 0){
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
		ea_hdr_prev = ea_hdr;
Packit Service 360c39
		ea_hdr = (struct gfs2_ea_header *)
Packit Service 360c39
			((char *)(ea_hdr) +
Packit Service 360c39
			 be32_to_cpu(ea_hdr->ea_rec_len));
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_leaf_eattr
Packit Service 360c39
 * @ip: the inode the eattr comes from
Packit Service 360c39
 * @block: block number of the leaf
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 on success, 1 if removal is needed, -1 on error
Packit Service 360c39
 */
Packit Service 360c39
static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			    uint64_t parent, struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_buffer_head *bh = NULL;
Packit Service 360c39
Packit Service 360c39
	if (pass->check_eattr_leaf) {
Packit Service 360c39
		int error = 0;
Packit Service 360c39
Packit Service 360c39
		log_debug( _("Checking EA leaf block #%llu (0x%llx) for "
Packit Service 360c39
			     "inode #%llu (0x%llx).\n"),
Packit Service 360c39
			   (unsigned long long)block,
Packit Service 360c39
			   (unsigned long long)block,
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
Packit Service 360c39
		error = pass->check_eattr_leaf(ip, block, parent, &bh,
Packit Service 360c39
					       pass->private);
Packit Service 360c39
		if (error < 0) {
Packit Service 360c39
			stack;
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
		if (error > 0) {
Packit Service 360c39
			if (bh)
Packit Service 360c39
				brelse(bh);
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
		if (bh) {
Packit Service 360c39
			error = check_eattr_entries(ip, bh, pass);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
		}
Packit Service 360c39
		return error;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_indirect_eattr
Packit Service 360c39
 * @ip: the inode the eattr comes from
Packit Service 360c39
 * @indirect_block
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 on success -1 on error
Packit Service 360c39
 */
Packit Service 360c39
static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
Packit Service 360c39
				struct gfs2_buffer_head *indirect_buf,
Packit Service 360c39
				struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0, err;
Packit Service 360c39
	uint64_t *ea_leaf_ptr, *end;
Packit Service 360c39
	uint64_t block;
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	int first_ea_is_bad = 0;
Packit Service 360c39
	uint64_t di_eattr_save = ip->i_di.di_eattr;
Packit Service 360c39
	uint64_t offset = ip->i_sbd->gfs1 ? sizeof(struct gfs_indirect) : sizeof(struct gfs2_meta_header);
Packit Service 360c39
	int leaf_pointers = 0, leaf_pointer_errors = 0;
Packit Service 360c39
Packit Service 360c39
	ea_leaf_ptr = (uint64_t *)(indirect_buf->b_data + offset);
Packit Service 360c39
	end = ea_leaf_ptr + ((sdp->sd_sb.sb_bsize - offset) / 8);
Packit Service 360c39
Packit Service 360c39
	while (*ea_leaf_ptr && (ea_leaf_ptr < end)){
Packit Service 360c39
		block = be64_to_cpu(*ea_leaf_ptr);
Packit Service 360c39
		leaf_pointers++;
Packit Service 360c39
		err = check_leaf_eattr(ip, block, indirect, pass);
Packit Service 360c39
		if (err) {
Packit Service 360c39
			error = err;
Packit Service 360c39
			log_err(_("Error detected in leaf block %lld (0x%llx) "
Packit Service 360c39
				  "referenced by indirect block %lld (0x%llx)"
Packit Service 360c39
				  ".\n"),
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)indirect,
Packit Service 360c39
				(unsigned long long)indirect);
Packit Service 360c39
			log_err(_("Subsequent leaf block pointers should be "
Packit Service 360c39
				  "cleared.\n"));
Packit Service 360c39
		}
Packit Service 360c39
		if (error) { /* leaf blocks following an error must also be
Packit Service 360c39
				treated as error blocks and cleared. */
Packit Service 360c39
			leaf_pointer_errors++;
Packit Service 360c39
			log_err(_("Pointer to EA leaf block %lld (0x%llx) in "
Packit Service 360c39
				  "indirect block %lld (0x%llx) should be "
Packit Service 360c39
				  "cleared.\n"),
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)indirect,
Packit Service 360c39
				(unsigned long long)indirect);
Packit Service 360c39
		}
Packit Service 360c39
		/* If the first eattr lead is bad, we can't have a hole, so we
Packit Service 360c39
		   have to treat this as an unrecoverable eattr error and
Packit Service 360c39
		   delete all eattr info. Calling finish_eattr_indir here
Packit Service 360c39
		   causes ip->i_di.di_eattr = 0 and that ensures that
Packit Service 360c39
		   subsequent calls to check_leaf_eattr result in the eattr
Packit Service 360c39
		   check_leaf_block nuking them all "due to previous errors" */
Packit Service 360c39
		if (leaf_pointers == 1 && leaf_pointer_errors == 1) {
Packit Service 360c39
			first_ea_is_bad = 1;
Packit Service 360c39
			if (pass->finish_eattr_indir)
Packit Service 360c39
				pass->finish_eattr_indir(ip, leaf_pointers,
Packit Service 360c39
							 leaf_pointer_errors,
Packit Service 360c39
							 pass->private);
Packit Service 360c39
		} else if (leaf_pointer_errors) {
Packit Service 360c39
			/* This is a bit tricky.  We can't have eattr holes.
Packit Service 360c39
			   So if we have 4 good eattrs, 1 bad eattr and 5 more
Packit Service 360c39
			   good ones: GGGGBGGGGG, we need to tell
Packit Service 360c39
			   check_leaf_eattr to delete all eattrs after the bad
Packit Service 360c39
			   one. So we want: GGGG when we finish. To do that,
Packit Service 360c39
			   we set di_eattr to 0 temporarily. */
Packit Service 360c39
			ip->i_di.di_eattr = 0;
Packit Service 360c39
			bmodified(ip->i_bh);
Packit Service 360c39
		}
Packit Service 360c39
		ea_leaf_ptr++;
Packit Service 360c39
	}
Packit Service 360c39
	/* If we temporarily nuked the ea block to prevent checking past
Packit Service 360c39
	   a corrupt ea leaf, we need to restore the saved di_eattr block. */
Packit Service 360c39
	if (di_eattr_save != 0)
Packit Service 360c39
		ip->i_di.di_eattr = di_eattr_save;
Packit Service 360c39
	if (pass->finish_eattr_indir) {
Packit Service 360c39
		if (!first_ea_is_bad) {
Packit Service 360c39
			pass->finish_eattr_indir(ip, leaf_pointers,
Packit Service 360c39
						 leaf_pointer_errors,
Packit Service 360c39
						 pass->private);
Packit Service 360c39
		}
Packit Service 360c39
		if (pass->delete_block && leaf_pointer_errors &&
Packit Service 360c39
		    leaf_pointer_errors == leaf_pointers) {
Packit Service 360c39
			pass->delete_block(ip, indirect, NULL, "leaf", NULL);
Packit Service 360c39
			error = 1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_inode_eattr - check the EA's for a single inode
Packit Service 360c39
 * @ip: the inode whose EA to check
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 on success, -1 on error
Packit Service 360c39
 */
Packit Service 360c39
int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	struct gfs2_buffer_head *indirect_buf = NULL;
Packit Service 360c39
Packit Service 360c39
	if (!ip->i_di.di_eattr)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT){
Packit Service 360c39
		if (!pass->check_eattr_indir)
Packit Service 360c39
			return 0;
Packit Service 360c39
Packit Service 360c39
		log_debug( _("Checking EA indirect block #%llu (0x%llx) for "
Packit Service 360c39
			     "inode #%llu (0x%llx)..\n"),
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_eattr,
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_eattr,
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			   (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
		error = pass->check_eattr_indir(ip, ip->i_di.di_eattr,
Packit Service 360c39
						ip->i_di.di_num.no_addr,
Packit Service 360c39
						&indirect_buf, pass->private);
Packit Service 360c39
		if (!error) {
Packit Service 360c39
			error = check_indirect_eattr(ip, ip->i_di.di_eattr,
Packit Service 360c39
						     indirect_buf, pass);
Packit Service 360c39
			if (error)
Packit Service 360c39
				stack;
Packit Service 360c39
		}
Packit Service 360c39
		if (indirect_buf)
Packit Service 360c39
			brelse(indirect_buf);
Packit Service 360c39
		return error;
Packit Service 360c39
	}
Packit Service 360c39
	error = check_leaf_eattr(ip, ip->i_di.di_eattr,
Packit Service 360c39
				 ip->i_di.di_num.no_addr, pass);
Packit Service 360c39
	if (error)
Packit Service 360c39
		stack;
Packit Service 360c39
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * free_metalist - free all metadata on a multi-level metadata list
Packit Service 360c39
 */
Packit Service 360c39
static void free_metalist(struct gfs2_inode *ip, osi_list_t *mlp)
Packit Service 360c39
{
Packit Service 360c39
	int i;
Packit Service 360c39
	struct gfs2_buffer_head *nbh;
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
Packit Service 360c39
		osi_list_t *list;
Packit Service 360c39
Packit Service 360c39
		list = &mlp[i];
Packit Service 360c39
		while (!osi_list_empty(list)) {
Packit Service 360c39
			nbh = osi_list_entry(list->next,
Packit Service 360c39
					     struct gfs2_buffer_head, b_altlist);
Packit Service 360c39
			if (nbh == ip->i_bh)
Packit Service 360c39
				osi_list_del_init(&nbh->b_altlist);
Packit Service 360c39
			else
Packit Service 360c39
				brelse(nbh);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void file_ra(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
Packit Service 360c39
		    int head_size, int maxptrs, int h)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	uint64_t *p, sblock = 0, block;
Packit Service 360c39
	int extlen = 0;
Packit Service 360c39
Packit Service 360c39
	if (h + 2 == ip->i_di.di_height) {
Packit Service 360c39
		p = (uint64_t *)(bh->b_data + head_size);
Packit Service 360c39
		if (*p && *(p + 1)) {
Packit Service 360c39
			sblock = be64_to_cpu(*p);
Packit Service 360c39
			p++;
Packit Service 360c39
			block = be64_to_cpu(*p);
Packit Service 360c39
			extlen = block - sblock;
Packit Service 360c39
			if (extlen > 1 && extlen <= maxptrs) {
Packit Service 360c39
				posix_fadvise(sdp->device_fd,
Packit Service 360c39
					      sblock * sdp->bsize,
Packit Service 360c39
					      (extlen + 1) * sdp->bsize,
Packit Service 360c39
					      POSIX_FADV_WILLNEED);
Packit Service 360c39
				return;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		extlen = 0;
Packit Service 360c39
	}
Packit Service 360c39
	for (p = (uint64_t *)(bh->b_data + head_size);
Packit Service 360c39
	     p < (uint64_t *)(bh->b_data + sdp->bsize); p++) {
Packit Service 360c39
		if (*p) {
Packit Service 360c39
			if (!sblock) {
Packit Service 360c39
				sblock = be64_to_cpu(*p);
Packit Service 360c39
				extlen = 1;
Packit Service 360c39
				continue;
Packit Service 360c39
			}
Packit Service 360c39
			block = be64_to_cpu(*p);
Packit Service 360c39
			if (block == sblock + extlen) {
Packit Service 360c39
				extlen++;
Packit Service 360c39
				continue;
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
		if (extlen && sblock) {
Packit Service 360c39
			if (extlen > 1)
Packit Service 360c39
				extlen--;
Packit Service 360c39
			posix_fadvise(sdp->device_fd, sblock * sdp->bsize,
Packit Service 360c39
				      extlen * sdp->bsize,
Packit Service 360c39
				      POSIX_FADV_WILLNEED);
Packit Service 360c39
			extlen = 0;
Packit Service 360c39
			p--;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (extlen)
Packit Service 360c39
		posix_fadvise(sdp->device_fd, sblock * sdp->bsize,
Packit Service 360c39
			      extlen * sdp->bsize, POSIX_FADV_WILLNEED);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * build_and_check_metalist - check a bunch of indirect blocks
Packit Service 360c39
 *                            This includes hash table blocks for directories
Packit Service 360c39
 *                            which are technically "data" in the bitmap.
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 - all is well, process the blocks this metadata references
Packit Service 360c39
 *          1 - something went wrong, but process the sub-blocks anyway
Packit Service 360c39
 *         -1 - something went wrong, so don't process the sub-blocks
Packit Service 360c39
 * @ip:
Packit Service 360c39
 * @mlp:
Packit Service 360c39
 */
Packit Service 360c39
static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
Packit Service 360c39
				    struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	uint32_t height = ip->i_di.di_height;
Packit Service 360c39
	struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
Packit Service 360c39
	osi_list_t *prev_list, *cur_list, *tmp;
Packit Service 360c39
	int h, head_size, iblk_type;
Packit Service 360c39
	uint64_t *ptr, block, *undoptr;
Packit Service 360c39
	int error, was_duplicate, is_valid;
Packit Service 360c39
	int maxptrs;
Packit Service 360c39
Packit Service 360c39
	osi_list_add(&metabh->b_altlist, &mlp[0]);
Packit Service 360c39
Packit Service 360c39
	/* Directories are special.  Their 'data' is the hash table, which is
Packit Service 360c39
	   basically an indirect block list. Their height is not important
Packit Service 360c39
	   because it checks everything through the hash table using
Packit Service 360c39
	   "depth" field calculations. However, we still have to check the
Packit Service 360c39
	   indirect blocks, even if the height == 1.  */
Packit Service 360c39
	if (is_dir(&ip->i_di, ip->i_sbd->gfs1))
Packit Service 360c39
		height++;
Packit Service 360c39
Packit Service 360c39
	/* if (<there are no indirect blocks to check>) */
Packit Service 360c39
	if (height < 2)
Packit Service 360c39
		return meta_is_good;
Packit Service 360c39
	for (h = 1; h < height; h++) {
Packit Service 360c39
		if (h > 1) {
Packit Service 360c39
			if (is_dir(&ip->i_di, ip->i_sbd->gfs1) &&
Packit Service 360c39
			    h == ip->i_di.di_height + 1)
Packit Service 360c39
				iblk_type = GFS2_METATYPE_JD;
Packit Service 360c39
			else
Packit Service 360c39
				iblk_type = GFS2_METATYPE_IN;
Packit Service 360c39
			if (ip->i_sbd->gfs1) {
Packit Service 360c39
				head_size = sizeof(struct gfs_indirect);
Packit Service 360c39
				maxptrs = (ip->i_sbd->bsize - head_size) /
Packit Service 360c39
					sizeof(uint64_t);
Packit Service 360c39
			} else {
Packit Service 360c39
				head_size = sizeof(struct gfs2_meta_header);
Packit Service 360c39
				maxptrs = ip->i_sbd->sd_inptrs;
Packit Service 360c39
			}
Packit Service 360c39
		} else {
Packit Service 360c39
			iblk_type = GFS2_METATYPE_DI;
Packit Service 360c39
			head_size = sizeof(struct gfs2_dinode);
Packit Service 360c39
			maxptrs = ip->i_sbd->sd_diptrs;
Packit Service 360c39
		}
Packit Service 360c39
		prev_list = &mlp[h - 1];
Packit Service 360c39
		cur_list = &mlp[h];
Packit Service 360c39
Packit Service 360c39
		for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
Packit Service 360c39
			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
Packit Service 360c39
					    b_altlist);
Packit Service 360c39
			if (gfs2_check_meta(bh, iblk_type)) {
Packit Service 360c39
				if (pass->invalid_meta_is_fatal)
Packit Service 360c39
					return meta_error;
Packit Service 360c39
Packit Service 360c39
				continue;
Packit Service 360c39
			}
Packit Service 360c39
Packit Service 360c39
			if (pass->readahead)
Packit Service 360c39
				file_ra(ip, bh, head_size, maxptrs, h);
Packit Service 360c39
			/* Now check the metadata itself */
Packit Service 360c39
			for (ptr = (uint64_t *)(bh->b_data + head_size);
Packit Service 360c39
			     (char *)ptr < (bh->b_data + ip->i_sbd->bsize);
Packit Service 360c39
			     ptr++) {
Packit Service 360c39
				if (skip_this_pass || fsck_abort) {
Packit Service 360c39
					free_metalist(ip, mlp);
Packit Service 360c39
					return meta_is_good;
Packit Service 360c39
				}
Packit Service 360c39
				nbh = NULL;
Packit Service 360c39
Packit Service 360c39
				if (!*ptr)
Packit Service 360c39
					continue;
Packit Service 360c39
Packit Service 360c39
				block = be64_to_cpu(*ptr);
Packit Service 360c39
				was_duplicate = 0;
Packit Service 360c39
				error = pass->check_metalist(ip, block, &nbh,
Packit Service 360c39
							     h, &is_valid,
Packit Service 360c39
							     &was_duplicate,
Packit Service 360c39
							     pass->private);
Packit Service 360c39
				/* check_metalist should hold any buffers
Packit Service 360c39
				   it gets with "bread". */
Packit Service 360c39
				if (error == meta_error) {
Packit Service 360c39
					stack;
Packit Service 360c39
					log_info(_("\nSerious metadata "
Packit Service 360c39
						   "error on block %llu "
Packit Service 360c39
						   "(0x%llx).\n"),
Packit Service 360c39
						 (unsigned long long)block,
Packit Service 360c39
						 (unsigned long long)block);
Packit Service 360c39
					goto error_undo;
Packit Service 360c39
				}
Packit Service 360c39
				if (error == meta_skip_further) {
Packit Service 360c39
					log_info(_("\nUnrecoverable metadata "
Packit Service 360c39
						   "error on block %llu "
Packit Service 360c39
						   "(0x%llx). Further metadata"
Packit Service 360c39
						   " will be skipped.\n"),
Packit Service 360c39
						 (unsigned long long)block,
Packit Service 360c39
						 (unsigned long long)block);
Packit Service 360c39
					goto error_undo;
Packit Service 360c39
				}
Packit Service 360c39
				if (!is_valid) {
Packit Service 360c39
					log_debug( _("Skipping rejected block "
Packit Service 360c39
						     "%llu (0x%llx)\n"),
Packit Service 360c39
						   (unsigned long long)block,
Packit Service 360c39
						   (unsigned long long)block);
Packit Service 360c39
					if (pass->invalid_meta_is_fatal) {
Packit Service 360c39
						error = meta_error;
Packit Service 360c39
						goto error_undo;
Packit Service 360c39
					}
Packit Service 360c39
					continue;
Packit Service 360c39
				}
Packit Service 360c39
				/* Note that there's a special case in which
Packit Service 360c39
				   we need to process the metadata block, even
Packit Service 360c39
				   if it was a duplicate. That's for cases
Packit Service 360c39
				   where we deleted the last reference as
Packit Service 360c39
				   metadata. */
Packit Service 360c39
				if (was_duplicate) {
Packit Service 360c39
					log_debug( _("Skipping duplicate %llu "
Packit Service 360c39
						     "(0x%llx)\n"),
Packit Service 360c39
						   (unsigned long long)block,
Packit Service 360c39
						   (unsigned long long)block);
Packit Service 360c39
					continue;
Packit Service 360c39
				}
Packit Service 360c39
				if (!valid_block_ip(ip, block)) {
Packit Service 360c39
					log_debug( _("Skipping invalid block "
Packit Service 360c39
						     "%lld (0x%llx)\n"),
Packit Service 360c39
						   (unsigned long long)block,
Packit Service 360c39
						   (unsigned long long)block);
Packit Service 360c39
					if (pass->invalid_meta_is_fatal) {
Packit Service 360c39
						error = meta_error;
Packit Service 360c39
						goto error_undo;
Packit Service 360c39
					}
Packit Service 360c39
					continue;
Packit Service 360c39
				}
Packit Service 360c39
				if (!nbh)
Packit Service 360c39
					nbh = bread(ip->i_sbd, block);
Packit Service 360c39
				osi_list_add_prev(&nbh->b_altlist, cur_list);
Packit Service 360c39
			} /* for all data on the indirect block */
Packit Service 360c39
		} /* for blocks at that height */
Packit Service 360c39
	} /* for height */
Packit Service 360c39
	return 0;
Packit Service 360c39
Packit Service 360c39
error_undo: /* undo what we've done so far for this block */
Packit Service 360c39
	if (pass->undo_check_meta == NULL)
Packit Service 360c39
		return error;
Packit Service 360c39
Packit Service 360c39
	log_info(_("Undoing the work we did before the error on block %llu "
Packit Service 360c39
		   "(0x%llx).\n"), (unsigned long long)bh->b_blocknr,
Packit Service 360c39
		 (unsigned long long)bh->b_blocknr);
Packit Service 360c39
	for (undoptr = (uint64_t *)(bh->b_data + head_size); undoptr < ptr &&
Packit Service 360c39
		     (char *)undoptr < (bh->b_data + ip->i_sbd->bsize);
Packit Service 360c39
	     undoptr++) {
Packit Service 360c39
		if (!*undoptr)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		block = be64_to_cpu(*undoptr);
Packit Service 360c39
		pass->undo_check_meta(ip, block, h, pass->private);
Packit Service 360c39
	}
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_data - check all data pointers for a given buffer
Packit Service 360c39
 *              This does not include "data" blocks that are really
Packit Service 360c39
 *              hash table blocks for directories.
Packit Service 360c39
 *
Packit Service 360c39
 * @ip:
Packit Service 360c39
 *
Packit Service 360c39
 * returns: +ENOENT if there are too many bad pointers
Packit Service 360c39
 *          -1 if a more serious error occurred.
Packit Service 360c39
 *          0 if no errors occurred
Packit Service 360c39
 *          1 if errors were found and corrected
Packit Service 360c39
 *          2 (ENOENT) is there were too many bad pointers
Packit Service 360c39
 */
Packit Service 360c39
static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
Packit Service 360c39
		      struct gfs2_buffer_head *bh, int head_size,
Packit Service 360c39
		      uint64_t *blks_checked, struct error_block *error_blk)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0, rc = 0;
Packit Service 360c39
	uint64_t block, *ptr;
Packit Service 360c39
	uint64_t *ptr_start = (uint64_t *)(bh->b_data + head_size);
Packit Service 360c39
	char *ptr_end = (bh->b_data + ip->i_sbd->bsize);
Packit Service 360c39
	uint64_t metablock = bh->b_blocknr;
Packit Service 360c39
Packit Service 360c39
	/* If there isn't much pointer corruption check the pointers */
Packit Service 360c39
	log_debug(_("\nProcessing data blocks for inode 0x%llx, metadata "
Packit Service 360c39
		    "block 0x%llx.\n"),
Packit Service 360c39
		  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
		  (unsigned long long)bh->b_blocknr);
Packit Service 360c39
	for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
Packit Service 360c39
		if (!*ptr)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		if (skip_this_pass || fsck_abort)
Packit Service 360c39
			return error;
Packit Service 360c39
		block =  be64_to_cpu(*ptr);
Packit Service 360c39
		/* It's important that we don't call valid_block() and
Packit Service 360c39
		   bypass calling check_data on invalid blocks because that
Packit Service 360c39
		   would defeat the rangecheck_block related functions in
Packit Service 360c39
		   pass1. Therefore the individual check_data functions
Packit Service 360c39
		   should do a range check. */
Packit Service 360c39
		rc = pass->check_data(ip, metablock, block, pass->private,
Packit Service 360c39
				      bh, ptr);
Packit Service 360c39
		if (rc && (!error || (rc < error))) {
Packit Service 360c39
			log_info("\n");
Packit Service 360c39
			if (rc < 0) {
Packit Service 360c39
				/* A fatal error trumps a non-fatal one. */
Packit Service 360c39
				if ((error_blk->errblk == 0) ||
Packit Service 360c39
				    (rc < error)) {
Packit Service 360c39
					log_debug(_("Fatal error on metadata "
Packit Service 360c39
						    "block 0x%llx, offset "
Packit Service 360c39
						    "0x%x, referencing block "
Packit Service 360c39
						    "0x%llx preempts non-fatal"
Packit Service 360c39
						    " error on block 0x%llx\n"),
Packit Service 360c39
						  (unsigned long long)metablock,
Packit Service 360c39
						  (int)(ptr - ptr_start),
Packit Service 360c39
						  (unsigned long long)block,
Packit Service 360c39
						  (unsigned long long)error_blk->errblk);
Packit Service 360c39
					error_blk->metablk = metablock;
Packit Service 360c39
					error_blk->metaoff = ptr - ptr_start;
Packit Service 360c39
					error_blk->errblk = block;
Packit Service 360c39
				}
Packit Service 360c39
				log_info(_("Unrecoverable "));
Packit Service 360c39
			} else { /* nonfatal error */
Packit Service 360c39
				if (error_blk->errblk == 0) {
Packit Service 360c39
					error_blk->metablk = metablock;
Packit Service 360c39
					error_blk->metaoff = ptr - ptr_start;
Packit Service 360c39
					error_blk->errblk = block;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			log_info(_("data block error %d on metadata block "
Packit Service 360c39
				   "%lld (0x%llx), offset %d (0x%x), "
Packit Service 360c39
				   "referencing data block %lld (0x%llx).\n"),
Packit Service 360c39
				 rc, (unsigned long long)metablock,
Packit Service 360c39
				 (unsigned long long)metablock,
Packit Service 360c39
				 (int)(ptr - ptr_start),
Packit Service 360c39
				 (int)(ptr - ptr_start),
Packit Service 360c39
				 (unsigned long long)block,
Packit Service 360c39
				 (unsigned long long)block);
Packit Service 360c39
			error = rc;
Packit Service 360c39
		}
Packit Service 360c39
		if (rc < 0)
Packit Service 360c39
			return rc;
Packit Service 360c39
		(*blks_checked)++;
Packit Service 360c39
	}
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
Packit Service 360c39
			   uint64_t metablock,
Packit Service 360c39
			   uint64_t *ptr_start, char *ptr_end,
Packit Service 360c39
			   struct error_block *error_blk, int error)
Packit Service 360c39
{
Packit Service 360c39
	int rc = 0;
Packit Service 360c39
	uint64_t block, *ptr;
Packit Service 360c39
	int found_error_blk = 0;
Packit Service 360c39
Packit Service 360c39
	/* If there isn't much pointer corruption check the pointers */
Packit Service 360c39
	for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
Packit Service 360c39
		if (!*ptr)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		if (skip_this_pass || fsck_abort)
Packit Service 360c39
			return 1;
Packit Service 360c39
		block =  be64_to_cpu(*ptr);
Packit Service 360c39
		if (metablock == error_blk->metablk &&
Packit Service 360c39
		    (ptr - ptr_start == error_blk->metaoff) &&
Packit Service 360c39
		    block == error_blk->errblk) {
Packit Service 360c39
			if (error < 0) { /* A fatal error that stopped it? */
Packit Service 360c39
				log_debug(_("Stopping the undo process: "
Packit Service 360c39
					    "fatal error block 0x%llx was "
Packit Service 360c39
					    "found at metadata block 0x%llx,"
Packit Service 360c39
					    "offset 0x%x.\n"),
Packit Service 360c39
					  (unsigned long long)error_blk->errblk,
Packit Service 360c39
					  (unsigned long long)error_blk->metablk,
Packit Service 360c39
					  error_blk->metaoff);
Packit Service 360c39
				return 1;
Packit Service 360c39
			}
Packit Service 360c39
			found_error_blk = 1;
Packit Service 360c39
			log_debug(_("The non-fatal error block 0x%llx was "
Packit Service 360c39
				    "found at metadata block 0x%llx, offset "
Packit Service 360c39
				    "0x%d, but undo processing will continue "
Packit Service 360c39
				    "until the end of this metadata block.\n"),
Packit Service 360c39
				  (unsigned long long)error_blk->errblk,
Packit Service 360c39
				  (unsigned long long)error_blk->metablk,
Packit Service 360c39
				  error_blk->metaoff);
Packit Service 360c39
		}
Packit Service 360c39
		rc = pass->undo_check_data(ip, block, pass->private);
Packit Service 360c39
		if (rc < 0)
Packit Service 360c39
			return rc;
Packit Service 360c39
	}
Packit Service 360c39
	return found_error_blk;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int hdr_size(struct gfs2_buffer_head *bh, int height)
Packit Service 360c39
{
Packit Service 360c39
	if (height > 1) {
Packit Service 360c39
		if (gfs2_check_meta(bh, GFS2_METATYPE_IN))
Packit Service 360c39
			return 0;
Packit Service 360c39
		if (bh->sdp->gfs1)
Packit Service 360c39
			return sizeof(struct gfs_indirect);
Packit Service 360c39
		else
Packit Service 360c39
			return sizeof(struct gfs2_meta_header);
Packit Service 360c39
	}
Packit Service 360c39
	/* if this isn't really a dinode, skip it */
Packit Service 360c39
	if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	return sizeof(struct gfs2_dinode);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_metatree
Packit Service 360c39
 * @ip: inode structure in memory
Packit Service 360c39
 * @pass: structure passed in from caller to determine the sub-functions
Packit Service 360c39
 *
Packit Service 360c39
 */
Packit Service 360c39
int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
Packit Service 360c39
	osi_list_t *list, *tmp;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	uint32_t height = ip->i_di.di_height;
Packit Service 360c39
	int  i, head_size;
Packit Service 360c39
	uint64_t blks_checked = 0;
Packit Service 360c39
	int error, rc;
Packit Service 360c39
	int metadata_clean = 0;
Packit Service 360c39
	struct error_block error_blk = {0, 0, 0};
Packit Service 360c39
	int hit_error_blk = 0;
Packit Service 360c39
Packit Service 360c39
	if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
Packit Service 360c39
		osi_list_init(&metalist[i]);
Packit Service 360c39
Packit Service 360c39
	/* create and check the metadata list for each height */
Packit Service 360c39
	error = build_and_check_metalist(ip, &metalist[0], pass);
Packit Service 360c39
	if (error) {
Packit Service 360c39
		stack;
Packit Service 360c39
		goto undo_metalist;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	metadata_clean = 1;
Packit Service 360c39
	/* For directories, we've already checked the "data" blocks which
Packit Service 360c39
	 * comprise the directory hash table, so we perform the directory
Packit Service 360c39
	 * checks and exit. */
Packit Service 360c39
        if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
Packit Service 360c39
		if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
Packit Service 360c39
			goto out;
Packit Service 360c39
		/* check validity of leaf blocks and leaf chains */
Packit Service 360c39
		error = check_leaf_blks(ip, pass);
Packit Service 360c39
		if (error)
Packit Service 360c39
			goto undo_metalist;
Packit Service 360c39
		goto out;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	/* check data blocks */
Packit Service 360c39
	list = &metalist[height - 1];
Packit Service 360c39
	if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
Packit Service 360c39
		last_reported_fblock = -10000000;
Packit Service 360c39
Packit Service 360c39
	for (tmp = list->next; !error && tmp != list; tmp = tmp->next) {
Packit Service 360c39
		if (fsck_abort) {
Packit Service 360c39
			free_metalist(ip, &metalist[0]);
Packit Service 360c39
			return 0;
Packit Service 360c39
		}
Packit Service 360c39
		bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist);
Packit Service 360c39
		head_size = hdr_size(bh, height);
Packit Service 360c39
		if (!head_size)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		if (pass->check_data)
Packit Service 360c39
			error = check_data(ip, pass, bh, head_size,
Packit Service 360c39
					   &blks_checked, &error_blk);
Packit Service 360c39
		if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS)
Packit Service 360c39
			pass->big_file_msg(ip, blks_checked);
Packit Service 360c39
	}
Packit Service 360c39
	if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS) {
Packit Service 360c39
		log_notice( _("\rLarge file at %lld (0x%llx) - 100 percent "
Packit Service 360c39
			      "complete.                                   "
Packit Service 360c39
			      "\n"),
Packit Service 360c39
			    (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
			    (unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
		fflush(stdout);
Packit Service 360c39
	}
Packit Service 360c39
undo_metalist:
Packit Service 360c39
	if (!error)
Packit Service 360c39
		goto out;
Packit Service 360c39
	log_err( _("Error: inode %llu (0x%llx) had unrecoverable errors at "
Packit Service 360c39
		   "metadata block %lld (0x%llx), offset %d (0x%x), block "
Packit Service 360c39
		   "%lld (0x%llx).\n"),
Packit Service 360c39
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
		 (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
		 (unsigned long long)error_blk.metablk,
Packit Service 360c39
		 (unsigned long long)error_blk.metablk,
Packit Service 360c39
		 error_blk.metaoff, error_blk.metaoff,
Packit Service 360c39
		 (unsigned long long)error_blk.errblk,
Packit Service 360c39
		 (unsigned long long)error_blk.errblk);
Packit Service 360c39
	if (!query( _("Remove the invalid inode? (y/n) "))) {
Packit Service 360c39
		free_metalist(ip, &metalist[0]);
Packit Service 360c39
		log_err(_("Invalid inode not deleted.\n"));
Packit Service 360c39
		return error;
Packit Service 360c39
	}
Packit Service 360c39
	for (i = 0; pass->undo_check_meta && i < height; i++) {
Packit Service 360c39
		while (!osi_list_empty(&metalist[i])) {
Packit Service 360c39
			list = &metalist[i];
Packit Service 360c39
			bh = osi_list_entry(list->next,
Packit Service 360c39
					    struct gfs2_buffer_head,
Packit Service 360c39
					    b_altlist);
Packit Service 360c39
			log_err(_("Undoing metadata work for block %llu "
Packit Service 360c39
				  "(0x%llx)\n"),
Packit Service 360c39
				(unsigned long long)bh->b_blocknr,
Packit Service 360c39
				(unsigned long long)bh->b_blocknr);
Packit Service 360c39
			if (i)
Packit Service 360c39
				rc = pass->undo_check_meta(ip, bh->b_blocknr,
Packit Service 360c39
							   i, pass->private);
Packit Service 360c39
			else
Packit Service 360c39
				rc = 0;
Packit Service 360c39
			if (metadata_clean && rc == 0 && i == height - 1 &&
Packit Service 360c39
			    !hit_error_blk) {
Packit Service 360c39
				head_size = hdr_size(bh, height);
Packit Service 360c39
				if (head_size) {
Packit Service 360c39
					rc = undo_check_data(ip, pass,
Packit Service 360c39
							     bh->b_blocknr,
Packit Service 360c39
							     (uint64_t *)
Packit Service 360c39
					      (bh->b_data + head_size),
Packit Service 360c39
					      (bh->b_data + ip->i_sbd->bsize),
Packit Service 360c39
							     &error_blk,
Packit Service 360c39
							     error);
Packit Service 360c39
					if (rc > 0) {
Packit Service 360c39
						hit_error_blk = 1;
Packit Service 360c39
						log_err("Reached the error "
Packit Service 360c39
							"block undoing work "
Packit Service 360c39
							"for inode %lld "
Packit Service 360c39
							"(0x%llx).\n",
Packit Service 360c39
							(unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
							(unsigned long long)ip->i_di.di_num.no_addr);
Packit Service 360c39
						rc = 0;
Packit Service 360c39
					}
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			if (bh == ip->i_bh)
Packit Service 360c39
				osi_list_del(&bh->b_altlist);
Packit Service 360c39
			else
Packit Service 360c39
				brelse(bh);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* There may be leftover duplicate records, so we need to delete them.
Packit Service 360c39
	   For example, if a metadata block was found to be a duplicate, we
Packit Service 360c39
	   may not have added it to the metalist, which means it's not there
Packit Service 360c39
	   to undo. */
Packit Service 360c39
	delete_all_dups(ip);
Packit Service 360c39
	/* Set the dinode as "bad" so it gets deleted */
Packit Service 360c39
	fsck_bitmap_set(ip, ip->i_di.di_num.no_addr, _("corrupt"),
Packit Service 360c39
			GFS2_BLKST_FREE);
Packit Service 360c39
	log_err(_("The corrupt inode was invalidated.\n"));
Packit Service 360c39
out:
Packit Service 360c39
	free_metalist(ip, &metalist[0]);
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* Checks stuffed inode directories */
Packit Service 360c39
int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
Packit Service 360c39
		     struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	uint32_t count = 0;
Packit Service 360c39
Packit Service 360c39
	error = check_entries(ip, bh, DIR_LINEAR, &count, 0, pass);
Packit Service 360c39
	if (error < 0) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
int check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip, struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0;
Packit Service 360c39
Packit Service 360c39
	if (ip->i_di.di_flags & GFS2_DIF_EXHASH)
Packit Service 360c39
		error = check_leaf_blks(ip, pass);
Packit Service 360c39
	else
Packit Service 360c39
		error = check_linear_dir(ip, ip->i_bh, pass);
Packit Service 360c39
Packit Service 360c39
	if (error < 0)
Packit Service 360c39
		stack;
Packit Service 360c39
Packit Service 360c39
	return error;
Packit Service 360c39
}