| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 
 |  * All Rights Reserved. | 
 |  */ | 
 |  | 
 | #include "libxfs.h" | 
 | #include <math.h> | 
 | #include <sys/time.h> | 
 | #include "bmap.h" | 
 | #include "check.h" | 
 | #include "command.h" | 
 | #include "io.h" | 
 | #include "type.h" | 
 | #include "fprint.h" | 
 | #include "faddr.h" | 
 | #include "field.h" | 
 | #include "sb.h" | 
 | #include "output.h" | 
 | #include "init.h" | 
 | #include "malloc.h" | 
 | #include "dir2.h" | 
 |  | 
 | typedef enum { | 
 | 	IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA, | 
 | } qtype_t; | 
 |  | 
 | typedef enum { | 
 | 	DBM_UNKNOWN,	DBM_AGF,	DBM_AGFL,	DBM_AGI, | 
 | 	DBM_ATTR,	DBM_BTBMAPA,	DBM_BTBMAPD,	DBM_BTBNO, | 
 | 	DBM_BTCNT,	DBM_BTINO,	DBM_DATA,	DBM_DIR, | 
 | 	DBM_FREE1,	DBM_FREE2,	DBM_FREELIST,	DBM_INODE, | 
 | 	DBM_LOG,	DBM_MISSING,	DBM_QUOTA,	DBM_RTBITMAP, | 
 | 	DBM_RTDATA,	DBM_RTFREE,	DBM_RTSUM,	DBM_SB, | 
 | 	DBM_SYMLINK,	DBM_BTFINO,	DBM_BTRMAP,	DBM_BTREFC, | 
 | 	DBM_RLDATA,	DBM_COWDATA, | 
 | 	DBM_NDBM | 
 | } dbm_t; | 
 |  | 
 | typedef struct inodata { | 
 | 	struct inodata	*next; | 
 | 	nlink_t		link_set; | 
 | 	nlink_t		link_add; | 
 | 	bool		isdir; | 
 | 	bool		isreflink; | 
 | 	char		security; | 
 | 	char		ilist; | 
 | 	xfs_ino_t	ino; | 
 | 	struct inodata	*parent; | 
 | 	char		*name; | 
 | } inodata_t; | 
 | #define	MIN_INODATA_HASH_SIZE	256 | 
 | #define	MAX_INODATA_HASH_SIZE	65536 | 
 | #define	INODATA_AVG_HASH_LENGTH	8 | 
 |  | 
 | typedef struct qinfo { | 
 | 	xfs_qcnt_t	bc; | 
 | 	xfs_qcnt_t	ic; | 
 | 	xfs_qcnt_t	rc; | 
 | } qinfo_t; | 
 |  | 
 | #define	QDATA_HASH_SIZE	256 | 
 | typedef	struct qdata { | 
 | 	struct qdata	*next; | 
 | 	xfs_dqid_t	id; | 
 | 	qinfo_t		count; | 
 | 	qinfo_t		dq; | 
 | } qdata_t; | 
 |  | 
 | typedef struct blkent { | 
 | 	xfs_fileoff_t	startoff; | 
 | 	int		nblks; | 
 | 	xfs_fsblock_t	blks[1]; | 
 | } blkent_t; | 
 | #define	BLKENT_SIZE(n)	\ | 
 | 	(offsetof(blkent_t, blks) + (sizeof(xfs_fsblock_t) * (n))) | 
 |  | 
 | typedef	struct blkmap { | 
 | 	int		naents; | 
 | 	int		nents; | 
 | 	blkent_t	*ents[1]; | 
 | } blkmap_t; | 
 | #define	BLKMAP_SIZE(n)	\ | 
 | 	(offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n))) | 
 |  | 
 | typedef struct freetab { | 
 | 	int			naents; | 
 | 	int			nents; | 
 | 	xfs_dir2_data_off_t	ents[1]; | 
 | } freetab_t; | 
 | #define	FREETAB_SIZE(n)	\ | 
 | 	(offsetof(freetab_t, ents) + (sizeof(xfs_dir2_data_off_t) * (n))) | 
 |  | 
 | typedef struct dirhash { | 
 | 	struct dirhash		*next; | 
 | 	__u32			hashval; | 
 | 	__u32			address; | 
 | 	int			seen; | 
 | } dirhash_t; | 
 | #define	DIR_HASH_SIZE	1024 | 
 | #define	DIR_HASH_FUNC(h,a)	(((h) ^ (a)) % DIR_HASH_SIZE) | 
 |  | 
 | static xfs_extlen_t	agffreeblks; | 
 | static xfs_extlen_t	agflongest; | 
 | static uint64_t	agf_aggr_freeblks;	/* aggregate count over all */ | 
 | static uint32_t	agfbtreeblks; | 
 | static int		lazycount; | 
 | static xfs_agino_t	agicount; | 
 | static xfs_agino_t	agifreecount; | 
 | static xfs_fsblock_t	*blist; | 
 | static int		blist_size; | 
 | static char		**dbmap;	/* really dbm_t:8 */ | 
 | static dirhash_t	**dirhash; | 
 | static int		error; | 
 | static uint64_t	fdblocks; | 
 | static uint64_t	frextents; | 
 | static uint64_t	icount; | 
 | static uint64_t	ifree; | 
 | static inodata_t	***inodata; | 
 | static int		inodata_hash_size; | 
 | static inodata_t	***inomap; | 
 | static int		nflag; | 
 | static int		pflag; | 
 | static int		tflag; | 
 | static qdata_t		**qpdata; | 
 | static int		qpdo; | 
 | static qdata_t		**qudata; | 
 | static int		qudo; | 
 | static qdata_t		**qgdata; | 
 | static int		qgdo; | 
 | static unsigned		sbversion; | 
 | static int		sbver_err; | 
 | static int		serious_error; | 
 | static int		sflag; | 
 | static union xfs_suminfo_raw *sumcompute; | 
 | static union xfs_suminfo_raw *sumfile; | 
 | static const char	*typename[] = { | 
 | 	"unknown", | 
 | 	"agf", | 
 | 	"agfl", | 
 | 	"agi", | 
 | 	"attr", | 
 | 	"btbmapa", | 
 | 	"btbmapd", | 
 | 	"btbno", | 
 | 	"btcnt", | 
 | 	"btino", | 
 | 	"data", | 
 | 	"dir", | 
 | 	"free1", | 
 | 	"free2", | 
 | 	"freelist", | 
 | 	"inode", | 
 | 	"log", | 
 | 	"missing", | 
 | 	"quota", | 
 | 	"rtbitmap", | 
 | 	"rtdata", | 
 | 	"rtfree", | 
 | 	"rtsum", | 
 | 	"sb", | 
 | 	"symlink", | 
 | 	"btfino", | 
 | 	"btrmap", | 
 | 	"btrefcnt", | 
 | 	"rldata", | 
 | 	"cowdata", | 
 | 	NULL | 
 | }; | 
 |  | 
 | /* | 
 |  * Make sure typename has the same number of elements as there are DBM types. | 
 |  * This function isn't called anywhere; we just use it to trip up the compiler. | 
 |  */ | 
 | static inline void check_typename(void) | 
 | { | 
 | 	BUILD_BUG_ON(ARRAY_SIZE(typename) != DBM_NDBM + 1); | 
 | } | 
 |  | 
 | static int		verbose; | 
 |  | 
 | #define	CHECK_BLIST(b)	(blist_size && check_blist(b)) | 
 | #define	CHECK_BLISTA(a,b)	\ | 
 | 	(blist_size && check_blist(XFS_AGB_TO_FSB(mp, a, b))) | 
 |  | 
 | typedef void	(*scan_lbtree_f_t)(struct xfs_btree_block *block, | 
 | 				   int			level, | 
 | 				   dbm_t		type, | 
 | 				   xfs_fsblock_t	bno, | 
 | 				   inodata_t		*id, | 
 | 				   xfs_rfsblock_t	*totd, | 
 | 				   xfs_rfsblock_t	*toti, | 
 | 				   xfs_extnum_t		*nex, | 
 | 				   blkmap_t		**blkmapp, | 
 | 				   int			isroot, | 
 | 				   typnm_t		btype); | 
 |  | 
 | typedef void	(*scan_sbtree_f_t)(struct xfs_btree_block *block, | 
 | 				   int			level, | 
 | 				   xfs_agf_t		*agf, | 
 | 				   xfs_agblock_t	bno, | 
 | 				   int			isroot); | 
 |  | 
 | static void		add_blist(xfs_fsblock_t	bno); | 
 | static void		add_ilist(xfs_ino_t ino); | 
 | static void		addlink_inode(inodata_t *id); | 
 | static void		addname_inode(inodata_t *id, char *name, int namelen); | 
 | static void		addparent_inode(inodata_t *id, xfs_ino_t parent); | 
 | static void		blkent_append(blkent_t **entp, xfs_fsblock_t b, | 
 | 				      xfs_extlen_t c); | 
 | static blkent_t		*blkent_new(xfs_fileoff_t o, xfs_fsblock_t b, | 
 | 				    xfs_extlen_t c); | 
 | static void		blkent_prepend(blkent_t **entp, xfs_fsblock_t b, | 
 | 				       xfs_extlen_t c); | 
 | static blkmap_t		*blkmap_alloc(xfs_extnum_t); | 
 | static void		blkmap_free(blkmap_t *blkmap); | 
 | static xfs_fsblock_t	blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o); | 
 | static int		blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, int nb, | 
 | 				    bmap_ext_t **bmpp); | 
 | static void		blkmap_grow(blkmap_t **blkmapp, blkent_t **entp, | 
 | 				    blkent_t *newent); | 
 | static xfs_fileoff_t	blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o, | 
 | 					int *t); | 
 | static void		blkmap_set_blk(blkmap_t **blkmapp, xfs_fileoff_t o, | 
 | 				       xfs_fsblock_t b); | 
 | static void		blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o, | 
 | 				       xfs_fsblock_t b, xfs_extlen_t c); | 
 | static void		blkmap_shrink(blkmap_t *blkmap, blkent_t **entp); | 
 | static int		blockfree_f(int argc, char **argv); | 
 | static int		blockget_f(int argc, char **argv); | 
 | static int		blocktrash_f(int argc, char **argv); | 
 | static int		blockuse_f(int argc, char **argv); | 
 | static int		check_blist(xfs_fsblock_t bno); | 
 | static void		check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				    xfs_extlen_t len, dbm_t type, | 
 | 				    int ignore_reflink); | 
 | static int		check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				     xfs_extlen_t len, xfs_ino_t c_ino); | 
 | static void		check_linkcounts(xfs_agnumber_t agno); | 
 | static int		check_range(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				    xfs_extlen_t len); | 
 | static void		check_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 				     dbm_t type); | 
 | static int		check_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 				      xfs_ino_t c_ino); | 
 | static void		check_rootdir(void); | 
 | static int		check_rrange(xfs_rfsblock_t bno, xfs_extlen_t len); | 
 | static void		check_set_dbmap(xfs_agnumber_t agno, | 
 | 					xfs_agblock_t agbno, xfs_extlen_t len, | 
 | 					dbm_t type1, dbm_t type2, | 
 | 					xfs_agnumber_t c_agno, | 
 | 					xfs_agblock_t c_agbno); | 
 | static void		check_set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 					 dbm_t type1, dbm_t type2); | 
 | static void		check_summary(void); | 
 | static void		checknot_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				       xfs_extlen_t len, int typemask); | 
 | static void		checknot_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 					int typemask); | 
 | static void		dir_hash_add(xfs_dahash_t hash, | 
 | 				     xfs_dir2_dataptr_t addr); | 
 | static void		dir_hash_check(inodata_t *id, int v); | 
 | static void		dir_hash_done(void); | 
 | static void		dir_hash_init(void); | 
 | static int		dir_hash_see(xfs_dahash_t hash, | 
 | 				     xfs_dir2_dataptr_t addr); | 
 | static inodata_t	*find_inode(xfs_ino_t ino, int add); | 
 | static void		free_inodata(xfs_agnumber_t agno); | 
 | static int		init(int argc, char **argv); | 
 | static char		*inode_name(xfs_ino_t ino, inodata_t **ipp); | 
 | static int		ncheck_f(int argc, char **argv); | 
 | static char		*prepend_path(char *oldpath, char *parent); | 
 | static xfs_ino_t	process_block_dir_v2(blkmap_t *blkmap, int *dot, | 
 | 					     int *dotdot, inodata_t *id); | 
 | static void		process_bmbt_reclist(xfs_bmbt_rec_t *rp, | 
 | 					     xfs_extnum_t numrecs, dbm_t type, | 
 | 					     inodata_t *id, xfs_rfsblock_t *tot, | 
 | 					     blkmap_t **blkmapp); | 
 | static void		process_btinode(inodata_t *id, struct xfs_dinode *dip, | 
 | 					dbm_t type, xfs_rfsblock_t *totd, | 
 | 					xfs_rfsblock_t *toti, xfs_extnum_t *nex, | 
 | 					blkmap_t **blkmapp, int whichfork); | 
 | static xfs_ino_t	process_data_dir_v2(int *dot, int *dotdot, | 
 | 					    inodata_t *id, int v, | 
 | 					    xfs_dablk_t dabno, | 
 | 					    freetab_t **freetabp); | 
 | static xfs_dir2_data_free_t *process_data_dir_v2_freefind( | 
 | 					struct xfs_dir2_data_hdr *data, | 
 | 					struct xfs_dir2_data_unused *dup); | 
 | static void		process_dir(struct xfs_dinode *dip, blkmap_t *blkmap, | 
 | 				    inodata_t *id); | 
 | static int		process_dir_v2(struct xfs_dinode *dip, blkmap_t *blkmap, | 
 | 				       int *dot, int *dotdot, inodata_t *id, | 
 | 				       xfs_ino_t *parent); | 
 | static void		process_exinode(inodata_t *id, struct xfs_dinode *dip, | 
 | 					dbm_t type, xfs_rfsblock_t *totd, | 
 | 					xfs_rfsblock_t *toti, xfs_extnum_t *nex, | 
 | 					blkmap_t **blkmapp, int whichfork); | 
 | static void		process_inode(xfs_agf_t *agf, xfs_agino_t agino, | 
 | 				      struct xfs_dinode *dip, int isfree); | 
 | static void		process_lclinode(inodata_t *id, struct xfs_dinode *dip, | 
 | 					 dbm_t type, xfs_rfsblock_t *totd, | 
 | 					 xfs_rfsblock_t *toti, xfs_extnum_t *nex, | 
 | 					 blkmap_t **blkmapp, int whichfork); | 
 | static xfs_ino_t	process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot, | 
 | 						 int *dotdot, inodata_t *id, | 
 | 						 xfs_fsize_t dirsize); | 
 | static void		process_leaf_node_dir_v2_free(inodata_t *id, int v, | 
 | 						      xfs_dablk_t dbno, | 
 | 						      freetab_t *freetab); | 
 | static void		process_leaf_node_dir_v2_int(inodata_t *id, int v, | 
 | 						     xfs_dablk_t dbno, | 
 | 						     freetab_t *freetab); | 
 | static void		process_quota(qtype_t qtype, inodata_t *id, | 
 | 				      blkmap_t *blkmap); | 
 | static void		process_rtbitmap(blkmap_t *blkmap); | 
 | static void		process_rtsummary(blkmap_t *blkmap); | 
 | static xfs_ino_t	process_sf_dir_v2(struct xfs_dinode *dip, int *dot, | 
 | 					  int *dotdot, inodata_t *id); | 
 | static void		quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u, | 
 | 				  int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, | 
 | 				  xfs_qcnt_t rc); | 
 | static void		quota_add1(qdata_t **qt, xfs_dqid_t id, int dq, | 
 | 				   xfs_qcnt_t bc, xfs_qcnt_t ic, | 
 | 				   xfs_qcnt_t rc); | 
 | static void		quota_check(char *s, qdata_t **qt); | 
 | static void		quota_init(void); | 
 | static void		scan_ag(xfs_agnumber_t agno); | 
 | static void		scan_freelist(xfs_agf_t *agf); | 
 | static void		scan_lbtree(xfs_fsblock_t root, int nlevels, | 
 | 				    scan_lbtree_f_t func, dbm_t type, | 
 | 				    inodata_t *id, xfs_rfsblock_t *totd, | 
 | 				    xfs_rfsblock_t *toti, xfs_extnum_t *nex, | 
 | 				    blkmap_t **blkmapp, int isroot, | 
 | 				    typnm_t btype); | 
 | static void		scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, | 
 | 				    int nlevels, int isroot, | 
 | 				    scan_sbtree_f_t func, typnm_t btype); | 
 | static void		scanfunc_bmap(struct xfs_btree_block *block, | 
 | 				      int level, dbm_t type, xfs_fsblock_t bno, | 
 | 				      inodata_t *id, xfs_rfsblock_t *totd, | 
 | 				      xfs_rfsblock_t *toti, xfs_extnum_t *nex, | 
 | 				      blkmap_t **blkmapp, int isroot, | 
 | 				      typnm_t btype); | 
 | static void		scanfunc_bno(struct xfs_btree_block *block, int level, | 
 | 				     xfs_agf_t *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		scanfunc_cnt(struct xfs_btree_block *block, int level, | 
 | 				     xfs_agf_t *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		scanfunc_ino(struct xfs_btree_block *block, int level, | 
 | 				     xfs_agf_t *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		scanfunc_fino(struct xfs_btree_block *block, int level, | 
 | 				     struct xfs_agf *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		scanfunc_rmap(struct xfs_btree_block *block, int level, | 
 | 				     struct xfs_agf *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		scanfunc_refcnt(struct xfs_btree_block *block, int level, | 
 | 				     struct xfs_agf *agf, xfs_agblock_t bno, | 
 | 				     int isroot); | 
 | static void		set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				  xfs_extlen_t len, dbm_t type, | 
 | 				  xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); | 
 | static void		set_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, | 
 | 				   xfs_extlen_t len, inodata_t *id); | 
 | static void		set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 				   dbm_t type); | 
 | static void		set_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len, | 
 | 				    inodata_t *id); | 
 | static void		setlink_inode(inodata_t *id, nlink_t nlink, int isdir, | 
 | 				       int security); | 
 |  | 
 | static const cmdinfo_t	blockfree_cmd = | 
 | 	{ "blockfree", NULL, blockfree_f, 0, 0, 0, | 
 | 	  NULL, N_("free block usage information"), NULL }; | 
 | static const cmdinfo_t	blockget_cmd = | 
 | 	{ "blockget", "check", blockget_f, 0, -1, 0, | 
 | 	  N_("[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..."), | 
 | 	  N_("get block usage and check consistency"), NULL }; | 
 | static const cmdinfo_t	blocktrash_cmd = | 
 | 	{ "blocktrash", NULL, blocktrash_f, 0, -1, 0, | 
 | 	  N_("[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..."), | 
 | 	  N_("trash randomly selected block(s)"), NULL }; | 
 | static const cmdinfo_t	blockuse_cmd = | 
 | 	{ "blockuse", NULL, blockuse_f, 0, 3, 0, | 
 | 	  N_("[-n] [-c blockcount]"), | 
 | 	  N_("print usage for current block(s)"), NULL }; | 
 | static const cmdinfo_t	ncheck_cmd = | 
 | 	{ "ncheck", NULL, ncheck_f, 0, -1, 0, | 
 | 	  N_("[-s] [-i ino] ..."), | 
 | 	  N_("print inode-name pairs"), NULL }; | 
 |  | 
 |  | 
 | static void | 
 | add_blist( | 
 | 	xfs_fsblock_t	bno) | 
 | { | 
 | 	blist_size++; | 
 | 	blist = xrealloc(blist, blist_size * sizeof(bno)); | 
 | 	blist[blist_size - 1] = bno; | 
 | } | 
 |  | 
 | static void | 
 | add_ilist( | 
 | 	xfs_ino_t	ino) | 
 | { | 
 | 	inodata_t	*id; | 
 |  | 
 | 	id = find_inode(ino, 1); | 
 | 	if (id == NULL) { | 
 | 		dbprintf(_("-i %lld bad inode number\n"), ino); | 
 | 		return; | 
 | 	} | 
 | 	id->ilist = 1; | 
 | } | 
 |  | 
 | static void | 
 | addlink_inode( | 
 | 	inodata_t	*id) | 
 | { | 
 | 	id->link_add++; | 
 | 	if (verbose || id->ilist) | 
 | 		dbprintf(_("inode %lld add link, now %u\n"), id->ino, | 
 | 			id->link_add); | 
 | } | 
 |  | 
 | static void | 
 | addname_inode( | 
 | 	inodata_t	*id, | 
 | 	char		*name, | 
 | 	int		namelen) | 
 | { | 
 | 	if (!nflag || id->name) | 
 | 		return; | 
 | 	id->name = xmalloc(namelen + 1); | 
 | 	memcpy(id->name, name, namelen); | 
 | 	id->name[namelen] = '\0'; | 
 | } | 
 |  | 
 | static void | 
 | addparent_inode( | 
 | 	inodata_t	*id, | 
 | 	xfs_ino_t	parent) | 
 | { | 
 | 	inodata_t	*pid; | 
 |  | 
 | 	pid = find_inode(parent, 1); | 
 | 	id->parent = pid; | 
 | 	if (verbose || id->ilist || (pid && pid->ilist)) | 
 | 		dbprintf(_("inode %lld parent %lld\n"), id->ino, parent); | 
 | } | 
 |  | 
 | static void | 
 | blkent_append( | 
 | 	blkent_t	**entp, | 
 | 	xfs_fsblock_t	b, | 
 | 	xfs_extlen_t	c) | 
 | { | 
 | 	blkent_t	*ent; | 
 | 	int		i; | 
 |  | 
 | 	ent = *entp; | 
 | 	*entp = ent = xrealloc(ent, BLKENT_SIZE(c + ent->nblks)); | 
 | 	for (i = 0; i < c; i++) | 
 | 		ent->blks[ent->nblks + i] = b + i; | 
 | 	ent->nblks += c; | 
 | } | 
 |  | 
 | static blkent_t * | 
 | blkent_new( | 
 | 	xfs_fileoff_t	o, | 
 | 	xfs_fsblock_t	b, | 
 | 	xfs_extlen_t	c) | 
 | { | 
 | 	blkent_t	*ent; | 
 | 	int		i; | 
 |  | 
 | 	ent = xmalloc(BLKENT_SIZE(c)); | 
 | 	ent->nblks = c; | 
 | 	ent->startoff = o; | 
 | 	for (i = 0; i < c; i++) | 
 | 		ent->blks[i] = b + i; | 
 | 	return ent; | 
 | } | 
 |  | 
 | static void | 
 | blkent_prepend( | 
 | 	blkent_t	**entp, | 
 | 	xfs_fsblock_t	b, | 
 | 	xfs_extlen_t	c) | 
 | { | 
 | 	int		i; | 
 | 	blkent_t	*newent; | 
 | 	blkent_t	*oldent; | 
 |  | 
 | 	oldent = *entp; | 
 | 	newent = xmalloc(BLKENT_SIZE(oldent->nblks + c)); | 
 | 	newent->nblks = oldent->nblks + c; | 
 | 	newent->startoff = oldent->startoff - c; | 
 | 	for (i = 0; i < c; i++) | 
 | 		newent->blks[i] = b + c; | 
 | 	for (; i < oldent->nblks + c; i++) | 
 | 		newent->blks[i] = oldent->blks[i - c]; | 
 | 	xfree(oldent); | 
 | 	*entp = newent; | 
 | } | 
 |  | 
 | static blkmap_t * | 
 | blkmap_alloc( | 
 | 	xfs_extnum_t	nex) | 
 | { | 
 | 	blkmap_t	*blkmap; | 
 |  | 
 | 	if (nex < 1) | 
 | 		nex = 1; | 
 | 	blkmap = xmalloc(BLKMAP_SIZE(nex)); | 
 | 	blkmap->naents = nex; | 
 | 	blkmap->nents = 0; | 
 | 	return blkmap; | 
 | } | 
 |  | 
 | static void | 
 | blkmap_free( | 
 | 	blkmap_t	*blkmap) | 
 | { | 
 | 	blkent_t	**entp; | 
 | 	xfs_extnum_t	i; | 
 |  | 
 | 	for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) | 
 | 		xfree(*entp); | 
 | 	xfree(blkmap); | 
 | } | 
 |  | 
 | static xfs_fsblock_t | 
 | blkmap_get( | 
 | 	blkmap_t	*blkmap, | 
 | 	xfs_fileoff_t	o) | 
 | { | 
 | 	blkent_t	*ent; | 
 | 	blkent_t	**entp; | 
 | 	int		i; | 
 |  | 
 | 	for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) { | 
 | 		ent = *entp; | 
 | 		if (o >= ent->startoff && o < ent->startoff + ent->nblks) | 
 | 			return ent->blks[o - ent->startoff]; | 
 | 	} | 
 | 	return NULLFSBLOCK; | 
 | } | 
 |  | 
 | static int | 
 | blkmap_getn( | 
 | 	blkmap_t	*blkmap, | 
 | 	xfs_fileoff_t	o, | 
 | 	int		nb, | 
 | 	bmap_ext_t	**bmpp) | 
 | { | 
 | 	bmap_ext_t	*bmp; | 
 | 	blkent_t	*ent; | 
 | 	xfs_fileoff_t	ento; | 
 | 	blkent_t	**entp; | 
 | 	int		i; | 
 | 	int		nex; | 
 |  | 
 | 	for (i = nex = 0, bmp = NULL, entp = blkmap->ents; | 
 | 	     i < blkmap->nents; | 
 | 	     i++, entp++) { | 
 | 		ent = *entp; | 
 | 		if (ent->startoff >= o + nb) | 
 | 			break; | 
 | 		if (ent->startoff + ent->nblks <= o) | 
 | 			continue; | 
 | 		for (ento = ent->startoff; | 
 | 		     ento < ent->startoff + ent->nblks && ento < o + nb; | 
 | 		     ento++) { | 
 | 			if (ento < o) | 
 | 				continue; | 
 | 			if (bmp && | 
 | 			    bmp[nex - 1].startoff + bmp[nex - 1].blockcount == | 
 | 				    ento && | 
 | 			    bmp[nex - 1].startblock + bmp[nex - 1].blockcount == | 
 | 				    ent->blks[ento - ent->startoff]) | 
 | 				bmp[nex - 1].blockcount++; | 
 | 			else { | 
 | 				bmp = realloc(bmp, ++nex * sizeof(*bmp)); | 
 | 				bmp[nex - 1].startoff = ento; | 
 | 				bmp[nex - 1].startblock = | 
 | 					ent->blks[ento - ent->startoff]; | 
 | 				bmp[nex - 1].blockcount = 1; | 
 | 				bmp[nex - 1].flag = 0; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	*bmpp = bmp; | 
 | 	return nex; | 
 | } | 
 |  | 
 | static void | 
 | blkmap_grow( | 
 | 	blkmap_t	**blkmapp, | 
 | 	blkent_t	**entp, | 
 | 	blkent_t	*newent) | 
 | { | 
 | 	blkmap_t	*blkmap; | 
 | 	int		i; | 
 | 	int		idx; | 
 |  | 
 | 	blkmap = *blkmapp; | 
 | 	idx = (int)(entp - blkmap->ents); | 
 | 	if (blkmap->naents == blkmap->nents) { | 
 | 		blkmap = xrealloc(blkmap, BLKMAP_SIZE(blkmap->nents + 1)); | 
 | 		*blkmapp = blkmap; | 
 | 		blkmap->naents++; | 
 | 	} | 
 | 	for (i = blkmap->nents; i > idx; i--) | 
 | 		blkmap->ents[i] = blkmap->ents[i - 1]; | 
 | 	blkmap->ents[idx] = newent; | 
 | 	blkmap->nents++; | 
 | } | 
 |  | 
 | static xfs_fileoff_t | 
 | blkmap_last_off( | 
 | 	blkmap_t	*blkmap) | 
 | { | 
 | 	blkent_t	*ent; | 
 |  | 
 | 	if (!blkmap->nents) | 
 | 		return NULLFILEOFF; | 
 | 	ent = blkmap->ents[blkmap->nents - 1]; | 
 | 	return ent->startoff + ent->nblks; | 
 | } | 
 |  | 
 | static xfs_fileoff_t | 
 | blkmap_next_off( | 
 | 	blkmap_t	*blkmap, | 
 | 	xfs_fileoff_t	o, | 
 | 	int		*t) | 
 | { | 
 | 	blkent_t	*ent; | 
 | 	blkent_t	**entp; | 
 |  | 
 | 	if (!blkmap->nents) | 
 | 		return NULLFILEOFF; | 
 | 	if (o == NULLFILEOFF) { | 
 | 		*t = 0; | 
 | 		ent = blkmap->ents[0]; | 
 | 		return ent->startoff; | 
 | 	} | 
 | 	entp = &blkmap->ents[*t]; | 
 | 	ent = *entp; | 
 | 	if (o < ent->startoff + ent->nblks - 1) | 
 | 		return o + 1; | 
 | 	entp++; | 
 | 	if (entp >= &blkmap->ents[blkmap->nents]) | 
 | 		return NULLFILEOFF; | 
 | 	(*t)++; | 
 | 	ent = *entp; | 
 | 	return ent->startoff; | 
 | } | 
 |  | 
 | static void | 
 | blkmap_set_blk( | 
 | 	blkmap_t	**blkmapp, | 
 | 	xfs_fileoff_t	o, | 
 | 	xfs_fsblock_t	b) | 
 | { | 
 | 	blkmap_t	*blkmap; | 
 | 	blkent_t	*ent; | 
 | 	blkent_t	**entp; | 
 | 	blkent_t	*nextent; | 
 |  | 
 | 	blkmap = *blkmapp; | 
 | 	for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) { | 
 | 		ent = *entp; | 
 | 		if (o < ent->startoff - 1) { | 
 | 			ent = blkent_new(o, b, 1); | 
 | 			blkmap_grow(blkmapp, entp, ent); | 
 | 			return; | 
 | 		} | 
 | 		if (o == ent->startoff - 1) { | 
 | 			blkent_prepend(entp, b, 1); | 
 | 			return; | 
 | 		} | 
 | 		if (o >= ent->startoff && o < ent->startoff + ent->nblks) { | 
 | 			ent->blks[o - ent->startoff] = b; | 
 | 			return; | 
 | 		} | 
 | 		if (o > ent->startoff + ent->nblks) | 
 | 			continue; | 
 | 		blkent_append(entp, b, 1); | 
 | 		if (entp == &blkmap->ents[blkmap->nents - 1]) | 
 | 			return; | 
 | 		ent = *entp; | 
 | 		nextent = entp[1]; | 
 | 		if (ent->startoff + ent->nblks < nextent->startoff) | 
 | 			return; | 
 | 		blkent_append(entp, nextent->blks[0], nextent->nblks); | 
 | 		blkmap_shrink(blkmap, &entp[1]); | 
 | 		return; | 
 | 	} | 
 | 	ent = blkent_new(o, b, 1); | 
 | 	blkmap_grow(blkmapp, entp, ent); | 
 | } | 
 |  | 
 | static void | 
 | blkmap_set_ext( | 
 | 	blkmap_t	**blkmapp, | 
 | 	xfs_fileoff_t	o, | 
 | 	xfs_fsblock_t	b, | 
 | 	xfs_extlen_t	c) | 
 | { | 
 | 	blkmap_t	*blkmap; | 
 | 	blkent_t	*ent; | 
 | 	blkent_t	**entp; | 
 | 	xfs_extnum_t	i; | 
 |  | 
 | 	blkmap = *blkmapp; | 
 | 	if (!blkmap->nents) { | 
 | 		blkmap->ents[0] = blkent_new(o, b, c); | 
 | 		blkmap->nents = 1; | 
 | 		return; | 
 | 	} | 
 | 	entp = &blkmap->ents[blkmap->nents - 1]; | 
 | 	ent = *entp; | 
 | 	if (ent->startoff + ent->nblks == o) { | 
 | 		blkent_append(entp, b, c); | 
 | 		return; | 
 | 	} | 
 | 	if (ent->startoff + ent->nblks < o) { | 
 | 		ent = blkent_new(o, b, c); | 
 | 		blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent); | 
 | 		return; | 
 | 	} | 
 | 	for (i = 0; i < c; i++) | 
 | 		blkmap_set_blk(blkmapp, o + i, b + i); | 
 | } | 
 |  | 
 | static void | 
 | blkmap_shrink( | 
 | 	blkmap_t	*blkmap, | 
 | 	blkent_t	**entp) | 
 | { | 
 | 	int		i; | 
 | 	int		idx; | 
 |  | 
 | 	xfree(*entp); | 
 | 	idx = (int)(entp - blkmap->ents); | 
 | 	for (i = idx + 1; i < blkmap->nents; i++) | 
 | 		blkmap->ents[i] = blkmap->ents[i - 1]; | 
 | 	blkmap->nents--; | 
 | } | 
 |  | 
 | /* ARGSUSED */ | 
 | static int | 
 | blockfree_f( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_agnumber_t	c; | 
 | 	int		rt; | 
 |  | 
 | 	if (!dbmap) { | 
 | 		dbprintf(_("block usage information not allocated\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	rt = mp->m_sb.sb_rextents != 0; | 
 | 	for (c = 0; c < mp->m_sb.sb_agcount; c++) { | 
 | 		xfree(dbmap[c]); | 
 | 		xfree(inomap[c]); | 
 | 		free_inodata(c); | 
 | 	} | 
 | 	if (rt) { | 
 | 		xfree(dbmap[c]); | 
 | 		xfree(inomap[c]); | 
 | 		xfree(sumcompute); | 
 | 		xfree(sumfile); | 
 | 		sumcompute = sumfile = NULL; | 
 | 	} | 
 | 	xfree(dbmap); | 
 | 	xfree(inomap); | 
 | 	xfree(inodata); | 
 | 	dbmap = NULL; | 
 | 	inomap = NULL; | 
 | 	inodata = NULL; | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * Check consistency of xfs filesystem contents. | 
 |  */ | 
 | static int | 
 | blockget_f( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_agnumber_t	agno; | 
 | 	int		oldprefix; | 
 | 	int		sbyell; | 
 |  | 
 | 	if (dbmap) { | 
 | 		dbprintf(_("already have block usage information\n")); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	if (!init(argc, argv)) { | 
 | 		if (serious_error) | 
 | 			exitcode = 3; | 
 | 		else | 
 | 			exitcode = 1; | 
 | 		return 0; | 
 | 	} | 
 | 	oldprefix = dbprefix; | 
 | 	dbprefix |= pflag; | 
 | 	for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) { | 
 | 		scan_ag(agno); | 
 | 		if (sbver_err > 4 && !sbyell && sbver_err >= agno) { | 
 | 			sbyell = 1; | 
 | 			dbprintf(_("WARNING: this may be a newer XFS " | 
 | 				 "filesystem.\n")); | 
 | 		} | 
 | 	} | 
 | 	if (blist_size) { | 
 | 		xfree(blist); | 
 | 		blist = NULL; | 
 | 		blist_size = 0; | 
 | 	} | 
 | 	if (serious_error) { | 
 | 		exitcode = 2; | 
 | 		dbprefix = oldprefix; | 
 | 		return 0; | 
 | 	} | 
 | 	check_rootdir(); | 
 | 	/* | 
 | 	 * Check that there are no blocks either | 
 | 	 * a) unaccounted for or | 
 | 	 * b) bno-free but not cnt-free | 
 | 	 */ | 
 | 	if (!tflag) {	/* are we in test mode, faking out freespace? */ | 
 | 		for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) | 
 | 			checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks, | 
 | 				(1 << DBM_UNKNOWN) | (1 << DBM_FREE1)); | 
 | 	} | 
 | 	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) | 
 | 		check_linkcounts(agno); | 
 | 	if (mp->m_sb.sb_rblocks) { | 
 | 		checknot_rdbmap(0, | 
 | 			(xfs_extlen_t)(mp->m_sb.sb_rextents * | 
 | 				       mp->m_sb.sb_rextsize), | 
 | 			1 << DBM_UNKNOWN); | 
 | 		check_summary(); | 
 | 	} | 
 | 	if (mp->m_sb.sb_icount != icount) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_icount %lld, counted %lld\n"), | 
 | 				mp->m_sb.sb_icount, icount); | 
 | 		error++; | 
 | 	} | 
 | 	if (mp->m_sb.sb_ifree != ifree) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_ifree %lld, counted %lld\n"), | 
 | 				mp->m_sb.sb_ifree, ifree); | 
 | 		error++; | 
 | 	} | 
 | 	if (mp->m_sb.sb_fdblocks != fdblocks) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_fdblocks %lld, counted %lld\n"), | 
 | 				mp->m_sb.sb_fdblocks, fdblocks); | 
 | 		error++; | 
 | 	} | 
 | 	if (lazycount && mp->m_sb.sb_fdblocks != agf_aggr_freeblks) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_fdblocks %lld, aggregate AGF count %lld\n"), | 
 | 				mp->m_sb.sb_fdblocks, agf_aggr_freeblks); | 
 | 		error++; | 
 | 	} | 
 | 	if (mp->m_sb.sb_frextents != frextents) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_frextents %lld, counted %lld\n"), | 
 | 				mp->m_sb.sb_frextents, frextents); | 
 | 		error++; | 
 | 	} | 
 | 	if (mp->m_sb.sb_bad_features2 != 0 && | 
 | 			mp->m_sb.sb_bad_features2 != mp->m_sb.sb_features2) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb_features2 (0x%x) not same as " | 
 | 				"sb_bad_features2 (0x%x)\n"), | 
 | 				mp->m_sb.sb_features2, | 
 | 				mp->m_sb.sb_bad_features2); | 
 | 		error++; | 
 | 	} | 
 | 	if ((sbversion & XFS_SB_VERSION_ATTRBIT) && | 
 | 					!xfs_has_attr(mp)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb versionnum missing attr bit %x\n"), | 
 | 				XFS_SB_VERSION_ATTRBIT); | 
 | 		error++; | 
 | 	} | 
 | 	if ((sbversion & XFS_SB_VERSION_QUOTABIT) && | 
 | 					!xfs_has_quota(mp)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb versionnum missing quota bit %x\n"), | 
 | 				XFS_SB_VERSION_QUOTABIT); | 
 | 		error++; | 
 | 	} | 
 | 	if (!(sbversion & XFS_SB_VERSION_ALIGNBIT) && | 
 | 					xfs_has_align(mp)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("sb versionnum extra align bit %x\n"), | 
 | 				XFS_SB_VERSION_ALIGNBIT); | 
 | 		error++; | 
 | 	} | 
 | 	if (qudo) | 
 | 		quota_check("user", qudata); | 
 | 	if (qpdo) | 
 | 		quota_check("project", qpdata); | 
 | 	if (qgdo) | 
 | 		quota_check("group", qgdata); | 
 | 	if (sbver_err > mp->m_sb.sb_agcount / 2) | 
 | 		dbprintf(_("WARNING: this may be a newer XFS filesystem.\n")); | 
 | 	if (error) | 
 | 		exitcode = 3; | 
 | 	dbprefix = oldprefix; | 
 | 	return 0; | 
 | } | 
 |  | 
 | typedef struct ltab { | 
 | 	int	min; | 
 | 	int	max; | 
 | } ltab_t; | 
 |  | 
 | static void | 
 | blocktrash_b( | 
 | 	int		bit_offset, | 
 | 	dbm_t		type, | 
 | 	ltab_t		*ltabp, | 
 | 	int		mode) | 
 | { | 
 | 	int		bit; | 
 | 	int		bitno; | 
 | 	char		*buf; | 
 | 	int		byte; | 
 | 	int		len; | 
 | 	int		mask; | 
 | 	int		newbit; | 
 | 	const struct xfs_buf_ops *stashed_ops; | 
 | 	static char	*modestr[] = { | 
 | 		N_("zeroed"), N_("set"), N_("flipped"), N_("randomized") | 
 | 	}; | 
 | 	xfs_agnumber_t	agno; | 
 | 	xfs_agblock_t	agbno; | 
 |  | 
 | 	agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); | 
 | 	agbno = XFS_FSB_TO_AGBNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb)); | 
 | 	if (iocur_top->len == 0) { | 
 | 		dbprintf(_("zero-length block %u/%u buffer to trash??\n"), | 
 | 				agno, agbno); | 
 | 		return; | 
 | 	} | 
 | 	len = (int)((random() % (ltabp->max - ltabp->min + 1)) + ltabp->min); | 
 | 	/* | 
 | 	 * bit_offset >= 0: start fuzzing at this exact bit_offset. | 
 | 	 * bit_offset < 0: pick an offset at least as high at -(bit_offset + 1). | 
 | 	 */ | 
 | 	if (bit_offset < 0) { | 
 | 		bit_offset = -(bit_offset + 1); | 
 | 		bit_offset += (int)(random() % (int)((iocur_top->len - bit_offset) * NBBY)); | 
 | 	} | 
 | 	if (bit_offset + len >= iocur_top->len * NBBY) | 
 | 		len = (iocur_top->len * NBBY) - bit_offset; | 
 | 	newbit = 0; | 
 | 	stashed_ops = iocur_top->bp->b_ops; | 
 | 	iocur_top->bp->b_ops = NULL; | 
 | 	if ((buf = iocur_top->data) == NULL) { | 
 | 		dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno); | 
 | 		return; | 
 | 	} | 
 | 	for (bitno = 0; bitno < len; bitno++) { | 
 | 		bit = (bit_offset + bitno) % (mp->m_sb.sb_blocksize * NBBY); | 
 | 		byte = bit / NBBY; | 
 | 		bit %= NBBY; | 
 | 		mask = 1 << bit; | 
 | 		switch (mode) { | 
 | 		case 0: | 
 | 			newbit = 0; | 
 | 			break; | 
 | 		case 1: | 
 | 			newbit = 1; | 
 | 			break; | 
 | 		case 2: | 
 | 			newbit = (buf[byte] & mask) == 0; | 
 | 			break; | 
 | 		case 3: | 
 | 			newbit = (int)random() & 1; | 
 | 			break; | 
 | 		} | 
 | 		if (newbit) | 
 | 			buf[byte] |= mask; | 
 | 		else | 
 | 			buf[byte] &= ~mask; | 
 | 	} | 
 | 	write_cur(); | 
 | 	iocur_top->bp->b_ops = stashed_ops; | 
 | 	printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"), | 
 | 		agno, agbno, typename[type], len, len == 1 ? "" : "s", | 
 | 		bit_offset / NBBY, bit_offset % NBBY, modestr[mode]); | 
 | } | 
 |  | 
 | static int | 
 | blocktrash_f( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_agblock_t	agbno; | 
 | 	xfs_agnumber_t	agno; | 
 | 	xfs_rfsblock_t	bi; | 
 | 	xfs_rfsblock_t	blocks; | 
 | 	int		c; | 
 | 	int		count; | 
 | 	int		done; | 
 | 	int		goodmask; | 
 | 	int		i; | 
 | 	ltab_t		*lentab; | 
 | 	int		lentablen; | 
 | 	int		max; | 
 | 	int		min; | 
 | 	int		mode; | 
 | 	struct timeval	now; | 
 | 	char		*p; | 
 | 	xfs_rfsblock_t	randb; | 
 | 	uint		seed; | 
 | 	int		sopt; | 
 | 	int		tmask; | 
 | 	bool		this_block = false; | 
 | 	int		bit_offset = -1; | 
 |  | 
 | 	optind = 0; | 
 | 	count = 1; | 
 | 	min = 1; | 
 | 	max = 128 * NBBY; | 
 | 	mode = 2; | 
 | 	gettimeofday(&now, NULL); | 
 | 	seed = (unsigned int)(now.tv_sec ^ now.tv_usec); | 
 | 	sopt = 0; | 
 | 	tmask = 0; | 
 | 	goodmask = (1 << DBM_AGF) | | 
 | 		   (1 << DBM_AGFL) | | 
 | 		   (1 << DBM_AGI) | | 
 | 		   (1 << DBM_ATTR) | | 
 | 		   (1 << DBM_BTBMAPA) | | 
 | 		   (1 << DBM_BTBMAPD) | | 
 | 		   (1 << DBM_BTBNO) | | 
 | 		   (1 << DBM_BTCNT) | | 
 | 		   (1 << DBM_BTINO) | | 
 | 		   (1 << DBM_DIR) | | 
 | 		   (1 << DBM_INODE) | | 
 | 		   (1 << DBM_LOG) | | 
 | 		   (1 << DBM_QUOTA) | | 
 | 		   (1 << DBM_RTBITMAP) | | 
 | 		   (1 << DBM_RTSUM) | | 
 | 		   (1 << DBM_SYMLINK) | | 
 | 		   (1 << DBM_BTFINO) | | 
 | 		   (1 << DBM_BTRMAP) | | 
 | 		   (1 << DBM_BTREFC) | | 
 | 		   (1 << DBM_SB); | 
 | 	while ((c = getopt(argc, argv, "0123n:o:s:t:x:y:z")) != EOF) { | 
 | 		switch (c) { | 
 | 		case '0': | 
 | 			mode = 0; | 
 | 			break; | 
 | 		case '1': | 
 | 			mode = 1; | 
 | 			break; | 
 | 		case '2': | 
 | 			mode = 2; | 
 | 			break; | 
 | 		case '3': | 
 | 			mode = 3; | 
 | 			break; | 
 | 		case 'n': | 
 | 			count = (int)strtol(optarg, &p, 0); | 
 | 			if (*p != '\0' || count <= 0) { | 
 | 				dbprintf(_("bad blocktrash count %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			break; | 
 | 		case 'o': { | 
 | 			int relative = 0; | 
 | 			if (optarg[0] == '+') { | 
 | 				optarg++; | 
 | 				relative = 1; | 
 | 			} | 
 | 			bit_offset = (int)strtol(optarg, &p, 0); | 
 | 			if (*p != '\0' || bit_offset < 0) { | 
 | 				dbprintf(_("bad blocktrash offset %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			if (relative) | 
 | 				bit_offset = -bit_offset - 1; | 
 | 			break; | 
 | 		} | 
 | 		case 's': | 
 | 			seed = (uint)strtoul(optarg, &p, 0); | 
 | 			sopt = 1; | 
 | 			break; | 
 | 		case 't': | 
 | 			for (i = 0; typename[i]; i++) { | 
 | 				if (strcmp(typename[i], optarg) == 0) | 
 | 					break; | 
 | 			} | 
 | 			if (!typename[i] || (((1 << i) & goodmask) == 0)) { | 
 | 				dbprintf(_("bad blocktrash type %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			tmask |= 1 << i; | 
 | 			break; | 
 | 		case 'x': | 
 | 			min = (int)strtol(optarg, &p, 0); | 
 | 			if (*p != '\0' || min <= 0 || | 
 | 			    min > mp->m_sb.sb_blocksize * NBBY) { | 
 | 				dbprintf(_("bad blocktrash min %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			break; | 
 | 		case 'y': | 
 | 			max = (int)strtol(optarg, &p, 0); | 
 | 			if (*p != '\0' || max <= 0 || | 
 | 			    max > mp->m_sb.sb_blocksize * NBBY) { | 
 | 				dbprintf(_("bad blocktrash max %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			break; | 
 | 		case 'z': | 
 | 			this_block = true; | 
 | 			break; | 
 | 		default: | 
 | 			dbprintf(_("bad option for blocktrash command\n")); | 
 | 			return 0; | 
 | 		} | 
 | 	} | 
 | 	if (!this_block && !dbmap) { | 
 | 		dbprintf(_("must run blockget first\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	if (this_block && iocur_sp == 0) { | 
 | 		dbprintf(_("nothing on stack\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	if (min > max) { | 
 | 		dbprintf(_("bad min/max for blocktrash command\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	if (tmask == 0) | 
 | 		tmask = goodmask & ~((1 << DBM_LOG) | (1 << DBM_SB)); | 
 | 	lentab = xmalloc(sizeof(ltab_t)); | 
 | 	lentab->min = lentab->max = min; | 
 | 	lentablen = 1; | 
 | 	for (i = min + 1; i <= max; i++) { | 
 | 		if ((i & (i - 1)) == 0) { | 
 | 			lentab = xrealloc(lentab, | 
 | 				sizeof(ltab_t) * (lentablen + 1)); | 
 | 			lentab[lentablen].min = lentab[lentablen].max = i; | 
 | 			lentablen++; | 
 | 		} else | 
 | 			lentab[lentablen - 1].max = i; | 
 | 	} | 
 | 	if (!sopt) | 
 | 		dbprintf(_("blocktrash: seed %u\n"), seed); | 
 | 	srandom(seed); | 
 | 	if (this_block) { | 
 | 		blocktrash_b(bit_offset, DBM_UNKNOWN, | 
 | 				&lentab[random() % lentablen], mode); | 
 | 		goto out; | 
 | 	} | 
 | 	for (blocks = 0, agno = 0; agno < mp->m_sb.sb_agcount; agno++) { | 
 | 		for (agbno = 0, p = dbmap[agno]; | 
 | 		     agbno < mp->m_sb.sb_agblocks; | 
 | 		     agbno++, p++) { | 
 | 			if ((1 << *p) & tmask) | 
 | 				blocks++; | 
 | 		} | 
 | 	} | 
 | 	if (blocks == 0) { | 
 | 		dbprintf(_("blocktrash: no matching blocks\n")); | 
 | 		goto out; | 
 | 	} | 
 | 	for (i = 0; i < count; i++) { | 
 | 		randb = (xfs_rfsblock_t)((((int64_t)random() << 32) | | 
 | 					 random()) % blocks); | 
 | 		for (bi = 0, agno = 0, done = 0; | 
 | 		     !done && agno < mp->m_sb.sb_agcount; | 
 | 		     agno++) { | 
 | 			for (agbno = 0, p = dbmap[agno]; | 
 | 			     agbno < mp->m_sb.sb_agblocks; | 
 | 			     agbno++, p++) { | 
 | 				if (!((1 << *p) & tmask)) | 
 | 					continue; | 
 | 				if (bi++ < randb) | 
 | 					continue; | 
 | 				push_cur(); | 
 | 				set_cur(NULL, | 
 | 					XFS_AGB_TO_DADDR(mp, agno, agbno), | 
 | 					blkbb, DB_RING_IGN, NULL); | 
 | 				blocktrash_b(bit_offset, (dbm_t)*p, | 
 | 					&lentab[random() % lentablen], mode); | 
 | 				pop_cur(); | 
 | 				done = 1; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | out: | 
 | 	xfree(lentab); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int | 
 | blockuse_f( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_agblock_t	agbno; | 
 | 	xfs_agnumber_t	agno; | 
 | 	int		c; | 
 | 	int		count; | 
 | 	xfs_agblock_t	end; | 
 | 	xfs_fsblock_t	fsb; | 
 | 	inodata_t	*i; | 
 | 	char		*p; | 
 | 	int		shownames; | 
 |  | 
 | 	if (!dbmap) { | 
 | 		dbprintf(_("must run blockget first\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	optind = 0; | 
 | 	shownames = 0; | 
 | 	fsb = XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT); | 
 | 	agno = XFS_FSB_TO_AGNO(mp, fsb); | 
 | 	end = agbno = XFS_FSB_TO_AGBNO(mp, fsb); | 
 | 	while ((c = getopt(argc, argv, "c:n")) != EOF) { | 
 | 		switch (c) { | 
 | 		case 'c': | 
 | 			count = (int)strtol(optarg, &p, 0); | 
 | 			end = agbno + count - 1; | 
 | 			if (*p != '\0' || count <= 0 || | 
 | 			    end >= mp->m_sb.sb_agblocks) { | 
 | 				dbprintf(_("bad blockuse count %s\n"), optarg); | 
 | 				return 0; | 
 | 			} | 
 | 			break; | 
 | 		case 'n': | 
 | 			if (!nflag) { | 
 | 				dbprintf(_("must run blockget -n first\n")); | 
 | 				return 0; | 
 | 			} | 
 | 			shownames = 1; | 
 | 			break; | 
 | 		default: | 
 | 			dbprintf(_("bad option for blockuse command\n")); | 
 | 			return 0; | 
 | 		} | 
 | 	} | 
 | 	while (agbno <= end) { | 
 | 		p = &dbmap[agno][agbno]; | 
 | 		i = inomap[agno][agbno]; | 
 | 		dbprintf(_("block %llu (%u/%u) type %s"), | 
 | 			(xfs_fsblock_t)XFS_AGB_TO_FSB(mp, agno, agbno), | 
 | 			agno, agbno, typename[(dbm_t)*p]); | 
 | 		if (i) { | 
 | 			dbprintf(_(" inode %lld"), i->ino); | 
 | 			if (shownames && (p = inode_name(i->ino, NULL))) { | 
 | 				dbprintf(" %s", p); | 
 | 				xfree(p); | 
 | 			} | 
 | 		} | 
 | 		dbprintf("\n"); | 
 | 		agbno++; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int | 
 | check_blist( | 
 | 	xfs_fsblock_t	bno) | 
 | { | 
 | 	int		i; | 
 |  | 
 | 	for (i = 0; i < blist_size; i++) { | 
 | 		if (blist[i] == bno) | 
 | 			return 1; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | static inline bool | 
 | dbmap_boundscheck( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno) | 
 | { | 
 | 	if (agno >= mp->m_sb.sb_agcount) | 
 | 		return false; | 
 | 	if (agbno >= mp->m_sb.sb_agblocks) | 
 | 		return false; | 
 | 	return true; | 
 | } | 
 |  | 
 | static void | 
 | check_dbmap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type, | 
 | 	int		ignore_reflink) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	char		*p; | 
 | 	dbm_t		d; | 
 |  | 
 | 	for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { | 
 | 		if (!dbmap_boundscheck(agno, agbno + i)) { | 
 | 			dbprintf(_("block %u/%u beyond end of expected area\n"), | 
 | 				agno, agbno + i); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		d = (dbm_t)*p; | 
 | 		if (ignore_reflink && (d == DBM_UNKNOWN || d == DBM_DATA || | 
 | 				       d == DBM_RLDATA)) | 
 | 			continue; | 
 | 		if ((dbm_t)*p != type) { | 
 | 			if (!sflag || CHECK_BLISTA(agno, agbno + i)) { | 
 | 				dbprintf(_("block %u/%u expected type %s got " | 
 | 					 "%s\n"), | 
 | 					agno, agbno + i, typename[type], | 
 | 					typename[(dbm_t)*p]); | 
 | 			} | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | void | 
 | check_init(void) | 
 | { | 
 | 	add_command(&blockfree_cmd); | 
 | 	add_command(&blockget_cmd); | 
 | 	if (expert_mode) | 
 | 		add_command(&blocktrash_cmd); | 
 | 	add_command(&blockuse_cmd); | 
 | 	add_command(&ncheck_cmd); | 
 | } | 
 |  | 
 | static int | 
 | check_inomap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	xfs_ino_t	c_ino) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	inodata_t	**idp; | 
 | 	int		rval; | 
 |  | 
 | 	if (!check_range(agno, agbno, len))  { | 
 | 		dbprintf(_("blocks %u/%u..%u claimed by inode %lld\n"), | 
 | 			agno, agbno, agbno + len - 1, c_ino); | 
 | 		return 0; | 
 | 	} | 
 | 	for (i = 0, rval = 1, idp = &inomap[agno][agbno]; i < len; i++, idp++) { | 
 | 		if (*idp && !(*idp)->isreflink) { | 
 | 			if (!sflag || (*idp)->ilist || | 
 | 			    CHECK_BLISTA(agno, agbno + i)) | 
 | 				dbprintf(_("block %u/%u claimed by inode %lld, " | 
 | 					 "previous inum %lld\n"), | 
 | 					agno, agbno + i, c_ino, (*idp)->ino); | 
 | 			error++; | 
 | 			rval = 0; | 
 | 		} | 
 | 	} | 
 | 	return rval; | 
 | } | 
 |  | 
 | static void | 
 | check_linkcounts( | 
 | 	xfs_agnumber_t	agno) | 
 | { | 
 | 	inodata_t	*ep; | 
 | 	inodata_t	**ht; | 
 | 	int		idx; | 
 | 	char		*path; | 
 |  | 
 | 	ht = inodata[agno]; | 
 | 	for (idx = 0; idx < inodata_hash_size; ht++, idx++) { | 
 | 		ep = *ht; | 
 | 		while (ep) { | 
 | 			if (ep->link_set != ep->link_add || ep->link_set == 0) { | 
 | 				path = inode_name(ep->ino, NULL); | 
 | 				if (!path && ep->link_add) | 
 | 					path = xstrdup("?"); | 
 | 				if (!sflag || ep->ilist) { | 
 | 					if (ep->link_add) | 
 | 						dbprintf(_("link count mismatch " | 
 | 							 "for inode %lld (name " | 
 | 							 "%s), nlink %d, " | 
 | 							 "counted %d\n"), | 
 | 							ep->ino, path, | 
 | 							ep->link_set, | 
 | 							ep->link_add); | 
 | 					else if (ep->link_set) | 
 | 						dbprintf(_("disconnected inode " | 
 | 							 "%lld, nlink %d\n"), | 
 | 							ep->ino, ep->link_set); | 
 | 					else | 
 | 						dbprintf(_("allocated inode %lld " | 
 | 							 "has 0 link count\n"), | 
 | 							ep->ino); | 
 | 				} | 
 | 				if (path) | 
 | 					xfree(path); | 
 | 				error++; | 
 | 			} else if (verbose || ep->ilist) { | 
 | 				path = inode_name(ep->ino, NULL); | 
 | 				if (path) { | 
 | 					dbprintf(_("inode %lld name %s\n"), | 
 | 						ep->ino, path); | 
 | 					xfree(path); | 
 | 				} | 
 | 			} | 
 | 			ep = ep->next; | 
 | 		} | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | static int | 
 | check_range( | 
 | 	xfs_agnumber_t  agno, | 
 | 	xfs_agblock_t   agbno, | 
 | 	xfs_extlen_t    len) | 
 | { | 
 | 	xfs_extlen_t    i; | 
 | 	xfs_agblock_t   low = 0; | 
 | 	xfs_agblock_t   high = 0; | 
 | 	int             valid_range = 0; | 
 | 	int             cur, prev = 0; | 
 |  | 
 | 	if (agno >= mp->m_sb.sb_agcount || | 
 | 	    agbno + len - 1 >= mp->m_sb.sb_agblocks) { | 
 | 		for (i = 0; i < len; i++) { | 
 | 			cur = !sflag || CHECK_BLISTA(agno, agbno + i) ? 1 : 0; | 
 | 			if (cur == 1 && prev == 0) { | 
 | 				low = high = agbno + i; | 
 | 				valid_range = 1; | 
 | 			} else if (cur == 0 && prev == 0) { | 
 | 				/* Do nothing */ | 
 | 			} else if (cur == 0 && prev == 1) { | 
 | 				if (low == high) { | 
 | 					dbprintf(_("block %u/%u out of range\n"), | 
 | 						agno, low); | 
 | 				} else { | 
 | 					dbprintf(_("blocks %u/%u..%u " | 
 | 						"out of range\n"), | 
 | 						agno, low, high); | 
 | 				} | 
 | 				valid_range = 0; | 
 | 			} else if (cur == 1 && prev == 1) { | 
 | 				high = agbno + i; | 
 | 			} | 
 | 			prev = cur; | 
 | 		} | 
 | 		if (valid_range) { | 
 |         		if (low == high) { | 
 |                			dbprintf(_("block %u/%u out of range\n"), | 
 |                        		agno, low); | 
 | 			} else { | 
 |                			dbprintf(_("blocks %u/%u..%u " | 
 |                				"out of range\n"), | 
 |                				agno, low, high); | 
 |       		 	} | 
 | 		} | 
 | 		error++; | 
 | 		return 0; | 
 | 	} | 
 | 	return 1; | 
 | } | 
 |  | 
 | static inline bool | 
 | rdbmap_boundscheck( | 
 | 	xfs_rfsblock_t	bno) | 
 | { | 
 | 	return bno < mp->m_sb.sb_rblocks; | 
 | } | 
 |  | 
 | static void | 
 | check_rdbmap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	char		*p; | 
 |  | 
 | 	for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { | 
 | 		if (!rdbmap_boundscheck(bno + i)) { | 
 | 			dbprintf(_("rtblock %llu beyond end of expected area\n"), | 
 | 				bno + i); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		if ((dbm_t)*p != type) { | 
 | 			if (!sflag || CHECK_BLIST(bno + i)) | 
 | 				dbprintf(_("rtblock %llu expected type %s got " | 
 | 					 "%s\n"), | 
 | 					bno + i, typename[type], | 
 | 					typename[(dbm_t)*p]); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static int | 
 | check_rinomap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	xfs_ino_t	c_ino) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	inodata_t	**idp; | 
 | 	int		rval; | 
 |  | 
 | 	if (!check_rrange(bno, len)) { | 
 | 		dbprintf(_("rtblocks %llu..%llu claimed by inode %lld\n"), | 
 | 			bno, bno + len - 1, c_ino); | 
 | 		return 0; | 
 | 	} | 
 | 	for (i = 0, rval = 1, idp = &inomap[mp->m_sb.sb_agcount][bno]; | 
 | 	     i < len; | 
 | 	     i++, idp++) { | 
 | 		if (*idp) { | 
 | 			if (!sflag || (*idp)->ilist || CHECK_BLIST(bno + i)) | 
 | 				dbprintf(_("rtblock %llu claimed by inode %lld, " | 
 | 					 "previous inum %lld\n"), | 
 | 					bno + i, c_ino, (*idp)->ino); | 
 | 			error++; | 
 | 			rval = 0; | 
 | 		} | 
 | 	} | 
 | 	return rval; | 
 | } | 
 |  | 
 | static void | 
 | check_rootdir(void) | 
 | { | 
 | 	inodata_t	*id; | 
 |  | 
 | 	id = find_inode(mp->m_sb.sb_rootino, 0); | 
 | 	if (id == NULL) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("root inode %lld is missing\n"), | 
 | 				mp->m_sb.sb_rootino); | 
 | 		error++; | 
 | 	} else if (!id->isdir) { | 
 | 		if (!sflag || id->ilist) | 
 | 			dbprintf(_("root inode %lld is not a directory\n"), | 
 | 				mp->m_sb.sb_rootino); | 
 | 		error++; | 
 | 	} | 
 | } | 
 |  | 
 | static inline void | 
 | report_rrange( | 
 | 	xfs_rfsblock_t	low, | 
 | 	xfs_rfsblock_t	high) | 
 | { | 
 | 	if (low == high) | 
 | 		dbprintf(_("rtblock %llu out of range\n"), low); | 
 | 	else | 
 | 		dbprintf(_("rtblocks %llu..%llu out of range\n"), low, high); | 
 | } | 
 |  | 
 | static int | 
 | check_rrange( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	xfs_rfsblock_t	low = 0; | 
 | 	xfs_rfsblock_t	high = 0; | 
 | 	bool		valid_range = false; | 
 | 	int		cur, prev = 0; | 
 |  | 
 | 	if (bno + len - 1 >= mp->m_sb.sb_rblocks) { | 
 | 		for (i = 0; i < len; i++) { | 
 | 			cur = !sflag || CHECK_BLIST(bno + i) ? 1 : 0; | 
 | 			if (cur == 1 && prev == 0) { | 
 | 				low = high = bno + i; | 
 | 				valid_range = true; | 
 | 			} else if (cur == 0 && prev == 0) { | 
 | 				/* Do nothing */ | 
 | 			} else if (cur == 0 && prev == 1) { | 
 | 				report_rrange(low, high); | 
 | 				valid_range = false; | 
 | 			} else if (cur == 1 && prev == 1) { | 
 | 				high = bno + i; | 
 | 			} | 
 | 			prev = cur; | 
 | 		} | 
 | 		if (valid_range) | 
 | 			report_rrange(low, high); | 
 | 		error++; | 
 | 		return 0; | 
 | 	} | 
 | 	return 1; | 
 | } | 
 |  | 
 | /* | 
 |  * We don't check the accuracy of reference counts -- all we do is ensure | 
 |  * that a data block never crosses with non-data blocks.  repair can check | 
 |  * those kinds of things. | 
 |  * | 
 |  * So with that in mind, if we're setting a block to be data or rldata, | 
 |  * don't complain so long as the block is currently unknown, data, or rldata. | 
 |  * Don't let blocks downgrade from rldata -> data. | 
 |  */ | 
 | static bool | 
 | is_reflink( | 
 | 	dbm_t		type2) | 
 | { | 
 | 	if (!xfs_has_reflink(mp)) | 
 | 		return false; | 
 | 	if (type2 == DBM_DATA || type2 == DBM_RLDATA) | 
 | 		return true; | 
 | 	return false; | 
 | } | 
 |  | 
 | static void | 
 | check_set_dbmap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type1, | 
 | 	dbm_t		type2, | 
 | 	xfs_agnumber_t	c_agno, | 
 | 	xfs_agblock_t	c_agbno) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	int		mayprint; | 
 | 	char		*p; | 
 |  | 
 | 	if (!check_range(agno, agbno, len))  { | 
 | 		dbprintf(_("blocks %u/%u..%u claimed by block %u/%u\n"), agno, | 
 | 			agbno, agbno + len - 1, c_agno, c_agbno); | 
 | 		return; | 
 | 	} | 
 | 	check_dbmap(agno, agbno, len, type1, is_reflink(type2)); | 
 | 	mayprint = verbose | blist_size; | 
 | 	for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { | 
 | 		if (!dbmap_boundscheck(agno, agbno + i)) { | 
 | 			dbprintf(_("block %u/%u beyond end of expected area\n"), | 
 | 				agno, agbno + i); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		if (*p == DBM_RLDATA && type2 == DBM_DATA) | 
 | 			;	/* do nothing */ | 
 | 		else if (*p == DBM_DATA && type2 == DBM_DATA) | 
 | 			*p = (char)DBM_RLDATA; | 
 | 		else | 
 | 			*p = (char)type2; | 
 | 		if (mayprint && (verbose || CHECK_BLISTA(agno, agbno + i))) | 
 | 			dbprintf(_("setting block %u/%u to %s\n"), agno, agbno + i, | 
 | 				typename[type2]); | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | check_set_rdbmap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type1, | 
 | 	dbm_t		type2) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	int		mayprint; | 
 | 	char		*p; | 
 |  | 
 | 	if (!check_rrange(bno, len)) | 
 | 		return; | 
 | 	check_rdbmap(bno, len, type1); | 
 | 	mayprint = verbose | blist_size; | 
 | 	for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { | 
 | 		if (!rdbmap_boundscheck(bno + i)) { | 
 | 			dbprintf(_("rtblock %llu beyond end of expected area\n"), | 
 | 				bno + i); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		*p = (char)type2; | 
 | 		if (mayprint && (verbose || CHECK_BLIST(bno + i))) | 
 | 			dbprintf(_("setting rtblock %llu to %s\n"), | 
 | 				bno + i, typename[type2]); | 
 | 	} | 
 | } | 
 |  | 
 | static inline xfs_suminfo_t | 
 | get_suminfo( | 
 | 	struct xfs_mount	*mp, | 
 | 	union xfs_suminfo_raw	*raw) | 
 | { | 
 | 	return raw->old; | 
 | } | 
 |  | 
 | static void | 
 | check_summary(void) | 
 | { | 
 | 	xfs_rfsblock_t	bno; | 
 | 	union xfs_suminfo_raw *csp; | 
 | 	union xfs_suminfo_raw *fsp; | 
 | 	int		log; | 
 |  | 
 | 	csp = sumcompute; | 
 | 	fsp = sumfile; | 
 | 	for (log = 0; log < mp->m_rsumlevels; log++) { | 
 | 		for (bno = 0; | 
 | 		     bno < mp->m_sb.sb_rbmblocks; | 
 | 		     bno++, csp++, fsp++) { | 
 | 			if (csp->old != fsp->old) { | 
 | 				if (!sflag) | 
 | 					dbprintf(_("rt summary mismatch, size %d " | 
 | 						 "block %llu, file: %d, " | 
 | 						 "computed: %d\n"), | 
 | 						log, bno, | 
 | 						get_suminfo(mp, fsp), | 
 | 						get_suminfo(mp, csp)); | 
 | 				error++; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | checknot_dbmap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	int		typemask) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	char		*p; | 
 |  | 
 | 	if (!check_range(agno, agbno, len)) | 
 | 		return; | 
 | 	for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { | 
 | 		if ((1 << *p) & typemask) { | 
 | 			if (!sflag || CHECK_BLISTA(agno, agbno + i)) | 
 | 				dbprintf(_("block %u/%u type %s not expected\n"), | 
 | 					agno, agbno + i, typename[(dbm_t)*p]); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | checknot_rdbmap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	int		typemask) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	char		*p; | 
 |  | 
 | 	if (!check_rrange(bno, len)) | 
 | 		return; | 
 | 	for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { | 
 | 		if ((1 << *p) & typemask) { | 
 | 			if (!sflag || CHECK_BLIST(bno + i)) | 
 | 				dbprintf(_("rtblock %llu type %s not expected\n"), | 
 | 					bno + i, typename[(dbm_t)*p]); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | dir_hash_add( | 
 | 	xfs_dahash_t		hash, | 
 | 	xfs_dir2_dataptr_t	addr) | 
 | { | 
 | 	int			i; | 
 | 	dirhash_t		*p; | 
 |  | 
 | 	i = DIR_HASH_FUNC(hash, addr); | 
 | 	p = malloc(sizeof(*p)); | 
 | 	p->next = dirhash[i]; | 
 | 	dirhash[i] = p; | 
 | 	p->hashval = hash; | 
 | 	p->address = addr; | 
 | 	p->seen = 0; | 
 | } | 
 |  | 
 | static void | 
 | dir_hash_check( | 
 | 	inodata_t	*id, | 
 | 	int		v) | 
 | { | 
 | 	int		i; | 
 | 	dirhash_t	*p; | 
 |  | 
 | 	for (i = 0; i < DIR_HASH_SIZE; i++) { | 
 | 		for (p = dirhash[i]; p; p = p->next) { | 
 | 			if (p->seen) | 
 | 				continue; | 
 | 			if (!sflag || id->ilist || v) | 
 | 				dbprintf(_("dir ino %lld missing leaf entry for " | 
 | 					 "%x/%x\n"), | 
 | 					id->ino, p->hashval, p->address); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | dir_hash_done(void) | 
 | { | 
 | 	int		i; | 
 | 	dirhash_t	*n; | 
 | 	dirhash_t	*p; | 
 |  | 
 | 	for (i = 0; i < DIR_HASH_SIZE; i++) { | 
 | 		for (p = dirhash[i]; p; p = n) { | 
 | 			n = p->next; | 
 | 			free(p); | 
 | 		} | 
 | 		dirhash[i] = NULL; | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | dir_hash_init(void) | 
 | { | 
 | 	if (!dirhash) | 
 | 		dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash)); | 
 | } | 
 |  | 
 | static int | 
 | dir_hash_see( | 
 | 	xfs_dahash_t		hash, | 
 | 	xfs_dir2_dataptr_t	addr) | 
 | { | 
 | 	int			i; | 
 | 	dirhash_t		*p; | 
 |  | 
 | 	i = DIR_HASH_FUNC(hash, addr); | 
 | 	for (p = dirhash[i]; p; p = p->next) { | 
 | 		if (p->hashval == hash && p->address == addr) { | 
 | 			if (p->seen) | 
 | 				return 1; | 
 | 			p->seen = 1; | 
 | 			return 0; | 
 | 		} | 
 | 	} | 
 | 	return -1; | 
 | } | 
 |  | 
 | static inodata_t * | 
 | find_inode( | 
 | 	xfs_ino_t	ino, | 
 | 	int		add) | 
 | { | 
 | 	xfs_agino_t	agino; | 
 | 	xfs_agnumber_t	agno; | 
 | 	inodata_t	*ent; | 
 | 	inodata_t	**htab; | 
 | 	xfs_agino_t	ih; | 
 |  | 
 | 	agno = XFS_INO_TO_AGNO(mp, ino); | 
 | 	agino = XFS_INO_TO_AGINO(mp, ino); | 
 | 	if (agno >= mp->m_sb.sb_agcount || | 
 | 	    XFS_AGINO_TO_INO(mp, agno, agino) != ino) | 
 | 		return NULL; | 
 | 	htab = inodata[agno]; | 
 | 	ih = agino % inodata_hash_size; | 
 | 	ent = htab[ih]; | 
 | 	while (ent) { | 
 | 		if (ent->ino == ino) | 
 | 			return ent; | 
 | 		ent = ent->next; | 
 | 	} | 
 | 	if (!add) | 
 | 		return NULL; | 
 | 	ent = xcalloc(1, sizeof(*ent)); | 
 | 	ent->ino = ino; | 
 | 	ent->next = htab[ih]; | 
 | 	htab[ih] = ent; | 
 | 	return ent; | 
 | } | 
 |  | 
 | static void | 
 | free_inodata( | 
 | 	xfs_agnumber_t	agno) | 
 | { | 
 | 	inodata_t	*hp; | 
 | 	inodata_t	**ht; | 
 | 	int		i; | 
 | 	inodata_t	*next; | 
 |  | 
 | 	ht = inodata[agno]; | 
 | 	for (i = 0; i < inodata_hash_size; i++) { | 
 | 		hp = ht[i]; | 
 | 		while (hp) { | 
 | 			next = hp->next; | 
 | 			if (hp->name) | 
 | 				xfree(hp->name); | 
 | 			xfree(hp); | 
 | 			hp = next; | 
 | 		} | 
 | 	} | 
 | 	xfree(ht); | 
 | } | 
 |  | 
 | static int | 
 | init( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_fsblock_t	bno; | 
 | 	int		c; | 
 | 	xfs_ino_t	ino; | 
 | 	int		rt; | 
 |  | 
 | 	serious_error = 0; | 
 | 	if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) { | 
 | 		dbprintf(_("bad superblock magic number %x, giving up\n"), | 
 | 			mp->m_sb.sb_magicnum); | 
 | 		serious_error = 1; | 
 | 		return 0; | 
 | 	} | 
 | 	if (!sb_logcheck()) | 
 | 		return 0; | 
 | 	rt = mp->m_sb.sb_rextents != 0; | 
 | 	dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap)); | 
 | 	inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap)); | 
 | 	inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata)); | 
 | 	inodata_hash_size = | 
 | 		(int)max(min(mp->m_sb.sb_icount / | 
 | 				(INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount), | 
 | 			     MAX_INODATA_HASH_SIZE), | 
 | 			 MIN_INODATA_HASH_SIZE); | 
 | 	for (c = 0; c < mp->m_sb.sb_agcount; c++) { | 
 | 		dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap)); | 
 | 		inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap)); | 
 | 		inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata)); | 
 | 	} | 
 | 	if (rt) { | 
 | 		unsigned long long	words; | 
 |  | 
 | 		dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap)); | 
 | 		inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap)); | 
 | 		words = XFS_FSB_TO_B(mp, mp->m_rsumblocks) >> XFS_WORDLOG; | 
 | 		sumfile = xcalloc(words, sizeof(union xfs_suminfo_raw)); | 
 | 		sumcompute = xcalloc(words, sizeof(union xfs_suminfo_raw)); | 
 | 	} | 
 | 	nflag = sflag = tflag = verbose = optind = 0; | 
 | 	while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) { | 
 | 		switch (c) { | 
 | 		case 'b': | 
 | 			bno = strtoll(optarg, NULL, 10); | 
 | 			add_blist(bno); | 
 | 			break; | 
 | 		case 'i': | 
 | 			ino = strtoll(optarg, NULL, 10); | 
 | 			add_ilist(ino); | 
 | 			break; | 
 | 		case 'n': | 
 | 			nflag = 1; | 
 | 			break; | 
 | 		case 'p': | 
 | 			pflag = 1; | 
 | 			break; | 
 | 		case 's': | 
 | 			sflag = 1; | 
 | 			break; | 
 | 		case 't': | 
 | 			tflag = 1; | 
 | 			break; | 
 | 		case 'v': | 
 | 			verbose = 1; | 
 | 			break; | 
 | 		default: | 
 | 			dbprintf(_("bad option for blockget command\n")); | 
 | 			return 0; | 
 | 		} | 
 | 	} | 
 | 	error = sbver_err = serious_error = 0; | 
 | 	fdblocks = frextents = icount = ifree = 0; | 
 | 	sbversion = XFS_SB_VERSION_4; | 
 | 	/* | 
 | 	 * Note that inoalignmt == 0 is valid when fsb size is large enough for | 
 | 	 * at least one full inode record per block. Check this case explicitly. | 
 | 	 */ | 
 | 	if (mp->m_sb.sb_inoalignmt || | 
 | 	    (xfs_has_align(mp) && | 
 | 	     mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK)) | 
 | 		sbversion |= XFS_SB_VERSION_ALIGNBIT; | 
 | 	if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) || | 
 | 	    (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) || | 
 | 	    (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO)) | 
 | 		sbversion |= XFS_SB_VERSION_QUOTABIT; | 
 | 	quota_init(); | 
 | 	return 1; | 
 | } | 
 |  | 
 | static char * | 
 | inode_name( | 
 | 	xfs_ino_t	ino, | 
 | 	inodata_t	**ipp) | 
 | { | 
 | 	inodata_t	*id; | 
 | 	char		*npath; | 
 | 	char		*path; | 
 |  | 
 | 	id = find_inode(ino, 0); | 
 | 	if (ipp) | 
 | 		*ipp = id; | 
 | 	if (id == NULL) | 
 | 		return NULL; | 
 | 	if (id->name == NULL) | 
 | 		return NULL; | 
 | 	path = xstrdup(id->name); | 
 | 	while (id->parent) { | 
 | 		id = id->parent; | 
 | 		if (id->name == NULL) | 
 | 			break; | 
 | 		npath = prepend_path(path, id->name); | 
 | 		xfree(path); | 
 | 		path = npath; | 
 | 	} | 
 | 	return path; | 
 | } | 
 |  | 
 | static int | 
 | ncheck_f( | 
 | 	int		argc, | 
 | 	char		**argv) | 
 | { | 
 | 	xfs_agnumber_t	agno; | 
 | 	int		c; | 
 | 	inodata_t	*hp; | 
 | 	inodata_t	**ht; | 
 | 	int		i; | 
 | 	inodata_t	*id; | 
 | 	xfs_ino_t	*ilist; | 
 | 	int		ilist_size; | 
 | 	xfs_ino_t	*ilp; | 
 | 	xfs_ino_t	ino; | 
 | 	char		*p; | 
 | 	int		security; | 
 |  | 
 | 	if (!inodata || !nflag) { | 
 | 		dbprintf(_("must run blockget -n first\n")); | 
 | 		return 0; | 
 | 	} | 
 | 	security = optind = ilist_size = 0; | 
 | 	ilist = NULL; | 
 | 	while ((c = getopt(argc, argv, "i:s")) != EOF) { | 
 | 		switch (c) { | 
 | 		case 'i': | 
 | 			ino = strtoll(optarg, NULL, 10); | 
 | 			ilist = xrealloc(ilist, (ilist_size + 1) * | 
 | 				sizeof(*ilist)); | 
 | 			ilist[ilist_size++] = ino; | 
 | 			break; | 
 | 		case 's': | 
 | 			security = 1; | 
 | 			break; | 
 | 		default: | 
 | 			dbprintf(_("bad option -%c for ncheck command\n"), c); | 
 | 			xfree(ilist); | 
 | 			return 0; | 
 | 		} | 
 | 	} | 
 | 	if (ilist) { | 
 | 		for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) { | 
 | 			ino = *ilp; | 
 | 			if ((p = inode_name(ino, &hp))) { | 
 | 				dbprintf("%11llu %s", ino, p); | 
 | 				if (hp->isdir) | 
 | 					dbprintf("/."); | 
 | 				dbprintf("\n"); | 
 | 				xfree(p); | 
 | 			} | 
 | 		} | 
 | 		xfree(ilist); | 
 | 		return 0; | 
 | 	} | 
 | 	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { | 
 | 		ht = inodata[agno]; | 
 | 		for (i = 0; i < inodata_hash_size; i++) { | 
 | 			hp = ht[i]; | 
 | 			for (hp = ht[i]; hp; hp = hp->next) { | 
 | 				ino = XFS_AGINO_TO_INO(mp, agno, hp->ino); | 
 | 				p = inode_name(ino, &id); | 
 | 				if (!p || !id) | 
 | 					continue; | 
 | 				if (!security || id->security) { | 
 | 					dbprintf("%11llu %s", ino, p); | 
 | 					if (hp->isdir) | 
 | 						dbprintf("/."); | 
 | 					dbprintf("\n"); | 
 | 				} | 
 | 				xfree(p); | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | static char * | 
 | prepend_path( | 
 | 	char	*oldpath, | 
 | 	char	*parent) | 
 | { | 
 | 	int	len; | 
 | 	char	*path; | 
 |  | 
 | 	len = (int)(strlen(oldpath) + strlen(parent) + 2); | 
 | 	path = xmalloc(len); | 
 | 	snprintf(path, len, "%s/%s", parent, oldpath); | 
 | 	return path; | 
 | } | 
 |  | 
 | static xfs_ino_t | 
 | process_block_dir_v2( | 
 | 	blkmap_t	*blkmap, | 
 | 	int		*dot, | 
 | 	int		*dotdot, | 
 | 	inodata_t	*id) | 
 | { | 
 | 	xfs_fsblock_t	b; | 
 | 	bbmap_t		bbmap; | 
 | 	bmap_ext_t	*bmp; | 
 | 	int		nex; | 
 | 	xfs_ino_t	parent; | 
 | 	int		v; | 
 | 	int		i; | 
 |  | 
 | 	nex = blkmap_getn(blkmap, 0, mp->m_dir_geo->fsbcount, &bmp); | 
 | 	v = id->ilist || verbose; | 
 | 	if (nex == 0) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("block 0 for directory inode %lld is " | 
 | 				 "missing\n"), | 
 | 				id->ino); | 
 | 		error++; | 
 | 		return 0; | 
 | 	} | 
 | 	push_cur(); | 
 | 	if (nex > 1) | 
 | 		make_bbmap(&bbmap, nex, bmp); | 
 | 	set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), | 
 | 		mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); | 
 | 	for (i = 0; !v && i < nex; i++) { | 
 | 		for (b = bmp[i].startblock; | 
 | 		     !v && b < bmp[i].startblock + bmp[i].blockcount; | 
 | 		     b++) | 
 | 			v = CHECK_BLIST(b); | 
 | 	} | 
 | 	free(bmp); | 
 | 	if (iocur_top->data == NULL) { | 
 | 		if (!sflag || id->ilist || v) | 
 | 			dbprintf(_("can't read block 0 for directory inode " | 
 | 				 "%lld\n"), | 
 | 				id->ino); | 
 | 		error++; | 
 | 		pop_cur(); | 
 | 		return 0; | 
 | 	} | 
 | 	dir_hash_init(); | 
 | 	parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dir_geo->datablk, | 
 | 		NULL); | 
 | 	dir_hash_check(id, v); | 
 | 	dir_hash_done(); | 
 | 	pop_cur(); | 
 | 	return parent; | 
 | } | 
 |  | 
 | static void | 
 | process_bmbt_reclist( | 
 | 	xfs_bmbt_rec_t		*rp, | 
 | 	xfs_extnum_t		numrecs, | 
 | 	dbm_t			type, | 
 | 	inodata_t		*id, | 
 | 	xfs_rfsblock_t		*tot, | 
 | 	blkmap_t		**blkmapp) | 
 | { | 
 | 	xfs_agblock_t		agbno; | 
 | 	xfs_agnumber_t		agno; | 
 | 	xfs_fsblock_t		b; | 
 | 	xfs_filblks_t		c; | 
 | 	xfs_filblks_t		cp; | 
 | 	int			f; | 
 | 	xfs_extnum_t		i; | 
 | 	xfs_agblock_t		iagbno; | 
 | 	xfs_agnumber_t		iagno; | 
 | 	xfs_fileoff_t		o; | 
 | 	xfs_fileoff_t		op; | 
 | 	xfs_fsblock_t		s; | 
 | 	int			v; | 
 |  | 
 | 	cp = op = 0; | 
 | 	v = verbose || id->ilist; | 
 | 	iagno = XFS_INO_TO_AGNO(mp, id->ino); | 
 | 	iagbno = XFS_INO_TO_AGBNO(mp, id->ino); | 
 | 	for (i = 0; i < numrecs; i++, rp++) { | 
 | 		convert_extent(rp, &o, &s, &c, &f); | 
 | 		if (v) | 
 | 			dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"), | 
 | 				id->ino, o, s, c, f); | 
 | 		if (!sflag && i > 0 && op + cp > o) | 
 | 			dbprintf(_("bmap rec out of order, inode %lld entry %d\n"), | 
 | 				id->ino, i); | 
 | 		op = o; | 
 | 		cp = c; | 
 | 		if (type == DBM_RTDATA) { | 
 | 			if (!sflag && s >= mp->m_sb.sb_rblocks) { | 
 | 				dbprintf(_("inode %lld bad rt block number %lld, " | 
 | 					 "offset %lld\n"), | 
 | 					id->ino, s, o); | 
 | 				continue; | 
 | 			} | 
 | 		} else if (!sflag) { | 
 | 			agno = XFS_FSB_TO_AGNO(mp, s); | 
 | 			agbno = XFS_FSB_TO_AGBNO(mp, s); | 
 | 			if (agno >= mp->m_sb.sb_agcount || | 
 | 			    agbno >= mp->m_sb.sb_agblocks) { | 
 | 				dbprintf(_("inode %lld bad block number %lld " | 
 | 					 "[%d,%d], offset %lld\n"), | 
 | 					id->ino, s, agno, agbno, o); | 
 | 				continue; | 
 | 			} | 
 | 			if (agbno + c - 1 >= mp->m_sb.sb_agblocks) { | 
 | 				dbprintf(_("inode %lld bad block number %lld " | 
 | 					 "[%d,%d], offset %lld\n"), | 
 | 					id->ino, s + c - 1, agno, | 
 | 					agbno + (xfs_agblock_t)c - 1, o); | 
 | 				continue; | 
 | 			} | 
 | 		} | 
 | 		if (blkmapp && *blkmapp) | 
 | 			blkmap_set_ext(blkmapp, (xfs_fileoff_t)o, | 
 | 				(xfs_fsblock_t)s, (xfs_extlen_t)c); | 
 | 		if (type == DBM_RTDATA) { | 
 | 			set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c, | 
 | 				DBM_RTDATA); | 
 | 			set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id); | 
 | 			for (b = (xfs_fsblock_t)s; | 
 | 			     blist_size && b < s + c; | 
 | 			     b++, o++) { | 
 | 				if (CHECK_BLIST(b)) | 
 | 					dbprintf(_("inode %lld block %lld at " | 
 | 						 "offset %lld\n"), | 
 | 						id->ino, (xfs_fsblock_t)b, o); | 
 | 			} | 
 | 		} else { | 
 | 			agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s); | 
 | 			agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s); | 
 | 			set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno, | 
 | 				iagbno); | 
 | 			set_inomap(agno, agbno, (xfs_extlen_t)c, id); | 
 | 			for (b = (xfs_fsblock_t)s; | 
 | 			     blist_size && b < s + c; | 
 | 			     b++, o++, agbno++) { | 
 | 				if (CHECK_BLIST(b)) | 
 | 					dbprintf(_("inode %lld block %lld at " | 
 | 						 "offset %lld\n"), | 
 | 						id->ino, (xfs_fsblock_t)b, o); | 
 | 			} | 
 | 		} | 
 | 		*tot += c; | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | process_btinode( | 
 | 	inodata_t		*id, | 
 | 	struct xfs_dinode	*dip, | 
 | 	dbm_t			type, | 
 | 	xfs_rfsblock_t		*totd, | 
 | 	xfs_rfsblock_t		*toti, | 
 | 	xfs_extnum_t		*nex, | 
 | 	blkmap_t		**blkmapp, | 
 | 	int			whichfork) | 
 | { | 
 | 	xfs_bmdr_block_t	*dib; | 
 | 	int			i; | 
 | 	xfs_bmbt_ptr_t		*pp; | 
 |  | 
 | 	dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); | 
 | 	if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) { | 
 | 		if (!sflag || id->ilist) | 
 | 			dbprintf(_("level for ino %lld %s fork bmap root too " | 
 | 				 "large (%u)\n"), | 
 | 				id->ino, | 
 | 				whichfork == XFS_DATA_FORK ? _("data") : _("attr"), | 
 | 				be16_to_cpu(dib->bb_level)); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(dib->bb_numrecs) > | 
 | 			libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), | 
 | 			be16_to_cpu(dib->bb_level) == 0)) { | 
 | 		if (!sflag || id->ilist) | 
 | 			dbprintf(_("numrecs for ino %lld %s fork bmap root too " | 
 | 				 "large (%u)\n"), | 
 | 				id->ino, | 
 | 				whichfork == XFS_DATA_FORK ? _("data") : _("attr"), | 
 | 				be16_to_cpu(dib->bb_numrecs)); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(dib->bb_level) == 0) { | 
 | 		xfs_bmbt_rec_t	*rp = xfs_bmdr_rec_addr(dib, 1); | 
 | 		process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type, | 
 | 							id, totd, blkmapp); | 
 | 		*nex += be16_to_cpu(dib->bb_numrecs); | 
 | 		return; | 
 | 	} else { | 
 | 		pp = xfs_bmdr_ptr_addr(dib, 1, libxfs_bmdr_maxrecs( | 
 | 				XFS_DFORK_SIZE(dip, mp, whichfork), 0)); | 
 | 		for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++) | 
 | 			scan_lbtree(get_unaligned_be64(&pp[i]), | 
 | 					be16_to_cpu(dib->bb_level), | 
 | 					scanfunc_bmap, type, id, totd, toti, | 
 | 					nex, blkmapp, 1, | 
 | 					whichfork == XFS_DATA_FORK ? | 
 | 						TYP_BMAPBTD : TYP_BMAPBTA); | 
 | 	} | 
 | 	if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) { | 
 | 		if (!sflag || id->ilist) | 
 | 			dbprintf(_("extent count for ino %lld %s fork too low " | 
 | 				 "(%d) for file format\n"), | 
 | 				id->ino, | 
 | 				whichfork == XFS_DATA_FORK ? _("data") : _("attr"), | 
 | 				*nex); | 
 | 		error++; | 
 | 	} | 
 | } | 
 |  | 
 | static xfs_ino_t | 
 | process_data_dir_v2( | 
 | 	int			*dot, | 
 | 	int			*dotdot, | 
 | 	inodata_t		*id, | 
 | 	int			v, | 
 | 	xfs_dablk_t		dabno, | 
 | 	freetab_t		**freetabp) | 
 | { | 
 | 	xfs_dir2_dataptr_t	addr; | 
 | 	xfs_dir2_data_free_t	*bf; | 
 | 	int			bf_err; | 
 | 	struct xfs_dir2_data_hdr *block; | 
 | 	xfs_dir2_block_tail_t	*btp = NULL; | 
 | 	inodata_t		*cid; | 
 | 	int			count; | 
 | 	struct xfs_dir2_data_hdr *data; | 
 | 	xfs_dir2_db_t		db; | 
 | 	xfs_dir2_data_entry_t	*dep; | 
 | 	xfs_dir2_data_free_t	*dfp; | 
 | 	xfs_dir2_data_unused_t	*dup; | 
 | 	char			*endptr; | 
 | 	int			freeseen; | 
 | 	freetab_t		*freetab; | 
 | 	int			i; | 
 | 	int			lastfree; | 
 | 	int			lastfree_err; | 
 | 	xfs_dir2_leaf_entry_t	*lep = NULL; | 
 | 	xfs_ino_t		lino; | 
 | 	xfs_ino_t		parent = 0; | 
 | 	char			*ptr; | 
 | 	int			stale = 0; | 
 | 	int			tag_err; | 
 | 	__be16			*tagp; | 
 | 	struct xfs_name		xname; | 
 |  | 
 | 	data = iocur_top->data; | 
 | 	block = iocur_top->data; | 
 | 	if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC && | 
 | 			be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC && | 
 | 			be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC && | 
 | 			be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad directory data magic # %#x for dir ino " | 
 | 				 "%lld block %d\n"), | 
 | 				be32_to_cpu(data->magic), id->ino, dabno); | 
 | 		error++; | 
 | 		return NULLFSINO; | 
 | 	} | 
 | 	db = xfs_dir2_da_to_db(mp->m_dir_geo, dabno); | 
 | 	bf = libxfs_dir2_data_bestfree_p(mp, data); | 
 | 	ptr = (char *)data + mp->m_dir_geo->data_entry_offset; | 
 | 	if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC || | 
 | 	    be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) { | 
 | 		btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block); | 
 | 		lep = xfs_dir2_block_leaf_p(btp); | 
 | 		endptr = (char *)lep; | 
 | 		if (endptr <= ptr || endptr > (char *)btp) { | 
 | 			endptr = (char *)data + mp->m_dir_geo->blksize; | 
 | 			lep = NULL; | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("bad block directory tail for dir ino " | 
 | 					 "%lld\n"), | 
 | 					id->ino); | 
 | 			error++; | 
 | 		} | 
 | 	} else | 
 | 		endptr = (char *)data + mp->m_dir_geo->blksize; | 
 | 	bf_err = lastfree_err = tag_err = 0; | 
 | 	count = lastfree = freeseen = 0; | 
 | 	if (be16_to_cpu(bf[0].length) == 0) { | 
 | 		bf_err += be16_to_cpu(bf[0].offset) != 0; | 
 | 		freeseen |= 1 << 0; | 
 | 	} | 
 | 	if (be16_to_cpu(bf[1].length) == 0) { | 
 | 		bf_err += be16_to_cpu(bf[1].offset) != 0; | 
 | 		freeseen |= 1 << 1; | 
 | 	} | 
 | 	if (be16_to_cpu(bf[2].length) == 0) { | 
 | 		bf_err += be16_to_cpu(bf[2].offset) != 0; | 
 | 		freeseen |= 1 << 2; | 
 | 	} | 
 | 	bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length); | 
 | 	bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length); | 
 | 	if (freetabp) { | 
 | 		freetab = *freetabp; | 
 | 		if (freetab->naents <= db) { | 
 | 			*freetabp = freetab = | 
 | 				realloc(freetab, FREETAB_SIZE(db + 1)); | 
 | 			for (i = freetab->naents; i < db; i++) | 
 | 				freetab->ents[i] = NULLDATAOFF; | 
 | 			freetab->naents = db + 1; | 
 | 		} | 
 | 		if (freetab->nents < db + 1) | 
 | 			freetab->nents = db + 1; | 
 | 		freetab->ents[db] = be16_to_cpu(bf[0].length); | 
 | 	} | 
 | 	while (ptr < endptr) { | 
 | 		dup = (xfs_dir2_data_unused_t *)ptr; | 
 | 		if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { | 
 | 			lastfree_err += lastfree != 0; | 
 | 			tagp = xfs_dir2_data_unused_tag_p(dup); | 
 | 			if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) || | 
 | 					be16_to_cpu(dup->length) == 0 || | 
 | 					(char *)tagp >= endptr) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("dir %lld block %d bad free " | 
 | 						 "entry at %d\n"), | 
 | 						id->ino, dabno, | 
 | 						(int)((char *)dup - | 
 | 						      (char *)data)); | 
 | 				error++; | 
 | 				break; | 
 | 			} | 
 | 			tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data; | 
 | 			dfp = process_data_dir_v2_freefind(data, dup); | 
 | 			if (dfp) { | 
 | 				i = (int)(dfp - bf); | 
 | 				bf_err += (freeseen & (1 << i)) != 0; | 
 | 				freeseen |= 1 << i; | 
 | 			} else | 
 | 				bf_err += be16_to_cpu(dup->length) > | 
 | 						be16_to_cpu(bf[2].length); | 
 | 			ptr += be16_to_cpu(dup->length); | 
 | 			lastfree = 1; | 
 | 			continue; | 
 | 		} | 
 | 		dep = (xfs_dir2_data_entry_t *)dup; | 
 | 		if (dep->namelen == 0) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("dir %lld block %d zero length entry " | 
 | 					 "at %d\n"), | 
 | 					id->ino, dabno, | 
 | 					(int)((char *)dep - (char *)data)); | 
 | 			error++; | 
 | 		} | 
 | 		tagp = libxfs_dir2_data_entry_tag_p(mp, dep); | 
 | 		if ((char *)tagp >= endptr) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("dir %lld block %d bad entry at %d\n"), | 
 | 					id->ino, dabno, | 
 | 					(int)((char *)dep - (char *)data)); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data; | 
 | 		addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db, | 
 | 			(char *)dep - (char *)data); | 
 | 		xname.name = dep->name; | 
 | 		xname.len = dep->namelen; | 
 | 		dir_hash_add(libxfs_dir2_hashname(mp, &xname), addr); | 
 | 		ptr += libxfs_dir2_data_entsize(mp, dep->namelen); | 
 | 		count++; | 
 | 		lastfree = 0; | 
 | 		lino = be64_to_cpu(dep->inumber); | 
 | 		cid = find_inode(lino, 1); | 
 | 		if (v) | 
 | 			dbprintf(_("dir %lld block %d entry %*.*s %lld\n"), | 
 | 				id->ino, dabno, dep->namelen, dep->namelen, | 
 | 				dep->name, lino); | 
 | 		if (cid) | 
 | 			addlink_inode(cid); | 
 | 		else { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("dir %lld block %d entry %*.*s bad " | 
 | 					 "inode number %lld\n"), | 
 | 					id->ino, dabno, dep->namelen, | 
 | 					dep->namelen, dep->name, lino); | 
 | 			error++; | 
 | 		} | 
 | 		if (dep->namelen == 2 && dep->name[0] == '.' && | 
 | 		    dep->name[1] == '.') { | 
 | 			if (parent) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("multiple .. entries in dir " | 
 | 						 "%lld (%lld, %lld)\n"), | 
 | 						id->ino, parent, lino); | 
 | 				error++; | 
 | 			} else | 
 | 				parent = cid ? lino : NULLFSINO; | 
 | 			(*dotdot)++; | 
 | 		} else if (dep->namelen != 1 || dep->name[0] != '.') { | 
 | 			if (cid != NULL) { | 
 | 				if (!cid->parent) | 
 | 					cid->parent = id; | 
 | 				addname_inode(cid, (char *)dep->name, | 
 | 					dep->namelen); | 
 | 			} | 
 | 		} else { | 
 | 			if (lino != id->ino) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("dir %lld entry . inode " | 
 | 						 "number mismatch (%lld)\n"), | 
 | 						id->ino, lino); | 
 | 				error++; | 
 | 			} | 
 | 			(*dot)++; | 
 | 		} | 
 | 	} | 
 | 	if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || | 
 | 	    be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) { | 
 | 		endptr = (char *)data + mp->m_dir_geo->blksize; | 
 | 		for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) { | 
 | 			if ((char *)&lep[i] >= endptr) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("dir %lld block %d bad count " | 
 | 						 "%u\n"), id->ino, dabno, | 
 | 						be32_to_cpu(btp->count)); | 
 | 				error++; | 
 | 				break; | 
 | 			} | 
 | 			if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) | 
 | 				stale++; | 
 | 			else if (dir_hash_see(be32_to_cpu(lep[i].hashval), | 
 | 						be32_to_cpu(lep[i].address))) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("dir %lld block %d extra leaf " | 
 | 						 "entry %x %x\n"), | 
 | 						id->ino, dabno, | 
 | 						be32_to_cpu(lep[i].hashval), | 
 | 						be32_to_cpu(lep[i].address)); | 
 | 				error++; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	bf_err += freeseen != 7; | 
 | 	if (bf_err) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d bad bestfree data\n"), | 
 | 				id->ino, dabno); | 
 | 		error++; | 
 | 	} | 
 | 	if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || | 
 | 	     be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) && | 
 | 	    count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d bad block tail count %d " | 
 | 				 "(stale %d)\n"), | 
 | 				id->ino, dabno, be32_to_cpu(btp->count), | 
 | 				be32_to_cpu(btp->stale)); | 
 | 		error++; | 
 | 	} | 
 | 	if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC || | 
 | 	     be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) && | 
 | 					stale != be32_to_cpu(btp->stale)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d bad stale tail count %d\n"), | 
 | 				id->ino, dabno, be32_to_cpu(btp->stale)); | 
 | 		error++; | 
 | 	} | 
 | 	if (lastfree_err) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d consecutive free entries\n"), | 
 | 				id->ino, dabno); | 
 | 		error++; | 
 | 	} | 
 | 	if (tag_err) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d entry/unused tag " | 
 | 				 "mismatch\n"), | 
 | 				id->ino, dabno); | 
 | 		error++; | 
 | 	} | 
 | 	return parent; | 
 | } | 
 |  | 
 | static xfs_dir2_data_free_t * | 
 | process_data_dir_v2_freefind( | 
 | 	struct xfs_dir2_data_hdr *data, | 
 | 	xfs_dir2_data_unused_t	*dup) | 
 | { | 
 | 	struct xfs_dir2_data_free *bf; | 
 | 	struct xfs_dir2_data_free *dfp; | 
 | 	xfs_dir2_data_aoff_t	off; | 
 |  | 
 | 	off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data); | 
 | 	bf = libxfs_dir2_data_bestfree_p(mp, data); | 
 | 	if (be16_to_cpu(dup->length) < | 
 | 			be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) | 
 | 		return NULL; | 
 | 	for (dfp = bf; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { | 
 | 		if (be16_to_cpu(dfp->offset) == 0) | 
 | 			return NULL; | 
 | 		if (be16_to_cpu(dfp->offset) == off) | 
 | 			return dfp; | 
 | 	} | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static void | 
 | process_dir( | 
 | 	struct xfs_dinode	*dip, | 
 | 	blkmap_t		*blkmap, | 
 | 	inodata_t		*id) | 
 | { | 
 | 	xfs_fsblock_t		bno; | 
 | 	int			dot; | 
 | 	int			dotdot; | 
 | 	xfs_ino_t		parent; | 
 |  | 
 | 	dot = dotdot = 0; | 
 | 	if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent)) | 
 | 		return; | 
 |  | 
 | 	bno = XFS_INO_TO_FSB(mp, id->ino); | 
 | 	if (dot == 0) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("no . entry for directory %lld\n"), id->ino); | 
 | 		error++; | 
 | 	} | 
 | 	if (dotdot == 0) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("no .. entry for directory %lld\n"), id->ino); | 
 | 		error++; | 
 | 	} else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_(". and .. same for non-root directory %lld\n"), | 
 | 				id->ino); | 
 | 		error++; | 
 | 	} else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("root directory %lld has .. %lld\n"), id->ino, | 
 | 				parent); | 
 | 		error++; | 
 | 	} else if (parent != NULLFSINO && id->ino != parent) | 
 | 		addparent_inode(id, parent); | 
 | } | 
 |  | 
 | static int | 
 | process_dir_v2( | 
 | 	struct xfs_dinode	*dip, | 
 | 	blkmap_t		*blkmap, | 
 | 	int			*dot, | 
 | 	int			*dotdot, | 
 | 	inodata_t		*id, | 
 | 	xfs_ino_t		*parent) | 
 | { | 
 | 	xfs_fileoff_t		last = 0; | 
 | 	xfs_fsize_t		size = be64_to_cpu(dip->di_size); | 
 |  | 
 | 	if (blkmap) | 
 | 		last = blkmap_last_off(blkmap); | 
 | 	if (size <= XFS_DFORK_DSIZE(dip, mp) && | 
 | 				dip->di_format == XFS_DINODE_FMT_LOCAL) | 
 | 		*parent = process_sf_dir_v2(dip, dot, dotdot, id); | 
 | 	else if (last == mp->m_dir_geo->fsbcount && | 
 | 			(dip->di_format == XFS_DINODE_FMT_EXTENTS || | 
 | 			dip->di_format == XFS_DINODE_FMT_BTREE)) | 
 | 		*parent = process_block_dir_v2(blkmap, dot, dotdot, id); | 
 | 	else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount && | 
 | 			(dip->di_format == XFS_DINODE_FMT_EXTENTS || | 
 | 			dip->di_format == XFS_DINODE_FMT_BTREE)) | 
 | 		*parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size); | 
 | 	else  { | 
 | 		dbprintf(_("bad size (%lld) or format (%d) for directory inode " | 
 | 			 "%lld\n"), | 
 | 			size, dip->di_format, id->ino); | 
 | 		error++; | 
 | 		return 1; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* ARGSUSED */ | 
 | static void | 
 | process_exinode( | 
 | 	inodata_t		*id, | 
 | 	struct xfs_dinode	*dip, | 
 | 	dbm_t			type, | 
 | 	xfs_rfsblock_t		*totd, | 
 | 	xfs_rfsblock_t		*toti, | 
 | 	xfs_extnum_t		*nex, | 
 | 	blkmap_t		**blkmapp, | 
 | 	int			whichfork) | 
 | { | 
 | 	xfs_bmbt_rec_t		*rp; | 
 | 	xfs_extnum_t		max_nex; | 
 |  | 
 | 	rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); | 
 | 	*nex = xfs_dfork_nextents(dip, whichfork); | 
 | 	max_nex = xfs_iext_max_nextents( | 
 | 			xfs_dinode_has_large_extent_counts(dip), | 
 | 			whichfork); | 
 | 	if (*nex > max_nex || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) / | 
 | 						sizeof(xfs_bmbt_rec_t)) { | 
 | 		if (!sflag || id->ilist) | 
 | 			dbprintf(_("bad number of extents %llu for inode %lld\n"), | 
 | 				(unsigned long long)*nex, id->ino); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp); | 
 | } | 
 |  | 
 | static void | 
 | process_inode( | 
 | 	xfs_agf_t		*agf, | 
 | 	xfs_agino_t		agino, | 
 | 	struct xfs_dinode	*dip, | 
 | 	int			isfree) | 
 | { | 
 | 	blkmap_t		*blkmap; | 
 | 	xfs_fsblock_t		bno = 0; | 
 | 	inodata_t		*id = NULL; | 
 | 	xfs_ino_t		ino; | 
 | 	xfs_extnum_t		nextents = 0; | 
 | 	xfs_extnum_t		dnextents; | 
 | 	int			security; | 
 | 	xfs_rfsblock_t		totblocks; | 
 | 	xfs_rfsblock_t		totdblocks = 0; | 
 | 	xfs_rfsblock_t		totiblocks = 0; | 
 | 	dbm_t			type; | 
 | 	xfs_extnum_t		anextents = 0; | 
 | 	xfs_extnum_t		danextents; | 
 | 	xfs_rfsblock_t		atotdblocks = 0; | 
 | 	xfs_rfsblock_t		atotiblocks = 0; | 
 | 	xfs_qcnt_t		bc = 0; | 
 | 	xfs_qcnt_t		ic = 0; | 
 | 	xfs_qcnt_t		rc = 0; | 
 | 	int			v = 0; | 
 | 	mode_t			mode; | 
 | 	uint16_t		diflags; | 
 | 	uint64_t		diflags2 = 0; | 
 | 	xfs_nlink_t		nlink; | 
 | 	xfs_dqid_t		uid; | 
 | 	xfs_dqid_t		gid; | 
 | 	xfs_dqid_t		prid; | 
 | 	static char		okfmts[] = { | 
 | 		0,				/* type 0 unused */ | 
 | 		1 << XFS_DINODE_FMT_DEV,	/* FIFO */ | 
 | 		1 << XFS_DINODE_FMT_DEV,	/* CHR */ | 
 | 		0,				/* type 3 unused */ | 
 | 		(1 << XFS_DINODE_FMT_LOCAL) | | 
 | 		(1 << XFS_DINODE_FMT_EXTENTS) | | 
 | 		(1 << XFS_DINODE_FMT_BTREE),	/* DIR */ | 
 | 		0,				/* type 5 unused */ | 
 | 		1 << XFS_DINODE_FMT_DEV,	/* BLK */ | 
 | 		0,				/* type 7 unused */ | 
 | 		(1 << XFS_DINODE_FMT_EXTENTS) | | 
 | 		(1 << XFS_DINODE_FMT_BTREE),	/* REG */ | 
 | 		0,				/* type 9 unused */ | 
 | 		(1 << XFS_DINODE_FMT_LOCAL) | | 
 | 		(1 << XFS_DINODE_FMT_EXTENTS),	/* LNK */ | 
 | 		0,				/* type 11 unused */ | 
 | 		1 << XFS_DINODE_FMT_DEV,	/* SOCK */ | 
 | 		0,				/* type 13 unused */ | 
 | 		1 << XFS_DINODE_FMT_UUID,	/* MNT */ | 
 | 		0				/* type 15 unused */ | 
 | 	}; | 
 | 	static char		*fmtnames[] = { | 
 | 		"dev", "local", "extents", "btree", "uuid" | 
 | 	}; | 
 |  | 
 | 	ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino); | 
 | 	if (!isfree) { | 
 | 		id = find_inode(ino, 1); | 
 | 		bno = XFS_INO_TO_FSB(mp, ino); | 
 | 		blkmap = NULL; | 
 | 	} | 
 | 	v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno)); | 
 | 	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) { | 
 | 		if (isfree || v) | 
 | 			dbprintf(_("bad magic number %#x for inode %lld\n"), | 
 | 				be16_to_cpu(dip->di_magic), ino); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (!libxfs_dinode_good_version(mp, dip->di_version)) { | 
 | 		if (isfree || v) | 
 | 			dbprintf(_("bad version number %#x for inode %lld\n"), | 
 | 				dip->di_version, ino); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (dip->di_version == 1) { | 
 | 		nlink = be16_to_cpu(dip->di_onlink); | 
 | 		prid = 0; | 
 | 	} else { | 
 | 		nlink = be32_to_cpu(dip->di_nlink); | 
 | 		prid = (xfs_dqid_t)be16_to_cpu(dip->di_projid_hi) << 16 | | 
 | 				   be16_to_cpu(dip->di_projid_lo); | 
 | 	} | 
 | 	uid = be32_to_cpu(dip->di_uid); | 
 | 	gid = be32_to_cpu(dip->di_gid); | 
 | 	diflags = be16_to_cpu(dip->di_flags); | 
 | 	if (xfs_has_v3inodes(mp)) | 
 | 		diflags2 = be64_to_cpu(dip->di_flags2); | 
 | 	if (isfree) { | 
 | 		if (be64_to_cpu(dip->di_nblocks) != 0) { | 
 | 			if (v) | 
 | 				dbprintf(_("bad nblocks %lld for free inode " | 
 | 					 "%lld\n"), | 
 | 					be64_to_cpu(dip->di_nblocks), ino); | 
 | 			error++; | 
 | 		} | 
 | 		if (nlink != 0) { | 
 | 			if (v) | 
 | 				dbprintf(_("bad nlink %d for free inode %lld\n"), | 
 | 					nlink, ino); | 
 | 			error++; | 
 | 		} | 
 | 		if (dip->di_mode != 0) { | 
 | 			if (v) | 
 | 				dbprintf(_("bad mode %#o for free inode %lld\n"), | 
 | 					be16_to_cpu(dip->di_mode), ino); | 
 | 			error++; | 
 | 		} | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad next unlinked %#x for inode %lld\n"), | 
 | 				be32_to_cpu(dip->di_next_unlinked), ino); | 
 | 		error++; | 
 | 	} | 
 | 	/* | 
 | 	 * di_mode is a 16-bit uint so no need to check the < 0 case | 
 | 	 */ | 
 | 	mode = be16_to_cpu(dip->di_mode); | 
 | 	if ((((mode & S_IFMT) >> 12) > 15) || | 
 | 	    (!(okfmts[(mode & S_IFMT) >> 12] & (1 << dip->di_format)))) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad format %d for inode %lld type %#o\n"), | 
 | 				dip->di_format, id->ino, mode & S_IFMT); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >= XFS_LITINO(mp)) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad fork offset %d for inode %lld\n"), | 
 | 				dip->di_forkoff, id->ino); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if ((unsigned int)dip->di_aformat > XFS_DINODE_FMT_BTREE)  { | 
 | 		if (v) | 
 | 			dbprintf(_("bad attribute format %d for inode %lld\n"), | 
 | 				dip->di_aformat, id->ino); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	dnextents = xfs_dfork_data_extents(dip); | 
 | 	danextents = xfs_dfork_attr_extents(dip); | 
 |  | 
 | 	if (verbose || (id && id->ilist) || CHECK_BLIST(bno)) | 
 | 		dbprintf(_("inode %lld mode %#o fmt %s " | 
 | 			 "afmt %s " | 
 | 			 "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"), | 
 | 			id->ino, mode, fmtnames[(int)dip->di_format], | 
 | 			fmtnames[(int)dip->di_aformat], | 
 | 			dnextents, danextents, | 
 | 			be64_to_cpu(dip->di_nblocks), be64_to_cpu(dip->di_size), | 
 | 			diflags & XFS_DIFLAG_REALTIME ? " rt" : "", | 
 | 			diflags & XFS_DIFLAG_PREALLOC ? " pre" : "", | 
 | 			diflags & XFS_DIFLAG_IMMUTABLE? " imm" : "", | 
 | 			diflags & XFS_DIFLAG_APPEND   ? " app" : "", | 
 | 			diflags & XFS_DIFLAG_SYNC     ? " syn" : "", | 
 | 			diflags & XFS_DIFLAG_NOATIME  ? " noa" : "", | 
 | 			diflags & XFS_DIFLAG_NODUMP   ? " nod" : ""); | 
 | 	security = 0; | 
 | 	switch (mode & S_IFMT) { | 
 | 	case S_IFDIR: | 
 | 		type = DBM_DIR; | 
 | 		if (dip->di_format == XFS_DINODE_FMT_LOCAL) | 
 | 			break; | 
 | 		blkmap = blkmap_alloc(dnextents); | 
 | 		break; | 
 | 	case S_IFREG: | 
 | 		if (diflags & XFS_DIFLAG_REALTIME) | 
 | 			type = DBM_RTDATA; | 
 | 		else if (id->ino == mp->m_sb.sb_rbmino) { | 
 | 			type = DBM_RTBITMAP; | 
 | 			blkmap = blkmap_alloc(dnextents); | 
 | 			addlink_inode(id); | 
 | 		} else if (id->ino == mp->m_sb.sb_rsumino) { | 
 | 			type = DBM_RTSUM; | 
 | 			blkmap = blkmap_alloc(dnextents); | 
 | 			addlink_inode(id); | 
 | 		} | 
 | 		else if (id->ino == mp->m_sb.sb_uquotino || | 
 | 			 id->ino == mp->m_sb.sb_gquotino || | 
 | 			 id->ino == mp->m_sb.sb_pquotino) { | 
 | 			type = DBM_QUOTA; | 
 | 			blkmap = blkmap_alloc(dnextents); | 
 | 			addlink_inode(id); | 
 | 		} | 
 | 		else | 
 | 			type = DBM_DATA; | 
 | 		if (mode & (S_ISUID | S_ISGID)) | 
 | 			security = 1; | 
 | 		break; | 
 | 	case S_IFLNK: | 
 | 		type = DBM_SYMLINK; | 
 | 		break; | 
 | 	default: | 
 | 		security = 1; | 
 | 		type = DBM_UNKNOWN; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	id->isreflink = !!(diflags2 & XFS_DIFLAG2_REFLINK); | 
 | 	setlink_inode(id, nlink, type == DBM_DIR, security); | 
 |  | 
 | 	switch (dip->di_format) { | 
 | 	case XFS_DINODE_FMT_LOCAL: | 
 | 		process_lclinode(id, dip, type, &totdblocks, &totiblocks, | 
 | 			&nextents, &blkmap, XFS_DATA_FORK); | 
 | 		break; | 
 | 	case XFS_DINODE_FMT_EXTENTS: | 
 | 		process_exinode(id, dip, type, &totdblocks, &totiblocks, | 
 | 			&nextents, &blkmap, XFS_DATA_FORK); | 
 | 		break; | 
 | 	case XFS_DINODE_FMT_BTREE: | 
 | 		process_btinode(id, dip, type, &totdblocks, &totiblocks, | 
 | 			&nextents, &blkmap, XFS_DATA_FORK); | 
 | 		break; | 
 | 	} | 
 | 	if (dip->di_forkoff) { | 
 | 		sbversion |= XFS_SB_VERSION_ATTRBIT; | 
 | 		switch (dip->di_aformat) { | 
 | 		case XFS_DINODE_FMT_LOCAL: | 
 | 			process_lclinode(id, dip, DBM_ATTR, &atotdblocks, | 
 | 				&atotiblocks, &anextents, NULL, XFS_ATTR_FORK); | 
 | 			break; | 
 | 		case XFS_DINODE_FMT_EXTENTS: | 
 | 			process_exinode(id, dip, DBM_ATTR, &atotdblocks, | 
 | 				&atotiblocks, &anextents, NULL, XFS_ATTR_FORK); | 
 | 			break; | 
 | 		case XFS_DINODE_FMT_BTREE: | 
 | 			process_btinode(id, dip, DBM_ATTR, &atotdblocks, | 
 | 				&atotiblocks, &anextents, NULL, XFS_ATTR_FORK); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	if (qgdo || qpdo || qudo) { | 
 | 		switch (type) { | 
 | 		case DBM_DATA: | 
 | 		case DBM_DIR: | 
 | 		case DBM_RTBITMAP: | 
 | 		case DBM_RTSUM: | 
 | 		case DBM_SYMLINK: | 
 | 		case DBM_UNKNOWN: | 
 | 			bc = totdblocks + totiblocks + | 
 | 			     atotdblocks + atotiblocks; | 
 | 			ic = 1; | 
 | 			break; | 
 | 		case DBM_RTDATA: | 
 | 			bc = totiblocks + atotdblocks + atotiblocks; | 
 | 			rc = totdblocks; | 
 | 			ic = 1; | 
 | 			break; | 
 | 		default: | 
 | 			break; | 
 | 		} | 
 | 		if (ic) | 
 | 			quota_add(&prid, &gid, &uid, 0, bc, ic, rc); | 
 | 	} | 
 | 	totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks; | 
 | 	if (totblocks != be64_to_cpu(dip->di_nblocks)) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad nblocks %lld for inode %lld, counted " | 
 | 				 "%lld\n"), | 
 | 				be64_to_cpu(dip->di_nblocks), id->ino, totblocks); | 
 | 		error++; | 
 | 	} | 
 | 	if (nextents != dnextents) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad nextents %d for inode %lld, counted %d\n"), | 
 | 				dnextents, id->ino, nextents); | 
 | 		error++; | 
 | 	} | 
 | 	if (anextents != danextents) { | 
 | 		if (v) | 
 | 			dbprintf(_("bad anextents %d for inode %lld, counted " | 
 | 				 "%d\n"), | 
 | 				danextents, id->ino, anextents); | 
 | 		error++; | 
 | 	} | 
 | 	if (type == DBM_DIR) | 
 | 		process_dir(dip, blkmap, id); | 
 | 	else if (type == DBM_RTBITMAP) | 
 | 		process_rtbitmap(blkmap); | 
 | 	else if (type == DBM_RTSUM) | 
 | 		process_rtsummary(blkmap); | 
 | 	/* | 
 | 	 * If the CHKD flag is not set, this can legitimately contain garbage; | 
 | 	 * xfs_repair may have cleared that bit. | 
 | 	 */ | 
 | 	else if (type == DBM_QUOTA) { | 
 | 		if (id->ino == mp->m_sb.sb_uquotino && | 
 | 		    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && | 
 | 		    (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD)) | 
 | 			process_quota(IS_USER_QUOTA, id, blkmap); | 
 | 		else if (id->ino == mp->m_sb.sb_gquotino && | 
 | 			 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && | 
 | 			 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD)) | 
 | 			process_quota(IS_GROUP_QUOTA, id, blkmap); | 
 | 		else if (id->ino == mp->m_sb.sb_pquotino && | 
 | 			 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) && | 
 | 			 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD)) | 
 | 			process_quota(IS_PROJECT_QUOTA, id, blkmap); | 
 | 	} | 
 | 	if (blkmap) | 
 | 		blkmap_free(blkmap); | 
 | } | 
 |  | 
 | /* ARGSUSED */ | 
 | static void | 
 | process_lclinode( | 
 | 	inodata_t			*id, | 
 | 	struct xfs_dinode		*dip, | 
 | 	dbm_t				type, | 
 | 	xfs_rfsblock_t			*totd, | 
 | 	xfs_rfsblock_t			*toti, | 
 | 	xfs_extnum_t			*nex, | 
 | 	blkmap_t			**blkmapp, | 
 | 	int				whichfork) | 
 | { | 
 | 	struct xfs_attr_sf_hdr		*hdr; | 
 | 	xfs_fsblock_t			bno; | 
 |  | 
 | 	bno = XFS_INO_TO_FSB(mp, id->ino); | 
 | 	if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) > | 
 | 						XFS_DFORK_DSIZE(dip, mp)) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("local inode %lld data is too large (size " | 
 | 				 "%lld)\n"), | 
 | 				id->ino, be64_to_cpu(dip->di_size)); | 
 | 		error++; | 
 | 	} | 
 | 	else if (whichfork == XFS_ATTR_FORK) { | 
 | 		hdr = XFS_DFORK_APTR(dip); | 
 | 		if (be16_to_cpu(hdr->totsize) > XFS_DFORK_ASIZE(dip, mp)) { | 
 | 			if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 				dbprintf(_("local inode %lld attr is too large " | 
 | 					 "(size %d)\n"), | 
 | 					id->ino, be16_to_cpu(hdr->totsize)); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static xfs_ino_t | 
 | process_leaf_node_dir_v2( | 
 | 	blkmap_t		*blkmap, | 
 | 	int			*dot, | 
 | 	int			*dotdot, | 
 | 	inodata_t		*id, | 
 | 	xfs_fsize_t		dirsize) | 
 | { | 
 | 	xfs_fsblock_t		b; | 
 | 	bbmap_t			bbmap; | 
 | 	bmap_ext_t		*bmp; | 
 | 	xfs_fileoff_t		dbno; | 
 | 	freetab_t		*freetab; | 
 | 	int			i; | 
 | 	xfs_ino_t		lino; | 
 | 	int			nex; | 
 | 	xfs_ino_t		parent; | 
 | 	int			t = 0; | 
 | 	int			v; | 
 | 	int			v2; | 
 |  | 
 | 	v2 = verbose || id->ilist; | 
 | 	v = parent = 0; | 
 | 	dbno = NULLFILEOFF; | 
 | 	freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dir_geo->blksize)); | 
 | 	freetab->naents = (int)(dirsize / mp->m_dir_geo->blksize); | 
 | 	freetab->nents = 0; | 
 | 	for (i = 0; i < freetab->naents; i++) | 
 | 		freetab->ents[i] = NULLDATAOFF; | 
 | 	dir_hash_init(); | 
 | 	while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) { | 
 | 		nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp); | 
 | 		ASSERT(nex > 0); | 
 | 		for (v = v2, i = 0; !v && i < nex; i++) { | 
 | 			for (b = bmp[i].startblock; | 
 | 			     !v && b < bmp[i].startblock + bmp[i].blockcount; | 
 | 			     b++) | 
 | 				v = CHECK_BLIST(b); | 
 | 		} | 
 | 		if (v) | 
 | 			dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino, | 
 | 				(uint32_t)dbno, | 
 | 				(xfs_fsblock_t)bmp->startblock); | 
 | 		push_cur(); | 
 | 		if (nex > 1) | 
 | 			make_bbmap(&bbmap, nex, bmp); | 
 | 		set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock), | 
 | 			mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, | 
 | 			nex > 1 ? &bbmap : NULL); | 
 | 		free(bmp); | 
 | 		if (iocur_top->data == NULL) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("can't read block %u for directory " | 
 | 					 "inode %lld\n"), | 
 | 					(uint32_t)dbno, id->ino); | 
 | 			error++; | 
 | 			pop_cur(); | 
 | 			dbno += mp->m_dir_geo->fsbcount - 1; | 
 | 			continue; | 
 | 		} | 
 | 		if (dbno < mp->m_dir_geo->leafblk) { | 
 | 			lino = process_data_dir_v2(dot, dotdot, id, v, | 
 | 				(xfs_dablk_t)dbno, &freetab); | 
 | 			if (lino) { | 
 | 				if (parent) { | 
 | 					if (!sflag || v) | 
 | 						dbprintf(_("multiple .. entries " | 
 | 							 "in dir %lld\n"), | 
 | 							id->ino); | 
 | 					error++; | 
 | 				} else | 
 | 					parent = lino; | 
 | 			} | 
 | 		} else if (dbno < mp->m_dir_geo->freeblk) { | 
 | 			process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno, | 
 | 				freetab); | 
 | 		} else { | 
 | 			process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno, | 
 | 				freetab); | 
 | 		} | 
 | 		pop_cur(); | 
 | 		dbno += mp->m_dir_geo->fsbcount - 1; | 
 | 	} | 
 | 	dir_hash_check(id, v); | 
 | 	dir_hash_done(); | 
 | 	for (i = 0; i < freetab->nents; i++) { | 
 | 		if (freetab->ents[i] != NULLDATAOFF) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("missing free index for data block %d " | 
 | 					 "in dir ino %lld\n"), | 
 | 					xfs_dir2_db_to_da(mp->m_dir_geo, i), id->ino); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | 	free(freetab); | 
 | 	return parent; | 
 | } | 
 |  | 
 | static void | 
 | process_leaf_node_dir_v3_free( | 
 | 	inodata_t		*id, | 
 | 	int			v, | 
 | 	xfs_dablk_t		dabno, | 
 | 	freetab_t		*freetab) | 
 | { | 
 | 	xfs_dir2_data_off_t	ent; | 
 | 	struct xfs_dir3_free	*free; | 
 | 	int			i; | 
 | 	int			maxent; | 
 | 	int			used; | 
 |  | 
 | 	free = iocur_top->data; | 
 | 	maxent = mp->m_dir_geo->free_max_bests; | 
 | 	if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo, | 
 | 					dabno - mp->m_dir_geo->freeblk) * maxent) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block firstdb %d for dir ino %lld " | 
 | 				 "block %d\n"), | 
 | 				be32_to_cpu(free->hdr.firstdb), id->ino, dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be32_to_cpu(free->hdr.nvalid) > maxent || | 
 | 				be32_to_cpu(free->hdr.nused) > maxent || | 
 | 				be32_to_cpu(free->hdr.nused) > | 
 | 					be32_to_cpu(free->hdr.nvalid)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block nvalid/nused %d/%d for dir " | 
 | 				 "ino %lld block %d\n"), | 
 | 				be32_to_cpu(free->hdr.nvalid), | 
 | 				be32_to_cpu(free->hdr.nused), id->ino, dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { | 
 | 		if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) | 
 | 			ent = NULLDATAOFF; | 
 | 		else | 
 | 			ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; | 
 | 		if (ent != be16_to_cpu(free->bests[i])) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("bad free block ent %d is %d should " | 
 | 					 "be %d for dir ino %lld block %d\n"), | 
 | 					i, be16_to_cpu(free->bests[i]), ent, | 
 | 					id->ino, dabno); | 
 | 			error++; | 
 | 		} | 
 | 		if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) | 
 | 			used++; | 
 | 		if (ent != NULLDATAOFF) | 
 | 			freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = | 
 | 								NULLDATAOFF; | 
 | 	} | 
 | 	if (used != be32_to_cpu(free->hdr.nused)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block nused %d should be %d for dir " | 
 | 				 "ino %lld block %d\n"), | 
 | 				be32_to_cpu(free->hdr.nused), used, id->ino, | 
 | 				dabno); | 
 | 		error++; | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | process_leaf_node_dir_v2_free( | 
 | 	inodata_t		*id, | 
 | 	int			v, | 
 | 	xfs_dablk_t		dabno, | 
 | 	freetab_t		*freetab) | 
 | { | 
 | 	xfs_dir2_data_off_t	ent; | 
 | 	xfs_dir2_free_t		*free; | 
 | 	int			i; | 
 | 	int			maxent; | 
 | 	int			used; | 
 |  | 
 | 	free = iocur_top->data; | 
 | 	if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC && | 
 | 	    be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block magic # %#x for dir ino %lld " | 
 | 				 "block %d\n"), | 
 | 				be32_to_cpu(free->hdr.magic), id->ino, dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) { | 
 | 		process_leaf_node_dir_v3_free(id, v, dabno, freetab); | 
 | 		return; | 
 | 	} | 
 | 	maxent = mp->m_dir_geo->free_max_bests; | 
 | 	if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo, | 
 | 					dabno - mp->m_dir_geo->freeblk) * maxent) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block firstdb %d for dir ino %lld " | 
 | 				 "block %d\n"), | 
 | 				be32_to_cpu(free->hdr.firstdb), id->ino, dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be32_to_cpu(free->hdr.nvalid) > maxent || | 
 | 				be32_to_cpu(free->hdr.nused) > maxent || | 
 | 				be32_to_cpu(free->hdr.nused) > | 
 | 					be32_to_cpu(free->hdr.nvalid)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block nvalid/nused %d/%d for dir " | 
 | 				 "ino %lld block %d\n"), | 
 | 				be32_to_cpu(free->hdr.nvalid), | 
 | 				be32_to_cpu(free->hdr.nused), id->ino, dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) { | 
 | 		if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i) | 
 | 			ent = NULLDATAOFF; | 
 | 		else | 
 | 			ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i]; | 
 | 		if (ent != be16_to_cpu(free->bests[i])) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("bad free block ent %d is %d should " | 
 | 					 "be %d for dir ino %lld block %d\n"), | 
 | 					i, be16_to_cpu(free->bests[i]), ent, | 
 | 					id->ino, dabno); | 
 | 			error++; | 
 | 		} | 
 | 		if (be16_to_cpu(free->bests[i]) != NULLDATAOFF) | 
 | 			used++; | 
 | 		if (ent != NULLDATAOFF) | 
 | 			freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] = | 
 | 								NULLDATAOFF; | 
 | 	} | 
 | 	if (used != be32_to_cpu(free->hdr.nused)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad free block nused %d should be %d for dir " | 
 | 				 "ino %lld block %d\n"), | 
 | 				be32_to_cpu(free->hdr.nused), used, id->ino, | 
 | 				dabno); | 
 | 		error++; | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  * Get address of the bestcount field in the single-leaf block. | 
 |  */ | 
 | static inline int | 
 | xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp) | 
 | { | 
 | 	if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || | 
 | 	    lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { | 
 | 		struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp; | 
 |  | 
 | 		return be16_to_cpu(lp3->hdr.count); | 
 | 	} | 
 | 	return be16_to_cpu(lp->hdr.count); | 
 | } | 
 |  | 
 | static void | 
 | process_leaf_node_dir_v2_int( | 
 | 	inodata_t		*id, | 
 | 	int			v, | 
 | 	xfs_dablk_t		dabno, | 
 | 	freetab_t		*freetab) | 
 | { | 
 | 	int			i; | 
 | 	__be16			*lbp; | 
 | 	xfs_dir2_leaf_t		*leaf; | 
 | 	struct xfs_dir3_leaf	*leaf3 = NULL; | 
 | 	xfs_dir2_leaf_entry_t	*lep; | 
 | 	xfs_dir2_leaf_tail_t	*ltp; | 
 | 	xfs_da_intnode_t	*node; | 
 | 	int			stale; | 
 | 	struct xfs_da3_icnode_hdr nodehdr; | 
 | 	struct xfs_dir3_icleaf_hdr leafhdr; | 
 |  | 
 | 	leaf = iocur_top->data; | 
 | 	libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf); | 
 |  | 
 | 	switch (be16_to_cpu(leaf->hdr.info.magic)) { | 
 | 	case XFS_DIR3_LEAF1_MAGIC: | 
 | 	case XFS_DIR3_LEAFN_MAGIC: | 
 | 	case XFS_DA3_NODE_MAGIC: | 
 | 		leaf3 = iocur_top->data; | 
 | 		break; | 
 | 	} | 
 | 	switch (be16_to_cpu(leaf->hdr.info.magic)) { | 
 | 	case XFS_DIR2_LEAF1_MAGIC: | 
 | 	case XFS_DIR3_LEAF1_MAGIC: | 
 | 		if (be32_to_cpu(leaf->hdr.info.forw) || | 
 | 					be32_to_cpu(leaf->hdr.info.back)) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("bad leaf block forw/back pointers " | 
 | 					 "%d/%d for dir ino %lld block %d\n"), | 
 | 					be32_to_cpu(leaf->hdr.info.forw), | 
 | 					be32_to_cpu(leaf->hdr.info.back), | 
 | 					id->ino, dabno); | 
 | 			error++; | 
 | 		} | 
 | 		if (dabno != mp->m_dir_geo->leafblk) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("single leaf block for dir ino %lld " | 
 | 					 "block %d should be at block %d\n"), | 
 | 					id->ino, dabno, | 
 | 					(xfs_dablk_t)mp->m_dir_geo->leafblk); | 
 | 			error++; | 
 | 		} | 
 | 		ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); | 
 | 		lbp = xfs_dir2_leaf_bests_p(ltp); | 
 | 		for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) { | 
 | 			if (freetab->nents <= i || freetab->ents[i] != | 
 | 						be16_to_cpu(lbp[i])) { | 
 | 				if (!sflag || v) | 
 | 					dbprintf(_("bestfree %d for dir ino %lld " | 
 | 						 "block %d doesn't match table " | 
 | 						 "value %d\n"), | 
 | 						freetab->nents <= i ? | 
 | 							NULLDATAOFF : | 
 | 							freetab->ents[i], | 
 | 						id->ino, | 
 | 						xfs_dir2_db_to_da(mp->m_dir_geo, i), | 
 | 						be16_to_cpu(lbp[i])); | 
 | 			} | 
 | 			if (freetab->nents > i) | 
 | 				freetab->ents[i] = NULLDATAOFF; | 
 | 		} | 
 | 		break; | 
 | 	case XFS_DIR2_LEAFN_MAGIC: | 
 | 	case XFS_DIR3_LEAFN_MAGIC: | 
 | 		/* if it's at the root location then we can check the | 
 | 		 * pointers are null XXX */ | 
 | 		break; | 
 | 	case XFS_DA_NODE_MAGIC: | 
 | 	case XFS_DA3_NODE_MAGIC: | 
 | 		node = iocur_top->data; | 
 | 		libxfs_da3_node_hdr_from_disk(mp, &nodehdr, node); | 
 | 		if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("bad node block level %d for dir ino " | 
 | 					 "%lld block %d\n"), | 
 | 					nodehdr.level, id->ino, | 
 | 					dabno); | 
 | 			error++; | 
 | 		} | 
 | 		return; | 
 | 	default: | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("bad directory data magic # %#x for dir ino " | 
 | 				 "%lld block %d\n"), | 
 | 				be16_to_cpu(leaf->hdr.info.magic), id->ino, | 
 | 				dabno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	lep = leafhdr.ents; | 
 | 	for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) { | 
 | 		if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR) | 
 | 			stale++; | 
 | 		else if (dir_hash_see(be32_to_cpu(lep[i].hashval), | 
 | 						be32_to_cpu(lep[i].address))) { | 
 | 			if (!sflag || v) | 
 | 				dbprintf(_("dir %lld block %d extra leaf entry " | 
 | 					 "%x %x\n"), id->ino, dabno, | 
 | 					be32_to_cpu(lep[i].hashval), | 
 | 					be32_to_cpu(lep[i].address)); | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | 	if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir3 %lld block %d stale mismatch " | 
 | 				 "%d/%d\n"), | 
 | 				 id->ino, dabno, stale, | 
 | 				 be16_to_cpu(leaf3->hdr.stale)); | 
 | 		error++; | 
 | 	} else if (!leaf3 && stale != be16_to_cpu(leaf->hdr.stale)) { | 
 | 		if (!sflag || v) | 
 | 			dbprintf(_("dir %lld block %d stale mismatch " | 
 | 				 "%d/%d\n"), | 
 | 				 id->ino, dabno, stale, | 
 | 				 be16_to_cpu(leaf->hdr.stale)); | 
 | 		error++; | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | process_quota( | 
 | 	qtype_t			qtype, | 
 | 	inodata_t		*id, | 
 | 	blkmap_t		*blkmap) | 
 | { | 
 | 	xfs_fsblock_t		bno; | 
 | 	int			cb; | 
 | 	struct xfs_dqblk	*dqb; | 
 | 	xfs_dqid_t		dqid; | 
 | 	uint8_t			exp_flags = 0; | 
 | 	uint			i; | 
 | 	uint			perblock; | 
 | 	xfs_fileoff_t		qbno; | 
 | 	char			*s = NULL; | 
 | 	int			scicb; | 
 | 	int			t = 0; | 
 |  | 
 | 	switch (qtype) { | 
 | 	case IS_USER_QUOTA: | 
 | 		s = "user"; | 
 | 		exp_flags = XFS_DQTYPE_USER; | 
 | 		break; | 
 | 	case IS_PROJECT_QUOTA: | 
 | 		s = "project"; | 
 | 		exp_flags = XFS_DQTYPE_PROJ; | 
 | 		break; | 
 | 	case IS_GROUP_QUOTA: | 
 | 		s = "group"; | 
 | 		exp_flags = XFS_DQTYPE_GROUP; | 
 | 		break; | 
 | 	default: | 
 | 		ASSERT(0); | 
 | 	} | 
 |  | 
 | 	perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb)); | 
 | 	dqid = 0; | 
 | 	qbno = NULLFILEOFF; | 
 | 	while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) { | 
 | 		bno = blkmap_get(blkmap, qbno); | 
 | 		dqid = (xfs_dqid_t)qbno * perblock; | 
 | 		cb = CHECK_BLIST(bno); | 
 | 		scicb = !sflag || id->ilist || cb; | 
 | 		push_cur(); | 
 | 		set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb, | 
 | 			DB_RING_IGN, NULL); | 
 | 		if ((dqb = iocur_top->data) == NULL) { | 
 | 			if (scicb) | 
 | 				dbprintf(_("can't read block %lld for %s quota " | 
 | 					 "inode (fsblock %lld)\n"), | 
 | 					(xfs_fileoff_t)qbno, s, | 
 | 					(xfs_fsblock_t)bno); | 
 | 			error++; | 
 | 			pop_cur(); | 
 | 			continue; | 
 | 		} | 
 | 		for (i = 0; i < perblock; i++, dqid++, dqb++) { | 
 | 			if (verbose || id->ilist || cb) | 
 | 				dbprintf(_("%s dqblk %lld entry %d id %u bc " | 
 | 					 "%lld ic %lld rc %lld\n"), | 
 | 					s, (xfs_fileoff_t)qbno, i, dqid, | 
 | 					be64_to_cpu(dqb->dd_diskdq.d_bcount), | 
 | 					be64_to_cpu(dqb->dd_diskdq.d_icount), | 
 | 					be64_to_cpu(dqb->dd_diskdq.d_rtbcount)); | 
 | 			if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) { | 
 | 				if (scicb) | 
 | 					dbprintf(_("bad magic number %#x for %s " | 
 | 						 "dqblk %lld entry %d id %u\n"), | 
 | 						be16_to_cpu(dqb->dd_diskdq.d_magic), s, | 
 | 						(xfs_fileoff_t)qbno, i, dqid); | 
 | 				error++; | 
 | 				continue; | 
 | 			} | 
 | 			if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) { | 
 | 				if (scicb) | 
 | 					dbprintf(_("bad version number %#x for " | 
 | 						 "%s dqblk %lld entry %d id " | 
 | 						 "%u\n"), | 
 | 						dqb->dd_diskdq.d_version, s, | 
 | 						(xfs_fileoff_t)qbno, i, dqid); | 
 | 				error++; | 
 | 				continue; | 
 | 			} | 
 | 			if (dqb->dd_diskdq.d_type & ~XFS_DQTYPE_ANY) { | 
 | 				if (scicb) | 
 | 					dbprintf(_("bad flags %#x for %s dqblk " | 
 | 						 "%lld entry %d id %u\n"), | 
 | 						dqb->dd_diskdq.d_type, s, | 
 | 						(xfs_fileoff_t)qbno, i, dqid); | 
 | 				error++; | 
 | 				continue; | 
 | 			} | 
 | 			if ((dqb->dd_diskdq.d_type & XFS_DQTYPE_REC_MASK) | 
 | 								!= exp_flags) { | 
 | 				if (scicb) | 
 | 					dbprintf(_("wrong type %#x for %s dqblk " | 
 | 						 "%lld entry %d id %u\n"), | 
 | 						dqb->dd_diskdq.d_type & | 
 | 							XFS_DQTYPE_REC_MASK, s, | 
 | 						(xfs_fileoff_t)qbno, i, dqid); | 
 | 				error++; | 
 | 				continue; | 
 | 			} | 
 | 			if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) { | 
 | 				if (scicb) | 
 | 					dbprintf(_("bad id %u for %s dqblk %lld " | 
 | 						 "entry %d id %u\n"), | 
 | 						be32_to_cpu(dqb->dd_diskdq.d_id), s, | 
 | 						(xfs_fileoff_t)qbno, i, dqid); | 
 | 				error++; | 
 | 				continue; | 
 | 			} | 
 | 			quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL, | 
 | 				  (qtype == IS_GROUP_QUOTA) ? &dqid : NULL, | 
 | 				  (qtype == IS_USER_QUOTA) ? &dqid : NULL, | 
 | 				  1, | 
 | 				  be64_to_cpu(dqb->dd_diskdq.d_bcount), | 
 | 				  be64_to_cpu(dqb->dd_diskdq.d_icount), | 
 | 				  be64_to_cpu(dqb->dd_diskdq.d_rtbcount)); | 
 | 		} | 
 | 		pop_cur(); | 
 | 	} | 
 | } | 
 |  | 
 | static inline void | 
 | inc_sumcount( | 
 | 	struct xfs_mount	*mp, | 
 | 	union xfs_suminfo_raw	*info, | 
 | 	xfs_rtsumoff_t		index) | 
 | { | 
 | 	union xfs_suminfo_raw	*p = info + index; | 
 |  | 
 | 	p->old++; | 
 | } | 
 |  | 
 | static void | 
 | process_rtbitmap( | 
 | 	blkmap_t	*blkmap) | 
 | { | 
 | 	int		bit; | 
 | 	int		bitsperblock; | 
 | 	xfs_fileoff_t	bmbno; | 
 | 	xfs_fsblock_t	bno; | 
 | 	xfs_rtxnum_t	extno; | 
 | 	int		len; | 
 | 	int		log; | 
 | 	int		offs; | 
 | 	int		prevbit; | 
 | 	xfs_rfsblock_t	rtbno; | 
 | 	int		start_bmbno; | 
 | 	int		start_bit; | 
 | 	int		t; | 
 | 	xfs_rtword_t	*words; | 
 |  | 
 | 	bitsperblock = mp->m_blockwsize << XFS_NBWORDLOG; | 
 | 	words = malloc(mp->m_blockwsize << XFS_WORDLOG); | 
 | 	if (!words) { | 
 | 		dbprintf(_("could not allocate rtwords buffer\n")); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	bit = extno = prevbit = start_bmbno = start_bit = 0; | 
 | 	bmbno = NULLFILEOFF; | 
 | 	while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) != NULLFILEOFF) { | 
 | 		struct xfs_rtalloc_args	args = { | 
 | 			.mp		= mp, | 
 | 		}; | 
 | 		xfs_rtword_t	*incore = words; | 
 | 		unsigned int	i; | 
 |  | 
 | 		bno = blkmap_get(blkmap, bmbno); | 
 | 		if (bno == NULLFSBLOCK) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("block %lld for rtbitmap inode is " | 
 | 					 "missing\n"), | 
 | 					(xfs_fileoff_t)bmbno); | 
 | 			error++; | 
 | 			continue; | 
 | 		} | 
 | 		push_cur(); | 
 | 		set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb, | 
 | 			DB_RING_IGN, NULL); | 
 | 		if (!iocur_top->bp) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("can't read block %lld for rtbitmap " | 
 | 					 "inode\n"), | 
 | 					(xfs_fileoff_t)bmbno); | 
 | 			error++; | 
 | 			pop_cur(); | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		args.rbmbp = iocur_top->bp; | 
 | 		for (i = 0; i < mp->m_blockwsize; i++, incore++) | 
 | 			*incore = libxfs_rtbitmap_getword(&args, i); | 
 |  | 
 | 		for (bit = 0; | 
 | 		     bit < bitsperblock && extno < mp->m_sb.sb_rextents; | 
 | 		     bit++, extno++) { | 
 | 			if (xfs_isset(words, bit)) { | 
 | 				rtbno = extno * mp->m_sb.sb_rextsize; | 
 | 				set_rdbmap(rtbno, mp->m_sb.sb_rextsize, | 
 | 					DBM_RTFREE); | 
 | 				frextents++; | 
 | 				if (prevbit == 0) { | 
 | 					start_bmbno = (int)bmbno; | 
 | 					start_bit = bit; | 
 | 					prevbit = 1; | 
 | 				} | 
 | 			} else if (prevbit == 1) { | 
 | 				len = ((int)bmbno - start_bmbno) * | 
 | 					bitsperblock + (bit - start_bit); | 
 | 				log = libxfs_highbit64(len); | 
 | 				offs = xfs_rtsumoffs(mp, log, start_bmbno); | 
 | 				inc_sumcount(mp, sumcompute, offs); | 
 | 				prevbit = 0; | 
 | 			} | 
 | 		} | 
 | 		pop_cur(); | 
 | 		if (extno == mp->m_sb.sb_rextents) | 
 | 			break; | 
 | 	} | 
 | 	if (prevbit == 1) { | 
 | 		len = ((int)bmbno - start_bmbno) * bitsperblock + | 
 | 			(bit - start_bit); | 
 | 		log = libxfs_highbit64(len); | 
 | 		offs = xfs_rtsumoffs(mp, log, start_bmbno); | 
 | 		inc_sumcount(mp, sumcompute, offs); | 
 | 	} | 
 | 	free(words); | 
 | } | 
 |  | 
 | static void | 
 | process_rtsummary( | 
 | 	blkmap_t	*blkmap) | 
 | { | 
 | 	xfs_fsblock_t	bno; | 
 | 	union xfs_suminfo_raw *sfile = sumfile; | 
 | 	xfs_fileoff_t	sumbno; | 
 | 	int		t; | 
 |  | 
 | 	sumbno = NULLFILEOFF; | 
 | 	while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) { | 
 | 		struct xfs_rtalloc_args	args = { | 
 | 			.mp		= mp, | 
 | 		}; | 
 | 		union xfs_suminfo_raw	*ondisk; | 
 |  | 
 | 		bno = blkmap_get(blkmap, sumbno); | 
 | 		if (bno == NULLFSBLOCK) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("block %lld for rtsummary inode is " | 
 | 					 "missing\n"), | 
 | 					(xfs_fileoff_t)sumbno); | 
 | 			error++; | 
 | 			continue; | 
 | 		} | 
 | 		push_cur(); | 
 | 		set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno), | 
 | 			blkbb, DB_RING_IGN, NULL); | 
 | 		if (!iocur_top->bp) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("can't read block %lld for rtsummary " | 
 | 					 "inode\n"), | 
 | 					(xfs_fileoff_t)sumbno); | 
 | 			error++; | 
 | 			pop_cur(); | 
 | 			sfile += mp->m_blockwsize; | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		args.sumbp = iocur_top->bp; | 
 | 		ondisk = xfs_rsumblock_infoptr(&args, 0); | 
 | 		memcpy(sfile, ondisk, mp->m_blockwsize << XFS_WORDLOG); | 
 | 		pop_cur(); | 
 | 		sfile += mp->m_blockwsize; | 
 | 	} | 
 | } | 
 |  | 
 | static xfs_ino_t | 
 | process_sf_dir_v2( | 
 | 	struct xfs_dinode	*dip, | 
 | 	int			*dot, | 
 | 	int			*dotdot, | 
 | 	inodata_t		*id) | 
 | { | 
 | 	inodata_t		*cid; | 
 | 	int			i; | 
 | 	int			i8; | 
 | 	xfs_ino_t		lino; | 
 | 	int			offset; | 
 | 	struct xfs_dir2_sf_hdr	*sf; | 
 | 	xfs_dir2_sf_entry_t	*sfe; | 
 | 	int			v; | 
 |  | 
 | 	sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip); | 
 | 	addlink_inode(id); | 
 | 	v = verbose || id->ilist; | 
 | 	if (v) | 
 | 		dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino); | 
 | 	(*dot)++; | 
 | 	sfe = xfs_dir2_sf_firstentry(sf); | 
 | 	offset = mp->m_dir_geo->data_first_offset; | 
 | 	for (i = sf->count - 1, i8 = 0; i >= 0; i--) { | 
 | 		if ((intptr_t)sfe + | 
 | 		    libxfs_dir2_sf_entsize(mp, sf, sfe->namelen) - | 
 | 		    (intptr_t)sf > be64_to_cpu(dip->di_size)) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("dir %llu bad size in entry at %d\n"), | 
 | 					id->ino, | 
 | 					(int)((char *)sfe - (char *)sf)); | 
 | 			error++; | 
 | 			break; | 
 | 		} | 
 | 		lino = libxfs_dir2_sf_get_ino(mp, sf, sfe); | 
 | 		if (lino > XFS_DIR2_MAX_SHORT_INUM) | 
 | 			i8++; | 
 | 		cid = find_inode(lino, 1); | 
 | 		if (cid == NULL) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("dir %lld entry %*.*s bad inode " | 
 | 					 "number %lld\n"), | 
 | 					id->ino, sfe->namelen, sfe->namelen, | 
 | 					sfe->name, lino); | 
 | 			error++; | 
 | 		} else { | 
 | 			addlink_inode(cid); | 
 | 			if (!cid->parent) | 
 | 				cid->parent = id; | 
 | 			addname_inode(cid, (char *)sfe->name, sfe->namelen); | 
 | 		} | 
 | 		if (v) | 
 | 			dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"), | 
 | 				id->ino, sfe->namelen, sfe->namelen, sfe->name, | 
 | 				xfs_dir2_sf_get_offset(sfe), lino); | 
 | 		if (xfs_dir2_sf_get_offset(sfe) < offset) { | 
 | 			if (!sflag) | 
 | 				dbprintf(_("dir %lld entry %*.*s bad offset %d\n"), | 
 | 					id->ino, sfe->namelen, sfe->namelen, | 
 | 					sfe->name, xfs_dir2_sf_get_offset(sfe)); | 
 | 			error++; | 
 | 		} | 
 | 		offset = | 
 | 			xfs_dir2_sf_get_offset(sfe) + | 
 | 			libxfs_dir2_sf_entsize(mp, sf, sfe->namelen); | 
 | 		sfe = libxfs_dir2_sf_nextentry(mp, sf, sfe); | 
 | 	} | 
 | 	if (i < 0 && (intptr_t)sfe - (intptr_t)sf != | 
 | 					be64_to_cpu(dip->di_size)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("dir %llu size is %lld, should be %u\n"), | 
 | 				id->ino, be64_to_cpu(dip->di_size), | 
 | 				(uint)((char *)sfe - (char *)sf)); | 
 | 		error++; | 
 | 	} | 
 | 	if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) + | 
 | 	    sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("dir %llu offsets too high\n"), id->ino); | 
 | 		error++; | 
 | 	} | 
 | 	lino = libxfs_dir2_sf_get_parent_ino(sf); | 
 | 	if (lino > XFS_DIR2_MAX_SHORT_INUM) | 
 | 		i8++; | 
 | 	cid = find_inode(lino, 1); | 
 | 	if (cid) | 
 | 		addlink_inode(cid); | 
 | 	else { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("dir %lld entry .. bad inode number %lld\n"), | 
 | 				id->ino, lino); | 
 | 		error++; | 
 | 	} | 
 | 	if (v) | 
 | 		dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino); | 
 | 	if (i8 != sf->i8count) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("dir %lld i8count mismatch is %d should be " | 
 | 				 "%d\n"), | 
 | 				id->ino, sf->i8count, i8); | 
 | 		error++; | 
 | 	} | 
 | 	(*dotdot)++; | 
 | 	return cid ? lino : NULLFSINO; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | quota_add( | 
 | 	xfs_dqid_t	*prjid, | 
 | 	xfs_dqid_t	*grpid, | 
 | 	xfs_dqid_t	*usrid, | 
 | 	int		dq, | 
 | 	xfs_qcnt_t	bc, | 
 | 	xfs_qcnt_t	ic, | 
 | 	xfs_qcnt_t	rc) | 
 | { | 
 | 	if (qudo && usrid != NULL) | 
 | 		quota_add1(qudata, *usrid, dq, bc, ic, rc); | 
 | 	if (qgdo && grpid != NULL) | 
 | 		quota_add1(qgdata, *grpid, dq, bc, ic, rc); | 
 | 	if (qpdo && prjid != NULL) | 
 | 		quota_add1(qpdata, *prjid, dq, bc, ic, rc); | 
 | } | 
 |  | 
 | static void | 
 | quota_add1( | 
 | 	qdata_t		**qt, | 
 | 	xfs_dqid_t	id, | 
 | 	int		dq, | 
 | 	xfs_qcnt_t	bc, | 
 | 	xfs_qcnt_t	ic, | 
 | 	xfs_qcnt_t	rc) | 
 | { | 
 | 	qdata_t		*qe; | 
 | 	int		qh; | 
 | 	qinfo_t		*qi; | 
 |  | 
 | 	qh = (int)(id % QDATA_HASH_SIZE); | 
 | 	qe = qt[qh]; | 
 | 	while (qe) { | 
 | 		if (qe->id == id) { | 
 | 			qi = dq ? &qe->dq : &qe->count; | 
 | 			qi->bc += bc; | 
 | 			qi->ic += ic; | 
 | 			qi->rc += rc; | 
 | 			return; | 
 | 		} | 
 | 		qe = qe->next; | 
 | 	} | 
 | 	qe = xmalloc(sizeof(*qe)); | 
 | 	qe->id = id; | 
 | 	qi = dq ? &qe->dq : &qe->count; | 
 | 	qi->bc = bc; | 
 | 	qi->ic = ic; | 
 | 	qi->rc = rc; | 
 | 	qi = dq ? &qe->count : &qe->dq; | 
 | 	qi->bc = qi->ic = qi->rc = 0; | 
 | 	qe->next = qt[qh]; | 
 | 	qt[qh] = qe; | 
 | } | 
 |  | 
 | static void | 
 | quota_check( | 
 | 	char	*s, | 
 | 	qdata_t	**qt) | 
 | { | 
 | 	int	i; | 
 | 	qdata_t	*next; | 
 | 	qdata_t	*qp; | 
 |  | 
 | 	for (i = 0; i < QDATA_HASH_SIZE; i++) { | 
 | 		qp = qt[i]; | 
 | 		while (qp) { | 
 | 			next = qp->next; | 
 | 			if (qp->count.bc != qp->dq.bc || | 
 | 			    qp->count.ic != qp->dq.ic || | 
 | 			    qp->count.rc != qp->dq.rc) { | 
 | 				if (!sflag) { | 
 | 					dbprintf(_("%s quota id %u, have/exp"), | 
 | 						s, qp->id); | 
 | 					if (qp->count.bc != qp->dq.bc) | 
 | 						dbprintf(_(" bc %lld/%lld"), | 
 | 							qp->dq.bc, | 
 | 							qp->count.bc); | 
 | 					if (qp->count.ic != qp->dq.ic) | 
 | 						dbprintf(_(" ic %lld/%lld"), | 
 | 							qp->dq.ic, | 
 | 							qp->count.ic); | 
 | 					if (qp->count.rc != qp->dq.rc) | 
 | 						dbprintf(_(" rc %lld/%lld"), | 
 | 							qp->dq.rc, | 
 | 							qp->count.rc); | 
 | 					dbprintf("\n"); | 
 | 				} | 
 | 				error++; | 
 | 			} | 
 | 			xfree(qp); | 
 | 			qp = next; | 
 | 		} | 
 | 	} | 
 | 	xfree(qt); | 
 | } | 
 |  | 
 | static void | 
 | quota_init(void) | 
 | { | 
 | 	qudo = mp->m_sb.sb_uquotino != 0 && | 
 | 	       mp->m_sb.sb_uquotino != NULLFSINO && | 
 | 	       (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && | 
 | 	       (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD); | 
 | 	qgdo = mp->m_sb.sb_gquotino != 0 && | 
 | 	       mp->m_sb.sb_gquotino != NULLFSINO && | 
 | 	       (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && | 
 | 	       (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD); | 
 | 	qpdo = mp->m_sb.sb_pquotino != 0 && | 
 | 	       mp->m_sb.sb_pquotino != NULLFSINO && | 
 | 	       (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) && | 
 | 	       (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD); | 
 | 	if (qudo) | 
 | 		qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); | 
 | 	if (qgdo) | 
 | 		qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); | 
 | 	if (qpdo) | 
 | 		qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); | 
 | } | 
 |  | 
 | static void | 
 | scan_ag( | 
 | 	xfs_agnumber_t	agno) | 
 | { | 
 | 	xfs_agf_t	*agf; | 
 | 	xfs_agi_t	*agi; | 
 | 	int		i; | 
 | 	xfs_sb_t	tsb; | 
 | 	xfs_sb_t	*sb = &tsb; | 
 |  | 
 | 	agffreeblks = agflongest = 0; | 
 | 	agfbtreeblks = -2; | 
 | 	agicount = agifreecount = 0; | 
 | 	push_cur();	/* 1 pushed */ | 
 | 	set_cur(&typtab[TYP_SB], | 
 | 		XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), | 
 | 		XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | 
 |  | 
 | 	if (!iocur_top->data) { | 
 | 		dbprintf(_("can't read superblock for ag %u\n"), agno); | 
 | 		serious_error++; | 
 | 		goto pop1_out; | 
 | 	} | 
 |  | 
 | 	libxfs_sb_from_disk(sb, iocur_top->data); | 
 |  | 
 | 	if (sb->sb_magicnum != XFS_SB_MAGIC) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad sb magic # %#x in ag %u\n"), | 
 | 				sb->sb_magicnum, agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (!xfs_sb_good_version(sb)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad sb version # %#x in ag %u\n"), | 
 | 				sb->sb_versionnum, agno); | 
 | 		error++; | 
 | 		sbver_err++; | 
 | 	} | 
 | 	if (!lazycount && xfs_sb_version_haslazysbcount(sb)) { | 
 | 		lazycount = 1; | 
 | 	} | 
 | 	if (agno == 0 && sb->sb_inprogress != 0) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("mkfs not completed successfully\n")); | 
 | 		error++; | 
 | 	} | 
 | 	if (xfs_sb_version_needsrepair(sb)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("filesystem needs xfs_repair\n")); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp)); | 
 | 	if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno) | 
 | 		set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart), | 
 | 			sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp)); | 
 | 	push_cur();	/* 2 pushed */ | 
 | 	set_cur(&typtab[TYP_AGF], | 
 | 		XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), | 
 | 		XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | 
 | 	if ((agf = iocur_top->data) == NULL) { | 
 | 		dbprintf(_("can't read agf block for ag %u\n"), agno); | 
 | 		serious_error++; | 
 | 		goto pop2_out; | 
 | 	} | 
 | 	if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad agf magic # %#x in ag %u\n"), | 
 | 				be32_to_cpu(agf->agf_magicnum), agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad agf version # %#x in ag %u\n"), | 
 | 				be32_to_cpu(agf->agf_versionnum), agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp)) | 
 | 		set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno, | 
 | 			XFS_SB_BLOCK(mp)); | 
 | 	if (sb->sb_agblocks > be32_to_cpu(agf->agf_length)) | 
 | 		set_dbmap(agno, be32_to_cpu(agf->agf_length), | 
 | 			sb->sb_agblocks - be32_to_cpu(agf->agf_length), | 
 | 			DBM_MISSING, agno, XFS_SB_BLOCK(mp)); | 
 | 	push_cur();	/* 3 pushed */ | 
 | 	set_cur(&typtab[TYP_AGI], | 
 | 		XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), | 
 | 		XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | 
 | 	if ((agi = iocur_top->data) == NULL) { | 
 | 		dbprintf(_("can't read agi block for ag %u\n"), agno); | 
 | 		serious_error++; | 
 | 		goto pop3_out; | 
 | 	} | 
 | 	if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad agi magic # %#x in ag %u\n"), | 
 | 				be32_to_cpu(agi->agi_magicnum), agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("bad agi version # %#x in ag %u\n"), | 
 | 				be32_to_cpu(agi->agi_versionnum), agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) && | 
 | 	    XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp)) | 
 | 		set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno, | 
 | 			XFS_SB_BLOCK(mp)); | 
 | 	scan_freelist(agf); | 
 | 	fdblocks--; | 
 | 	scan_sbtree(agf, | 
 | 		be32_to_cpu(agf->agf_bno_root), | 
 | 		be32_to_cpu(agf->agf_bno_level), | 
 | 		1, scanfunc_bno, TYP_BNOBT); | 
 | 	fdblocks--; | 
 | 	scan_sbtree(agf, | 
 | 		be32_to_cpu(agf->agf_cnt_root), | 
 | 		be32_to_cpu(agf->agf_cnt_level), | 
 | 		1, scanfunc_cnt, TYP_CNTBT); | 
 | 	if (agf->agf_rmap_root) { | 
 | 		scan_sbtree(agf, | 
 | 			be32_to_cpu(agf->agf_rmap_root), | 
 | 			be32_to_cpu(agf->agf_rmap_level), | 
 | 			1, scanfunc_rmap, TYP_RMAPBT); | 
 | 	} | 
 | 	if (agf->agf_refcount_root) { | 
 | 		scan_sbtree(agf, | 
 | 			be32_to_cpu(agf->agf_refcount_root), | 
 | 			be32_to_cpu(agf->agf_refcount_level), | 
 | 			1, scanfunc_refcnt, TYP_REFCBT); | 
 | 	} | 
 | 	scan_sbtree(agf, | 
 | 		be32_to_cpu(agi->agi_root), | 
 | 		be32_to_cpu(agi->agi_level), | 
 | 		1, scanfunc_ino, TYP_INOBT); | 
 | 	if (agi->agi_free_root) { | 
 | 		scan_sbtree(agf, | 
 | 			be32_to_cpu(agi->agi_free_root), | 
 | 			be32_to_cpu(agi->agi_free_level), | 
 | 			1, scanfunc_fino, TYP_FINOBT); | 
 | 	} | 
 | 	if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"), | 
 | 				be32_to_cpu(agf->agf_freeblks), | 
 | 				agffreeblks, agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (be32_to_cpu(agf->agf_longest) != agflongest) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("agf_longest %u, counted %u in ag %u\n"), | 
 | 				be32_to_cpu(agf->agf_longest), | 
 | 				agflongest, agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (lazycount && | 
 | 	    be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"), | 
 | 				be32_to_cpu(agf->agf_btreeblks), | 
 | 				agfbtreeblks, agno); | 
 | 		error++; | 
 | 	} | 
 | 	agf_aggr_freeblks += agffreeblks + agfbtreeblks; | 
 | 	if (be32_to_cpu(agi->agi_count) != agicount) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("agi_count %u, counted %u in ag %u\n"), | 
 | 				be32_to_cpu(agi->agi_count), | 
 | 				agicount, agno); | 
 | 		error++; | 
 | 	} | 
 | 	if (be32_to_cpu(agi->agi_freecount) != agifreecount) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("agi_freecount %u, counted %u in ag %u\n"), | 
 | 				be32_to_cpu(agi->agi_freecount), | 
 | 				agifreecount, agno); | 
 | 		error++; | 
 | 	} | 
 | 	for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { | 
 | 		if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) { | 
 | 			if (!sflag) { | 
 | 				xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]); | 
 | 				dbprintf(_("agi unlinked bucket %d is %u in ag " | 
 | 					 "%u (inode=%lld)\n"), i, agino, agno, | 
 | 					XFS_AGINO_TO_INO(mp, agno, agino)); | 
 | 			} | 
 | 			error++; | 
 | 		} | 
 | 	} | 
 | pop3_out: | 
 | 	pop_cur(); | 
 | pop2_out: | 
 | 	pop_cur(); | 
 | pop1_out: | 
 | 	pop_cur(); | 
 | } | 
 |  | 
 | struct agfl_state { | 
 | 	xfs_agnumber_t	agno; | 
 | 	unsigned int	count; | 
 | }; | 
 |  | 
 | static int | 
 | scan_agfl( | 
 | 	struct xfs_mount	*mp, | 
 | 	xfs_agblock_t		bno, | 
 | 	void			*priv) | 
 | { | 
 | 	struct agfl_state	*as = priv; | 
 |  | 
 | 	set_dbmap(as->agno, bno, 1, DBM_FREELIST, as->agno, XFS_AGFL_BLOCK(mp)); | 
 | 	as->count++; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void | 
 | scan_freelist( | 
 | 	xfs_agf_t		*agf) | 
 | { | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	struct agfl_state	state; | 
 |  | 
 | 	if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && | 
 | 	    XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && | 
 | 	    XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp)) | 
 | 		set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno, | 
 | 			XFS_SB_BLOCK(mp)); | 
 | 	if (be32_to_cpu(agf->agf_flcount) == 0) | 
 | 		return; | 
 | 	push_cur(); | 
 | 	set_cur(&typtab[TYP_AGFL], | 
 | 		XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)), | 
 | 		XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | 
 | 	if (iocur_top->data == NULL) { | 
 | 		dbprintf(_("can't read agfl block for ag %u\n"), seqno); | 
 | 		serious_error++; | 
 | 		pop_cur(); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* verify agf values before proceeding */ | 
 | 	if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) || | 
 | 	    be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) { | 
 | 		dbprintf(_("agf %d freelist blocks bad, skipping " | 
 | 			  "freelist scan\n"), seqno); | 
 | 		pop_cur(); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* open coded xfs_buf_to_agfl_bno */ | 
 | 	state.count = 0; | 
 | 	state.agno = seqno; | 
 | 	libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &state); | 
 | 	if (state.count != be32_to_cpu(agf->agf_flcount)) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("freeblk count %u != flcount %u in ag %u\n"), | 
 | 					state.count, | 
 | 					be32_to_cpu(agf->agf_flcount), | 
 | 					seqno); | 
 | 		error++; | 
 | 	} | 
 | 	fdblocks += state.count; | 
 | 	agf_aggr_freeblks += state.count; | 
 | 	pop_cur(); | 
 | } | 
 |  | 
 | static void | 
 | scan_lbtree( | 
 | 	xfs_fsblock_t	root, | 
 | 	int		nlevels, | 
 | 	scan_lbtree_f_t	func, | 
 | 	dbm_t		type, | 
 | 	inodata_t	*id, | 
 | 	xfs_rfsblock_t	*totd, | 
 | 	xfs_rfsblock_t	*toti, | 
 | 	xfs_extnum_t	*nex, | 
 | 	blkmap_t	**blkmapp, | 
 | 	int		isroot, | 
 | 	typnm_t		btype) | 
 | { | 
 | 	push_cur(); | 
 | 	set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN, | 
 | 		NULL); | 
 | 	if (iocur_top->data == NULL) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("can't read btree block %u/%u\n"), | 
 | 				XFS_FSB_TO_AGNO(mp, root), | 
 | 				XFS_FSB_TO_AGBNO(mp, root)); | 
 | 		error++; | 
 | 		pop_cur(); | 
 | 		return; | 
 | 	} | 
 | 	(*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex, | 
 | 		blkmapp, isroot, btype); | 
 | 	pop_cur(); | 
 | } | 
 |  | 
 | static void | 
 | scan_sbtree( | 
 | 	xfs_agf_t	*agf, | 
 | 	xfs_agblock_t	root, | 
 | 	int		nlevels, | 
 | 	int		isroot, | 
 | 	scan_sbtree_f_t	func, | 
 | 	typnm_t		btype) | 
 | { | 
 | 	xfs_agnumber_t	seqno = be32_to_cpu(agf->agf_seqno); | 
 |  | 
 | 	push_cur(); | 
 | 	set_cur(&typtab[btype], | 
 | 		XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL); | 
 | 	if (iocur_top->data == NULL) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("can't read btree block %u/%u\n"), seqno, root); | 
 | 		error++; | 
 | 		pop_cur(); | 
 | 		return; | 
 | 	} | 
 | 	(*func)(iocur_top->data, nlevels - 1, agf, root, isroot); | 
 | 	pop_cur(); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_bmap( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	dbm_t			type, | 
 | 	xfs_fsblock_t		bno, | 
 | 	inodata_t		*id, | 
 | 	xfs_rfsblock_t		*totd, | 
 | 	xfs_rfsblock_t		*toti, | 
 | 	xfs_extnum_t		*nex, | 
 | 	blkmap_t		**blkmapp, | 
 | 	int			isroot, | 
 | 	typnm_t			btype) | 
 | { | 
 | 	xfs_agblock_t		agbno; | 
 | 	xfs_agnumber_t		agno; | 
 | 	int			i; | 
 | 	xfs_bmbt_ptr_t		*pp; | 
 | 	xfs_bmbt_rec_t		*rp; | 
 |  | 
 | 	agno = XFS_FSB_TO_AGNO(mp, bno); | 
 | 	agbno = XFS_FSB_TO_AGBNO(mp, bno); | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC && | 
 | 	    be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("bad magic # %#x in inode %lld bmbt block " | 
 | 				 "%u/%u\n"), | 
 | 				be32_to_cpu(block->bb_magic), id->ino, agno, agbno); | 
 | 		error++; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("expected level %d got %d in inode %lld bmbt " | 
 | 				 "block %u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), id->ino, agno, agbno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(agno, agbno, 1, type, agno, agbno); | 
 | 	set_inomap(agno, agbno, 1, id); | 
 | 	(*toti)++; | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) { | 
 | 			if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 				dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) " | 
 | 					 "in inode %lld bmap block %lld\n"), | 
 | 					be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0], | 
 | 					mp->m_bmap_dmxr[0], id->ino, | 
 | 					(xfs_fsblock_t)bno); | 
 | 			error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = xfs_bmbt_rec_addr(mp, block, 1); | 
 | 		*nex += be16_to_cpu(block->bb_numrecs); | 
 | 		process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd, | 
 | 			blkmapp); | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) { | 
 | 		if (!sflag || id->ilist || CHECK_BLIST(bno)) | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "inode %lld bmap block %lld\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1], | 
 | 				mp->m_bmap_dmxr[1], id->ino, (xfs_fsblock_t)bno); | 
 | 		error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[0]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id, | 
 | 					totd, toti, nex, blkmapp, 0, btype); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_bno( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	xfs_agf_t		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	int			i; | 
 | 	xfs_alloc_ptr_t		*pp; | 
 | 	xfs_alloc_rec_t		*rp; | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	xfs_agblock_t		lastblock; | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC && | 
 | 	    be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in btbno block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	fdblocks++; | 
 | 	agfbtreeblks++; | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in btbno block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "btbno block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0], | 
 | 				mp->m_alloc_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_ALLOC_REC_ADDR(mp, block, 1); | 
 | 		lastblock = 0; | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock), | 
 | 				be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, | 
 | 				seqno, bno); | 
 | 			if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) { | 
 | 				dbprintf(_( | 
 | 		"out-of-order bno btree record %d (%u %u) block %u/%u\n"), | 
 | 				i, be32_to_cpu(rp[i].ar_startblock), | 
 | 				be32_to_cpu(rp[i].ar_blockcount), | 
 | 				be32_to_cpu(agf->agf_seqno), bno); | 
 | 				serious_error++; | 
 | 			} else { | 
 | 				lastblock = be32_to_cpu(rp[i].ar_startblock); | 
 | 			} | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block " | 
 | 			 "%u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1], | 
 | 			mp->m_alloc_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_cnt( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	xfs_agf_t		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	int			i; | 
 | 	xfs_alloc_ptr_t		*pp; | 
 | 	xfs_alloc_rec_t		*rp; | 
 | 	xfs_extlen_t		lastcount; | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC && | 
 | 	    be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	fdblocks++; | 
 | 	agfbtreeblks++; | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in btcnt block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "btbno block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0], | 
 | 				mp->m_alloc_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_ALLOC_REC_ADDR(mp, block, 1); | 
 | 		lastcount = 0; | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock), | 
 | 				be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2, | 
 | 				seqno, bno); | 
 | 			fdblocks += be32_to_cpu(rp[i].ar_blockcount); | 
 | 			agffreeblks += be32_to_cpu(rp[i].ar_blockcount); | 
 | 			if (be32_to_cpu(rp[i].ar_blockcount) > agflongest) | 
 | 				agflongest = be32_to_cpu(rp[i].ar_blockcount); | 
 | 			if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) { | 
 | 				dbprintf(_( | 
 | 		"out-of-order cnt btree record %d (%u %u) block %u/%u\n"), | 
 | 					 i, be32_to_cpu(rp[i].ar_startblock), | 
 | 					 be32_to_cpu(rp[i].ar_blockcount), | 
 | 					 be32_to_cpu(agf->agf_seqno), bno); | 
 | 			} else { | 
 | 				lastcount = be32_to_cpu(rp[i].ar_blockcount); | 
 | 			} | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block " | 
 | 			 "%u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1], | 
 | 			mp->m_alloc_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_ino( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	xfs_agf_t		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	xfs_agino_t		agino; | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	int			i; | 
 | 	int			isfree; | 
 | 	int			j; | 
 | 	int			freecount; | 
 | 	int			nfree; | 
 | 	int			off; | 
 | 	xfs_inobt_ptr_t		*pp; | 
 | 	xfs_inobt_rec_t		*rp; | 
 | 	xfs_agblock_t		agbno; | 
 | 	xfs_agblock_t		end_agbno; | 
 | 	struct xfs_dinode	*dip; | 
 | 	int			blks_per_buf; | 
 | 	int			inodes_per_buf; | 
 | 	int			ioff; | 
 | 	struct xfs_ino_geometry	*igeo = M_IGEO(mp); | 
 |  | 
 | 	if (xfs_has_sparseinodes(mp)) | 
 | 		blks_per_buf = igeo->blocks_per_cluster; | 
 | 	else | 
 | 		blks_per_buf = igeo->ialloc_blks; | 
 | 	inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), | 
 | 			     XFS_INODES_PER_CHUNK); | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC && | 
 | 	    be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in inobt block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in inobt block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "inobt block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0], | 
 | 				igeo->inobt_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_INOBT_REC_ADDR(mp, block, 1); | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			agino = be32_to_cpu(rp[i].ir_startino); | 
 | 			agbno = XFS_AGINO_TO_AGBNO(mp, agino); | 
 | 			off = XFS_AGINO_TO_OFFSET(mp, agino); | 
 | 			end_agbno = agbno + igeo->ialloc_blks; | 
 | 			if (off == 0) { | 
 | 				if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && | 
 | 				    mp->m_sb.sb_inoalignmt && | 
 | 				    (XFS_INO_TO_AGBNO(mp, agino) % | 
 | 				     mp->m_sb.sb_inoalignmt)) | 
 | 					sbversion &= ~XFS_SB_VERSION_ALIGNBIT; | 
 | 			} | 
 |  | 
 | 			push_cur(); | 
 |  | 
 | 			ioff = 0; | 
 | 			nfree = 0; | 
 | 			while (agbno < end_agbno && | 
 | 			       ioff < XFS_INODES_PER_CHUNK) { | 
 | 				if (xfs_inobt_is_sparse_disk(&rp[i], ioff)) | 
 | 					goto next_buf; | 
 |  | 
 | 				if (off < XFS_INODES_PER_CHUNK) | 
 | 					set_dbmap(seqno, agbno, blks_per_buf, | 
 | 						  DBM_INODE, seqno, bno); | 
 |  | 
 | 				icount += inodes_per_buf; | 
 | 				agicount += inodes_per_buf; | 
 |  | 
 | 				set_cur(&typtab[TYP_INODE], | 
 | 					XFS_AGB_TO_DADDR(mp, seqno, agbno), | 
 | 					XFS_FSB_TO_BB(mp, blks_per_buf), | 
 | 					DB_RING_IGN, NULL); | 
 | 				if (iocur_top->data == NULL) { | 
 | 					if (!sflag) | 
 | 						dbprintf(_("can't read inode block " | 
 | 							   "%u/%u\n"), seqno, | 
 | 							 agbno); | 
 | 					error++; | 
 | 					goto next_buf; | 
 | 				} | 
 |  | 
 | 				for (j = 0; j < inodes_per_buf; j++) { | 
 | 					isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j); | 
 | 					if (isfree) | 
 | 						nfree++; | 
 | 					dip = (struct xfs_dinode *)((char *)iocur_top->data + | 
 | 						((off + j) << mp->m_sb.sb_inodelog)); | 
 | 					process_inode(agf, agino + ioff + j, dip, isfree); | 
 | 				} | 
 |  | 
 | next_buf: | 
 | 				agbno += blks_per_buf; | 
 | 				ioff += inodes_per_buf; | 
 | 			} | 
 |  | 
 | 			if (xfs_has_sparseinodes(mp)) | 
 | 				freecount = rp[i].ir_u.sp.ir_freecount; | 
 | 			else | 
 | 				freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount); | 
 |  | 
 | 			ifree += freecount; | 
 | 			agifreecount += freecount; | 
 |  | 
 | 			if (nfree != freecount) { | 
 | 				if (!sflag) | 
 | 					dbprintf(_("ir_freecount/free mismatch, " | 
 | 						 "inode chunk %u/%u, freecount " | 
 | 						 "%d nfree %d\n"), | 
 | 						seqno, agino, freecount, nfree); | 
 | 				error++; | 
 | 			} | 
 | 			pop_cur(); | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block " | 
 | 			 "%u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1], | 
 | 			igeo->inobt_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_fino( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	struct xfs_agf		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	xfs_agino_t		agino; | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	int			i; | 
 | 	int			off; | 
 | 	xfs_inobt_ptr_t		*pp; | 
 | 	struct xfs_inobt_rec	*rp; | 
 | 	xfs_agblock_t		agbno; | 
 | 	xfs_agblock_t		end_agbno; | 
 | 	int			blks_per_buf; | 
 | 	int			inodes_per_buf; | 
 | 	int			ioff; | 
 | 	struct xfs_ino_geometry	*igeo = M_IGEO(mp); | 
 |  | 
 | 	if (xfs_has_sparseinodes(mp)) | 
 | 		blks_per_buf = igeo->blocks_per_cluster; | 
 | 	else | 
 | 		blks_per_buf = igeo->ialloc_blks; | 
 | 	inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf), | 
 | 			     XFS_INODES_PER_CHUNK); | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC && | 
 | 	    be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in finobt block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in finobt block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "finobt block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0], | 
 | 				igeo->inobt_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_INOBT_REC_ADDR(mp, block, 1); | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			agino = be32_to_cpu(rp[i].ir_startino); | 
 | 			agbno = XFS_AGINO_TO_AGBNO(mp, agino); | 
 | 			off = XFS_AGINO_TO_OFFSET(mp, agino); | 
 | 			end_agbno = agbno + igeo->ialloc_blks; | 
 | 			if (off == 0) { | 
 | 				if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && | 
 | 				    mp->m_sb.sb_inoalignmt && | 
 | 				    (XFS_INO_TO_AGBNO(mp, agino) % | 
 | 				     mp->m_sb.sb_inoalignmt)) | 
 | 					sbversion &= ~XFS_SB_VERSION_ALIGNBIT; | 
 | 			} | 
 |  | 
 | 			ioff = 0; | 
 | 			while (agbno < end_agbno && | 
 | 			       ioff < XFS_INODES_PER_CHUNK) { | 
 | 				if (xfs_inobt_is_sparse_disk(&rp[i], ioff)) | 
 | 					goto next_buf; | 
 |  | 
 |                                 check_set_dbmap(seqno, agbno, | 
 |                                         (xfs_extlen_t)max(1, | 
 |                                                 inodes_per_buf >> | 
 |                                                 mp->m_sb.sb_inopblog), | 
 |                                         DBM_INODE, DBM_INODE, seqno, bno); | 
 |  | 
 | next_buf: | 
 | 				agbno += blks_per_buf; | 
 | 				ioff += inodes_per_buf; | 
 | 			} | 
 |  | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block " | 
 | 			 "%u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1], | 
 | 			igeo->inobt_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_fino, TYP_FINOBT); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_rmap( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	struct xfs_agf		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	int			i; | 
 | 	xfs_rmap_ptr_t		*pp; | 
 | 	struct xfs_rmap_rec	*rp; | 
 | 	xfs_agblock_t		lastblock; | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in rmapbt block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	if (!isroot) { | 
 | 		fdblocks++; | 
 | 		agfbtreeblks++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "rmapbt block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0], | 
 | 				mp->m_rmap_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_RMAP_REC_ADDR(block, 1); | 
 | 		lastblock = 0; | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			if (be32_to_cpu(rp[i].rm_startblock) < lastblock) { | 
 | 				dbprintf(_( | 
 | 		"out-of-order rmap btree record %d (%u %u) block %u/%u\n"), | 
 | 					 i, be32_to_cpu(rp[i].rm_startblock), | 
 | 					 be32_to_cpu(rp[i].rm_startblock), | 
 | 					 be32_to_cpu(agf->agf_seqno), bno); | 
 | 			} else { | 
 | 				lastblock = be32_to_cpu(rp[i].rm_startblock); | 
 | 			} | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt " | 
 | 			 "block %u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1], | 
 | 			mp->m_rmap_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap, | 
 | 				TYP_RMAPBT); | 
 | } | 
 |  | 
 | static void | 
 | scanfunc_refcnt( | 
 | 	struct xfs_btree_block	*block, | 
 | 	int			level, | 
 | 	struct xfs_agf		*agf, | 
 | 	xfs_agblock_t		bno, | 
 | 	int			isroot) | 
 | { | 
 | 	xfs_agnumber_t		seqno = be32_to_cpu(agf->agf_seqno); | 
 | 	int			i; | 
 | 	xfs_refcount_ptr_t	*pp; | 
 | 	struct xfs_refcount_rec	*rp; | 
 | 	xfs_agblock_t		lastblock; | 
 |  | 
 | 	if (be32_to_cpu(block->bb_magic) != XFS_REFC_CRC_MAGIC) { | 
 | 		dbprintf(_("bad magic # %#x in refcntbt block %u/%u\n"), | 
 | 			be32_to_cpu(block->bb_magic), seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_level) != level) { | 
 | 		if (!sflag) | 
 | 			dbprintf(_("expected level %d got %d in refcntbt block " | 
 | 				 "%u/%u\n"), | 
 | 				level, be16_to_cpu(block->bb_level), seqno, bno); | 
 | 		error++; | 
 | 	} | 
 | 	set_dbmap(seqno, bno, 1, DBM_BTREFC, seqno, bno); | 
 | 	if (level == 0) { | 
 | 		if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[0] || | 
 | 		    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[0])) { | 
 | 			dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in " | 
 | 				 "refcntbt block %u/%u\n"), | 
 | 				be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0], | 
 | 				mp->m_refc_mxr[0], seqno, bno); | 
 | 			serious_error++; | 
 | 			return; | 
 | 		} | 
 | 		rp = XFS_REFCOUNT_REC_ADDR(block, 1); | 
 | 		lastblock = 0; | 
 | 		for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) { | 
 | 			if (be32_to_cpu(rp[i].rc_refcount) == 1) { | 
 | 				xfs_agblock_t	agbno; | 
 | 				char		*msg; | 
 |  | 
 | 				agbno = be32_to_cpu(rp[i].rc_startblock); | 
 | 				if (agbno & XFS_REFC_COWFLAG) { | 
 | 					agbno &= ~XFS_REFC_COWFLAG; | 
 | 					msg = _( | 
 | 		"leftover CoW extent (%u/%u) len %u\n"); | 
 | 				} else { | 
 | 					msg = _( | 
 | 		"leftover CoW extent at unexpected address (%u/%u) len %u\n"); | 
 | 				} | 
 | 				dbprintf(msg, | 
 | 					seqno, | 
 | 					agbno, | 
 | 					be32_to_cpu(rp[i].rc_blockcount)); | 
 | 				set_dbmap(seqno, | 
 | 					agbno, | 
 | 					be32_to_cpu(rp[i].rc_blockcount), | 
 | 					DBM_COWDATA, seqno, bno); | 
 | 			} else { | 
 | 				set_dbmap(seqno, | 
 | 					be32_to_cpu(rp[i].rc_startblock), | 
 | 					be32_to_cpu(rp[i].rc_blockcount), | 
 | 					DBM_RLDATA, seqno, bno); | 
 | 			} | 
 | 			if (be32_to_cpu(rp[i].rc_startblock) < lastblock) { | 
 | 				dbprintf(_( | 
 | 		"out-of-order refcnt btree record %d (%u %u) block %u/%u\n"), | 
 | 					 i, be32_to_cpu(rp[i].rc_startblock), | 
 | 					 be32_to_cpu(rp[i].rc_startblock), | 
 | 					 be32_to_cpu(agf->agf_seqno), bno); | 
 | 			} else { | 
 | 				lastblock = be32_to_cpu(rp[i].rc_startblock) + | 
 | 					    be32_to_cpu(rp[i].rc_blockcount); | 
 | 			} | 
 | 		} | 
 | 		return; | 
 | 	} | 
 | 	if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[1] || | 
 | 	    (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[1])) { | 
 | 		dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in refcntbt " | 
 | 			 "block %u/%u\n"), | 
 | 			be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1], | 
 | 			mp->m_refc_mxr[1], seqno, bno); | 
 | 		serious_error++; | 
 | 		return; | 
 | 	} | 
 | 	pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]); | 
 | 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) | 
 | 		scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_refcnt, | 
 | 				TYP_REFCBT); | 
 | } | 
 |  | 
 | static void | 
 | set_dbmap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type, | 
 | 	xfs_agnumber_t	c_agno, | 
 | 	xfs_agblock_t	c_agbno) | 
 | { | 
 | 	check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno); | 
 | } | 
 |  | 
 | static void | 
 | set_inomap( | 
 | 	xfs_agnumber_t	agno, | 
 | 	xfs_agblock_t	agbno, | 
 | 	xfs_extlen_t	len, | 
 | 	inodata_t	*id) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	inodata_t	**idp; | 
 | 	int		mayprint; | 
 |  | 
 | 	if (!check_inomap(agno, agbno, len, id->ino)) | 
 | 		return; | 
 | 	mayprint = verbose | id->ilist | blist_size; | 
 | 	for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) { | 
 | 		*idp = id; | 
 | 		if (mayprint && | 
 | 		    (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i))) | 
 | 			dbprintf(_("setting inode to %lld for block %u/%u\n"), | 
 | 				id->ino, agno, agbno + i); | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | set_rdbmap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	dbm_t		type) | 
 | { | 
 | 	check_set_rdbmap(bno, len, DBM_UNKNOWN, type); | 
 | } | 
 |  | 
 | static void | 
 | set_rinomap( | 
 | 	xfs_rfsblock_t	bno, | 
 | 	xfs_extlen_t	len, | 
 | 	inodata_t	*id) | 
 | { | 
 | 	xfs_extlen_t	i; | 
 | 	inodata_t	**idp; | 
 | 	int		mayprint; | 
 |  | 
 | 	if (!check_rinomap(bno, len, id->ino)) | 
 | 		return; | 
 | 	mayprint = verbose | id->ilist | blist_size; | 
 | 	for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno]; | 
 | 	     i < len; | 
 | 	     i++, idp++) { | 
 | 		*idp = id; | 
 | 		if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i))) | 
 | 			dbprintf(_("setting inode to %lld for rtblock %llu\n"), | 
 | 				id->ino, bno + i); | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | setlink_inode( | 
 | 	inodata_t	*id, | 
 | 	nlink_t		nlink, | 
 | 	int		isdir, | 
 | 	int		security) | 
 | { | 
 | 	id->link_set = nlink; | 
 | 	id->isdir = isdir; | 
 | 	id->security = security; | 
 | 	if (verbose || id->ilist) | 
 | 		dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink, | 
 | 			isdir ? "is" : "not"); | 
 | } |