[PATCH 12/13] xfs_repair: move common dir2 and attr_repair code to da_util.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Now that dir2.c and attr_repair.c are functionally identical,
move the duplicate code into a new file da_util.c, with da_util.h
as a header file for the common functions.

Last step will be to fix up comments and printfs' to be appropriate
for code that checks both dirs and attrs.

Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx>
Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxxx>
---
 repair/Makefile      |    6 +-
 repair/attr_repair.c |  617 +-------------------------------------------
 repair/da_util.c     |  701 ++++++++++++++++++++++++++++++++++++++++++++++++++
 repair/da_util.h     |   82 ++++++
 repair/dir2.c        |  649 +---------------------------------------------
 repair/dir2.h        |   49 ----
 6 files changed, 801 insertions(+), 1303 deletions(-)
 create mode 100644 repair/da_util.c
 create mode 100644 repair/da_util.h

diff --git a/repair/Makefile b/repair/Makefile
index 6d84ade..251722b 100644
--- a/repair/Makefile
+++ b/repair/Makefile
@@ -10,11 +10,11 @@ LSRCFILES = README
 LTCOMMAND = xfs_repair
 
 HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h btree.h \
-	dinode.h dir2.h err_protos.h globals.h incore.h protos.h rt.h \
-	progress.h scan.h versions.h prefetch.h threads.h
+	da_util.h dinode.h dir2.h err_protos.h globals.h incore.h protos.h \
+	rt.h progress.h scan.h versions.h prefetch.h threads.h
 
 CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \
-	dino_chunks.c dinode.c dir2.c globals.c incore.c \
+	da_util.c dino_chunks.c dinode.c dir2.c globals.c incore.c \
 	incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \
 	phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \
 	progress.c prefetch.c rt.c sb.c scan.c threads.c \
diff --git a/repair/attr_repair.c b/repair/attr_repair.c
index 0804a22..0d3b7a5 100644
--- a/repair/attr_repair.c
+++ b/repair/attr_repair.c
@@ -24,6 +24,7 @@
 #include "bmap.h"
 #include "protos.h"
 #include "dir2.h"
+#include "da_util.h"
 
 static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp);
 static int xfs_mac_valid(xfs_mac_label_t *lp);
@@ -39,43 +40,6 @@ static int xfs_mac_valid(xfs_mac_label_t *lp);
 typedef unsigned char	da_freemap_t;
 
 /*
- * the cursor gets passed up and down the da btree processing
- * routines.  The interior block processing routines use the
- * cursor to determine if the pointers to and from the preceding
- * and succeeding sibling blocks are ok and whether the values in
- * the current block are consistent with the entries in the parent
- * nodes.  When a block is traversed, a parent-verification routine
- * is called to verify if the next logical entry in the next level up
- * is consistent with the greatest hashval in the next block of the
- * current level.  The verification routine is itself recursive and
- * calls itself if it has to traverse an interior block to get
- * the next logical entry.  The routine recurses upwards through
- * the tree until it finds a block where it can simply step to
- * the next entry.  The hashval in that entry should be equal to
- * the hashval being passed to it (the greatest hashval in the block
- * that the entry points to).  If that isn't true, then the tree
- * is blown and we need to trash it, salvage and trash it, or fix it.
- * Currently, we just trash it.
- */
-typedef struct da_level_state  {
-	xfs_buf_t	*bp;		/* block bp */
-	xfs_dablk_t	bno;		/* file block number */
-	xfs_dahash_t	hashval;	/* last verified hashval */
-	int		index;		/* current index in block */
-	int		dirty;		/* is buffer dirty ? (1 == yes) */
-} da_level_state_t;
-
-typedef struct da_bt_cursor  {
-	int			active;	/* highest level in tree (# levels-1) */
-	xfs_ino_t		ino;
-	xfs_dablk_t		greatest_bno;
-	xfs_dinode_t		*dip;
-	da_level_state_t	level[XFS_DA_NODE_MAXDEPTH];
-	struct blkmap		*blkmap;
-} da_bt_cursor_t;
-
-
-/*
  * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
  * 1 == used, 0 == free.
  */
@@ -127,577 +91,6 @@ set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
 }
 
 /*
- * walk tree from root to the left-most leaf block reading in
- * blocks and setting up cursor.  passes back file block number of the
- * left-most leaf block if successful (bno).  returns 1 if successful,
- * 0 if unsuccessful.
- */
-static int
-traverse_int_dablock(xfs_mount_t	*mp,
-		da_bt_cursor_t		*da_cursor,
-		xfs_dablk_t		*rbno,
-		int			whichfork)
-{
-	bmap_ext_t		*bmp;
-	xfs_dablk_t		bno;
-	int			i;
-	int			nex;
-	xfs_da_intnode_t	*node;
-	bmap_ext_t		lbmp;
-	xfs_fsblock_t		fsbno;
-	xfs_buf_t		*bp;
-	struct xfs_da_geometry	*geo;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-	geo = mp->m_attr_geo;
-
-	/*
-	 * traverse down left-side of tree until we hit the
-	 * left-most leaf block setting up the btree cursor along
-	 * the way.
-	 */
-	bno = 0;
-	i = -1;
-	node = NULL;
-	da_cursor->active = 0;
-
-	do {
-		/*
-		 * read in each block along the way and set up cursor
-		 */
-		nex = blkmap_getn(da_cursor->blkmap, bno,
-				geo->fsbcount, &bmp, &lbmp);
-
-		if (nex == 0)
-			goto error_out;
-
-		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
-		if (bmp != &lbmp)
-			free(bmp);
-
-		if (!bp) {
-			do_warn(
-	_("can't read block %u (fsbno %" PRIu64 ") for attrbute fork of inode %" PRIu64 "\n"),
-					bno, fsbno, da_cursor->ino);
-			goto error_out;
-		}
-
-		node = bp->b_addr;
-		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
-		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
-			do_warn(_("bad dir/attr magic number in inode %" PRIu64 ", "
-				  "file bno = %u, fsbno = %" PRIu64 "\n"),
-				da_cursor->ino, bno, fsbno);
-			libxfs_putbuf(bp);
-			goto error_out;
-		}
-
-		/* corrupt node; rebuild the dir. */
-		if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
-			libxfs_putbuf(bp);
-			do_warn(
-_("corrupt tree block %u for directory inode %" PRIu64 "\n"),
-				bno, da_cursor->ino);
-			goto error_out;
-		}
-
-		btree = M_DIROPS(mp)->node_tree_p(node);
-		if (nodehdr.count > geo->node_ents) {
-			do_warn(_("bad record count in inode %" PRIu64 ", "
-				  "count = %d, max = %d\n"),
-				da_cursor->ino, nodehdr.count, geo->node_ents);
-			libxfs_putbuf(bp);
-			goto error_out;
-		}
-
-		/*
-		 * maintain level counter
-		 */
-		if (i == -1) {
-			i = da_cursor->active = nodehdr.level;
-			if (i < 1 || i >= XFS_DA_NODE_MAXDEPTH) {
-				do_warn(
-_("bad header depth for directory inode %" PRIu64 "\n"),
-					da_cursor->ino);
-				libxfs_putbuf(bp);
-				i = -1;
-				goto error_out;
-			}
-		} else {
-			if (nodehdr.level == i - 1) {
-				i--;
-			} else {
-				do_warn(_("bad attribute fork btree "
-					  "for inode %" PRIu64 "\n"),
-					da_cursor->ino);
-				libxfs_putbuf(bp);
-				goto error_out;
-			}
-		}
-
-		da_cursor->level[i].hashval = be32_to_cpu(btree[0].hashval);
-		da_cursor->level[i].bp = bp;
-		da_cursor->level[i].bno = bno;
-		da_cursor->level[i].index = 0;
-
-		/*
-		 * set up new bno for next level down
-		 */
-		bno = be32_to_cpu(btree[0].before);
-	} while (node != NULL && i > 1);
-
-	/*
-	 * now return block number and get out
-	 */
-	*rbno = da_cursor->level[0].bno = bno;
-	return(1);
-
-error_out:
-	while (i > 1 && i <= da_cursor->active) {
-		libxfs_putbuf(da_cursor->level[i].bp);
-		i++;
-	}
-
-	return(0);
-}
-
-/*
- * blow out buffer for this level and all the rest above as well
- * if error == 0, we are not expecting to encounter any unreleased
- * buffers (e.g. if we do, it's a mistake).  if error == 1, we're
- * in an error-handling case so unreleased buffers may exist.
- */
-static void
-release_da_cursor_int(xfs_mount_t	*mp,
-			da_bt_cursor_t	*cursor,
-			int		prev_level,
-			int		error)
-{
-	int	level = prev_level + 1;
-
-	if (cursor->level[level].bp != NULL)  {
-		if (!error)  {
-			do_warn(_("release_da_cursor_int got unexpected "
-				  "non-null bp, dabno = %u\n"),
-				cursor->level[level].bno);
-		}
-		ASSERT(error != 0);
-
-		libxfs_putbuf(cursor->level[level].bp);
-		cursor->level[level].bp = NULL;
-	}
-
-	if (level < cursor->active)
-		release_da_cursor_int(mp, cursor, level, error);
-
-	return;
-}
-
-static void
-release_da_cursor(xfs_mount_t	*mp,
-		da_bt_cursor_t	*cursor,
-		int		prev_level)
-{
-	release_da_cursor_int(mp, cursor, prev_level, 0);
-}
-
-static void
-err_release_da_cursor(xfs_mount_t	*mp,
-			da_bt_cursor_t	*cursor,
-			int		prev_level)
-{
-	release_da_cursor_int(mp, cursor, prev_level, 1);
-}
-
-/*
- * make sure that all entries in all blocks along the right side of
- * of the tree are used and hashval's are consistent.  level is the
- * level of the descendent block.  returns 0 if good (even if it had
- * to be fixed up), and 1 if bad.  The right edge of the tree is
- * technically a block boundary.  this routine should be used then
- * instead of verify_da_path().
- */
-static int
-verify_final_da_path(xfs_mount_t	*mp,
-		da_bt_cursor_t		*cursor,
-		const int		p_level)
-{
-	xfs_da_intnode_t	*node;
-	xfs_dahash_t		hashval;
-	int			bad = 0;
-	int			entry;
-	int			this_level = p_level + 1;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-#ifdef XR_DIR_TRACE
-	fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
-		this_level);
-#endif
-	/*
-	 * the index should point to the next "unprocessed" entry
-	 * in the block which should be the final (rightmost) entry
-	 */
-	entry = cursor->level[this_level].index;
-	node = cursor->level[this_level].bp->b_addr;
-	btree = M_DIROPS(mp)->node_tree_p(node);
-	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-	/*
-	 * check internal block consistency on this level -- ensure
-	 * that all entries are used, encountered and expected hashvals
-	 * match, etc.
-	 */
-	if (entry != nodehdr.count - 1) {
-		do_warn(_("directory/attribute block used/count "
-			  "inconsistency - %d/%hu\n"),
-			entry, nodehdr.count);
-		bad++;
-	}
-	/*
-	 * hash values monotonically increasing ???
-	 */
-	if (cursor->level[this_level].hashval >= 
-				be32_to_cpu(btree[entry].hashval)) {
-		do_warn(_("directory/attribute block hashvalue inconsistency, "
-			  "expected > %u / saw %u\n"),
-			cursor->level[this_level].hashval,
-			be32_to_cpu(btree[entry].hashval));
-		bad++;
-	}
-	if (nodehdr.forw != 0) {
-		do_warn(_("bad directory/attribute forward block pointer, "
-			  "expected 0, saw %u\n"),
-			nodehdr.forw);
-		bad++;
-	}
-	if (bad) {
-		do_warn(_("bad directory block in dir ino %" PRIu64 "\n"),
-			cursor->ino);
-		return(1);
-	}
-	/*
-	 * keep track of greatest block # -- that gets
-	 * us the length of the directory
-	 */
-	if (cursor->level[this_level].bno > cursor->greatest_bno)
-		cursor->greatest_bno = cursor->level[this_level].bno;
-
-	/*
-	 * ok, now check descendant block number against this level
-	 */
-	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "bad directory btree pointer, child bno should "
-				"be %d, block bno is %d, hashval is %u\n",
-			be16_to_cpu(btree[entry].before),
-			cursor->level[p_level].bno,
-			cursor->level[p_level].hashval);
-		fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
-#endif
-		return(1);
-	}
-
-	if (cursor->level[p_level].hashval != be32_to_cpu(btree[entry].hashval)) {
-		if (!no_modify) {
-			do_warn(_("correcting bad hashval in non-leaf "
-				  "dir/attr block\n\tin (level %d) in "
-				  "inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-			btree[entry].hashval = cpu_to_be32(
-						cursor->level[p_level].hashval);
-			cursor->level[this_level].dirty++;
-		} else {
-			do_warn(_("would correct bad hashval in non-leaf "
-				  "dir/attr block\n\tin (level %d) in "
-				  "inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-		}
-	}
-
-	/*
-	 * Note: squirrel hashval away _before_ releasing the
-	 * buffer, preventing a use-after-free problem.
-	 */
-	hashval = be32_to_cpu(btree[entry].hashval);
-
-	/*
-	 * release/write buffer
-	 */
-	ASSERT(cursor->level[this_level].dirty == 0 ||
-		(cursor->level[this_level].dirty && !no_modify));
-
-	if (cursor->level[this_level].dirty && !no_modify)
-		libxfs_writebuf(cursor->level[this_level].bp, 0);
-	else
-		libxfs_putbuf(cursor->level[this_level].bp);
-
-	cursor->level[this_level].bp = NULL;
-
-	/*
-	 * bail out if this is the root block (top of tree)
-	 */
-	if (this_level >= cursor->active) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
-#endif
-		return(0);
-	}
-	/*
-	 * set hashvalue to correctly reflect the now-validated
-	 * last entry in this block and continue upwards validation
-	 */
-	cursor->level[this_level].hashval = hashval;
-	return(verify_final_da_path(mp, cursor, this_level));
-}
-
-/*
- * Verifies the path from a descendant block up to the root.
- * Should be called when the descendant level traversal hits
- * a block boundary before crossing the boundary (reading in a new
- * block).
- *
- * the directory/attr btrees work differently to the other fs btrees.
- * each interior block contains records that are <hashval, bno>
- * pairs.  The bno is a file bno, not a filesystem bno.  The last
- * hashvalue in the block <bno> will be <hashval>.  BUT unlike
- * the freespace btrees, the *last* value in each block gets
- * propagated up the tree instead of the first value in each block.
- * that is, the interior records point to child blocks and the *greatest*
- * hash value contained by the child block is the one the block above
- * uses as the key for the child block.
- *
- * level is the level of the descendent block.  returns 0 if good,
- * and 1 if bad.  The descendant block may be a leaf block.
- *
- * the invariant here is that the values in the cursor for the
- * levels beneath this level (this_level) and the cursor index
- * for this level *must* be valid.
- *
- * that is, the hashval/bno info is accurate for all
- * DESCENDANTS and match what the node[index] information
- * for the current index in the cursor for this level.
- *
- * the index values in the cursor for the descendant level
- * are allowed to be off by one as they will reflect the
- * next entry at those levels to be processed.
- *
- * the hashvalue for the current level can't be set until
- * we hit the last entry in the block so, it's garbage
- * until set by this routine.
- *
- * bno and bp for the current block/level are always valid
- * since they have to be set so we can get a buffer for the
- * block.
- */
-static int
-verify_da_path(xfs_mount_t	*mp,
-	da_bt_cursor_t		*cursor,
-	const int		p_level)
-{
-	xfs_da_intnode_t	*node;
-	xfs_da_intnode_t	*newnode;
-	xfs_fsblock_t		fsbno;
-	xfs_dablk_t		dabno;
-	xfs_buf_t		*bp;
-	int			bad;
-	int			entry;
-	int			this_level = p_level + 1;
-	bmap_ext_t		*bmp;
-	int			nex;
-	bmap_ext_t		lbmp;
-	struct xfs_da_geometry	*geo;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-	geo = mp->m_attr_geo;
-
-	/*
-	 * index is currently set to point to the entry that
-	 * should be processed now in this level.
-	 */
-	entry = cursor->level[this_level].index;
-	node = cursor->level[this_level].bp->b_addr;
-	btree = M_DIROPS(mp)->node_tree_p(node);
-	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-	/*
-	 * if this block is out of entries, validate this
-	 * block and move on to the next block.
-	 * and update cursor value for said level
-	 */
-	if (entry >= nodehdr.count) {
-		/*
-		 * update the hash value for this level before
-		 * validating it.  bno value should be ok since
-		 * it was set when the block was first read in.
-		 */
-		cursor->level[this_level].hashval =
-				be32_to_cpu(btree[entry - 1].hashval);
-
-		/*
-		 * keep track of greatest block # -- that gets
-		 * us the length of the directory
-		 */
-		if (cursor->level[this_level].bno > cursor->greatest_bno)
-			cursor->greatest_bno = cursor->level[this_level].bno;
-
-		/*
-		 * validate the path for the current used-up block
-		 * before we trash it
-		 */
-		if (verify_da_path(mp, cursor, this_level))
-			return(1);
-		/*
-		 * ok, now get the next buffer and check sibling pointers
-		 */
-		dabno = nodehdr.forw;
-		ASSERT(dabno != 0);
-		nex = blkmap_getn(cursor->blkmap, dabno, geo->fsbcount,
-			&bmp, &lbmp);
-		if (nex == 0) {
-			do_warn(
-_("can't get map info for block %u of directory inode %" PRIu64 "\n"),
-				dabno, cursor->ino);
-			return(1);
-		}
-
-		fsbno = bmp[0].startblock;
-
-		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
-		if (bmp != &lbmp)
-			free(bmp);
-
-		if (!bp) {
-			do_warn(
-	_("can't read block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
-				dabno, fsbno, cursor->ino);
-			return(1);
-		}
-
-		newnode = bp->b_addr;
-		btree = M_DIROPS(mp)->node_tree_p(newnode);
-		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, newnode);
-
-		/*
-		 * verify magic number and back pointer, sanity-check
-		 * entry count, verify level
-		 */
-		bad = 0;
-		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
-		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
-			do_warn(
-	_("bad magic number %x in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
-				nodehdr.magic,
-				dabno, fsbno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.back != cursor->level[this_level].bno) {
-			do_warn(
-	_("bad back pointer in block %u (%"PRIu64 ") for directory inode %" PRIu64 "\n"),
-				dabno, fsbno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.count > geo->node_ents) {
-			do_warn(
-	_("entry count %d too large in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
-				nodehdr.count,
-				dabno, fsbno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.level != this_level) {
-			do_warn(
-	_("bad level %d in block %u (%" PRIu64 ") for directory inode %" PRIu64 "\n"),
-				nodehdr.level,
-				dabno, fsbno, cursor->ino);
-			bad++;
-		}
-		if (bad) {
-#ifdef XR_DIR_TRACE
-			fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
-#endif
-			libxfs_putbuf(bp);
-			return(1);
-		}
-
-		/*
-		 * update cursor, write out the *current* level if
-		 * required.  don't write out the descendant level
-		 */
-		ASSERT(cursor->level[this_level].dirty == 0 ||
-			(cursor->level[this_level].dirty && !no_modify));
-
-		/*
-		 * If block looks ok but CRC didn't match, make sure to
-		 * recompute it.
-		 */
-		if (!no_modify &&
-		    cursor->level[this_level].bp->b_error == -EFSBADCRC)
-			cursor->level[this_level].dirty = 1;
-
-		if (cursor->level[this_level].dirty && !no_modify)
-			libxfs_writebuf(cursor->level[this_level].bp, 0);
-		else
-			libxfs_putbuf(cursor->level[this_level].bp);
-
-		/* switch cursor to point at the new buffer we just read */
-		cursor->level[this_level].bp = bp;
-		cursor->level[this_level].dirty = 0;
-		cursor->level[this_level].bno = dabno;
-		cursor->level[this_level].hashval =
-					be32_to_cpu(btree[0].hashval);
-		entry = cursor->level[this_level].index = 0;
-	}
-	/*
-	 * ditto for block numbers
-	 */
-	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "bad directory btree pointer, child bno "
-			"should be %d, block bno is %d, hashval is %u\n",
-			be32_to_cpu(btree[entry].before),
-			cursor->level[p_level].bno,
-			cursor->level[p_level].hashval);
-		fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
-#endif
-		return(1);
-	}
-	/*
-	 * ok, now validate last hashvalue in the descendant
-	 * block against the hashval in the current entry
-	 */
-	if (cursor->level[p_level].hashval !=
-				be32_to_cpu(btree[entry].hashval)) {
-		if (!no_modify) {
-			do_warn(_("correcting bad hashval in interior "
-				  "dir/attr block\n\tin (level %d) in "
-				  "inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-			btree[entry].hashval = cpu_to_be32(
-						cursor->level[p_level].hashval);
-			cursor->level[this_level].dirty++;
-		} else {
-			do_warn(_("would correct bad hashval in interior "
-				  "dir/attr block\n\tin (level %d) in "
-				  "inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-		}
-	}
-	/*
-	 * increment index for this level to point to next entry
-	 * (which should point to the next descendant block)
-	 */
-	cursor->level[this_level].index++;
-#ifdef XR_DIR_TRACE
-	fprintf(stderr, "verify_da_path returns 0 (ok)\n");
-#endif
-	return(0);
-}
-
-/*
  * For attribute repair, there are 3 formats to worry about. First, is
  * shortform attributes which reside in the inode. Second is the leaf
  * form, and lastly the btree. Much of this models after the directory
@@ -1435,9 +828,11 @@ process_leaf_attr_level(xfs_mount_t	*mp,
 		prev_bno = da_bno;
 		da_bno = leafhdr.forw;
 
-		if (da_bno != 0 && verify_da_path(mp, da_cursor, 0))  {
-			libxfs_putbuf(bp);
-			goto error_out;
+		if (da_bno != 0) {
+			if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
+				libxfs_putbuf(bp);
+				goto error_out;
+			}
 		}
 
 		current_hashval = greatest_hashval;
diff --git a/repair/da_util.c b/repair/da_util.c
new file mode 100644
index 0000000..e5d5535
--- /dev/null
+++ b/repair/da_util.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+
+/* Various utilities for repair of directory and attribute metadata */
+
+#include "libxfs.h"
+#include "globals.h"
+#include "err_protos.h"
+#include "bmap.h"
+#include "da_util.h"
+
+/*
+ * takes a name and length (name need not be null-terminated)
+ * and returns 1 if the name contains a '/' or a \0, returns 0
+ * otherwise
+ */
+int
+namecheck(char *name, int length)
+{
+	char *c;
+	int i;
+
+	ASSERT(length < MAXNAMELEN);
+
+	for (c = name, i = 0; i < length; i++, c++) {
+		if (*c == '/' || *c == '\0')
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * the cursor gets passed up and down the da btree processing
+ * routines.  The interior block processing routines use the
+ * cursor to determine if the pointers to and from the preceding
+ * and succeeding sibling blocks are ok and whether the values in
+ * the current block are consistent with the entries in the parent
+ * nodes.  When a block is traversed, a parent-verification routine
+ * is called to verify if the next logical entry in the next level up
+ * is consistent with the greatest hashval in the next block of the
+ * current level.  The verification routine is itself recursive and
+ * calls itself if it has to traverse an interior block to get
+ * the next logical entry.  The routine recurses upwards through
+ * the tree until it finds a block where it can simply step to
+ * the next entry.  The hashval in that entry should be equal to
+ * the hashval being passed to it (the greatest hashval in the block
+ * that the entry points to).  If that isn't true, then the tree
+ * is blown and we need to trash it, salvage and trash it, or fix it.
+ * Currently, we just trash it.
+ */
+
+/*
+ * Multibuffer handling.
+ * V2 directory blocks can be noncontiguous, needing multiple buffers.
+ */
+struct xfs_buf *
+da_read_buf(
+	xfs_mount_t	*mp,
+	int		nex,
+	bmap_ext_t	*bmp,
+	const struct xfs_buf_ops *ops)
+{
+#define MAP_ARRAY_SZ 4
+	struct xfs_buf_map map_array[MAP_ARRAY_SZ];
+	struct xfs_buf_map *map;
+	struct xfs_buf	*bp;
+	int		i;
+
+	if (nex > MAP_ARRAY_SZ) {
+		map = calloc(nex, sizeof(*map));
+		if (map == NULL) {
+			do_error(_("couldn't malloc dir2 buffer list\n"));
+			exit(1);
+		}
+	} else {
+		/* common case avoids calloc/free */
+		map = map_array;
+	}
+	for (i = 0; i < nex; i++) {
+		map[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock);
+		map[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount);
+	}
+	bp = libxfs_readbuf_map(mp->m_dev, map, nex, 0, ops);
+	if (map != map_array)
+		free(map);
+	return bp;
+}
+
+/*
+ * walk tree from root to the left-most leaf block reading in
+ * blocks and setting up cursor.  passes back file block number of the
+ * left-most leaf block if successful (bno).  returns 1 if successful,
+ * 0 if unsuccessful.
+ */
+int
+traverse_int_dablock(
+	xfs_mount_t		*mp,
+	da_bt_cursor_t		*da_cursor,
+	xfs_dablk_t		*rbno,
+	int			whichfork)
+{
+	bmap_ext_t		*bmp;
+	xfs_dablk_t		bno;
+	struct xfs_buf		*bp;
+	int			i;
+	int			nex;
+	xfs_da_intnode_t	*node;
+	bmap_ext_t		lbmp;
+	struct xfs_da_geometry	*geo;
+	struct xfs_da_node_entry *btree;
+	struct xfs_da3_icnode_hdr nodehdr;
+
+	if (whichfork == XFS_DATA_FORK) {
+		geo = mp->m_dir_geo;
+		bno = geo->leafblk;
+	} else {
+		geo = mp->m_attr_geo;
+		bno = 0;
+	}
+
+	/*
+	 * traverse down left-side of tree until we hit the
+	 * left-most leaf block setting up the btree cursor along
+	 * the way.
+	 */
+	i = -1;
+	node = NULL;
+	da_cursor->active = 0;
+
+	do {
+		/*
+		 * read in each block along the way and set up cursor
+		 */
+		nex = blkmap_getn(da_cursor->blkmap, bno,
+				geo->fsbcount, &bmp, &lbmp);
+
+		if (nex == 0)
+			goto error_out;
+
+		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
+		if (bmp != &lbmp)
+			free(bmp);
+
+		if (!bp) {
+			do_warn(
+_("can't read block %u for directory inode %" PRIu64 "\n"),
+				bno, da_cursor->ino);
+			goto error_out;
+		}
+
+		node = bp->b_addr;
+		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
+
+		if (whichfork == XFS_DATA_FORK &&
+		    (nodehdr.magic == XFS_DIR2_LEAFN_MAGIC ||
+		    nodehdr.magic == XFS_DIR3_LEAFN_MAGIC)) {
+			if (i != -1) {
+				do_warn(
+_("found non-root LEAFN node in inode %" PRIu64 " bno = %u\n"),
+					da_cursor->ino, bno);
+			}
+			*rbno = 0;
+			libxfs_putbuf(bp);
+			return 1;
+		}
+
+		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
+		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
+			do_warn(
+_("bad dir magic number 0x%x in inode %" PRIu64 " bno = %u\n"),
+					nodehdr.magic,
+					da_cursor->ino, bno);
+			libxfs_putbuf(bp);
+			goto error_out;
+		}
+
+		/* corrupt node; rebuild the dir. */
+		if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
+			libxfs_putbuf(bp);
+			do_warn(
+_("corrupt tree block %u for directory inode %" PRIu64 "\n"),
+				bno, da_cursor->ino);
+			goto error_out;
+		}
+
+		btree = M_DIROPS(mp)->node_tree_p(node);
+		if (nodehdr.count > geo->node_ents) {
+			do_warn(
+_("bad record count in inode %" PRIu64 ", count = %d, max = %d\n"),
+				da_cursor->ino, nodehdr.count, geo->node_ents);
+			libxfs_putbuf(bp);
+			goto error_out;
+		}
+
+		/*
+		 * maintain level counter
+		 */
+		if (i == -1) {
+			i = da_cursor->active = nodehdr.level;
+			if (i < 1 || i >= XFS_DA_NODE_MAXDEPTH) {
+				do_warn(
+_("bad header depth for directory inode %" PRIu64 "\n"),
+					da_cursor->ino);
+				libxfs_putbuf(bp);
+				i = -1;
+				goto error_out;
+			}
+		} else {
+			if (nodehdr.level == i - 1) {
+				i--;
+			} else {
+				do_warn(
+_("bad directory btree for directory inode %" PRIu64 "\n"),
+					da_cursor->ino);
+				libxfs_putbuf(bp);
+				goto error_out;
+			}
+		}
+
+		da_cursor->level[i].hashval = be32_to_cpu(btree[0].hashval);
+		da_cursor->level[i].bp = bp;
+		da_cursor->level[i].bno = bno;
+		da_cursor->level[i].index = 0;
+
+		/*
+		 * set up new bno for next level down
+		 */
+		bno = be32_to_cpu(btree[0].before);
+	} while (node != NULL && i > 1);
+
+	/*
+	 * now return block number and get out
+	 */
+	*rbno = da_cursor->level[0].bno = bno;
+	return 1;
+
+error_out:
+	while (i > 1 && i <= da_cursor->active) {
+		libxfs_putbuf(da_cursor->level[i].bp);
+		i++;
+	}
+
+	return 0;
+}
+
+/*
+ * blow out buffer for this level and all the rest above as well
+ * if error == 0, we are not expecting to encounter any unreleased
+ * buffers (e.g. if we do, it's a mistake).  if error == 1, we're
+ * in an error-handling case so unreleased buffers may exist.
+ */
+static void
+release_da_cursor_int(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	int		prev_level,
+	int		error)
+{
+	int		level = prev_level + 1;
+
+	if (cursor->level[level].bp != NULL)  {
+		if (!error)  {
+			do_warn(_("release_da_cursor_int got unexpected "
+				  "non-null bp, dabno = %u\n"),
+				cursor->level[level].bno);
+		}
+		ASSERT(error != 0);
+
+		libxfs_putbuf(cursor->level[level].bp);
+		cursor->level[level].bp = NULL;
+	}
+
+	if (level < cursor->active)
+		release_da_cursor_int(mp, cursor, level, error);
+
+	return;
+}
+
+void
+release_da_cursor(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	int		prev_level)
+{
+	release_da_cursor_int(mp, cursor, prev_level, 0);
+}
+
+void
+err_release_da_cursor(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	int		prev_level)
+{
+	release_da_cursor_int(mp, cursor, prev_level, 1);
+}
+
+/*
+ * make sure that all entries in all blocks along the right side of
+ * of the tree are used and hashval's are consistent.  level is the
+ * level of the descendent block.  returns 0 if good (even if it had
+ * to be fixed up), and 1 if bad.  The right edge of the tree is
+ * technically a block boundary.  This routine should be used then
+ * instead of verify_da_path().
+ */
+int
+verify_final_da_path(
+	xfs_mount_t		*mp,
+	da_bt_cursor_t		*cursor,
+	const int		p_level)
+{
+	xfs_da_intnode_t	*node;
+	xfs_dahash_t		hashval;
+	int			bad = 0;
+	int			entry;
+	int			this_level = p_level + 1;
+	struct xfs_da_node_entry *btree;
+	struct xfs_da3_icnode_hdr nodehdr;
+
+#ifdef XR_DIR_TRACE
+	fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
+		this_level);
+#endif
+
+	/*
+	 * the index should point to the next "unprocessed" entry
+	 * in the block which should be the final (rightmost) entry
+	 */
+	entry = cursor->level[this_level].index;
+	node = cursor->level[this_level].bp->b_addr;
+	btree = M_DIROPS(mp)->node_tree_p(node);
+	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
+
+	/*
+	 * check internal block consistency on this level -- ensure
+	 * that all entries are used, encountered and expected hashvals
+	 * match, etc.
+	 */
+	if (entry != nodehdr.count - 1) {
+		do_warn(
+		_("directory block used/count inconsistency - %d/%hu\n"),
+			entry, nodehdr.count);
+		bad++;
+	}
+	/*
+	 * hash values monotonically increasing ???
+	 */
+	if (cursor->level[this_level].hashval >=
+				be32_to_cpu(btree[entry].hashval)) {
+		do_warn(_("directory/attribute block hashvalue inconsistency, "
+			  "expected > %u / saw %u\n"),
+			cursor->level[this_level].hashval,
+			be32_to_cpu(btree[entry].hashval));
+		bad++;
+	}
+	if (nodehdr.forw != 0) {
+		do_warn(_("bad directory/attribute forward block pointer, "
+			  "expected 0, saw %u\n"),
+			nodehdr.forw);
+		bad++;
+	}
+	if (bad) {
+		do_warn(_("bad directory block in inode %" PRIu64 "\n"), cursor->ino);
+		return 1;
+	}
+	/*
+	 * keep track of greatest block # -- that gets
+	 * us the length of the directory
+	 */
+	if (cursor->level[this_level].bno > cursor->greatest_bno)
+		cursor->greatest_bno = cursor->level[this_level].bno;
+
+	/*
+	 * ok, now check descendant block number against this level
+	 */
+	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
+#ifdef XR_DIR_TRACE
+		fprintf(stderr, "bad directory btree pointer, child bno should "
+				"be %d, block bno is %d, hashval is %u\n",
+			be16_to_cpu(btree[entry].before),
+			cursor->level[p_level].bno,
+			cursor->level[p_level].hashval);
+		fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
+#endif
+		return 1;
+	}
+
+	if (cursor->level[p_level].hashval !=
+				be32_to_cpu(btree[entry].hashval)) {
+		if (!no_modify) {
+			do_warn(
+_("correcting bad hashval in non-leaf dir block\n"
+ "\tin (level %d) in inode %" PRIu64 ".\n"),
+				this_level, cursor->ino);
+			btree[entry].hashval = cpu_to_be32(
+						cursor->level[p_level].hashval);
+			cursor->level[this_level].dirty++;
+		} else {
+			do_warn(
+_("would correct bad hashval in non-leaf dir block\n"
+ "\tin (level %d) in inode %" PRIu64 ".\n"),
+				this_level, cursor->ino);
+		}
+	}
+
+	/*
+	 * Note: squirrel hashval away _before_ releasing the
+	 * buffer, preventing a use-after-free problem.
+	 */
+	hashval = be32_to_cpu(btree[entry].hashval);
+
+	/*
+	 * release/write buffer
+	 */
+	ASSERT(cursor->level[this_level].dirty == 0 ||
+		(cursor->level[this_level].dirty && !no_modify));
+
+	if (cursor->level[this_level].dirty && !no_modify)
+		libxfs_writebuf(cursor->level[this_level].bp, 0);
+	else
+		libxfs_putbuf(cursor->level[this_level].bp);
+
+	cursor->level[this_level].bp = NULL;
+
+	/*
+	 * bail out if this is the root block (top of tree)
+	 */
+	if (this_level >= cursor->active) {
+#ifdef XR_DIR_TRACE
+		fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
+#endif
+		return 0;
+	}
+	/*
+	 * set hashvalue to correctly reflect the now-validated
+	 * last entry in this block and continue upwards validation
+	 */
+	cursor->level[this_level].hashval = hashval;
+
+	return verify_final_da_path(mp, cursor, this_level);
+}
+
+/*
+ * Verifies the path from a descendant block up to the root.
+ * Should be called when the descendant level traversal hits
+ * a block boundary before crossing the boundary (reading in a new
+ * block).
+ *
+ * the directory/attr btrees work differently to the other fs btrees.
+ * each interior block contains records that are <hashval, bno>
+ * pairs.  The bno is a file bno, not a filesystem bno.  The last
+ * hashvalue in the block <bno> will be <hashval>.  BUT unlike
+ * the freespace btrees, the *last* value in each block gets
+ * propagated up the tree instead of the first value in each block.
+ * that is, the interior records point to child blocks and the *greatest*
+ * hash value contained by the child block is the one the block above
+ * uses as the key for the child block.
+ *
+ * level is the level of the descendent block.  returns 0 if good,
+ * and 1 if bad.  The descendant block may be a leaf block.
+ *
+ * the invariant here is that the values in the cursor for the
+ * levels beneath this level (this_level) and the cursor index
+ * for this level *must* be valid.
+ *
+ * that is, the hashval/bno info is accurate for all
+ * DESCENDANTS and match what the node[index] information
+ * for the current index in the cursor for this level.
+ *
+ * the index values in the cursor for the descendant level
+ * are allowed to be off by one as they will reflect the
+ * next entry at those levels to be processed.
+ *
+ * the hashvalue for the current level can't be set until
+ * we hit the last entry in the block so, it's garbage
+ * until set by this routine.
+ *
+ * bno and bp for the current block/level are always valid
+ * since they have to be set so we can get a buffer for the
+ * block.
+ */
+int
+verify_da_path(
+	xfs_mount_t		*mp,
+	da_bt_cursor_t		*cursor,
+	const int		p_level,
+	int			whichfork)
+{
+	xfs_da_intnode_t	*node;
+	xfs_da_intnode_t	*newnode;
+	xfs_dablk_t		dabno;
+	struct xfs_buf		*bp;
+	int			bad;
+	int			entry;
+	int			this_level = p_level + 1;
+	bmap_ext_t		*bmp;
+	int			nex;
+	bmap_ext_t		lbmp;
+	struct xfs_da_geometry	*geo;
+	struct xfs_da_node_entry *btree;
+	struct xfs_da3_icnode_hdr nodehdr;
+
+	if (whichfork == XFS_DATA_FORK)
+		geo = mp->m_dir_geo;
+	else
+		geo = mp->m_attr_geo;
+
+	/*
+	 * index is currently set to point to the entry that
+	 * should be processed now in this level.
+	 */
+	entry = cursor->level[this_level].index;
+	node = cursor->level[this_level].bp->b_addr;
+	btree = M_DIROPS(mp)->node_tree_p(node);
+	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
+
+	/*
+	 * if this block is out of entries, validate this
+	 * block and move on to the next block.
+	 * and update cursor value for said level
+	 */
+	if (entry >= nodehdr.count) {
+		/*
+		 * update the hash value for this level before
+		 * validating it.  bno value should be ok since
+		 * it was set when the block was first read in.
+		 */
+		cursor->level[this_level].hashval =
+				be32_to_cpu(btree[entry - 1].hashval);
+
+		/*
+		 * keep track of greatest block # -- that gets
+		 * us the length of the directory
+		 */
+		if (cursor->level[this_level].bno > cursor->greatest_bno)
+			cursor->greatest_bno = cursor->level[this_level].bno;
+
+		/*
+		 * validate the path for the current used-up block
+		 * before we trash it
+		 */
+		if (verify_da_path(mp, cursor, this_level, whichfork))
+			return 1;
+		/*
+		 * ok, now get the next buffer and check sibling pointers
+		 */
+		dabno = nodehdr.forw;
+		ASSERT(dabno != 0);
+		nex = blkmap_getn(cursor->blkmap, dabno, geo->fsbcount,
+			&bmp, &lbmp);
+		if (nex == 0) {
+			do_warn(
+_("can't get map info for block %u of directory inode %" PRIu64 "\n"),
+				dabno, cursor->ino);
+			return 1;
+		}
+
+		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
+		if (bmp != &lbmp)
+			free(bmp);
+
+		if (!bp) {
+			do_warn(
+_("can't read block %u for directory inode %" PRIu64 "\n"),
+				dabno, cursor->ino);
+			return 1;
+		}
+
+		newnode = bp->b_addr;
+		btree = M_DIROPS(mp)->node_tree_p(newnode);
+		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, newnode);
+
+		/*
+		 * verify magic number and back pointer, sanity-check
+		 * entry count, verify level
+		 */
+		bad = 0;
+		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
+		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
+			do_warn(
+_("bad magic number %x in block %u for directory inode %" PRIu64 "\n"),
+				nodehdr.magic,
+				dabno, cursor->ino);
+			bad++;
+		}
+		if (nodehdr.back != cursor->level[this_level].bno) {
+			do_warn(
+_("bad back pointer in block %u for directory inode %" PRIu64 "\n"),
+				dabno, cursor->ino);
+			bad++;
+		}
+		if (nodehdr.count > geo->node_ents) {
+			do_warn(
+_("entry count %d too large in block %u for directory inode %" PRIu64 "\n"),
+				nodehdr.count,
+				dabno, cursor->ino);
+			bad++;
+		}
+		if (nodehdr.level != this_level) {
+			do_warn(
+_("bad level %d in block %u for directory inode %" PRIu64 "\n"),
+				nodehdr.level,
+				dabno, cursor->ino);
+			bad++;
+		}
+		if (bad) {
+#ifdef XR_DIR_TRACE
+			fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
+#endif
+			libxfs_putbuf(bp);
+			return 1;
+		}
+
+		/*
+		 * update cursor, write out the *current* level if
+		 * required.  don't write out the descendant level
+		 */
+		ASSERT(cursor->level[this_level].dirty == 0 ||
+			(cursor->level[this_level].dirty && !no_modify));
+
+		/*
+		 * If block looks ok but CRC didn't match, make sure to
+		 * recompute it.
+		 */
+		if (!no_modify &&
+		    cursor->level[this_level].bp->b_error == -EFSBADCRC)
+			cursor->level[this_level].dirty = 1;
+
+		if (cursor->level[this_level].dirty && !no_modify)
+			libxfs_writebuf(cursor->level[this_level].bp, 0);
+		else
+			libxfs_putbuf(cursor->level[this_level].bp);
+
+		/* switch cursor to point at the new buffer we just read */
+		cursor->level[this_level].bp = bp;
+		cursor->level[this_level].dirty = 0;
+		cursor->level[this_level].bno = dabno;
+		cursor->level[this_level].hashval =
+					be32_to_cpu(btree[0].hashval);
+
+		entry = cursor->level[this_level].index = 0;
+	}
+	/*
+	 * ditto for block numbers
+	 */
+	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
+#ifdef XR_DIR_TRACE
+		fprintf(stderr, "bad directory btree pointer, child bno "
+			"should be %d, block bno is %d, hashval is %u\n",
+			be32_to_cpu(btree[entry].before),
+			cursor->level[p_level].bno,
+			cursor->level[p_level].hashval);
+		fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
+#endif
+		return 1;
+	}
+	/*
+	 * ok, now validate last hashvalue in the descendant
+	 * block against the hashval in the current entry
+	 */
+	if (cursor->level[p_level].hashval !=
+				be32_to_cpu(btree[entry].hashval)) {
+		if (!no_modify) {
+			do_warn(
+_("correcting bad hashval in interior dir block\n"
+  "\tin (level %d) in inode %" PRIu64 ".\n"),
+				this_level, cursor->ino);
+			btree[entry].hashval = cpu_to_be32(
+						cursor->level[p_level].hashval);
+			cursor->level[this_level].dirty++;
+		} else {
+			do_warn(
+_("would correct bad hashval in interior dir block\n"
+  "\tin (level %d) in inode %" PRIu64 ".\n"),
+				this_level, cursor->ino);
+		}
+	}
+	/*
+	 * increment index for this level to point to next entry
+	 * (which should point to the next descendant block)
+	 */
+	cursor->level[this_level].index++;
+#ifdef XR_DIR_TRACE
+	fprintf(stderr, "verify_da_path returns 0 (ok)\n");
+#endif
+	return 0;
+}
diff --git a/repair/da_util.h b/repair/da_util.h
new file mode 100644
index 0000000..7971d63
--- /dev/null
+++ b/repair/da_util.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _XR_DA_UTIL_H
+#define	_XR_DA_UTIL_H
+
+struct da_level_state  {
+	xfs_buf_t	*bp;		/* block bp */
+	xfs_dablk_t	bno;		/* file block number */
+	xfs_dahash_t	hashval;	/* last verified hashval */
+	int		index;		/* current index in block */
+	int		dirty;		/* is buffer dirty ? (1 == yes) */
+};
+
+typedef struct da_bt_cursor {
+	int			active;	/* highest level in tree (# levels-1) */
+	xfs_ino_t		ino;
+	xfs_dablk_t		greatest_bno;
+	xfs_dinode_t		*dip;
+	struct da_level_state	level[XFS_DA_NODE_MAXDEPTH];
+	struct blkmap		*blkmap;
+} da_bt_cursor_t;
+
+int
+namecheck(
+	char		*name,
+	int		length);
+
+struct xfs_buf *
+da_read_buf(
+	xfs_mount_t	*mp,
+	int		nex,
+	bmap_ext_t	*bmp,
+	const struct xfs_buf_ops *ops);
+
+void
+release_da_cursor(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	int		prev_level);
+
+void
+err_release_da_cursor(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	int		prev_level);
+
+int
+traverse_int_dablock(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*da_cursor,
+	xfs_dablk_t	*rbno,
+	int		whichfork);
+
+int
+verify_da_path(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	const int	p_level,
+	int		whichfork);
+
+int
+verify_final_da_path(
+	xfs_mount_t	*mp,
+	da_bt_cursor_t	*cursor,
+	const int	p_level);
+#endif	/* _XR_DA_UTIL_H */
diff --git a/repair/dir2.c b/repair/dir2.c
index 7b47a9e..492b3e7 100644
--- a/repair/dir2.c
+++ b/repair/dir2.c
@@ -24,6 +24,7 @@
 #include "dinode.h"
 #include "dir2.h"
 #include "bmap.h"
+#include "da_util.h"
 #include "prefetch.h"
 #include "progress.h"
 
@@ -68,638 +69,6 @@ dir2_is_badino(
 }
 
 /*
- * takes a name and length (name need not be null-terminated)
- * and returns 1 if the name contains a '/' or a \0, returns 0
- * otherwise
- */
-int
-namecheck(char *name, int length)
-{
-	char *c;
-	int i;
-
-	ASSERT(length < MAXNAMELEN);
-
-	for (c = name, i = 0; i < length; i++, c++)  {
-		if (*c == '/' || *c == '\0')
-			return(1);
-	}
-
-	return(0);
-}
-
-/*
- * Multibuffer handling.
- * V2 directory blocks can be noncontiguous, needing multiple buffers.
- */
-struct xfs_buf *
-da_read_buf(
-	xfs_mount_t	*mp,
-	int		nex,
-	bmap_ext_t	*bmp,
-	const struct xfs_buf_ops *ops)
-{
-#define MAP_ARRAY_SZ 4
-	struct xfs_buf_map map_array[MAP_ARRAY_SZ];
-	struct xfs_buf_map *map;
-	struct xfs_buf	*bp;
-	int		i;
-
-	if (nex > MAP_ARRAY_SZ) {
-		map = calloc(nex, sizeof(*map));
-		if (map == NULL) {
-			do_error(_("couldn't malloc dir2 buffer list\n"));
-			exit(1);
-		}
-	} else {
-		/* common case avoids calloc/free */
-		map = map_array;
-	}
-	for (i = 0; i < nex; i++) {
-		map[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock);
-		map[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount);
-	}
-	bp = libxfs_readbuf_map(mp->m_dev, map, nex, 0, ops);
-	if (map != map_array)
-		free(map);
-	return bp;
-}
-
-/*
- * walk tree from root to the left-most leaf block reading in
- * blocks and setting up cursor.  passes back file block number of the
- * left-most leaf block if successful (bno).  returns 1 if successful,
- * 0 if unsuccessful.
- */
-static int
-traverse_int_dir2block(xfs_mount_t	*mp,
-		dir2_bt_cursor_t	*da_cursor,
-		xfs_dablk_t		*rbno)
-{
-	bmap_ext_t		*bmp;
-	xfs_dablk_t		bno;
-	struct xfs_buf		*bp;
-	int			i;
-	int			nex;
-	xfs_da_intnode_t	*node;
-	bmap_ext_t		lbmp;
-	struct xfs_da_geometry	*geo;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-	geo = mp->m_dir_geo;
-
-	/*
-	 * traverse down left-side of tree until we hit the
-	 * left-most leaf block setting up the btree cursor along
-	 * the way.
-	 */
-	bno = mp->m_dir_geo->leafblk;
-	i = -1;
-	node = NULL;
-	da_cursor->active = 0;
-
-	do {
-		/*
-		 * read in each block along the way and set up cursor
-		 */
-		nex = blkmap_getn(da_cursor->blkmap, bno,
-				geo->fsbcount, &bmp, &lbmp);
-
-		if (nex == 0)
-			goto error_out;
-
-		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
-		if (bmp != &lbmp)
-			free(bmp);
-		if (!bp) {
-			do_warn(
-_("can't read block %u for directory inode %" PRIu64 "\n"),
-				bno, da_cursor->ino);
-			goto error_out;
-		}
-
-		node = bp->b_addr;
-		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-		if (nodehdr.magic == XFS_DIR2_LEAFN_MAGIC ||
-		    nodehdr.magic == XFS_DIR3_LEAFN_MAGIC) {
-			if ( i != -1 ) {
-				do_warn(
-_("found non-root LEAFN node in inode %" PRIu64 " bno = %u\n"),
-					da_cursor->ino, bno);
-			}
-			*rbno = 0;
-			libxfs_putbuf(bp);
-			return(1);
-		}
-
-		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
-		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
-			libxfs_putbuf(bp);
-			do_warn(
-_("bad dir magic number 0x%x in inode %" PRIu64 " bno = %u\n"),
-					nodehdr.magic,
-					da_cursor->ino, bno);
-			goto error_out;
-		}
-		/* corrupt node; rebuild the dir. */
-		if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
-			libxfs_putbuf(bp);
-			do_warn(
-_("corrupt tree block %u for directory inode %" PRIu64 "\n"),
-				bno, da_cursor->ino);
-			goto error_out;
-		}
-		btree = M_DIROPS(mp)->node_tree_p(node);
-		if (nodehdr.count > geo->node_ents) {
-			do_warn(
-_("bad record count in inode %" PRIu64 ", count = %d, max = %d\n"),
-				da_cursor->ino, nodehdr.count, geo->node_ents);
-			libxfs_putbuf(bp);
-			goto error_out;
-		}
-		/*
-		 * maintain level counter
-		 */
-		if (i == -1) {
-			i = da_cursor->active = nodehdr.level;
-			if (i < 1 || i >= XFS_DA_NODE_MAXDEPTH) {
-				do_warn(
-_("bad header depth for directory inode %" PRIu64 "\n"),
-					da_cursor->ino);
-				libxfs_putbuf(bp);
-				i = -1;
-				goto error_out;
-			}
-		} else {
-			if (nodehdr.level == i - 1) {
-				i--;
-			} else {
-				do_warn(
-_("bad directory btree for directory inode %" PRIu64 "\n"),
-					da_cursor->ino);
-				libxfs_putbuf(bp);
-				goto error_out;
-			}
-		}
-
-		da_cursor->level[i].hashval = be32_to_cpu(btree[0].hashval);
-		da_cursor->level[i].bp = bp;
-		da_cursor->level[i].bno = bno;
-		da_cursor->level[i].index = 0;
-
-		/*
-		 * set up new bno for next level down
-		 */
-		bno = be32_to_cpu(btree[0].before);
-	} while (node != NULL && i > 1);
-
-	/*
-	 * now return block number and get out
-	 */
-	*rbno = da_cursor->level[0].bno = bno;
-	return(1);
-
-error_out:
-	while (i > 1 && i <= da_cursor->active) {
-		libxfs_putbuf(da_cursor->level[i].bp);
-		i++;
-	}
-
-	return(0);
-}
-
-/*
- * blow out buffer for this level and all the rest above as well
- * if error == 0, we are not expecting to encounter any unreleased
- * buffers (e.g. if we do, it's a mistake).  if error == 1, we're
- * in an error-handling case so unreleased buffers may exist.
- */
-static void
-release_dir2_cursor_int(xfs_mount_t		*mp,
-			dir2_bt_cursor_t	*cursor,
-			int			prev_level,
-			int			error)
-{
-	int	level = prev_level + 1;
-
-	if (cursor->level[level].bp != NULL)  {
-		if (!error)  {
-			do_warn(_("release_dir2_cursor_int got unexpected "
-				  "non-null bp, dabno = %u\n"),
-				cursor->level[level].bno);
-		}
-		ASSERT(error != 0);
-
-		libxfs_putbuf(cursor->level[level].bp);
-		cursor->level[level].bp = NULL;
-	}
-
-	if (level < cursor->active)
-		release_dir2_cursor_int(mp, cursor, level, error);
-
-	return;
-}
-
-static void
-release_dir2_cursor(xfs_mount_t		*mp,
-		dir2_bt_cursor_t	*cursor,
-		int			prev_level)
-{
-	release_dir2_cursor_int(mp, cursor, prev_level, 0);
-}
-
-static void
-err_release_dir2_cursor(xfs_mount_t		*mp,
-			dir2_bt_cursor_t	*cursor,
-			int			prev_level)
-{
-	release_dir2_cursor_int(mp, cursor, prev_level, 1);
-}
-
-/*
- * make sure that all entries in all blocks along the right side of
- * of the tree are used and hashval's are consistent.  level is the
- * level of the descendent block.  returns 0 if good (even if it had
- * to be fixed up), and 1 if bad.  The right edge of the tree is
- * technically a block boundary.  This routine should be used then
- * instead of verify_dir2_path().
- */
-static int
-verify_final_dir2_path(xfs_mount_t	*mp,
-		dir2_bt_cursor_t	*cursor,
-		const int		p_level)
-{
-	xfs_da_intnode_t	*node;
-	xfs_dahash_t		hashval;
-	int			bad = 0;
-	int			entry;
-	int			this_level = p_level + 1;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-#ifdef XR_DIR_TRACE
-	fprintf(stderr, "in verify_final_dir2_path, this_level = %d\n",
-		this_level);
-#endif
-
-	/*
-	 * the index should point to the next "unprocessed" entry
-	 * in the block which should be the final (rightmost) entry
-	 */
-	entry = cursor->level[this_level].index;
-	node = cursor->level[this_level].bp->b_addr;
-	btree = M_DIROPS(mp)->node_tree_p(node);
-	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-	/*
-	 * check internal block consistency on this level -- ensure
-	 * that all entries are used, encountered and expected hashvals
-	 * match, etc.
-	 */
-	if (entry != nodehdr.count - 1) {
-		do_warn(
-		_("directory block used/count inconsistency - %d / %hu\n"),
-			entry, nodehdr.count);
-		bad++;
-	}
-	/*
-	 * hash values monotonically increasing ???
-	 */
-	if (cursor->level[this_level].hashval >=
-				be32_to_cpu(btree[entry].hashval)) {
-		do_warn(_("directory/attribute block hashvalue inconsistency, "
-			  "expected > %u / saw %u\n"),
-			cursor->level[this_level].hashval,
-			be32_to_cpu(btree[entry].hashval));
-		bad++;
-	}
-	if (nodehdr.forw != 0) {
-		do_warn(_("bad directory/attribute forward block pointer, "
-			  "expected 0, saw %u\n"),
-			nodehdr.forw);
-		bad++;
-	}
-	if (bad) {
-		do_warn(_("bad directory block in inode %" PRIu64 "\n"), cursor->ino);
-		return(1);
-	}
-	/*
-	 * keep track of greatest block # -- that gets
-	 * us the length of the directory
-	 */
-	if (cursor->level[this_level].bno > cursor->greatest_bno)
-		cursor->greatest_bno = cursor->level[this_level].bno;
-
-	/*
-	 * ok, now check descendant block number against this level
-	 */
-	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "bad directory btree pointer, child bno should "
-				"be %d, block bno is %d, hashval is %u\n",
-			be16_to_cpu(btree[entry].before),
-			cursor->level[p_level].bno,
-			cursor->level[p_level].hashval);
-		fprintf(stderr, "verify_final_dir2_path returns 1 (bad) #1a\n");
-#endif
-		return(1);
-	}
-
-	if (cursor->level[p_level].hashval !=
-				be32_to_cpu(btree[entry].hashval)) {
-		if (!no_modify) {
-			do_warn(
-_("correcting bad hashval in non-leaf dir block\n"
-  "\tin (level %d) in inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-			btree[entry].hashval = cpu_to_be32(
-						cursor->level[p_level].hashval);
-			cursor->level[this_level].dirty++;
-		} else {
-			do_warn(
-_("would correct bad hashval in non-leaf dir block\n"
-  "\tin (level %d) in inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-		}
-	}
-
-	/*
-	 * Note: squirrel hashval away _before_ releasing the
-	 * buffer, preventing a use-after-free problem.
-	 */
-	hashval = be32_to_cpu(btree[entry].hashval);
-
-	/*
-	 * release/write buffer
-	 */
-	ASSERT(cursor->level[this_level].dirty == 0 ||
-		(cursor->level[this_level].dirty && !no_modify));
-
-	if (cursor->level[this_level].dirty && !no_modify)
-		libxfs_writebuf(cursor->level[this_level].bp, 0);
-	else
-		libxfs_putbuf(cursor->level[this_level].bp);
-
-	cursor->level[this_level].bp = NULL;
-
-	/*
-	 * bail out if this is the root block (top of tree)
-	 */
-	if (this_level >= cursor->active) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "verify_final_dir2_path returns 0 (ok)\n");
-#endif
-		return(0);
-	}
-	/*
-	 * set hashvalue to correctly reflect the now-validated
-	 * last entry in this block and continue upwards validation
-	 */
-	cursor->level[this_level].hashval = hashval;
-
-	return(verify_final_dir2_path(mp, cursor, this_level));
-}
-
-/*
- * Verifies the path from a descendant block up to the root.
- * Should be called when the descendant level traversal hits
- * a block boundary before crossing the boundary (reading in a new
- * block).
- *
- * the directory/attr btrees work differently to the other fs btrees.
- * each interior block contains records that are <hashval, bno>
- * pairs.  The bno is a file bno, not a filesystem bno.  The last
- * hashvalue in the block <bno> will be <hashval>.  BUT unlike
- * the freespace btrees, the *last* value in each block gets
- * propagated up the tree instead of the first value in each block.
- * that is, the interior records point to child blocks and the *greatest*
- * hash value contained by the child block is the one the block above
- * uses as the key for the child block.
- *
- * level is the level of the descendent block.  returns 0 if good,
- * and 1 if bad.  The descendant block may be a leaf block.
- *
- * the invariant here is that the values in the cursor for the
- * levels beneath this level (this_level) and the cursor index
- * for this level *must* be valid.
- *
- * that is, the hashval/bno info is accurate for all
- * DESCENDANTS and match what the node[index] information
- * for the current index in the cursor for this level.
- *
- * the index values in the cursor for the descendant level
- * are allowed to be off by one as they will reflect the
- * next entry at those levels to be processed.
- *
- * the hashvalue for the current level can't be set until
- * we hit the last entry in the block so, it's garbage
- * until set by this routine.
- *
- * bno and bp for the current block/level are always valid
- * since they have to be set so we can get a buffer for the
- * block.
- */
-static int
-verify_dir2_path(xfs_mount_t	*mp,
-	dir2_bt_cursor_t	*cursor,
-	const int		p_level)
-{
-	xfs_da_intnode_t	*node;
-	xfs_da_intnode_t	*newnode;
-	xfs_dablk_t		dabno;
-	struct xfs_buf		*bp;
-	int			bad;
-	int			entry;
-	int			this_level = p_level + 1;
-	bmap_ext_t		*bmp;
-	int			nex;
-	bmap_ext_t		lbmp;
-	struct xfs_da_geometry	*geo;
-	struct xfs_da_node_entry *btree;
-	struct xfs_da3_icnode_hdr nodehdr;
-
-	geo = mp->m_dir_geo;
-
-	/*
-	 * index is currently set to point to the entry that
-	 * should be processed now in this level.
-	 */
-	entry = cursor->level[this_level].index;
-	node = cursor->level[this_level].bp->b_addr;
-	btree = M_DIROPS(mp)->node_tree_p(node);
-	M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
-
-	/*
-	 * if this block is out of entries, validate this
-	 * block and move on to the next block.
-	 * and update cursor value for said level
-	 */
-	if (entry >= nodehdr.count) {
-		/*
-		 * update the hash value for this level before
-		 * validating it.  bno value should be ok since
-		 * it was set when the block was first read in.
-		 */
-		cursor->level[this_level].hashval =
-			be32_to_cpu(btree[entry - 1].hashval);
-
-		/*
-		 * keep track of greatest block # -- that gets
-		 * us the length of the directory
-		 */
-		if (cursor->level[this_level].bno > cursor->greatest_bno)
-			cursor->greatest_bno = cursor->level[this_level].bno;
-
-		/*
-		 * validate the path for the current used-up block
-		 * before we trash it
-		 */
-		if (verify_dir2_path(mp, cursor, this_level))
-			return(1);
-		/*
-		 * ok, now get the next buffer and check sibling pointers
-		 */
-		dabno = nodehdr.forw;
-		ASSERT(dabno != 0);
-		nex = blkmap_getn(cursor->blkmap, dabno, geo->fsbcount,
-			&bmp, &lbmp);
-		if (nex == 0) {
-			do_warn(
-_("can't get map info for block %u of directory inode %" PRIu64 "\n"),
-				dabno, cursor->ino);
-			return(1);
-		}
-
-		bp = da_read_buf(mp, nex, bmp, &xfs_da3_node_buf_ops);
-		if (bmp != &lbmp)
-			free(bmp);
-
-		if (!bp) {
-			do_warn(
-_("can't read block %u for directory inode %" PRIu64 "\n"),
-				dabno, cursor->ino);
-			return(1);
-		}
-
-		newnode = bp->b_addr;
-		btree = M_DIROPS(mp)->node_tree_p(newnode);
-		M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, newnode);
-		/*
-		 * verify magic number and back pointer, sanity-check
-		 * entry count, verify level
-		 */
-		bad = 0;
-		if (nodehdr.magic != XFS_DA_NODE_MAGIC &&
-		    nodehdr.magic != XFS_DA3_NODE_MAGIC) {
-			do_warn(
-_("bad magic number %x in block %u for directory inode %" PRIu64 "\n"),
-				nodehdr.magic,
-				dabno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.back != cursor->level[this_level].bno) {
-			do_warn(
-_("bad back pointer in block %u for directory inode %" PRIu64 "\n"),
-				dabno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.count > geo->node_ents) {
-			do_warn(
-_("entry count %d too large in block %u for directory inode %" PRIu64 "\n"),
-				nodehdr.count,
-				dabno, cursor->ino);
-			bad++;
-		}
-		if (nodehdr.level != this_level) {
-			do_warn(
-_("bad level %d in block %u for directory inode %" PRIu64 "\n"),
-				nodehdr.level,
-				dabno, cursor->ino);
-			bad++;
-		}
-		if (bad) {
-#ifdef XR_DIR_TRACE
-			fprintf(stderr, "verify_dir2_path returns 1 (bad) #4\n");
-#endif
-			libxfs_putbuf(bp);
-			return(1);
-		}
-		/*
-		 * update cursor, write out the *current* level if
-		 * required.  don't write out the descendant level
-		 */
-		ASSERT(cursor->level[this_level].dirty == 0 ||
-			(cursor->level[this_level].dirty && !no_modify));
-		/*
-		 * If block looks ok but CRC didn't match, make sure to
-		 * recompute it.
-		 */
-		if (!no_modify &&
-		    cursor->level[this_level].bp->b_error == -EFSBADCRC)
-			cursor->level[this_level].dirty = 1;
-		if (cursor->level[this_level].dirty && !no_modify)
-			libxfs_writebuf(cursor->level[this_level].bp, 0);
-		else
-			libxfs_putbuf(cursor->level[this_level].bp);
-
-		/* switch cursor to point at the new buffer we just read */
-		cursor->level[this_level].bp = bp;
-		cursor->level[this_level].dirty = 0;
-		cursor->level[this_level].bno = dabno;
-		cursor->level[this_level].hashval =
-			be32_to_cpu(btree[0].hashval);
-
-		entry = cursor->level[this_level].index = 0;
-	}
-	/*
-	 * ditto for block numbers
-	 */
-	if (cursor->level[p_level].bno != be32_to_cpu(btree[entry].before)) {
-#ifdef XR_DIR_TRACE
-		fprintf(stderr, "bad directory btree pointer, child bno "
-			"should be %d, block bno is %d, hashval is %u\n",
-			be32_to_cpu(btree[entry].before),
-			cursor->level[p_level].bno,
-			cursor->level[p_level].hashval);
-		fprintf(stderr, "verify_dir2_path returns 1 (bad) #1a\n");
-#endif
-		return(1);
-	}
-	/*
-	 * ok, now validate last hashvalue in the descendant
-	 * block against the hashval in the current entry
-	 */
-	if (cursor->level[p_level].hashval !=
-				be32_to_cpu(btree[entry].hashval)) {
-		if (!no_modify) {
-			do_warn(
-_("correcting bad hashval in interior dir block\n"
-  "\tin (level %d) in inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-			btree[entry].hashval = cpu_to_be32(
-					cursor->level[p_level].hashval);
-			cursor->level[this_level].dirty++;
-		} else {
-			do_warn(
-_("would correct bad hashval in interior dir block\n"
-  "\tin (level %d) in inode %" PRIu64 ".\n"),
-				this_level, cursor->ino);
-		}
-	}
-	/*
-	 * increment index for this level to point to next entry
-	 * (which should point to the next descendant block)
-	 */
-	cursor->level[this_level].index++;
-#ifdef XR_DIR_TRACE
-       fprintf(stderr, "verify_dir2_path returns 0 (ok)\n");
-#endif
-	return(0);
-}
-
-/*
  * Fix up a shortform directory which was in long form (i8count set)
  * and is now in short form (i8count clear).
  * Return pointer to the end of the data when done.
@@ -1697,7 +1066,7 @@ _("bad stale count in block %u of directory inode %" PRIu64 "\n"),
 static int
 process_leaf_level_dir2(
 	xfs_mount_t		*mp,
-	dir2_bt_cursor_t	*da_cursor,
+	da_bt_cursor_t		*da_cursor,
 	int			*repair)
 {
 	bmap_ext_t		*bmp;
@@ -1791,7 +1160,7 @@ _("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
 		prev_bno = da_bno;
 		da_bno = leafhdr.forw;
 		if (da_bno != 0) {
-			if (verify_dir2_path(mp, da_cursor, 0)) {
+			if (verify_da_path(mp, da_cursor, 0, XFS_DATA_FORK)) {
 				libxfs_putbuf(bp);
 				goto error_out;
 			}
@@ -1810,7 +1179,7 @@ _("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
 		} else
 			libxfs_putbuf(bp);
 	} while (da_bno != 0);
-	if (verify_final_dir2_path(mp, da_cursor, 0)) {
+	if (verify_final_da_path(mp, da_cursor, 0)) {
 		/*
 		 * Verify the final path up (right-hand-side) if still ok.
 		 */
@@ -1820,14 +1189,14 @@ _("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
 	/*
 	 * Redundant but just for testing.
 	 */
-	release_dir2_cursor(mp, da_cursor, 0);
+	release_da_cursor(mp, da_cursor, 0);
 	return 0;
 
 error_out:
 	/*
 	 * Release all buffers holding interior btree blocks.
 	 */
-	err_release_dir2_cursor(mp, da_cursor, 0);
+	err_release_da_cursor(mp, da_cursor, 0);
 	if (bmp && (bmp != &lbmp))
 		free(bmp);
 	return 1;
@@ -1846,7 +1215,7 @@ process_node_dir2(
 	int		*repair)
 {
 	xfs_dablk_t		bno;
-	dir2_bt_cursor_t	da_cursor;
+	da_bt_cursor_t		da_cursor;
 
 	/*
 	 * Try again -- traverse down left-side of tree until we hit the
@@ -1862,14 +1231,14 @@ process_node_dir2(
 	/*
 	 * Now process interior node.
 	 */
-	if (traverse_int_dir2block(mp, &da_cursor, &bno) == 0)
+	if (traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK) == 0)
 		return 1;
 
 	/*
 	 * Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC
 	 */
 	if (bno == 0) {
-		release_dir2_cursor(mp, &da_cursor, 0);
+		release_da_cursor(mp, &da_cursor, 0);
 		return 0;
 	} else {
 		/*
diff --git a/repair/dir2.h b/repair/dir2.h
index 186633f..e4d4eeb 100644
--- a/repair/dir2.h
+++ b/repair/dir2.h
@@ -22,50 +22,6 @@
 struct blkmap;
 struct bmap_ext;
 
-/*
- * the cursor gets passed up and down the da btree processing
- * routines.  The interior block processing routines use the
- * cursor to determine if the pointers to and from the preceding
- * and succeeding sibling blocks are ok and whether the values in
- * the current block are consistent with the entries in the parent
- * nodes.  When a block is traversed, a parent-verification routine
- * is called to verify if the next logical entry in the next level up
- * is consistent with the greatest hashval in the next block of the
- * current level.  The verification routine is itself recursive and
- * calls itself if it has to traverse an interior block to get
- * the next logical entry.  The routine recurses upwards through
- * the tree until it finds a block where it can simply step to
- * the next entry.  The hashval in that entry should be equal to
- * the hashval being passed to it (the greatest hashval in the block
- * that the entry points to).  If that isn't true, then the tree
- * is blown and we need to trash it, salvage and trash it, or fix it.
- * Currently, we just trash it.
- */
-typedef struct dir2_level_state  {
-	xfs_buf_t	*bp;		/* block bp */
-	xfs_dablk_t	bno;		/* file block number */
-	xfs_dahash_t	hashval;	/* last verified hashval */
-	int		index;		/* current index in block */
-	int		dirty;		/* is buffer dirty ? (1 == yes) */
-} dir2_level_state_t;
-
-typedef struct dir2_bt_cursor  {
-	int			active;	/* highest level in tree (# levels-1) */
-	xfs_ino_t		ino;
-	xfs_dablk_t		greatest_bno;
-	xfs_dinode_t		*dip;
-	dir2_level_state_t	level[XFS_DA_NODE_MAXDEPTH];
-	struct blkmap		*blkmap;
-} dir2_bt_cursor_t;
-
-#include "bmap.h"	/* Goes away in later refactoring */
-struct xfs_buf *
-da_read_buf(
-	xfs_mount_t	*mp,
-	int		nex,
-	bmap_ext_t	*bmp,
-	const struct xfs_buf_ops *ops);
-
 int
 process_dir2(
 	xfs_mount_t	*mp,
@@ -87,9 +43,4 @@ int
 dir2_is_badino(
 	xfs_ino_t	ino);
 
-int
-namecheck(
-	char		*name,
-	int		length);
-
 #endif	/* _XR_DIR2_H */
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux