Blame gfs2/fsck/pass1.c

Packit Service 360c39
/* pass1 checks inodes for format & type, duplicate blocks, & incorrect
Packit Service 360c39
 * block count.
Packit Service 360c39
 *
Packit Service 360c39
 * It builds up tables that contains the state of each block (free,
Packit Service 360c39
 * block in use, metadata type, etc), as well as bad blocks and
Packit Service 360c39
 * duplicate blocks.  (See block_list.[ch] for more info)
Packit Service 360c39
 *
Packit Service 360c39
 */
Packit Service 360c39
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <sys/time.h>
Packit Service 360c39
#include <sys/stat.h>
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <time.h>
Packit Service 360c39
#include <fcntl.h>
Packit Service 360c39
#include <sys/ioctl.h>
Packit Service 360c39
#include <inttypes.h>
Packit Service 360c39
#include <libintl.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 "fsck.h"
Packit Service 360c39
#include "inode_hash.h"
Packit Service 360c39
#include "util.h"
Packit Service 360c39
#include "link.h"
Packit Service 360c39
#include "metawalk.h"
Packit Service 360c39
#include "fs_recovery.h"
Packit Service 360c39
Packit Service 360c39
struct special_blocks gfs1_rindex_blks;
Packit Service 360c39
struct gfs2_bmap *bl = NULL;
Packit Service 360c39
Packit Service 360c39
struct block_count {
Packit Service 360c39
	uint64_t indir_count;
Packit Service 360c39
	uint64_t data_count;
Packit Service 360c39
	uint64_t ea_count;
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
Packit Service 360c39
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit Service 360c39
			  int *was_duplicate, void *private);
Packit Service 360c39
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			       int h, void *private);
Packit Service 360c39
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
		      uint64_t block, void *private,
Packit Service 360c39
		      struct gfs2_buffer_head *bh, uint64_t *ptr);
Packit Service 360c39
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			   void *private);
Packit Service 360c39
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
Packit Service 360c39
			     uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
			     void *private);
Packit Service 360c39
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			    uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
			    void *private);
Packit Service 360c39
static int check_eattr_entries(struct gfs2_inode *ip,
Packit Service 360c39
			       struct gfs2_buffer_head *leaf_bh,
Packit Service 360c39
			       struct gfs2_ea_header *ea_hdr,
Packit Service 360c39
			       struct gfs2_ea_header *ea_hdr_prev,
Packit Service 360c39
			       void *private);
Packit Service 360c39
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
Packit Service 360c39
				     uint64_t *data_ptr,
Packit Service 360c39
				     struct gfs2_buffer_head *leaf_bh,
Packit Service 360c39
				     uint32_t tot_ealen,
Packit Service 360c39
				     struct gfs2_ea_header *ea_hdr,
Packit Service 360c39
				     struct gfs2_ea_header *ea_hdr_prev,
Packit Service 360c39
				     void *private);
Packit Service 360c39
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
Packit Service 360c39
			      int leaf_pointer_errors, void *private);
Packit Service 360c39
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			       struct gfs2_buffer_head **bh, int h,
Packit Service 360c39
			       int *is_valid, int *was_duplicate,
Packit Service 360c39
			       void *private);
Packit Service 360c39
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			   void *private);
Packit Service 360c39
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
			   uint64_t block, void *private,
Packit Service 360c39
			   struct gfs2_buffer_head *bh, uint64_t *ptr);
Packit Service 360c39
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				  uint64_t parent,
Packit Service 360c39
				  struct gfs2_buffer_head **bh,
Packit Service 360c39
				  void *private);
Packit Service 360c39
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
				 void *private);
Packit Service 360c39
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip);
Packit Service 360c39
static int delete_block(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			struct gfs2_buffer_head **bh, const char *btype,
Packit Service 360c39
			void *private);
Packit Service 360c39
Packit Service 360c39
static int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark)
Packit Service 360c39
{
Packit Service 360c39
	static unsigned char *byte;
Packit Service 360c39
	static uint64_t b;
Packit Service 360c39
Packit Service 360c39
	if (!bmap)
Packit Service 360c39
		return 0;
Packit Service 360c39
	if (bblock > bmap->size)
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	byte = bmap->map + BLOCKMAP_SIZE2(bblock);
Packit Service 360c39
	b = BLOCKMAP_BYTE_OFFSET2(bblock);
Packit Service 360c39
	*byte &= ~(BLOCKMAP_MASK2 << b);
Packit Service 360c39
	*byte |= (mark & BLOCKMAP_MASK2) << b;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * _fsck_blockmap_set - Mark a block in the 4-bit blockmap and the 2-bit
Packit Service 360c39
 *                      bitmap, and adjust free space accordingly.
Packit Service 360c39
 */
Packit Service 360c39
static int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
Packit Service 360c39
			      const char *btype, int mark, int error_on_dinode,
Packit Service 360c39
			      const char *caller, int fline)
Packit Service 360c39
{
Packit Service 360c39
	int error = _fsck_bitmap_set(ip, bblock, btype, mark, error_on_dinode,
Packit Service 360c39
				     caller, fline);
Packit Service 360c39
	if (error)
Packit Service 360c39
		return error;
Packit Service 360c39
Packit Service 360c39
	return gfs2_blockmap_set(bl, bblock, mark);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
#define fsck_blockmap_set(ip, b, bt, m) \
Packit Service 360c39
	_fsck_blockmap_set(ip, b, bt, m, 0, __FUNCTION__, __LINE__)
Packit Service 360c39
#define fsck_blkmap_set_noino(ip, b, bt, m) \
Packit Service 360c39
	_fsck_blockmap_set(ip, b, bt, m, 1, __FUNCTION__, __LINE__)
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * delete_block - delete a block associated with an inode
Packit Service 360c39
 */
Packit Service 360c39
static int delete_block(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			struct gfs2_buffer_head **bh, const char *btype,
Packit Service 360c39
			void *private)
Packit Service 360c39
{
Packit Service 360c39
	if (valid_block_ip(ip, block)) {
Packit Service 360c39
		fsck_blockmap_set(ip, block, btype, GFS2_BLKST_FREE);
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	return -1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* This is a pass1-specific leaf repair. Since we are not allowed to do
Packit Service 360c39
 * block allocations, we do what we can. */
Packit Service 360c39
static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
Packit Service 360c39
			     int lindex, int ref_count, const char *msg)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t *cpyptr;
Packit Service 360c39
	char *padbuf;
Packit Service 360c39
	int pad_size, i;
Packit Service 360c39
Packit Service 360c39
	log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
Packit Service 360c39
		   " (0x%llx) %s.\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, msg);
Packit Service 360c39
	if (!query( _("Attempt to patch around it? (y/n) "))) {
Packit Service 360c39
		log_err( _("Bad leaf left in place.\n"));
Packit Service 360c39
		goto out;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	padbuf = malloc(ref_count * sizeof(uint64_t));
Packit Service 360c39
	cpyptr = (uint64_t *)padbuf;
Packit Service 360c39
	for (i = 0; i < ref_count; i++) {
Packit Service 360c39
		*cpyptr = 0;
Packit Service 360c39
		cpyptr++;
Packit Service 360c39
	}
Packit Service 360c39
	pad_size = ref_count * sizeof(uint64_t);
Packit Service 360c39
	log_err(_("Writing zeros to the hash table of directory %lld "
Packit Service 360c39
		  "(0x%llx) at index: 0x%x for 0x%x pointers.\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, lindex,
Packit Service 360c39
		ref_count);
Packit Service 360c39
	if (ip->i_sbd->gfs1)
Packit Service 360c39
		gfs1_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
Packit Service 360c39
	else
Packit Service 360c39
		gfs2_writei(ip, padbuf, lindex * sizeof(uint64_t), pad_size);
Packit Service 360c39
	free(padbuf);
Packit Service 360c39
	log_err( _("Directory Inode %llu (0x%llx) patched.\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
Packit Service 360c39
out:
Packit Service 360c39
	*leaf_no = 0;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns pass1_fxns = {
Packit Service 360c39
	.private = NULL,
Packit Service 360c39
	.check_leaf = p1check_leaf,
Packit Service 360c39
	.check_metalist = check_metalist,
Packit Service 360c39
	.check_data = check_data,
Packit Service 360c39
	.check_eattr_indir = check_eattr_indir,
Packit Service 360c39
	.check_eattr_leaf = check_eattr_leaf,
Packit Service 360c39
	.check_dentry = NULL,
Packit Service 360c39
	.check_eattr_entry = check_eattr_entries,
Packit Service 360c39
	.check_eattr_extentry = check_extended_leaf_eattr,
Packit Service 360c39
	.big_file_msg = big_file_comfort,
Packit Service 360c39
	.repair_leaf = pass1_repair_leaf,
Packit Service 360c39
	.undo_check_meta = undo_check_metalist,
Packit Service 360c39
	.undo_check_data = undo_check_data,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns invalidate_fxns = {
Packit Service 360c39
	.private = NULL,
Packit Service 360c39
	.check_metalist = invalidate_metadata,
Packit Service 360c39
	.check_data = invalidate_data,
Packit Service 360c39
	.check_leaf = invalidate_leaf,
Packit Service 360c39
	.check_eattr_indir = invalidate_eattr_indir,
Packit Service 360c39
	.check_eattr_leaf = invalidate_eattr_leaf,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * resuscitate_metalist - make sure a system directory entry's metadata blocks
Packit Service 360c39
 *                        are marked "in use" in the bitmap.
Packit Service 360c39
 *
Packit Service 360c39
 * This function makes sure metadata blocks for system and root directories are
Packit Service 360c39
 * marked "in use" by the bitmap.  You don't want root's indirect blocks
Packit Service 360c39
 * deleted, do you? Or worse, reused for lost+found.
Packit Service 360c39
 */
Packit Service 360c39
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				struct gfs2_buffer_head **bh, int h,
Packit Service 360c39
				int *is_valid, int *was_duplicate,
Packit Service 360c39
				void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct block_count *bc = (struct block_count *)private;
Packit Service 360c39
Packit Service 360c39
	*is_valid = 1;
Packit Service 360c39
	*was_duplicate = 0;
Packit Service 360c39
	*bh = NULL;
Packit Service 360c39
	if (!valid_block_ip(ip, block)){ /* blk outside of FS */
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("itself"), GFS2_BLKST_UNLINKED);
Packit Service 360c39
		log_err( _("Bad indirect block pointer (invalid or out of "
Packit Service 360c39
			   "range) found in system inode %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
		*is_valid = 0;
Packit Service 360c39
		return meta_is_good;
Packit Service 360c39
	}
Packit Service 360c39
	if (fsck_system_inode(ip->i_sbd, block))
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("system file"),
Packit Service 360c39
				  ip->i_sbd->gfs1 ?
Packit Service 360c39
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
	else
Packit Service 360c39
		check_n_fix_bitmap(ip->i_sbd, ip->i_rgd, block, 0,
Packit Service 360c39
				   ip->i_sbd->gfs1 ?
Packit Service 360c39
				   GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
	bc->indir_count++;
Packit Service 360c39
	return meta_is_good;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * resuscitate_dentry - make sure a system directory entry is alive
Packit Service 360c39
 *
Packit Service 360c39
 * This function makes sure directory entries in system directories are
Packit Service 360c39
 * kept alive.  You don't want journal0 deleted from jindex, do you?
Packit Service 360c39
 */
Packit Service 360c39
static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
Packit Service 360c39
			      struct gfs2_dirent *prev_de,
Packit Service 360c39
			      struct gfs2_buffer_head *bh, char *filename,
Packit Service 360c39
			      uint32_t *count, int *lindex, void *priv)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	struct gfs2_dirent dentry, *de;
Packit Service 360c39
	char tmp_name[PATH_MAX];
Packit Service 360c39
	uint64_t block;
Packit Service 360c39
Packit Service 360c39
	memset(&dentry, 0, sizeof(struct gfs2_dirent));
Packit Service 360c39
	gfs2_dirent_in(&dentry, (char *)dent);
Packit Service 360c39
	de = &dentry;
Packit Service 360c39
	block = de->de_inum.no_addr;
Packit Service 360c39
	/* Start of checks */
Packit Service 360c39
	memset(tmp_name, 0, sizeof(tmp_name));
Packit Service 360c39
	if (de->de_name_len < sizeof(tmp_name))
Packit Service 360c39
		strncpy(tmp_name, filename, de->de_name_len);
Packit Service 360c39
	else
Packit Service 360c39
		strncpy(tmp_name, filename, sizeof(tmp_name) - 1);
Packit Service 360c39
	if (!valid_block_ip(ip, block)) {
Packit Service 360c39
		log_err( _("Block # referenced by system directory entry %s "
Packit Service 360c39
			   "in inode %lld (0x%llx) is invalid or out of range;"
Packit Service 360c39
			   " ignored.\n"),
Packit Service 360c39
			 tmp_name, (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
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	/* If this is a system dinode, we'll handle it later in
Packit Service 360c39
	   check_system_inodes.  If not, it'll be handled by pass1 but
Packit Service 360c39
	   since it's in a system directory we need to make sure it's
Packit Service 360c39
	   represented in the rgrp bitmap. */
Packit Service 360c39
	if (fsck_system_inode(sdp, block))
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("system file"),
Packit Service 360c39
				  GFS2_BLKST_DINODE);
Packit Service 360c39
	else
Packit Service 360c39
		check_n_fix_bitmap(sdp, ip->i_rgd, block, 0,
Packit Service 360c39
				   GFS2_BLKST_DINODE);
Packit Service 360c39
	/* Return the number of leaf entries so metawalk doesn't flag this
Packit Service 360c39
	   leaf as having none. */
Packit Service 360c39
	*count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns sysdir_fxns = {
Packit Service 360c39
	.private = NULL,
Packit Service 360c39
	.check_metalist = resuscitate_metalist,
Packit Service 360c39
	.check_dentry = resuscitate_dentry,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
	int q;
Packit Service 360c39
Packit Service 360c39
	/* Note if we've gotten this far, the block has already passed the
Packit Service 360c39
	   check in metawalk: gfs2_check_meta(lbh, GFS2_METATYPE_LF).
Packit Service 360c39
	   So we know it's a leaf block. */
Packit Service 360c39
	bc->indir_count++;
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
		log_err( _("Found duplicate block #%llu (0x%llx) referenced "
Packit Service 360c39
			   "as a directory leaf in dinode "
Packit Service 360c39
			   "%llu (0x%llx) - was marked %d (%s)\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, q,
Packit Service 360c39
			 block_type_string(q));
Packit Service 360c39
		add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
Packit Service 360c39
		if (q == (ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit Service 360c39
			  GFS2_BLKST_USED))
Packit Service 360c39
			/* If the previous reference also saw this as a leaf,
Packit Service 360c39
			   it was already checked, so don't check again. */
Packit Service 360c39
			return EEXIST; /* non-fatal */
Packit Service 360c39
	}
Packit Service 360c39
	fsck_blockmap_set(ip, block, _("directory leaf"),
Packit Service 360c39
			  ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit Service 360c39
			  GFS2_BLKST_USED);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit Service 360c39
			  int *was_duplicate, void *private)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
	int iblk_type;
Packit Service 360c39
	struct gfs2_buffer_head *nbh;
Packit Service 360c39
	struct block_count *bc = (struct block_count *)private;
Packit Service 360c39
	const char *blktypedesc;
Packit Service 360c39
Packit Service 360c39
	*bh = NULL;
Packit Service 360c39
Packit Service 360c39
	*was_duplicate = 0;
Packit Service 360c39
	*is_valid = 0;
Packit Service 360c39
	if (!valid_block_ip(ip, block)) { /* blk outside of FS */
Packit Service 360c39
		/* The bad dinode should be invalidated later due to
Packit Service 360c39
		   "unrecoverable" errors.  The inode itself should be
Packit Service 360c39
		   set "free" and removed from the inodetree by
Packit Service 360c39
		   undo_check_metalist. */
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("bad block referencing"), GFS2_BLKST_UNLINKED);
Packit Service 360c39
		log_debug( _("Bad indirect block (invalid/out of range) "
Packit Service 360c39
			     "found in inode %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
Packit Service 360c39
		return meta_skip_further;
Packit Service 360c39
	}
Packit Service 360c39
	if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
Packit Service 360c39
		iblk_type = GFS2_METATYPE_JD;
Packit Service 360c39
		blktypedesc = _("a directory hash table block");
Packit Service 360c39
	} else {
Packit Service 360c39
		iblk_type = GFS2_METATYPE_IN;
Packit Service 360c39
		blktypedesc = _("a journaled data block");
Packit Service 360c39
	}
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
		log_err( _("Found duplicate block #%llu (0x%llx) referenced "
Packit Service 360c39
			   "as metadata in indirect block for dinode "
Packit Service 360c39
			   "%llu (0x%llx) - was marked %d (%s)\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, q,
Packit Service 360c39
			 block_type_string(q));
Packit Service 360c39
		*was_duplicate = 1;
Packit Service 360c39
	}
Packit Service 360c39
	nbh = bread(ip->i_sbd, block);
Packit Service 360c39
Packit Service 360c39
	*is_valid = (gfs2_check_meta(nbh, iblk_type) == 0);
Packit Service 360c39
Packit Service 360c39
	if (!(*is_valid)) {
Packit Service 360c39
		log_err( _("Inode %lld (0x%llx) has a bad indirect block "
Packit Service 360c39
			   "pointer %lld (0x%llx) (points to something "
Packit Service 360c39
			   "that is not %s).\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)block,
Packit Service 360c39
			 (unsigned long long)block, blktypedesc);
Packit Service 360c39
		brelse(nbh);
Packit Service 360c39
		return meta_skip_further;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	bc->indir_count++;
Packit Service 360c39
	if (*was_duplicate) {
Packit Service 360c39
		add_duplicate_ref(ip, block, ref_as_meta, 0,
Packit Service 360c39
				  *is_valid ? INODE_VALID : INODE_INVALID);
Packit Service 360c39
		brelse(nbh);
Packit Service 360c39
	} else {
Packit Service 360c39
		*bh = nbh;
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("indirect"), ip->i_sbd->gfs1 ?
Packit Service 360c39
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (*is_valid)
Packit Service 360c39
		return meta_is_good;
Packit Service 360c39
	return meta_skip_further;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* undo_reference - undo previously processed data or metadata
Packit Service 360c39
 * We've treated the metadata for this dinode as good so far, but not we
Packit Service 360c39
 * realize it's bad. So we need to undo what we've done.
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 - We need to process the block as metadata. In other words,
Packit Service 360c39
 *              we need to undo any blocks it refers to.
Packit Service 360c39
 *          1 - We can't process the block as metadata.
Packit Service 360c39
 */
Packit Service 360c39
Packit Service 360c39
static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
Packit Service 360c39
			  void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct block_count *bc = (struct block_count *)private;
Packit Service 360c39
	struct duptree *dt;
Packit Service 360c39
	struct inode_with_dups *id;
Packit Service 360c39
	int old_bitmap_state = 0;
Packit Service 360c39
	struct rgrp_tree *rgd;
Packit Service 360c39
Packit Service 360c39
	if (!valid_block_ip(ip, block)) { /* blk outside of FS */
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("bad block referencing"), GFS2_BLKST_FREE);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (meta)
Packit Service 360c39
		bc->indir_count--;
Packit Service 360c39
	dt = dupfind(block);
Packit Service 360c39
	if (dt) {
Packit Service 360c39
		/* remove all duplicate reference structures from this inode */
Packit Service 360c39
		do {
Packit Service 360c39
			id = find_dup_ref_inode(dt, ip);
Packit Service 360c39
			if (!id)
Packit Service 360c39
				break;
Packit Service 360c39
Packit Service 360c39
			dup_listent_delete(dt, id);
Packit Service 360c39
		} while (id);
Packit Service 360c39
Packit Service 360c39
		if (dt->refs) {
Packit Service 360c39
			log_err(_("Block %llu (0x%llx) is still referenced "
Packit Service 360c39
				  "from another inode; not freeing.\n"),
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)block);
Packit Service 360c39
			if (dt->refs == 1) {
Packit Service 360c39
				log_err(_("This was the only duplicate "
Packit Service 360c39
					  "reference so far; removing it.\n"));
Packit Service 360c39
				dup_delete(dt);
Packit Service 360c39
			}
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (!meta) {
Packit Service 360c39
		rgd = gfs2_blk2rgrpd(ip->i_sbd, block);
Packit Service 360c39
		old_bitmap_state = lgfs2_get_bitmap(ip->i_sbd, block, rgd);
Packit Service 360c39
		if (old_bitmap_state == GFS2_BLKST_DINODE)
Packit Service 360c39
			return -1;
Packit Service 360c39
	}
Packit Service 360c39
	fsck_blockmap_set(ip, block,
Packit Service 360c39
			  meta ? _("bad indirect") : _("referenced data"),
Packit Service 360c39
			  GFS2_BLKST_FREE);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			       int h, void *private)
Packit Service 360c39
{
Packit Service 360c39
	return undo_reference(ip, block, 1, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			   void *private)
Packit Service 360c39
{
Packit Service 360c39
	return undo_reference(ip, block, 0, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* blockmap_set_as_data - set block as 'data' in the blockmap, if not dinode
Packit Service 360c39
 *
Packit Service 360c39
 * This function tries to set a block that's referenced as data as 'data'
Packit Service 360c39
 * in the fsck blockmap. But if that block is marked as 'dinode' in the
Packit Service 360c39
 * rgrp bitmap, it does additional checks to see if it looks like a dinode.
Packit Service 360c39
 * Note that previous checks were done for duplicate references, so this
Packit Service 360c39
 * is checking for dinodes that we haven't processed yet.
Packit Service 360c39
 */
Packit Service 360c39
static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	struct gfs2_dinode *di;
Packit Service 360c39
Packit Service 360c39
	error = fsck_blkmap_set_noino(ip, block, _("data"), GFS2_BLKST_USED);
Packit Service 360c39
	if (!error)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	error = 0;
Packit Service 360c39
	/* The bitmap says it's a dinode, but a block reference begs to differ.
Packit Service 360c39
	   So which is it? */
Packit Service 360c39
	bh = bread(ip->i_sbd, block);
Packit Service 360c39
	if (gfs2_check_meta(bh, GFS2_METATYPE_DI) != 0)
Packit Service 360c39
		goto out;
Packit Service 360c39
Packit Service 360c39
	/* The meta header agrees it's a dinode. But it might be data in
Packit Service 360c39
	   disguise, so do some extra checks. */
Packit Service 360c39
	di = (struct gfs2_dinode *)bh->b_data;
Packit Service 360c39
	if (be64_to_cpu(di->di_num.no_addr) != block)
Packit Service 360c39
		goto out;
Packit Service 360c39
Packit Service 360c39
	log_err(_("Inode %lld (0x%llx) has a reference to block %lld (0x%llx) "
Packit Service 360c39
		  "as a data block, but it appears to be a dinode we "
Packit Service 360c39
		  "haven't checked yet.\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)block, (unsigned long long)block);
Packit Service 360c39
	error = -1;
Packit Service 360c39
out:
Packit Service 360c39
	if (!error)
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("data"),  GFS2_BLKST_USED);
Packit Service 360c39
	brelse(bh);
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
		      uint64_t block, void *private,
Packit Service 360c39
		      struct gfs2_buffer_head *bbh, uint64_t *ptr)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
Packit Service 360c39
	if (!valid_block_ip(ip, block)) {
Packit Service 360c39
		log_err( _("inode %lld (0x%llx) has a bad data block pointer "
Packit Service 360c39
			   "%lld (0x%llx) (invalid or out of range) "),
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)block, (unsigned long long)block);
Packit Service 360c39
		if (metablock == ip->i_di.di_num.no_addr)
Packit Service 360c39
			log_err("\n");
Packit Service 360c39
		else
Packit Service 360c39
			log_err(_("from metadata block %llu (0x%llx)\n"),
Packit Service 360c39
				(unsigned long long)metablock,
Packit Service 360c39
				(unsigned long long)metablock);
Packit Service 360c39
		/* Mark the owner of this block with the bad_block
Packit Service 360c39
		 * designator so we know to check it for out of range
Packit Service 360c39
		 * blocks later */
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("bad (out of range) data"),
Packit Service 360c39
				  GFS2_BLKST_UNLINKED);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	bc->data_count++; /* keep the count sane anyway */
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
		struct gfs2_buffer_head *bh;
Packit Service 360c39
		struct gfs2_meta_header mh;
Packit Service 360c39
Packit Service 360c39
		log_err( _("Found duplicate %s block %llu (0x%llx) "
Packit Service 360c39
			   "referenced as data by dinode %llu (0x%llx) "),
Packit Service 360c39
			 block_type_string(q),
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
		if (metablock == ip->i_di.di_num.no_addr)
Packit Service 360c39
			log_err("\n");
Packit Service 360c39
		else
Packit Service 360c39
			log_err(_("from metadata block %llu (0x%llx)\n"),
Packit Service 360c39
				(unsigned long long)metablock,
Packit Service 360c39
				(unsigned long long)metablock);
Packit Service 360c39
Packit Service 360c39
		switch (q) {
Packit Service 360c39
		case GFS2_BLKST_DINODE:
Packit Service 360c39
			log_info(_("The block was processed earlier as an "
Packit Service 360c39
				   "inode, so it can't possibly be data.\n"));
Packit Service 360c39
			/* We still need to add a duplicate record here because
Packit Service 360c39
			   when check_metatree tries to delete the inode, we
Packit Service 360c39
			   can't have the "undo" functions freeing the block
Packit Service 360c39
			   out from other the original referencing inode. */
Packit Service 360c39
			add_duplicate_ref(ip, block, ref_as_data, 0,
Packit Service 360c39
					  INODE_VALID);
Packit Service 360c39
			return 1;
Packit Service 360c39
		case GFS2_BLKST_USED: /* tough decision: May be data or meta */
Packit Service 360c39
			bh = bread(ip->i_sbd, block);
Packit Service 360c39
			gfs2_meta_header_in(&mh, bh->b_data);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			if (mh.mh_magic == GFS2_MAGIC &&
Packit Service 360c39
			    mh.mh_type >= GFS2_METATYPE_RG &&
Packit Service 360c39
			    mh.mh_type <= GFS2_METATYPE_QC &&
Packit Service 360c39
			    mh.mh_type != GFS2_METATYPE_DI &&
Packit Service 360c39
			    mh.mh_format % 100 == 0) {
Packit Service 360c39
				log_info(_("The block was processed earlier "
Packit Service 360c39
					   "as valid metadata, so it can't "
Packit Service 360c39
					   "possibly be data.\n"));
Packit Service 360c39
				/* We still need to add a duplicate record here
Packit Service 360c39
				   because when check_metatree tries to delete
Packit Service 360c39
				   the inode, we can't have the "undo"
Packit Service 360c39
				   functions freeing the block out from other
Packit Service 360c39
				   the original referencing inode. */
Packit Service 360c39
				add_duplicate_ref(ip, block, ref_as_data, 0,
Packit Service 360c39
						  INODE_VALID);
Packit Service 360c39
				return 1;
Packit Service 360c39
			}
Packit Service 360c39
			log_info( _("Seems to be a normal duplicate; I'll "
Packit Service 360c39
				    "sort it out in pass1b.\n"));
Packit Service 360c39
			add_duplicate_ref(ip, block, ref_as_data, 0,
Packit Service 360c39
					  INODE_VALID);
Packit Service 360c39
			/* This inode references the block as data. So if this
Packit Service 360c39
			   all is validated, we want to keep this count. */
Packit Service 360c39
			return 0;
Packit Service 360c39
		case GFS2_BLKST_UNLINKED:
Packit Service 360c39
			log_info( _("The block was invalid as metadata but might be "
Packit Service 360c39
				    "okay as data.  I'll sort it out in pass1b.\n"));
Packit Service 360c39
			add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
Packit Service 360c39
			return 0;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
Packit Service 360c39
	   In gfs2, "meta" is only for dinodes. So here we dummy up the
Packit Service 360c39
	   blocks so that the bitmap isn't changed improperly. */
Packit Service 360c39
	if (ip->i_sbd->gfs1 && ip == ip->i_sbd->md.riinode) {
Packit Service 360c39
		log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"),
Packit Service 360c39
			 (unsigned long long)block, (unsigned long long)block);
Packit Service 360c39
		gfs2_special_set(&gfs1_rindex_blks, block);
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("rgrp"), GFS2_BLKST_DINODE);
Packit Service 360c39
		/*gfs2_meta_rgrp);*/
Packit Service 360c39
	} else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) {
Packit Service 360c39
		log_info(_("Block %lld (0x%llx) is a GFS1 journaled data "
Packit Service 360c39
			   "block\n"),
Packit Service 360c39
			 (unsigned long long)block, (unsigned long long)block);
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("jdata"), GFS2_BLKST_DINODE);
Packit Service 360c39
	} else
Packit Service 360c39
		return blockmap_set_as_data(ip, block);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int ask_remove_inode_eattr(struct gfs2_inode *ip,
Packit Service 360c39
				  struct block_count *bc)
Packit Service 360c39
{
Packit Service 360c39
	if (ip->i_di.di_eattr == 0)
Packit Service 360c39
		return 0; /* eattr was removed prior to this call */
Packit Service 360c39
	log_err( _("Inode %lld (0x%llx) has unrecoverable Extended Attribute "
Packit Service 360c39
		   "errors.\n"), (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( _("Clear all Extended Attributes from the inode? (y/n) "))){
Packit Service 360c39
		undo_reference(ip, ip->i_di.di_eattr, 0, bc);
Packit Service 360c39
		ip->i_di.di_eattr = 0;
Packit Service 360c39
		bc->ea_count = 0;
Packit Service 360c39
		ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
Packit Service 360c39
		ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
Packit Service 360c39
		bmodified(ip->i_bh);
Packit Service 360c39
		log_err( _("Extended attributes were removed.\n"));
Packit Service 360c39
	} else {
Packit Service 360c39
		log_err( _("Extended attributes were not removed.\n"));
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int undo_eattr_indir_or_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				    uint64_t parent,
Packit Service 360c39
				    struct gfs2_buffer_head **bh,
Packit Service 360c39
				    void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	int q;
Packit Service 360c39
	int error;
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
Packit Service 360c39
	if (!valid_block_ip(ip, block))
Packit Service 360c39
		return meta_error;
Packit Service 360c39
Packit Service 360c39
	/* Need to check block_type before undoing the reference, which can
Packit Service 360c39
	   set it to free, which would cause the test below to fail. */
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
Packit Service 360c39
	error = undo_reference(ip, block, 0, private);
Packit Service 360c39
	if (error)
Packit Service 360c39
		return error;
Packit Service 360c39
Packit Service 360c39
	bc->ea_count--;
Packit Service 360c39
Packit Service 360c39
	if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED))
Packit Service 360c39
		return 1;
Packit Service 360c39
Packit Service 360c39
	*bh = bread(sdp, block);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* complain_eas - complain about extended attribute errors for an inode
Packit Service 360c39
 *
Packit Service 360c39
 * @ip       - in core inode pointer
Packit Service 360c39
 * block     - the block that had the problem
Packit Service 360c39
 * duplicate - if this is a duplicate block, don't set it "free"
Packit Service 360c39
 * emsg      - what to tell the user about the eas being checked
Packit Service 360c39
 * Returns: 1 if the EA is fixed, else 0 if it was not fixed.
Packit Service 360c39
 */
Packit Service 360c39
static void complain_eas(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			 const char *emsg)
Packit Service 360c39
{
Packit Service 360c39
	log_err(_("Inode #%llu (0x%llx): %s"),
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, emsg);
Packit Service 360c39
	log_err(_(" at block #%lld (0x%llx).\n"),
Packit Service 360c39
		 (unsigned long long)block, (unsigned long long)block);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
Packit Service 360c39
			     uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
			     void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	int ret = 0;
Packit Service 360c39
	int q;
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
Packit Service 360c39
	/* This inode contains an eattr - it may be invalid, but the
Packit Service 360c39
	 * eattr attributes points to a non-zero block */
Packit Service 360c39
	if (!valid_block_ip(ip, indirect)) {
Packit Service 360c39
		/* Doesn't help to mark this here - this gets checked
Packit Service 360c39
		 * in pass1c */
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	q = block_type(bl, indirect);
Packit Service 360c39
Packit Service 360c39
	/* Special duplicate processing:  If we have an EA block,
Packit Service 360c39
	   check if it really is an EA.  If it is, let duplicate
Packit Service 360c39
	   handling sort it out.  If it isn't, clear it but don't
Packit Service 360c39
	   count it as a duplicate. */
Packit Service 360c39
	*bh = bread(sdp, indirect);
Packit Service 360c39
	if (gfs2_check_meta(*bh, GFS2_METATYPE_IN)) {
Packit Service 360c39
		bc->ea_count++;
Packit Service 360c39
		if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit Service 360c39
			add_duplicate_ref(ip, indirect, ref_as_ea, 0,
Packit Service 360c39
					  INODE_VALID);
Packit Service 360c39
			complain_eas(ip, indirect,
Packit Service 360c39
				     _("Bad indirect Extended Attribute "
Packit Service 360c39
				       "duplicate found"));
Packit Service 360c39
			/* Return 0 here because if all that's wrong is a
Packit Service 360c39
			   duplicate block reference, we want pass1b to figure
Packit Service 360c39
			   it out. We don't want to delete all the extended
Packit Service 360c39
			   attributes as if they are in error. */
Packit Service 360c39
			return 0;
Packit Service 360c39
		}
Packit Service 360c39
		complain_eas(ip, indirect,
Packit Service 360c39
			     _("Extended Attribute indirect block has "
Packit Service 360c39
			       "incorrect type"));
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit Service 360c39
		add_duplicate_ref(ip, indirect, ref_as_ea, 0, INODE_VALID);
Packit Service 360c39
		complain_eas(ip, indirect,
Packit Service 360c39
			     _("Duplicate Extended Attribute indirect block"));
Packit Service 360c39
		bc->ea_count++;
Packit Service 360c39
		ret = 0; /* For the same reason stated above. */
Packit Service 360c39
	} else {
Packit Service 360c39
		fsck_blockmap_set(ip, indirect,
Packit Service 360c39
				  _("indirect Extended Attribute"), sdp->gfs1 ?
Packit Service 360c39
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
		bc->ea_count++;
Packit Service 360c39
	}
Packit Service 360c39
	return ret;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
Packit Service 360c39
			      int leaf_pointer_errors, void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
Packit Service 360c39
	if (leaf_pointer_errors == leaf_pointers) /* All eas were bad */
Packit Service 360c39
		return ask_remove_inode_eattr(ip, bc);
Packit Service 360c39
	log_debug( _("Marking inode #%llu (0x%llx) with extended "
Packit Service 360c39
		     "attribute block\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
	if (!leaf_pointer_errors)
Packit Service 360c39
		return 0;
Packit Service 360c39
	log_err( _("Inode %lld (0x%llx) has recoverable indirect "
Packit Service 360c39
		   "Extended Attribute errors.\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
	if (query( _("Okay to fix the block count for the inode? (y/n) "))) {
Packit Service 360c39
		ip->i_di.di_blocks = 1 + bc->indir_count +
Packit Service 360c39
			bc->data_count + bc->ea_count;
Packit Service 360c39
		bmodified(ip->i_bh);
Packit Service 360c39
		log_err(_("Block count fixed: 1+%lld+%lld+%lld = %lld.\n"),
Packit Service 360c39
			(unsigned long long)bc->indir_count,
Packit Service 360c39
			(unsigned long long)bc->data_count,
Packit Service 360c39
			(unsigned long long)bc->ea_count,
Packit Service 360c39
			(unsigned long long)ip->i_di.di_blocks);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	log_err( _("Block count not fixed.\n"));
Packit Service 360c39
	return 1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* check_ealeaf_block
Packit Service 360c39
 *      checks an extended attribute (not directory) leaf block
Packit Service 360c39
 */
Packit Service 360c39
static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
Packit Service 360c39
			      struct gfs2_buffer_head **bh, void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_buffer_head *leaf_bh = NULL;
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	int q;
Packit Service 360c39
	struct block_count *bc = (struct block_count *) private;
Packit Service 360c39
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	/* Special duplicate processing:  If we have an EA block, check if it
Packit Service 360c39
	   really is an EA.  If it is, let duplicate handling sort it out.
Packit Service 360c39
	   If it isn't, clear it but don't count it as a duplicate. */
Packit Service 360c39
	leaf_bh = bread(sdp, block);
Packit Service 360c39
	if (gfs2_check_meta(leaf_bh, btype)) {
Packit Service 360c39
		bc->ea_count++;
Packit Service 360c39
		if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit Service 360c39
			add_duplicate_ref(ip, block, ref_as_ea, 0,
Packit Service 360c39
					  INODE_VALID);
Packit Service 360c39
			complain_eas(ip, block, _("Extended attribute leaf "
Packit Service 360c39
						  "duplicate found"));
Packit Service 360c39
			/* Return 0 here because if all that's wrong is a
Packit Service 360c39
			   duplicate block reference, we want pass1b to figure
Packit Service 360c39
			   it out. We don't want to delete all the extended
Packit Service 360c39
			   attributes as if they are in error. */
Packit Service 360c39
			return 0;
Packit Service 360c39
		}
Packit Service 360c39
		complain_eas(ip, block, _("Extended Attribute leaf block has "
Packit Service 360c39
					  "incorrect type"));
Packit Service 360c39
		brelse(leaf_bh);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) { /* Duplicate? */
Packit Service 360c39
		complain_eas(ip, block, _("Extended Attribute leaf "
Packit Service 360c39
					  "duplicate found"));
Packit Service 360c39
		add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
Packit Service 360c39
		bc->ea_count++;
Packit Service 360c39
		brelse(leaf_bh);
Packit Service 360c39
		/* Return 0 here because if all that's wrong is a duplicate
Packit Service 360c39
		   block reference, we want pass1b to figure it out. We don't
Packit Service 360c39
		   want to delete all the extended attributes as if they are
Packit Service 360c39
		   in error. */
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	/* Point of confusion: We've got to set the ea block itself to
Packit Service 360c39
	   GFS2_BLKST_USED here.  Elsewhere we mark the inode with
Packit Service 360c39
	   gfs2_eattr_block meaning it contains an eattr. */
Packit Service 360c39
	fsck_blockmap_set(ip, block, _("Extended Attribute"),
Packit Service 360c39
			  sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
	bc->ea_count++;
Packit Service 360c39
	*bh = leaf_bh;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * check_extended_leaf_eattr
Packit Service 360c39
 * @ip
Packit Service 360c39
 * @el_blk: block number of the extended leaf
Packit Service 360c39
 *
Packit Service 360c39
 * An EA leaf block can contain EA's with pointers to blocks
Packit Service 360c39
 * where the data for that EA is kept.  Those blocks still
Packit Service 360c39
 * have the gfs2 meta header of type GFS2_METATYPE_EA
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 if correct[able], -1 if removal is needed
Packit Service 360c39
 */
Packit Service 360c39
static int check_extended_leaf_eattr(struct gfs2_inode *ip, int i,
Packit Service 360c39
				     uint64_t *data_ptr,
Packit Service 360c39
				     struct gfs2_buffer_head *leaf_bh,
Packit Service 360c39
				     uint32_t tot_ealen,
Packit Service 360c39
				     struct gfs2_ea_header *ea_hdr,
Packit Service 360c39
				     struct gfs2_ea_header *ea_hdr_prev,
Packit Service 360c39
				     void *private)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t el_blk = be64_to_cpu(*data_ptr);
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	struct gfs2_buffer_head *bh = NULL;
Packit Service 360c39
	int error = 0;
Packit Service 360c39
Packit Service 360c39
	if (!valid_block_ip(ip, el_blk)) {
Packit Service 360c39
		log_err( _("Inode #%llu (0x%llx): Extended Attribute block "
Packit Service 360c39
			   "%llu (0x%llx) has an extended leaf block #%llu "
Packit Service 360c39
			   "(0x%llx) that is invalid or out of range.\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)ip->i_di.di_eattr,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_eattr,
Packit Service 360c39
			 (unsigned long long)el_blk,
Packit Service 360c39
			 (unsigned long long)el_blk);
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit Service 360c39
				  _("bad (out of range) Extended Attribute "),
Packit Service 360c39
				  GFS2_BLKST_UNLINKED);
Packit Service 360c39
		error = 1;
Packit Service 360c39
	} else {
Packit Service 360c39
		error = check_ealeaf_block(ip, el_blk, GFS2_METATYPE_ED, &bh,
Packit Service 360c39
					   private);
Packit Service 360c39
	}
Packit Service 360c39
	if (bh)
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
	if (error) {
Packit Service 360c39
		log_err(_("Bad extended attribute found at block %lld "
Packit Service 360c39
			  "(0x%llx)"),
Packit Service 360c39
			(unsigned long long)be64_to_cpu(*data_ptr),
Packit Service 360c39
			(unsigned long long)be64_to_cpu(*data_ptr));
Packit Service 360c39
		if (query( _("Repair the bad Extended Attribute? (y/n) "))) {
Packit Service 360c39
			ea_hdr->ea_num_ptrs = i;
Packit Service 360c39
			ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
Packit Service 360c39
			*data_ptr = 0;
Packit Service 360c39
			bmodified(leaf_bh);
Packit Service 360c39
			/* Endianness doesn't matter in this case because it's
Packit Service 360c39
			   a single byte. */
Packit Service 360c39
			fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit Service 360c39
					  _("extended attribute"),
Packit Service 360c39
					  sdp->gfs1 ? GFS2_BLKST_DINODE :
Packit Service 360c39
					  GFS2_BLKST_USED);
Packit Service 360c39
			log_err( _("The EA was fixed.\n"));
Packit Service 360c39
			error = 0;
Packit Service 360c39
		} else {
Packit Service 360c39
			error = 1;
Packit Service 360c39
			log_err( _("The bad EA was not fixed.\n"));
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			    uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
			    void *private)
Packit Service 360c39
{
Packit Service 360c39
	if (!valid_block_ip(ip, block)) {
Packit Service 360c39
		log_warn( _("Inode #%llu (0x%llx): Extended Attribute leaf "
Packit Service 360c39
			    "block #%llu (0x%llx) is invalid or out of "
Packit Service 360c39
			    "range.\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)block, (unsigned long long)block);
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_eattr,
Packit Service 360c39
				  _("bad (out of range) Extended "
Packit Service 360c39
				    "Attribute leaf"), GFS2_BLKST_UNLINKED);
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	return check_ealeaf_block(ip, block, GFS2_METATYPE_EA, bh, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int ask_remove_eattr_entry(struct gfs2_sbd *sdp,
Packit Service 360c39
				  struct gfs2_buffer_head *leaf_bh,
Packit Service 360c39
				  struct gfs2_ea_header *curr,
Packit Service 360c39
				  struct gfs2_ea_header *prev,
Packit Service 360c39
				  int fix_curr, int fix_curr_len)
Packit Service 360c39
{
Packit Service 360c39
	if (!query( _("Remove the bad Extended Attribute entry? (y/n) "))) {
Packit Service 360c39
		log_err( _("Bad Extended Attribute not removed.\n"));
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	if (fix_curr)
Packit Service 360c39
		curr->ea_flags |= GFS2_EAFLAG_LAST;
Packit Service 360c39
	if (fix_curr_len) {
Packit Service 360c39
		uint32_t max_size = sdp->sd_sb.sb_bsize;
Packit Service 360c39
		uint32_t offset = (uint32_t)(((unsigned long)curr) -
Packit Service 360c39
					     ((unsigned long)leaf_bh->b_data));
Packit Service 360c39
		curr->ea_rec_len = cpu_to_be32(max_size - offset);
Packit Service 360c39
	}
Packit Service 360c39
	if (!prev)
Packit Service 360c39
		curr->ea_type = GFS2_EATYPE_UNUSED;
Packit Service 360c39
	else {
Packit Service 360c39
		uint32_t tmp32 = be32_to_cpu(curr->ea_rec_len) +
Packit Service 360c39
			be32_to_cpu(prev->ea_rec_len);
Packit Service 360c39
		prev->ea_rec_len = cpu_to_be32(tmp32);
Packit Service 360c39
		if (curr->ea_flags & GFS2_EAFLAG_LAST)
Packit Service 360c39
			prev->ea_flags |= GFS2_EAFLAG_LAST;	
Packit Service 360c39
	}
Packit Service 360c39
	log_err( _("Bad Extended Attribute at block #%llu"
Packit Service 360c39
		   " (0x%llx) removed.\n"),
Packit Service 360c39
		 (unsigned long long)leaf_bh->b_blocknr,
Packit Service 360c39
		 (unsigned long long)leaf_bh->b_blocknr);
Packit Service 360c39
	bmodified(leaf_bh);
Packit Service 360c39
	return 1;
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 *leaf_bh,
Packit Service 360c39
			       struct gfs2_ea_header *ea_hdr,
Packit Service 360c39
			       struct gfs2_ea_header *ea_hdr_prev,
Packit Service 360c39
			       void *private)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit Service 360c39
	char ea_name[256];
Packit Service 360c39
	uint32_t offset = (uint32_t)(((unsigned long)ea_hdr) -
Packit Service 360c39
				     ((unsigned long)leaf_bh->b_data));
Packit Service 360c39
	uint32_t max_size = sdp->sd_sb.sb_bsize;
Packit Service 360c39
	uint32_t avail_size;
Packit Service 360c39
	int max_ptrs;
Packit Service 360c39
Packit Service 360c39
	if (!ea_hdr->ea_name_len){
Packit Service 360c39
		log_err( _("EA has name length of zero\n"));
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 1, 1);
Packit Service 360c39
	}
Packit Service 360c39
	if (offset + be32_to_cpu(ea_hdr->ea_rec_len) > max_size){
Packit Service 360c39
		log_err( _("EA rec length too long\n"));
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 1, 1);
Packit Service 360c39
	}
Packit Service 360c39
	if (offset + be32_to_cpu(ea_hdr->ea_rec_len) == max_size &&
Packit Service 360c39
	   (ea_hdr->ea_flags & GFS2_EAFLAG_LAST) == 0){
Packit Service 360c39
		log_err( _("last EA has no last entry flag\n"));
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 0, 0);
Packit Service 360c39
	}
Packit Service 360c39
	if (!ea_hdr->ea_name_len){
Packit Service 360c39
		log_err( _("EA has name length of zero\n"));
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 0, 0);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	memset(ea_name, 0, sizeof(ea_name));
Packit Service 360c39
	strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
Packit Service 360c39
		ea_hdr->ea_name_len);
Packit Service 360c39
Packit Service 360c39
	if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
Packit Service 360c39
	   ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
Packit Service 360c39
		/* Skip invalid entry */
Packit Service 360c39
		log_err(_("EA (%s) type is invalid (%d > %d).\n"),
Packit Service 360c39
			ea_name, ea_hdr->ea_type, GFS2_EATYPE_LAST);
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 0, 0);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (!ea_hdr->ea_num_ptrs)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
Packit Service 360c39
	max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len)+avail_size-1)/avail_size;
Packit Service 360c39
Packit Service 360c39
	if (max_ptrs > ea_hdr->ea_num_ptrs) {
Packit Service 360c39
		log_err(_("EA (%s) has incorrect number of pointers.\n"),
Packit Service 360c39
			ea_name);
Packit Service 360c39
		log_err(_("  Required:  %d\n  Reported:  %d\n"),
Packit Service 360c39
			max_ptrs, ea_hdr->ea_num_ptrs);
Packit Service 360c39
		return ask_remove_eattr_entry(sdp, leaf_bh, ea_hdr,
Packit Service 360c39
					      ea_hdr_prev, 0, 0);
Packit Service 360c39
	} else {
Packit Service 360c39
		log_debug( _("  Pointers Required: %d\n  Pointers Reported: %d\n"),
Packit Service 360c39
			   max_ptrs, ea_hdr->ea_num_ptrs);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * mark_block_invalid - mark blocks associated with an inode as invalid
Packit Service 360c39
 *                      unless the block is a duplicate.
Packit Service 360c39
 *
Packit Service 360c39
 * An "invalid" block is now considered free in the bitmap, and pass2 will
Packit Service 360c39
 * delete any invalid blocks.  This is nearly identical to function
Packit Service 360c39
 * delete_block_if_notdup.
Packit Service 360c39
 */
Packit Service 360c39
static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			      enum dup_ref_type reftype, const char *btype,
Packit Service 360c39
			      int *is_valid, int *was_duplicate)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
Packit Service 360c39
	/* If the block isn't valid, we obviously can't invalidate it.
Packit Service 360c39
	 * However, if we return an error, invalidating will stop, and
Packit Service 360c39
	 * we want it to continue to invalidate the valid blocks.  If we
Packit Service 360c39
	 * don't do this, block references that follow that are also
Packit Service 360c39
	 * referenced elsewhere (duplicates) won't be flagged as such,
Packit Service 360c39
	 * and as a result, they'll be freed when this dinode is deleted,
Packit Service 360c39
	 * despite being used by another dinode as a valid block. */
Packit Service 360c39
	if (is_valid)
Packit Service 360c39
		*is_valid = 1;
Packit Service 360c39
	if (was_duplicate)
Packit Service 360c39
		*was_duplicate = 0;
Packit Service 360c39
	if (!valid_block_ip(ip, block)) {
Packit Service 360c39
		if (is_valid)
Packit Service 360c39
			*is_valid = 0;
Packit Service 360c39
		return meta_is_good;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
		if (was_duplicate)
Packit Service 360c39
			*was_duplicate = 1;
Packit Service 360c39
		add_duplicate_ref(ip, block, reftype, 0, INODE_INVALID);
Packit Service 360c39
		log_info( _("%s block %lld (0x%llx), part of inode "
Packit Service 360c39
			    "%lld (0x%llx), was previously referenced so "
Packit Service 360c39
			    "the invalid reference is ignored.\n"),
Packit Service 360c39
			  btype, (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
		return meta_is_good;
Packit Service 360c39
	}
Packit Service 360c39
	fsck_blockmap_set(ip, block, btype, GFS2_BLKST_UNLINKED);
Packit Service 360c39
	return meta_is_good;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			       struct gfs2_buffer_head **bh, int h,
Packit Service 360c39
			       int *is_valid, int *was_duplicate,
Packit Service 360c39
			       void *private)
Packit Service 360c39
{
Packit Service 360c39
	*is_valid = 1;
Packit Service 360c39
	*was_duplicate = 0;
Packit Service 360c39
	return mark_block_invalid(ip, block, ref_as_meta, _("metadata"),
Packit Service 360c39
				  is_valid, was_duplicate);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			   void *private)
Packit Service 360c39
{
Packit Service 360c39
	return mark_block_invalid(ip, block, ref_as_meta, _("leaf"),
Packit Service 360c39
				  NULL, NULL);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
			   uint64_t block, void *private,
Packit Service 360c39
			   struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit Service 360c39
{
Packit Service 360c39
	return mark_block_invalid(ip, block, ref_as_data, _("data"),
Packit Service 360c39
				  NULL, NULL);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				  uint64_t parent,
Packit Service 360c39
				  struct gfs2_buffer_head **bh, void *private)
Packit Service 360c39
{
Packit Service 360c39
	return mark_block_invalid(ip, block, ref_as_ea,
Packit Service 360c39
				  _("indirect extended attribute"),
Packit Service 360c39
				  NULL, NULL);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
				 void *private)
Packit Service 360c39
{
Packit Service 360c39
	return mark_block_invalid(ip, block, ref_as_ea,
Packit Service 360c39
				  _("extended attribute"),
Packit Service 360c39
				  NULL, NULL);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Check for massive amounts of pointer corruption.  If the block has
Packit Service 360c39
 * lots of out-of-range pointers, we can't trust any of the pointers.
Packit Service 360c39
 * For example, a stray pointer with a value of 0x1d might be
Packit Service 360c39
 * corruption/nonsense, and if so, we don't want to delete an
Packit Service 360c39
 * important file (like master or the root directory) because of it.
Packit Service 360c39
 * We need to check for a large number of bad pointers BEFORE we start
Packit Service 360c39
 * messing with them because we don't want to mark a block as a
Packit Service 360c39
 * duplicate (for example) until we know if the pointers in general can
Packit Service 360c39
 * be trusted. Thus it needs to be in a separate loop.
Packit Service 360c39
 * Returns: 0 if good range, otherwise != 0
Packit Service 360c39
 */
Packit Service 360c39
enum b_types { btype_meta, btype_leaf, btype_data, btype_ieattr, btype_eattr};
Packit Service 360c39
const char *btypes[5] = {
Packit Service 360c39
	"metadata", "leaf", "data", "indirect extended attribute",
Packit Service 360c39
	"extended attribute" };
Packit Service 360c39
Packit Service 360c39
static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			    struct gfs2_buffer_head **bh, enum b_types btype,
Packit Service 360c39
			    void *private)
Packit Service 360c39
{
Packit Service 360c39
	long *bad_pointers = (long *)private;
Packit Service 360c39
	int q;
Packit Service 360c39
Packit Service 360c39
	if (!valid_block_ip(ip, block)) {
Packit Service 360c39
		(*bad_pointers)++;
Packit Service 360c39
		log_info( _("Bad %s block pointer (invalid or out of range "
Packit Service 360c39
			    "#%ld) found in inode %lld (0x%llx).\n"),
Packit Service 360c39
			  btypes[btype], *bad_pointers,
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 ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
Packit Service 360c39
			return meta_is_good;
Packit Service 360c39
		else
Packit Service 360c39
			return meta_error; /* Exits check_metatree quicker */
Packit Service 360c39
	}
Packit Service 360c39
	/* See how many duplicate blocks it has */
Packit Service 360c39
	q = block_type(bl, block);
Packit Service 360c39
	if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
		(*bad_pointers)++;
Packit Service 360c39
		log_info( _("Duplicated %s block pointer (violation %ld, block"
Packit Service 360c39
			    " %lld (0x%llx)) found in inode %lld (0x%llx).\n"),
Packit Service 360c39
			  btypes[btype], *bad_pointers,
Packit Service 360c39
			  (unsigned long long)block, (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
		if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
Packit Service 360c39
			return meta_is_good;
Packit Service 360c39
		else {
Packit Service 360c39
			log_debug(_("Inode 0x%llx bad pointer tolerance "
Packit Service 360c39
				    "exceeded: block 0x%llx.\n"),
Packit Service 360c39
				  (unsigned long long)ip->i_di.di_num.no_addr,
Packit Service 360c39
				  (unsigned long long)block);
Packit Service 360c39
			return meta_error; /* Exits check_metatree quicker */
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return meta_is_good;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			       struct gfs2_buffer_head **bh, int h,
Packit Service 360c39
			       int *is_valid, int *was_duplicate,
Packit Service 360c39
			       void *private)
Packit Service 360c39
{
Packit Service 360c39
	*is_valid = 1;
Packit Service 360c39
	*was_duplicate = 0;
Packit Service 360c39
	return rangecheck_block(ip, block, bh, btype_meta, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			   void *private)
Packit Service 360c39
{
Packit Service 360c39
	return rangecheck_block(ip, block, NULL, btype_leaf, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
			   uint64_t block, void *private,
Packit Service 360c39
			   struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit Service 360c39
{
Packit Service 360c39
	return rangecheck_block(ip, block, NULL, btype_data, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int rangecheck_eattr_indir(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				  uint64_t parent,
Packit Service 360c39
				  struct gfs2_buffer_head **bh, void *private)
Packit Service 360c39
{
Packit Service 360c39
	return rangecheck_block(ip, block, NULL, btype_ieattr, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int rangecheck_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
				 uint64_t parent, struct gfs2_buffer_head **bh,
Packit Service 360c39
				 void *private)
Packit Service 360c39
{
Packit Service 360c39
	return rangecheck_block(ip, block, NULL, btype_eattr, private);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns rangecheck_fxns = {
Packit Service 360c39
        .private = NULL,
Packit Service 360c39
	.readahead = 1,
Packit Service 360c39
        .check_metalist = rangecheck_metadata,
Packit Service 360c39
        .check_data = rangecheck_data,
Packit Service 360c39
        .check_leaf = rangecheck_leaf,
Packit Service 360c39
        .check_eattr_indir = rangecheck_eattr_indir,
Packit Service 360c39
        .check_eattr_leaf = rangecheck_eattr_leaf,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns eattr_undo_fxns = {
Packit Service 360c39
	.private = NULL,
Packit Service 360c39
	.check_eattr_indir = undo_eattr_indir_or_leaf,
Packit Service 360c39
	.check_eattr_leaf = undo_eattr_indir_or_leaf,
Packit Service 360c39
	.finish_eattr_indir = finish_eattr_indir,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
/* set_ip_blockmap - set the blockmap for a dinode
Packit Service 360c39
 *
Packit Service 360c39
 * returns: 0 if no error, -EINVAL if dinode has a bad mode, -EPERM on error
Packit Service 360c39
 */
Packit Service 360c39
static int set_ip_blockmap(struct gfs2_inode *ip)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t block = ip->i_bh->b_blocknr;
Packit Service 360c39
	uint32_t mode;
Packit Service 360c39
	const char *ty;
Packit Service 360c39
Packit Service 360c39
	if (ip->i_sbd->gfs1)
Packit Service 360c39
		mode = gfs_to_gfs2_mode(ip);
Packit Service 360c39
	else
Packit Service 360c39
		mode = ip->i_di.di_mode & S_IFMT;
Packit Service 360c39
Packit Service 360c39
	switch (mode) {
Packit Service 360c39
	case S_IFDIR:
Packit Service 360c39
		ty = _("directory");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFREG:
Packit Service 360c39
		ty = _("file");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFLNK:
Packit Service 360c39
		ty = _("symlink");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFBLK:
Packit Service 360c39
		ty = _("block device");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFCHR:
Packit Service 360c39
		ty = _("character device");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFIFO:
Packit Service 360c39
		ty = _("fifo");
Packit Service 360c39
		break;
Packit Service 360c39
	case S_IFSOCK:
Packit Service 360c39
		ty = _("socket");
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		return -EINVAL;
Packit Service 360c39
	}
Packit Service 360c39
	if (fsck_blockmap_set(ip, block, ty, GFS2_BLKST_DINODE) ||
Packit Service 360c39
	    (mode == S_IFDIR && !dirtree_insert(ip->i_di.di_num))) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -EPERM;
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
Packit Service 360c39
			  struct gfs2_buffer_head **bh, int h, int *is_valid,
Packit Service 360c39
			  int *was_duplicate, void *private)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
	const char *desc = (const char *)private;
Packit Service 360c39
Packit Service 360c39
	/* No need to range_check here--if it was added, it's in range. */
Packit Service 360c39
	/* We can't check the bitmap here because this function is called
Packit Service 360c39
	   after the bitmap has been set but before the blockmap has. */
Packit Service 360c39
	*is_valid = 1;
Packit Service 360c39
	*was_duplicate = 0;
Packit Service 360c39
	*bh = bread(ip->i_sbd, block);
Packit Service 360c39
	q = bitmap_type(ip->i_sbd, block);
Packit Service 360c39
	if (q == GFS2_BLKST_FREE) {
Packit Service 360c39
		log_debug(_("%s reference to new metadata block "
Packit Service 360c39
			    "%lld (0x%llx) is now marked as indirect.\n"),
Packit Service 360c39
			  desc, (unsigned long long)block,
Packit Service 360c39
			  (unsigned long long)block);
Packit Service 360c39
		gfs2_blockmap_set(bl, block, ip->i_sbd->gfs1 ?
Packit Service 360c39
				  GFS2_BLKST_DINODE : GFS2_BLKST_USED);
Packit Service 360c39
	}
Packit Service 360c39
	return meta_is_good;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
Packit Service 360c39
		      uint64_t block, void *private,
Packit Service 360c39
		      struct gfs2_buffer_head *bh, uint64_t *ptr)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
	const char *desc = (const char *)private;
Packit Service 360c39
Packit Service 360c39
	/* No need to range_check here--if it was added, it's in range. */
Packit Service 360c39
	/* We can't check the bitmap here because this function is called
Packit Service 360c39
	   after the bitmap has been set but before the blockmap has. */
Packit Service 360c39
	q = bitmap_type(ip->i_sbd, block);
Packit Service 360c39
	if (q == GFS2_BLKST_FREE) {
Packit Service 360c39
		log_debug(_("%s reference to new data block "
Packit Service 360c39
			    "%lld (0x%llx) is now marked as data.\n"),
Packit Service 360c39
			  desc, (unsigned long long)block,
Packit Service 360c39
			  (unsigned long long)block);
Packit Service 360c39
		gfs2_blockmap_set(bl, block, GFS2_BLKST_USED);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
Packit Service 360c39
{
Packit Service 360c39
	int q;
Packit Service 360c39
Packit Service 360c39
	/* No need to range_check here--if it was added, it's in range. */
Packit Service 360c39
	/* We can't check the bitmap here because this function is called
Packit Service 360c39
	   after the bitmap has been set but before the blockmap has. */
Packit Service 360c39
	q = bitmap_type(ip->i_sbd, block);
Packit Service 360c39
	if (q == GFS2_BLKST_FREE)
Packit Service 360c39
		fsck_blockmap_set(ip, block, _("newly allocated leaf"),
Packit Service 360c39
				  ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit Service 360c39
				  GFS2_BLKST_USED);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct metawalk_fxns alloc_fxns = {
Packit Service 360c39
	.private = NULL,
Packit Service 360c39
	.check_leaf = alloc_leaf,
Packit Service 360c39
	.check_metalist = alloc_metalist,
Packit Service 360c39
	.check_data = alloc_data,
Packit Service 360c39
	.check_eattr_indir = NULL,
Packit Service 360c39
	.check_eattr_leaf = NULL,
Packit Service 360c39
	.check_dentry = NULL,
Packit Service 360c39
	.check_eattr_entry = NULL,
Packit Service 360c39
	.check_eattr_extentry = NULL,
Packit Service 360c39
	.finish_eattr_indir = NULL,
Packit Service 360c39
	.delete_block = delete_block,
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * pass1_check_metatree - wrapper function for check_metatree
Packit Service 360c39
 *
Packit Service 360c39
 * Generic function check_metatree sets the bitmap values, but not the
Packit Service 360c39
 * corresponding values in the blockmap. If we get an error, the inode will
Packit Service 360c39
 * have been freed in the bitmap. We need to set the inode address as free
Packit Service 360c39
 * as well.
Packit Service 360c39
 */
Packit Service 360c39
static int pass1_check_metatree(struct gfs2_inode *ip,
Packit Service 360c39
				struct metawalk_fxns *pass)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
Packit Service 360c39
	error = check_metatree(ip, pass);
Packit Service 360c39
	if (error)
Packit Service 360c39
		gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  GFS2_BLKST_FREE);		
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * reprocess_inode - fixes the blockmap to match the bitmap due to an
Packit Service 360c39
 *                   unexpected block allocation via libgfs2.
Packit Service 360c39
 *
Packit Service 360c39
 * The problem we're trying to overcome here is when a new block must be
Packit Service 360c39
 * added to a dinode because of a write.  This will happen when lost+found
Packit Service 360c39
 * needs a new indirect block for its hash table.  In that case, the write
Packit Service 360c39
 * causes a new block to be assigned in the bitmap but that block is not yet
Packit Service 360c39
 * accurately reflected in the fsck blockmap.  We need to compensate here.
Packit Service 360c39
 *
Packit Service 360c39
 * We can't really use fsck_blockmap_set here because the new block
Packit Service 360c39
 * was already allocated by libgfs2 and therefore it took care of
Packit Service 360c39
 * the rgrp free space variable.  fsck_blockmap_set adjusts the free space
Packit Service 360c39
 * in the rgrp according to the change, which has already been done.
Packit Service 360c39
 * So it's only our blockmap that now disagrees with the rgrp bitmap, so we
Packit Service 360c39
 * need to fix only that.
Packit Service 360c39
 */
Packit Service 360c39
static void reprocess_inode(struct gfs2_inode *ip, const char *desc)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
Packit Service 360c39
	alloc_fxns.private = (void *)desc;
Packit Service 360c39
	log_info( _("%s inode %llu (0x%llx) had blocks added; reprocessing "
Packit Service 360c39
		    "its metadata tree at height=%d.\n"), desc,
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
		  ip->i_di.di_height);
Packit Service 360c39
	error = pass1_check_metatree(ip, &alloc_fxns);
Packit Service 360c39
	if (error)
Packit Service 360c39
		log_err( _("Error %d reprocessing the %s metadata tree.\n"),
Packit Service 360c39
			 error, desc);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * handle_ip - process an incore structure representing a dinode.
Packit Service 360c39
 */
Packit Service 360c39
static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
Packit Service 360c39
{
Packit Service 360c39
	int error;
Packit Service 360c39
	struct block_count bc = {0};
Packit Service 360c39
	long bad_pointers;
Packit Service 360c39
	uint64_t lf_blks = 0;
Packit Service 360c39
Packit Service 360c39
	bad_pointers = 0L;
Packit Service 360c39
Packit Service 360c39
	/* First, check the metadata for massive amounts of pointer corruption.
Packit Service 360c39
	   Such corruption can only lead us to ruin trying to clean it up,
Packit Service 360c39
	   so it's better to check it up front and delete the inode if
Packit Service 360c39
	   there is corruption. */
Packit Service 360c39
	rangecheck_fxns.private = &bad_pointers;
Packit Service 360c39
	error = pass1_check_metatree(ip, &rangecheck_fxns);
Packit Service 360c39
	if (bad_pointers > BAD_POINTER_TOLERANCE) {
Packit Service 360c39
		log_err( _("Error: inode %llu (0x%llx) has more than "
Packit Service 360c39
			   "%d bad pointers.\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
			 BAD_POINTER_TOLERANCE);
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("badly corrupt"), GFS2_BLKST_FREE);
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	error = set_ip_blockmap(ip);
Packit Service 360c39
	if (error == -EINVAL) {
Packit Service 360c39
		/* We found a dinode that has an invalid mode. At this point
Packit Service 360c39
		   set_ip_blockmap returned an error, which means it never
Packit Service 360c39
		   got inserted into the inode tree. Since we haven't even
Packit Service 360c39
		   processed its metadata with pass1_fxns, none of its
Packit Service 360c39
		   metadata will be flagged as metadata or data blocks yet.
Packit Service 360c39
		   Therefore, we don't need to invalidate anything. */
Packit Service 360c39
		fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
Packit Service 360c39
				  _("invalid mode"), GFS2_BLKST_FREE);
Packit Service 360c39
		return 0;
Packit Service 360c39
	} else if (error)
Packit Service 360c39
		goto bad_dinode;
Packit Service 360c39
Packit Service 360c39
	if (set_di_nlink(ip))
Packit Service 360c39
		goto bad_dinode;
Packit Service 360c39
Packit Service 360c39
	if (lf_dip)
Packit Service 360c39
		lf_blks = lf_dip->i_di.di_blocks;
Packit Service 360c39
Packit Service 360c39
	pass1_fxns.private = &bc;
Packit Service 360c39
	error = pass1_check_metatree(ip, &pass1_fxns);
Packit Service 360c39
Packit Service 360c39
	/* Pass1 may have added some blocks to lost+found by virtue of leafs
Packit Service 360c39
	   that were misplaced. If it did, we need to reprocess lost+found
Packit Service 360c39
	   to correctly account for its blocks. */
Packit Service 360c39
	if (lf_dip && lf_dip->i_di.di_blocks != lf_blks)
Packit Service 360c39
		reprocess_inode(lf_dip, "lost+found");
Packit Service 360c39
Packit Service 360c39
	/* We there was an error, we return 0 because we want fsck to continue
Packit Service 360c39
	   and analyze the other dinodes as well. */
Packit Service 360c39
	if (fsck_abort)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	if (!error) {
Packit Service 360c39
		error = check_inode_eattr(ip, &pass1_fxns);
Packit Service 360c39
Packit Service 360c39
		if (error) {
Packit Service 360c39
			if (!query(_("Clear the bad Extended Attributes? "
Packit Service 360c39
				    "(y/n) "))) {
Packit Service 360c39
				log_err( _("The bad Extended Attributes were "
Packit Service 360c39
					   "not fixed.\n"));
Packit Service 360c39
				return 0;
Packit Service 360c39
			}
Packit Service 360c39
			log_err(_("Clearing the bad Extended Attributes in "
Packit Service 360c39
				  "inode %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
			eattr_undo_fxns.private = &bc;
Packit Service 360c39
			check_inode_eattr(ip, &eattr_undo_fxns);
Packit Service 360c39
			ask_remove_inode_eattr(ip, &bc);
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (ip->i_di.di_blocks != 
Packit Service 360c39
		(1 + bc.indir_count + bc.data_count + bc.ea_count)) {
Packit Service 360c39
		log_err( _("Inode #%llu (0x%llx): Ondisk block count (%llu"
Packit Service 360c39
			") does not match what fsck found (%llu)\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)ip->i_di.di_blocks,
Packit Service 360c39
			(unsigned long long)1 + bc.indir_count +
Packit Service 360c39
			bc.data_count + bc.ea_count);
Packit Service 360c39
		log_info( _("inode has: %lld, but fsck counts: Dinode:1 + "
Packit Service 360c39
			    "indir:%lld + data: %lld + ea: %lld\n"),
Packit Service 360c39
			  (unsigned long long)ip->i_di.di_blocks,
Packit Service 360c39
			  (unsigned long long)bc.indir_count,
Packit Service 360c39
			  (unsigned long long)bc.data_count,
Packit Service 360c39
			  (unsigned long long)bc.ea_count);
Packit Service 360c39
		if (query( _("Fix ondisk block count? (y/n) "))) {
Packit Service 360c39
			ip->i_di.di_blocks = 1 + bc.indir_count + bc.data_count +
Packit Service 360c39
				bc.ea_count;
Packit Service 360c39
			bmodified(ip->i_bh);
Packit Service 360c39
			log_err( _("Block count for #%llu (0x%llx) fixed\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
		} else
Packit Service 360c39
			log_err( _("Bad block count for #%llu (0x%llx"
Packit Service 360c39
				") not fixed\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
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
bad_dinode:
Packit Service 360c39
	stack;
Packit Service 360c39
	return -1;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void check_i_goal(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
Packit Service 360c39
{
Packit Service 360c39
	if (sdp->gfs1 || ip->i_di.di_flags & GFS2_DIF_SYSTEM)
Packit Service 360c39
		return;
Packit Service 360c39
Packit Service 360c39
	if (ip->i_di.di_goal_meta <= LGFS2_SB_ADDR(sdp) ||
Packit Service 360c39
	    ip->i_di.di_goal_meta > sdp->fssize) {
Packit Service 360c39
		log_err(_("Inode #%llu (0x%llx): Bad allocation goal block "
Packit Service 360c39
			  "found: %llu (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)ip->i_di.di_goal_meta,
Packit Service 360c39
			(unsigned long long)ip->i_di.di_goal_meta);
Packit Service 360c39
		if (query( _("Fix goal block in inode #%llu (0x%llx)? (y/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
			ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr;
Packit Service 360c39
			bmodified(ip->i_bh);
Packit Service 360c39
		} else
Packit Service 360c39
			log_err(_("Allocation goal block in inode #%lld "
Packit Service 360c39
				  "(0x%llx) not fixed\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
	}
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * handle_di - This is now a wrapper function that takes a gfs2_buffer_head
Packit Service 360c39
 *             and calls handle_ip, which takes an in-code dinode structure.
Packit Service 360c39
 */
Packit Service 360c39
static int handle_di(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit Service 360c39
		     struct gfs2_buffer_head *bh)
Packit Service 360c39
{
Packit Service 360c39
	int error = 0;
Packit Service 360c39
	uint64_t block = bh->b_blocknr;
Packit Service 360c39
	struct gfs2_inode *ip;
Packit Service 360c39
Packit Service 360c39
	ip = fsck_inode_get(sdp, rgd, bh);
Packit Service 360c39
Packit Service 360c39
	if (ip->i_di.di_num.no_addr != block) {
Packit Service 360c39
		log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
Packit Service 360c39
			"(0x%llx)\n"), (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
		if (query( _("Fix address in inode at block #%llu"
Packit Service 360c39
			    " (0x%llx)? (y/n) "),
Packit Service 360c39
			  (unsigned long long)block, (unsigned long long)block)) {
Packit Service 360c39
			ip->i_di.di_num.no_addr = ip->i_di.di_num.no_formal_ino = block;
Packit Service 360c39
			bmodified(ip->i_bh);
Packit Service 360c39
		} else
Packit Service 360c39
			log_err( _("Address in inode at block #%llu"
Packit Service 360c39
				 " (0x%llx) not fixed\n"),
Packit Service 360c39
				(unsigned long long)block,
Packit Service 360c39
				(unsigned long long)block);
Packit Service 360c39
	}
Packit Service 360c39
	if (sdp->gfs1 && ip->i_di.di_num.no_formal_ino != block) {
Packit Service 360c39
		log_err( _("Inode #%llu (0x%llx): GFS1 formal inode number "
Packit Service 360c39
			   "mismatch: was %llu (0x%llx)\n"),
Packit Service 360c39
			 (unsigned long long)block, (unsigned long long)block,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_formal_ino,
Packit Service 360c39
			 (unsigned long long)ip->i_di.di_num.no_formal_ino);
Packit Service 360c39
		if (query( _("Fix formal inode number in inode #%llu"
Packit Service 360c39
			    " (0x%llx)? (y/n) "), (unsigned long long)block,
Packit Service 360c39
			   (unsigned long long)block)) {
Packit Service 360c39
			ip->i_di.di_num.no_formal_ino = block;
Packit Service 360c39
			bmodified(ip->i_bh);
Packit Service 360c39
		} else
Packit Service 360c39
			log_err( _("Inode number in inode at block #%lld "
Packit Service 360c39
				   "(0x%llx) not fixed\n"),
Packit Service 360c39
				 (unsigned long long)block,
Packit Service 360c39
				 (unsigned long long)block);
Packit Service 360c39
	}
Packit Service 360c39
	check_i_goal(sdp, ip);
Packit Service 360c39
	error = handle_ip(sdp, ip);
Packit Service 360c39
	fsck_inode_put(&ip);
Packit Service 360c39
	return error;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/* Check system inode and verify it's marked "in use" in the bitmap:       */
Packit Service 360c39
/* Should work for all system inodes: root, master, jindex, per_node, etc. */
Packit Service 360c39
/* We have to pass the sysinode as ** because the pointer may change out from
Packit Service 360c39
   under the reference by way of the builder() function.  */
Packit Service 360c39
static int check_system_inode(struct gfs2_sbd *sdp,
Packit Service 360c39
			      struct gfs2_inode **sysinode,
Packit Service 360c39
			      const char *filename,
Packit Service 360c39
			      int builder(struct gfs2_sbd *sdp), int isdir,
Packit Service 360c39
			      struct gfs2_inode *sysdir, int needs_sysbit)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t iblock = 0;
Packit Service 360c39
	struct dir_status ds = {0};
Packit Service 360c39
	int error, err = 0;
Packit Service 360c39
Packit Service 360c39
	log_info( _("Checking system inode '%s'\n"), filename);
Packit Service 360c39
	if (*sysinode) {
Packit Service 360c39
		/* Read in the system inode, look at its dentries, and start
Packit Service 360c39
		 * reading through them */
Packit Service 360c39
		iblock = (*sysinode)->i_di.di_num.no_addr;
Packit Service 360c39
		log_info( _("System inode for '%s' is located at block %llu"
Packit Service 360c39
			 " (0x%llx)\n"), filename,
Packit Service 360c39
			 (unsigned long long)iblock,
Packit Service 360c39
			 (unsigned long long)iblock);
Packit Service 360c39
		if (gfs2_check_meta((*sysinode)->i_bh, GFS2_METATYPE_DI)) {
Packit Service 360c39
			log_err( _("Found invalid system dinode at block #"
Packit Service 360c39
				   "%llu (0x%llx)\n"),
Packit Service 360c39
				 (unsigned long long)iblock,
Packit Service 360c39
				 (unsigned long long)iblock);
Packit Service 360c39
			gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
Packit Service 360c39
			check_n_fix_bitmap(sdp, (*sysinode)->i_rgd, iblock, 0,
Packit Service 360c39
					   GFS2_BLKST_FREE);
Packit Service 360c39
			inode_put(sysinode);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (*sysinode) {
Packit Service 360c39
		ds.q = block_type(bl, iblock);
Packit Service 360c39
		/* If the inode exists but the block is marked free, we might
Packit Service 360c39
		   be recovering from a corrupt bitmap.  In that case, don't
Packit Service 360c39
		   rebuild the inode.  Just reuse the inode and fix the
Packit Service 360c39
		   bitmap. */
Packit Service 360c39
		if (ds.q == GFS2_BLKST_FREE) {
Packit Service 360c39
			log_info( _("The inode exists but the block is not "
Packit Service 360c39
				    "marked 'in use'; fixing it.\n"));
Packit Service 360c39
			fsck_blockmap_set(*sysinode,
Packit Service 360c39
					  (*sysinode)->i_di.di_num.no_addr,
Packit Service 360c39
					  filename, GFS2_BLKST_DINODE);
Packit Service 360c39
			ds.q = GFS2_BLKST_DINODE;
Packit Service 360c39
			if (isdir)
Packit Service 360c39
				dirtree_insert((*sysinode)->i_di.di_num);
Packit Service 360c39
		}
Packit Service 360c39
		/* Make sure it's marked as a system file/directory */
Packit Service 360c39
		if (needs_sysbit &&
Packit Service 360c39
		    !((*sysinode)->i_di.di_flags & GFS2_DIF_SYSTEM)) {
Packit Service 360c39
			log_err( _("System inode %s is missing the 'system' "
Packit Service 360c39
				   "flag. It should be rebuilt.\n"), filename);
Packit Service 360c39
			if (sysdir && query(_("Delete the corrupt %s system "
Packit Service 360c39
					      "inode? (y/n) "), filename)) {
Packit Service 360c39
				inode_put(sysinode);
Packit Service 360c39
				gfs2_dirent_del(sysdir, filename,
Packit Service 360c39
						strlen(filename));
Packit Service 360c39
				/* Set the blockmap (but not bitmap) back to
Packit Service 360c39
				   'free' so that it gets checked like any
Packit Service 360c39
				   normal dinode. */
Packit Service 360c39
				gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE);
Packit Service 360c39
				log_err( _("Removed system inode \"%s\".\n"),
Packit Service 360c39
					 filename);
Packit Service 360c39
			}
Packit Service 360c39
		}
Packit Service 360c39
	} else
Packit Service 360c39
		log_info( _("System inode for '%s' is corrupt or missing.\n"),
Packit Service 360c39
			  filename);
Packit Service 360c39
	/* If there are errors with the inode here, we need to create a new
Packit Service 360c39
	   inode and get it all setup - of course, everything will be in
Packit Service 360c39
	   lost+found then, but we *need* our system inodes before we can
Packit Service 360c39
	   do any of that. */
Packit Service 360c39
	if (!(*sysinode) || ds.q != GFS2_BLKST_DINODE) {
Packit Service 360c39
		log_err(_("Invalid or missing %s system inode (is '%s', "
Packit Service 360c39
			  "should be '%s').\n"), filename,
Packit Service 360c39
			block_type_string(ds.q),
Packit Service 360c39
			block_type_string(GFS2_BLKST_DINODE));
Packit Service 360c39
		if (query(_("Create new %s system inode? (y/n) "), filename)) {
Packit Service 360c39
			log_err( _("Rebuilding system file \"%s\"\n"),
Packit Service 360c39
				 filename);
Packit Service 360c39
			error = builder(sdp);
Packit Service 360c39
			if (error) {
Packit Service 360c39
				log_err( _("Error rebuilding system "
Packit Service 360c39
					   "inode %s: Cannot continue\n"),
Packit Service 360c39
					 filename);
Packit Service 360c39
				return error;
Packit Service 360c39
			}
Packit Service 360c39
			if (*sysinode == sdp->md.jiinode)
Packit Service 360c39
				ji_update(sdp);
Packit Service 360c39
			fsck_blockmap_set(*sysinode,
Packit Service 360c39
					  (*sysinode)->i_di.di_num.no_addr,
Packit Service 360c39
					  filename, GFS2_BLKST_DINODE);
Packit Service 360c39
			ds.q = GFS2_BLKST_DINODE;
Packit Service 360c39
			if (isdir)
Packit Service 360c39
				dirtree_insert((*sysinode)->i_di.di_num);
Packit Service 360c39
		} else {
Packit Service 360c39
			log_err( _("Cannot continue without valid %s inode\n"),
Packit Service 360c39
				filename);
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	if (is_dir(&(*sysinode)->i_di, sdp->gfs1)) {
Packit Service 360c39
		struct block_count bc = {0};
Packit Service 360c39
Packit Service 360c39
		sysdir_fxns.private = &bc;
Packit Service 360c39
		if ((*sysinode)->i_di.di_flags & GFS2_DIF_EXHASH)
Packit Service 360c39
			pass1_check_metatree(*sysinode, &sysdir_fxns);
Packit Service 360c39
		else {
Packit Service 360c39
			err = check_linear_dir(*sysinode, (*sysinode)->i_bh,
Packit Service 360c39
					       &sysdir_fxns);
Packit Service 360c39
			/* If we encountered an error in our directory check
Packit Service 360c39
			   we should still call handle_ip, but return the
Packit Service 360c39
			   error later. */
Packit Service 360c39
			if (err)
Packit Service 360c39
				log_err(_("Error found in %s while checking "
Packit Service 360c39
					  "directory entries.\n"), filename);
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	check_i_goal(sdp, *sysinode);
Packit Service 360c39
	error = handle_ip(sdp, *sysinode);
Packit Service 360c39
	return error ? error : err;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int build_a_journal(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	char name[256];
Packit Service 360c39
	int err = 0;
Packit Service 360c39
Packit Service 360c39
	/* First, try to delete the journal if it's in jindex */
Packit Service 360c39
	sprintf(name, "journal%u", sdp->md.journals);
Packit Service 360c39
	gfs2_dirent_del(sdp->md.jiinode, name, strlen(name));
Packit Service 360c39
	/* Now rebuild it */
Packit Service 360c39
	err = build_journal(sdp, sdp->md.journals, sdp->md.jiinode);
Packit Service 360c39
	if (err) {
Packit Service 360c39
		log_crit(_("Error %d building journal\n"), err);
Packit Service 360c39
		exit(FSCK_ERROR);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int check_system_inodes(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	int journal_count;
Packit Service 360c39
Packit Service 360c39
	/*******************************************************************
Packit Service 360c39
	 *******  Check the system inode integrity             *************
Packit Service 360c39
	 *******************************************************************/
Packit Service 360c39
	/* Mark the master system dinode as a "dinode" in the block map.
Packit Service 360c39
	   All other system dinodes in master will be taken care of by function
Packit Service 360c39
	   resuscitate_metalist.  But master won't since it has no parent.*/
Packit Service 360c39
	if (!sdp->gfs1) {
Packit Service 360c39
		fsck_blockmap_set(sdp->master_dir,
Packit Service 360c39
				  sdp->master_dir->i_di.di_num.no_addr,
Packit Service 360c39
				  "master", GFS2_BLKST_DINODE);
Packit Service 360c39
		if (check_system_inode(sdp, &sdp->master_dir, "master",
Packit Service 360c39
				       build_master, 1, NULL, 1)) {
Packit Service 360c39
			stack;
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	/* Mark the root dinode as a "dinode" in the block map as we did
Packit Service 360c39
	   for master, since it has no parent. */
Packit Service 360c39
	fsck_blockmap_set(sdp->md.rooti, sdp->md.rooti->i_di.di_num.no_addr,
Packit Service 360c39
			  "root", GFS2_BLKST_DINODE);
Packit Service 360c39
	if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root, 1,
Packit Service 360c39
			       NULL, 0)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (!sdp->gfs1 &&
Packit Service 360c39
	    check_system_inode(sdp, &sdp->md.inum, "inum", build_inum, 0,
Packit Service 360c39
			       sdp->master_dir, 1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs, 0,
Packit Service 360c39
			       sdp->master_dir, !sdp->gfs1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex,
Packit Service 360c39
			       (sdp->gfs1 ? 0 : 1), sdp->master_dir,
Packit Service 360c39
			       !sdp->gfs1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (check_system_inode(sdp, &sdp->md.riinode, "rindex", build_rindex,
Packit Service 360c39
			       0, sdp->master_dir, !sdp->gfs1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (check_system_inode(sdp, &sdp->md.qinode, "quota", build_quota,
Packit Service 360c39
			       0, sdp->master_dir, !sdp->gfs1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (!sdp->gfs1 &&
Packit Service 360c39
	    check_system_inode(sdp, &sdp->md.pinode, "per_node",
Packit Service 360c39
			       build_per_node, 1, sdp->master_dir, 1)) {
Packit Service 360c39
		stack;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	/* We have to play a trick on build_journal:  We swap md.journals
Packit Service 360c39
	   in order to keep a count of which journal we need to build. */
Packit Service 360c39
	journal_count = sdp->md.journals;
Packit Service 360c39
	/* gfs1's journals aren't dinode, they're just a bunch of blocks. */
Packit Service 360c39
	if (sdp->gfs1) {
Packit Service 360c39
		/* gfs1 has four dinodes that are set in the superblock and
Packit Service 360c39
		   therefore not linked to anything else. We need to adjust
Packit Service 360c39
		   the link counts so pass4 doesn't get confused. */
Packit Service 360c39
		incr_link_count(sdp->md.statfs->i_di.di_num, NULL,
Packit Service 360c39
				_("gfs1 statfs inode"));
Packit Service 360c39
		incr_link_count(sdp->md.jiinode->i_di.di_num, NULL,
Packit Service 360c39
				_("gfs1 jindex inode"));
Packit Service 360c39
		incr_link_count(sdp->md.riinode->i_di.di_num, NULL,
Packit Service 360c39
				_("gfs1 rindex inode"));
Packit Service 360c39
		incr_link_count(sdp->md.qinode->i_di.di_num, NULL,
Packit Service 360c39
				_("gfs1 quota inode"));
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	for (sdp->md.journals = 0; sdp->md.journals < journal_count;
Packit Service 360c39
	     sdp->md.journals++) {
Packit Service 360c39
		char jname[16];
Packit Service 360c39
Packit Service 360c39
		sprintf(jname, "journal%d", sdp->md.journals);
Packit Service 360c39
		if (check_system_inode(sdp, &sdp->md.journal[sdp->md.journals],
Packit Service 360c39
				       jname, build_a_journal, 0,
Packit Service 360c39
				       sdp->md.jiinode, 1)) {
Packit Service 360c39
			stack;
Packit Service 360c39
			return -1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uint64_t *ibuf, unsigned n)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_buffer_head *bh;
Packit Service 360c39
	unsigned i;
Packit Service 360c39
	uint64_t block;
Packit Service 360c39
	struct gfs2_inode *ip;
Packit Service 360c39
	int q;
Packit Service 360c39
	/* Readahead numbers arrived at by experiment */
Packit Service 360c39
	unsigned rawin = 50;
Packit Service 360c39
	unsigned ralen = 100 * sdp->bsize;
Packit Service 360c39
	unsigned r = 0;
Packit Service 360c39
Packit Service 360c39
	for (i = 0; i < n; i++) {
Packit Service 360c39
		int is_inode;
Packit Service 360c39
		uint32_t check_magic;
Packit Service 360c39
Packit Service 360c39
		block = ibuf[i];
Packit Service 360c39
Packit Service 360c39
		if (r++ == rawin) {
Packit Service 360c39
			posix_fadvise(sdp->device_fd, block * sdp->bsize, ralen, POSIX_FADV_WILLNEED);
Packit Service 360c39
			r = 0;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		/* skip gfs1 rindex indirect blocks */
Packit Service 360c39
		if (sdp->gfs1 && blockfind(&gfs1_rindex_blks, block)) {
Packit Service 360c39
			log_debug(_("Skipping rindex indir 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
			continue;
Packit Service 360c39
		}
Packit Service 360c39
		warm_fuzzy_stuff(block);
Packit Service 360c39
Packit Service 360c39
		if (fsck_abort) { /* if asked to abort */
Packit Service 360c39
			gfs2_special_free(&gfs1_rindex_blks);
Packit Service 360c39
			return FSCK_OK;
Packit Service 360c39
		}
Packit Service 360c39
		if (skip_this_pass) {
Packit Service 360c39
			printf( _("Skipping pass 1 is not a good idea.\n"));
Packit Service 360c39
			skip_this_pass = FALSE;
Packit Service 360c39
			fflush(stdout);
Packit Service 360c39
		}
Packit Service 360c39
		if (fsck_system_inode(sdp, block)) {
Packit Service 360c39
			log_debug(_("Already processed system inode "
Packit Service 360c39
				    "%lld (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
Packit Service 360c39
		bh = bread(sdp, block);
Packit Service 360c39
Packit Service 360c39
		is_inode = 0;
Packit Service 360c39
		if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
Packit Service 360c39
			is_inode = 1;
Packit Service 360c39
Packit Service 360c39
		check_magic = ((struct gfs2_meta_header *)
Packit Service 360c39
			       (bh->b_data))->mh_magic;
Packit Service 360c39
Packit Service 360c39
		q = block_type(bl, block);
Packit Service 360c39
		if (q != GFS2_BLKST_FREE) {
Packit Service 360c39
			if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
Packit Service 360c39
			    sdp->gfs1 && !is_inode) {
Packit Service 360c39
				log_debug(_("Block 0x%llx assumed to be "
Packit Service 360c39
					    "previously processed GFS1 "
Packit Service 360c39
					    "non-dinode metadata.\n"),
Packit Service 360c39
					  (unsigned long long)block);
Packit Service 360c39
				brelse(bh);
Packit Service 360c39
				continue;
Packit Service 360c39
			}
Packit Service 360c39
			log_err( _("Found a duplicate inode block at #%llu "
Packit Service 360c39
				   "(0x%llx) previously marked as a %s\n"),
Packit Service 360c39
				 (unsigned long long)block,
Packit Service 360c39
				 (unsigned long long)block,
Packit Service 360c39
				 block_type_string(q));
Packit Service 360c39
			ip = fsck_inode_get(sdp, rgd, bh);
Packit Service 360c39
			if (is_inode && ip->i_di.di_num.no_addr == block)
Packit Service 360c39
				add_duplicate_ref(ip, block, ref_is_inode, 0,
Packit Service 360c39
						  INODE_VALID);
Packit Service 360c39
			else
Packit Service 360c39
				log_info(_("dinum.no_addr is wrong, so I "
Packit Service 360c39
					   "assume the bitmap is just "
Packit Service 360c39
					   "wrong.\n"));
Packit Service 360c39
			fsck_inode_put(&ip);
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			continue;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if (!is_inode) {
Packit Service 360c39
			if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
Packit Service 360c39
			/* In gfs2, a bitmap mark of 2 means an inode,
Packit Service 360c39
			   but in gfs1 it means any metadata.  So if
Packit Service 360c39
			   this is gfs1 and not an inode, it may be
Packit Service 360c39
			   okay.  If it's non-dinode metadata, it will
Packit Service 360c39
			   be referenced by an inode, so we need to
Packit Service 360c39
			   skip it here and it will be sorted out
Packit Service 360c39
			   when the referencing inode is checked. */
Packit Service 360c39
				if (sdp->gfs1) {
Packit Service 360c39
					log_debug( _("Deferring GFS1 "
Packit Service 360c39
						     "metadata block #"
Packit Service 360c39
						     "%" PRIu64" (0x%"
Packit Service 360c39
						     PRIx64 ")\n"),
Packit Service 360c39
						   block, block);
Packit Service 360c39
					brelse(bh);
Packit Service 360c39
					continue;
Packit Service 360c39
				}
Packit Service 360c39
			}
Packit Service 360c39
			log_err( _("Found invalid inode at 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
			check_n_fix_bitmap(sdp, rgd, block, 0,
Packit Service 360c39
					   GFS2_BLKST_FREE);
Packit Service 360c39
		} else if (handle_di(sdp, rgd, bh) < 0) {
Packit Service 360c39
			stack;
Packit Service 360c39
			brelse(bh);
Packit Service 360c39
			gfs2_special_free(&gfs1_rindex_blks);
Packit Service 360c39
			return FSCK_ERROR;
Packit Service 360c39
		}
Packit Service 360c39
		/* Ignore everything else - they should be hit by the
Packit Service 360c39
		   handle_di step.  Don't check NONE either, because
Packit Service 360c39
		   check_meta passes everything if GFS2_METATYPE_NONE
Packit Service 360c39
		   is specified.  Hopefully, other metadata types such
Packit Service 360c39
		   as indirect blocks will be handled when the inode
Packit Service 360c39
		   itself is processed, and if it's not, it should be
Packit Service 360c39
		   caught in pass5. */
Packit Service 360c39
		brelse(bh);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int pass1_process_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
Packit Service 360c39
{
Packit Service 360c39
	unsigned k, n, i;
Packit Service 360c39
	uint64_t *ibuf = malloc(sdp->bsize * GFS2_NBBY * sizeof(uint64_t));
Packit Service 360c39
	int ret = 0;
Packit Service 360c39
Packit Service 360c39
	if (ibuf == NULL)
Packit Service 360c39
		return FSCK_ERROR;
Packit Service 360c39
Packit Service 360c39
	for (k = 0; k < rgd->ri.ri_length; k++) {
Packit Service 360c39
		n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_DINODE);
Packit Service 360c39
Packit Service 360c39
		if (n) {
Packit Service 360c39
			ret = pass1_process_bitmap(sdp, rgd, ibuf, n);
Packit Service 360c39
			if (ret)
Packit Service 360c39
				goto out;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		if (fsck_abort)
Packit Service 360c39
			goto out;
Packit Service 360c39
		/*
Packit Service 360c39
		  For GFS1, we have to count the "free meta" blocks in the
Packit Service 360c39
		  resource group and mark them specially so we can count them
Packit Service 360c39
		  properly in pass5.
Packit Service 360c39
		 */
Packit Service 360c39
		if (!sdp->gfs1)
Packit Service 360c39
			continue;
Packit Service 360c39
Packit Service 360c39
		n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_UNLINKED);
Packit Service 360c39
		for (i = 0; i < n; i++) {
Packit Service 360c39
			gfs2_blockmap_set(bl, ibuf[i], GFS2_BLKST_UNLINKED);
Packit Service 360c39
			if (fsck_abort)
Packit Service 360c39
				goto out;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
out:
Packit Service 360c39
	free(ibuf);
Packit Service 360c39
	return ret;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int gfs2_blockmap_create(struct gfs2_bmap *bmap, uint64_t size)
Packit Service 360c39
{
Packit Service 360c39
	bmap->size = size;
Packit Service 360c39
Packit Service 360c39
	/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
Packit Service 360c39
	 * must be 1-based */
Packit Service 360c39
	bmap->mapsize = BLOCKMAP_SIZE2(size) + 1;
Packit Service 360c39
Packit Service 360c39
	if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
Packit Service 360c39
		return -ENOMEM;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
Packit Service 360c39
static int link1_create(struct gfs2_bmap *bmap, uint64_t size)
Packit Service 360c39
{
Packit Service 360c39
	bmap->size = size;
Packit Service 360c39
Packit Service 360c39
	/* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs
Packit Service 360c39
	 * must be 1-based */
Packit Service 360c39
	bmap->mapsize = BLOCKMAP_SIZE1(size) + 1;
Packit Service 360c39
Packit Service 360c39
	if (!(bmap->map = calloc(bmap->mapsize, sizeof(char))))
Packit Service 360c39
		return -ENOMEM;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
Packit Service 360c39
					  uint64_t *addl_mem_needed)
Packit Service 360c39
{
Packit Service 360c39
	struct gfs2_bmap *il;
Packit Service 360c39
Packit Service 360c39
	*addl_mem_needed = 0L;
Packit Service 360c39
	il = calloc(1, sizeof(*il));
Packit Service 360c39
	if (!il)
Packit Service 360c39
		return NULL;
Packit Service 360c39
Packit Service 360c39
	if (gfs2_blockmap_create(il, size)) {
Packit Service 360c39
		*addl_mem_needed = il->mapsize;
Packit Service 360c39
		free(il);
Packit Service 360c39
		il = NULL;
Packit Service 360c39
	}
Packit Service 360c39
	return il;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void gfs2_blockmap_destroy(struct gfs2_bmap *bmap)
Packit Service 360c39
{
Packit Service 360c39
	if (bmap->map)
Packit Service 360c39
		free(bmap->map);
Packit Service 360c39
	bmap->size = 0;
Packit Service 360c39
	bmap->mapsize = 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il)
Packit Service 360c39
{
Packit Service 360c39
	if (il) {
Packit Service 360c39
		gfs2_blockmap_destroy(il);
Packit Service 360c39
		free(il);
Packit Service 360c39
		il = NULL;
Packit Service 360c39
	}
Packit Service 360c39
	return il;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void enomem(uint64_t addl_mem_needed)
Packit Service 360c39
{
Packit Service 360c39
	log_crit( _("This system doesn't have enough memory and swap space to fsck this file system.\n"));
Packit Service 360c39
	log_crit( _("Additional memory needed is approximately: %lluMB\n"),
Packit Service 360c39
		  (unsigned long long)(addl_mem_needed / 1048576ULL));
Packit Service 360c39
	log_crit( _("Please increase your swap space by that amount and run fsck.gfs2 again.\n"));
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * pass1 - walk through inodes and check inode state
Packit Service 360c39
 *
Packit Service 360c39
 * this walk can be done using root inode and depth first search,
Packit Service 360c39
 * watching for repeat inode numbers
Packit Service 360c39
 *
Packit Service 360c39
 * format & type
Packit Service 360c39
 * link count
Packit Service 360c39
 * duplicate blocks
Packit Service 360c39
 * bad blocks
Packit Service 360c39
 * inodes size
Packit Service 360c39
 * dir info
Packit Service 360c39
 */
Packit Service 360c39
int pass1(struct gfs2_sbd *sdp)
Packit Service 360c39
{
Packit Service 360c39
	struct osi_node *n, *next = NULL;
Packit Service 360c39
	struct rgrp_tree *rgd;
Packit Service 360c39
	uint64_t i;
Packit Service 360c39
	uint64_t rg_count = 0;
Packit Service 360c39
	struct timeval timer;
Packit Service 360c39
	int ret = FSCK_OK;
Packit Service 360c39
	uint64_t addl_mem_needed;
Packit Service 360c39
Packit Service 360c39
	bl = gfs2_bmap_create(sdp, last_fs_block+1, &addl_mem_needed);
Packit Service 360c39
	if (!bl) {
Packit Service 360c39
		enomem(addl_mem_needed);
Packit Service 360c39
		return FSCK_ERROR;
Packit Service 360c39
	}
Packit Service 360c39
	addl_mem_needed = link1_create(&nlink1map, last_fs_block+1);
Packit Service 360c39
	if (addl_mem_needed) {
Packit Service 360c39
		enomem(addl_mem_needed);
Packit Service 360c39
		gfs2_bmap_destroy(sdp, bl);
Packit Service 360c39
		return FSCK_ERROR;
Packit Service 360c39
	}
Packit Service 360c39
	addl_mem_needed = link1_create(&clink1map, last_fs_block+1);
Packit Service 360c39
	if (addl_mem_needed) {
Packit Service 360c39
		enomem(addl_mem_needed);
Packit Service 360c39
		link1_destroy(&nlink1map);
Packit Service 360c39
		gfs2_bmap_destroy(sdp, bl);
Packit Service 360c39
		return FSCK_ERROR;
Packit Service 360c39
	}
Packit Service 360c39
	osi_list_init(&gfs1_rindex_blks.list);
Packit Service 360c39
Packit Service 360c39
	/* FIXME: In the gfs fsck, we had to mark things like the
Packit Service 360c39
	 * journals and indices and such as 'other_meta' - in gfs2,
Packit Service 360c39
	 * the journals are files and are found in the normal file
Packit Service 360c39
	 * sweep - is there any metadata we need to mark here before
Packit Service 360c39
	 * the sweeps start that we won't find otherwise? */
Packit Service 360c39
Packit Service 360c39
	/* Make sure the system inodes are okay & represented in the bitmap. */
Packit Service 360c39
	check_system_inodes(sdp);
Packit Service 360c39
Packit Service 360c39
	/* So, do we do a depth first search starting at the root
Packit Service 360c39
	 * inode, or use the rg bitmaps, or just read every fs block
Packit Service 360c39
	 * to find the inodes?  If we use the depth first search, why
Packit Service 360c39
	 * have pass3 at all - if we use the rg bitmaps, pass5 is at
Packit Service 360c39
	 * least partially invalidated - if we read every fs block,
Packit Service 360c39
	 * things will probably be intolerably slow.  The current fsck
Packit Service 360c39
	 * uses the rg bitmaps, so maybe that's the best way to start
Packit Service 360c39
	 * things - we can change the method later if necessary.
Packit Service 360c39
	 */
Packit Service 360c39
	for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) {
Packit Service 360c39
		if (fsck_abort) {
Packit Service 360c39
			ret = FSCK_CANCELED;
Packit Service 360c39
			goto out;
Packit Service 360c39
		}
Packit Service 360c39
		next = osi_next(n);
Packit Service 360c39
		log_debug( _("Checking metadata in Resource Group #%llu\n"),
Packit Service 360c39
				 (unsigned long long)rg_count);
Packit Service 360c39
		rgd = (struct rgrp_tree *)n;
Packit Service 360c39
		for (i = 0; i < rgd->ri.ri_length; i++) {
Packit Service 360c39
			log_debug( _("rgrp block %lld (0x%llx) "
Packit Service 360c39
				     "is now marked as 'rgrp data'\n"),
Packit Service 360c39
				   rgd->ri.ri_addr + i, rgd->ri.ri_addr + i);
Packit Service 360c39
			if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i,
Packit Service 360c39
					      GFS2_BLKST_USED)) {
Packit Service 360c39
				stack;
Packit Service 360c39
				gfs2_special_free(&gfs1_rindex_blks);
Packit Service 360c39
				ret = FSCK_ERROR;
Packit Service 360c39
				goto out;
Packit Service 360c39
			}
Packit Service 360c39
			/* rgrps and bitmaps don't have bits to represent
Packit Service 360c39
			   their blocks, so don't do this:
Packit Service 360c39
			check_n_fix_bitmap(sdp, rgd, rgd->ri.ri_addr + i, 0,
Packit Service 360c39
			gfs2_meta_rgrp);*/
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		ret = pass1_process_rgrp(sdp, rgd);
Packit Service 360c39
		if (ret)
Packit Service 360c39
			goto out;
Packit Service 360c39
	}
Packit Service 360c39
	log_notice(_("Reconciling bitmaps.\n"));
Packit Service 360c39
	gettimeofday(&timer, NULL);
Packit Service 360c39
	pass5(sdp, bl);
Packit Service 360c39
	print_pass_duration("reconcile_bitmaps", &timer;;
Packit Service 360c39
out:
Packit Service 360c39
	gfs2_special_free(&gfs1_rindex_blks);
Packit Service 360c39
	if (bl)
Packit Service 360c39
		gfs2_bmap_destroy(sdp, bl);
Packit Service 360c39
	return ret;
Packit Service 360c39
}