#ifndef _METAWALK_H
#define _METAWALK_H

#define DIR_LINEAR 1
#define DIR_EXHASH 2

#include "util.h"

struct metawalk_fxns;

extern int check_inode_eattr(struct gfs2_inode *ip,
			     struct metawalk_fxns *pass);
extern int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass);
extern int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass);
extern int check_dir(struct gfs2_sbd *sdp, struct gfs2_inode *ip,
		     struct metawalk_fxns *pass);
extern int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
			    struct metawalk_fxns *pass);
extern int check_leaf(struct gfs2_inode *ip, int lindex,
		      struct metawalk_fxns *pass, uint64_t *leaf_no,
		      struct gfs2_leaf *leaf, int *ref_count);
extern int _fsck_bitmap_set(struct gfs2_inode *ip, uint64_t bblock,
			    const char *btype, int mark, int error_on_dinode,
			    const char *caller, int line);
extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
			      uint64_t blk, int error_on_dinode,
			      int new_state);
extern struct duptree *dupfind(uint64_t block);
extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp,
					    uint64_t block);

#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)

#define fsck_bitmap_set(ip, b, bt, m) \
	_fsck_bitmap_set(ip, b, bt, m, 0, __FUNCTION__, __LINE__)
#define fsck_bitmap_set_noino(ip, b, bt, m) \
	_fsck_bitmap_set(ip, b, bt, m, 1, __FUNCTION__, __LINE__)
enum meta_check_rc {
	meta_error = -1,
	meta_is_good = 0,
	meta_skip_further = 1,
	meta_skip_one = 2,
};

struct iptr {
	struct gfs2_inode *ipt_ip;
	struct gfs2_buffer_head *ipt_bh;
	unsigned ipt_off;
};

#define iptr_ptr(i) ((uint64_t *)(i.ipt_bh->b_data + i.ipt_off))
#define iptr_block(i) be64_to_cpu(*iptr_ptr(i))
#define iptr_endptr(i) ((uint64_t *)(iptr.ipt_bh->b_data + i.ipt_ip->i_sbd->bsize))
#define iptr_buf(i) (i.ipt_bh->b_data)

/* metawalk_fxns: function pointers to check various parts of the fs
 *
 * The functions should return -1 on fatal errors, 1 if the block
 * should be skipped, and 0 on success
 *
 * private: Data that should be passed to the fxns
 * check_leaf:
 * check_metalist:
 * check_data:
 * check_eattr_indir:
 * check_eattr_leaf:
 * check_dentry:
 * check_eattr_entry:
 * check_eattr_extentry:
 */
struct metawalk_fxns {
	void *private;
	int invalid_meta_is_fatal;
	int readahead;
	int (*check_leaf_depth) (struct gfs2_inode *ip, uint64_t leaf_no,
				 int ref_count, struct gfs2_buffer_head *lbh);
	int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
			   void *private);
	/* parameters to the check_metalist sub-functions:
	   iptr: reference to the inode and its indirect pointer that we're analyzing
	   block: block number of the metadata block to be checked
	   bh: buffer_head to be returned
	   h: height
	   is_valid: returned as 1 if the metadata block is valid and should
	             be added to the metadata list for further processing.
	   was_duplicate: returns as 1 if the metadata block was determined
	             to be a duplicate reference, in which case we want to
		     skip adding it to the metadata list.
	   private: Pointer to pass-specific data
	   returns: 0 - everything is good, but there may be duplicates
	            1 - skip further processing
	*/
	int (*check_metalist) (struct iptr iptr,
			       struct gfs2_buffer_head **bh, int h,
			       int *is_valid, int *was_duplicate,
			       void *private);
	int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
			   uint64_t block, void *private,
			   struct gfs2_buffer_head *bh, uint64_t *ptr);
	int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
				  uint64_t parent,
				  struct gfs2_buffer_head **bh, void *private);
	int (*check_eattr_leaf) (struct gfs2_inode *ip, uint64_t block,
				 uint64_t parent, struct gfs2_buffer_head **bh,
				 void *private);
	int (*check_dentry) (struct gfs2_inode *ip, struct gfs2_dirent *de,
			     struct gfs2_dirent *prev,
			     struct gfs2_buffer_head *bh,
			     char *filename, uint32_t *count,
			     int *lindex, void *private);
	int (*check_eattr_entry) (struct gfs2_inode *ip,
				  struct gfs2_buffer_head *leaf_bh,
				  struct gfs2_ea_header *ea_hdr,
				  struct gfs2_ea_header *ea_hdr_prev,
				  void *private);
	int (*check_eattr_extentry) (struct gfs2_inode *ip, int i,
				     uint64_t *ea_data_ptr,
				     struct gfs2_buffer_head *leaf_bh,
				     uint32_t tot_ealen,
				     struct gfs2_ea_header *ea_hdr,
				     struct gfs2_ea_header *ea_hdr_prev,
				     void *private);
	int (*finish_eattr_indir) (struct gfs2_inode *ip, int leaf_pointers,
				   int leaf_pointer_errors, void *private);
	void (*big_file_msg) (struct gfs2_inode *ip, uint64_t blks_checked);
	int (*check_hash_tbl) (struct gfs2_inode *ip, uint64_t *tbl,
			       unsigned hsize, void *private);
	int (*repair_leaf) (struct gfs2_inode *ip, uint64_t *leaf_no,
			    int lindex, int ref_count, const char *msg);
	int (*undo_check_meta) (struct gfs2_inode *ip, uint64_t block,
				int h, void *private);
	int (*undo_check_data) (struct gfs2_inode *ip, uint64_t block,
				void *private);
	int (*delete_block) (struct gfs2_inode *ip, uint64_t block,
			     struct gfs2_buffer_head **bh, const char *btype,
			     void *private);
};

#endif /* _METAWALK_H */
