diff options
Diffstat (limited to 'fs/xfs/xfs_dir2_node.c')
| -rw-r--r-- | fs/xfs/xfs_dir2_node.c | 1014 | 
1 files changed, 641 insertions, 373 deletions
| diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 5980f9b7fa9..2226a00acd1 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -1,5 +1,6 @@  /*   * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * Copyright (c) 2013 Red Hat, Inc.   * All Rights Reserved.   *   * This program is free software; you can redistribute it and/or @@ -32,20 +33,14 @@  #include "xfs_dir2_priv.h"  #include "xfs_error.h"  #include "xfs_trace.h" +#include "xfs_buf_item.h" +#include "xfs_cksum.h"  /*   * Function declarations.   */  static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args,  			      int index); -#ifdef DEBUG -static void xfs_dir2_leafn_check(struct xfs_inode *dp, struct xfs_buf *bp); -#else -#define	xfs_dir2_leafn_check(dp, bp) -#endif -static void xfs_dir2_leafn_moveents(xfs_da_args_t *args, struct xfs_buf *bp_s, -				    int start_s, struct xfs_buf *bp_d, -				    int start_d, int count);  static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state,  				     xfs_da_state_blk_t *blk1,  				     xfs_da_state_blk_t *blk2); @@ -55,52 +50,126 @@ static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,  static int xfs_dir2_node_addname_int(xfs_da_args_t *args,  				     xfs_da_state_blk_t *fblk); -static void -xfs_dir2_free_verify( +/* + * Check internal consistency of a leafn block. + */ +#ifdef DEBUG +#define	xfs_dir3_leaf_check(mp, bp) \ +do { \ +	if (!xfs_dir3_leafn_check((mp), (bp))) \ +		ASSERT(0); \ +} while (0); + +static bool +xfs_dir3_leafn_check( +	struct xfs_mount	*mp, +	struct xfs_buf		*bp) +{ +	struct xfs_dir2_leaf	*leaf = bp->b_addr; +	struct xfs_dir3_icleaf_hdr leafhdr; + +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); + +	if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { +		struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; +		if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) +			return false; +	} else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) +		return false; + +	return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf); +} +#else +#define	xfs_dir3_leaf_check(mp, bp) +#endif + +static bool +xfs_dir3_free_verify(  	struct xfs_buf		*bp)  {  	struct xfs_mount	*mp = bp->b_target->bt_mount;  	struct xfs_dir2_free_hdr *hdr = bp->b_addr; -	int			block_ok = 0; -	block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC); -	if (!block_ok) { -		XFS_CORRUPTION_ERROR("xfs_dir2_free_verify magic", -				     XFS_ERRLEVEL_LOW, mp, hdr); -		xfs_buf_ioerror(bp, EFSCORRUPTED); +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; + +		if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC)) +			return false; +		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid)) +			return false; +		if (be64_to_cpu(hdr3->blkno) != bp->b_bn) +			return false; +	} else { +		if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) +			return false;  	} + +	/* XXX: should bounds check the xfs_dir3_icfree_hdr here */ + +	return true;  }  static void -xfs_dir2_free_read_verify( +xfs_dir3_free_read_verify(  	struct xfs_buf	*bp)  { -	xfs_dir2_free_verify(bp); +	struct xfs_mount	*mp = bp->b_target->bt_mount; + +	if ((xfs_sb_version_hascrc(&mp->m_sb) && +	     !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), +					  XFS_DIR3_FREE_CRC_OFF)) || +	    !xfs_dir3_free_verify(bp)) { +		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); +		xfs_buf_ioerror(bp, EFSCORRUPTED); +	}  }  static void -xfs_dir2_free_write_verify( +xfs_dir3_free_write_verify(  	struct xfs_buf	*bp)  { -	xfs_dir2_free_verify(bp); +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_buf_log_item	*bip = bp->b_fspriv; +	struct xfs_dir3_blk_hdr	*hdr3 = bp->b_addr; + +	if (!xfs_dir3_free_verify(bp)) { +		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); +		xfs_buf_ioerror(bp, EFSCORRUPTED); +		return; +	} + +	if (!xfs_sb_version_hascrc(&mp->m_sb)) +		return; + +	if (bip) +		hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); + +	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_FREE_CRC_OFF);  } -static const struct xfs_buf_ops xfs_dir2_free_buf_ops = { -	.verify_read = xfs_dir2_free_read_verify, -	.verify_write = xfs_dir2_free_write_verify, +const struct xfs_buf_ops xfs_dir3_free_buf_ops = { +	.verify_read = xfs_dir3_free_read_verify, +	.verify_write = xfs_dir3_free_write_verify,  };  static int -__xfs_dir2_free_read( +__xfs_dir3_free_read(  	struct xfs_trans	*tp,  	struct xfs_inode	*dp,  	xfs_dablk_t		fbno,  	xfs_daddr_t		mappedbno,  	struct xfs_buf		**bpp)  { -	return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, -				XFS_DATA_FORK, &xfs_dir2_free_buf_ops); +	int			err; + +	err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, +				XFS_DATA_FORK, &xfs_dir3_free_buf_ops); + +	/* try read returns without an error or *bpp if it lands in a hole */ +	if (!err && tp && *bpp) +		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); +	return err;  }  int @@ -110,7 +179,7 @@ xfs_dir2_free_read(  	xfs_dablk_t		fbno,  	struct xfs_buf		**bpp)  { -	return __xfs_dir2_free_read(tp, dp, fbno, -1, bpp); +	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);  }  static int @@ -120,7 +189,96 @@ xfs_dir2_free_try_read(  	xfs_dablk_t		fbno,  	struct xfs_buf		**bpp)  { -	return __xfs_dir2_free_read(tp, dp, fbno, -2, bpp); +	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); +} + + +void +xfs_dir3_free_hdr_from_disk( +	struct xfs_dir3_icfree_hdr	*to, +	struct xfs_dir2_free		*from) +{ +	if (from->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)) { +		to->magic = be32_to_cpu(from->hdr.magic); +		to->firstdb = be32_to_cpu(from->hdr.firstdb); +		to->nvalid = be32_to_cpu(from->hdr.nvalid); +		to->nused = be32_to_cpu(from->hdr.nused); +	} else { +		struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; + +		to->magic = be32_to_cpu(hdr3->hdr.magic); +		to->firstdb = be32_to_cpu(hdr3->firstdb); +		to->nvalid = be32_to_cpu(hdr3->nvalid); +		to->nused = be32_to_cpu(hdr3->nused); +	} + +	ASSERT(to->magic == XFS_DIR2_FREE_MAGIC || +	       to->magic == XFS_DIR3_FREE_MAGIC); +} + +static void +xfs_dir3_free_hdr_to_disk( +	struct xfs_dir2_free		*to, +	struct xfs_dir3_icfree_hdr	*from) +{ +	ASSERT(from->magic == XFS_DIR2_FREE_MAGIC || +	       from->magic == XFS_DIR3_FREE_MAGIC); + +	if (from->magic == XFS_DIR2_FREE_MAGIC) { +		to->hdr.magic = cpu_to_be32(from->magic); +		to->hdr.firstdb = cpu_to_be32(from->firstdb); +		to->hdr.nvalid = cpu_to_be32(from->nvalid); +		to->hdr.nused = cpu_to_be32(from->nused); +	} else { +		struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; + +		hdr3->hdr.magic = cpu_to_be32(from->magic); +		hdr3->firstdb = cpu_to_be32(from->firstdb); +		hdr3->nvalid = cpu_to_be32(from->nvalid); +		hdr3->nused = cpu_to_be32(from->nused); +	} +} + +static int +xfs_dir3_free_get_buf( +	struct xfs_trans	*tp, +	struct xfs_inode	*dp, +	xfs_dir2_db_t		fbno, +	struct xfs_buf		**bpp) +{ +	struct xfs_mount	*mp = dp->i_mount; +	struct xfs_buf		*bp; +	int			error; +	struct xfs_dir3_icfree_hdr hdr; + +	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno), +				   -1, &bp, XFS_DATA_FORK); +	if (error) +		return error; + +	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); +	bp->b_ops = &xfs_dir3_free_buf_ops; + +	/* +	 * Initialize the new block to be empty, and remember +	 * its first slot as our empty slot. +	 */ +	memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr)); +	memset(&hdr, 0, sizeof(hdr)); + +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; + +		hdr.magic = XFS_DIR3_FREE_MAGIC; + +		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); +		hdr3->hdr.owner = cpu_to_be64(dp->i_ino); +		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid); +	} else +		hdr.magic = XFS_DIR2_FREE_MAGIC; +	xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr); +	*bpp = bp; +	return 0;  }  /* @@ -134,13 +292,16 @@ xfs_dir2_free_log_bests(  	int			last)		/* last entry to log */  {  	xfs_dir2_free_t		*free;		/* freespace structure */ +	__be16			*bests;  	free = bp->b_addr; -	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); +	bests = xfs_dir3_free_bests_p(tp->t_mountp, free); +	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || +	       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));  	xfs_trans_log_buf(tp, bp, -		(uint)((char *)&free->bests[first] - (char *)free), -		(uint)((char *)&free->bests[last] - (char *)free + -		       sizeof(free->bests[0]) - 1)); +		(uint)((char *)&bests[first] - (char *)free), +		(uint)((char *)&bests[last] - (char *)free + +		       sizeof(bests[0]) - 1));  }  /* @@ -154,9 +315,9 @@ xfs_dir2_free_log_header(  	xfs_dir2_free_t		*free;		/* freespace structure */  	free = bp->b_addr; -	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); -	xfs_trans_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free), -		(uint)(sizeof(xfs_dir2_free_hdr_t) - 1)); +	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || +	       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); +	xfs_trans_log_buf(tp, bp, 0, xfs_dir3_free_hdr_size(tp->t_mountp) - 1);  }  /* @@ -183,6 +344,7 @@ xfs_dir2_leaf_to_node(  	xfs_dir2_data_off_t	off;		/* freespace entry value */  	__be16			*to;		/* pointer to freespace entry */  	xfs_trans_t		*tp;		/* transaction pointer */ +	struct xfs_dir3_icfree_hdr freehdr;  	trace_xfs_dir2_leaf_to_node(args); @@ -199,44 +361,53 @@ xfs_dir2_leaf_to_node(  	/*  	 * Get the buffer for the new freespace block.  	 */ -	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb), -1, &fbp, -				XFS_DATA_FORK); +	error = xfs_dir3_free_get_buf(tp, dp, fdb, &fbp);  	if (error)  		return error; -	fbp->b_ops = &xfs_dir2_free_buf_ops;  	free = fbp->b_addr; +	xfs_dir3_free_hdr_from_disk(&freehdr, free);  	leaf = lbp->b_addr;  	ltp = xfs_dir2_leaf_tail_p(mp, leaf); -	/* -	 * Initialize the freespace block header. -	 */ -	free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC); -	free->hdr.firstdb = 0; -	ASSERT(be32_to_cpu(ltp->bestcount) <= (uint)dp->i_d.di_size / mp->m_dirblksize); -	free->hdr.nvalid = ltp->bestcount; +	ASSERT(be32_to_cpu(ltp->bestcount) <= +				(uint)dp->i_d.di_size / mp->m_dirblksize); +  	/*  	 * Copy freespace entries from the leaf block to the new block.  	 * Count active entries.  	 */ -	for (i = n = 0, from = xfs_dir2_leaf_bests_p(ltp), to = free->bests; -	     i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { +	from = xfs_dir2_leaf_bests_p(ltp); +	to = xfs_dir3_free_bests_p(mp, free); +	for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {  		if ((off = be16_to_cpu(*from)) != NULLDATAOFF)  			n++;  		*to = cpu_to_be16(off);  	} -	free->hdr.nused = cpu_to_be32(n); - -	lbp->b_ops = &xfs_dir2_leafn_buf_ops; -	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);  	/* -	 * Log everything. +	 * Now initialize the freespace block header.  	 */ -	xfs_dir2_leaf_log_header(tp, lbp); +	freehdr.nused = n; +	freehdr.nvalid = be32_to_cpu(ltp->bestcount); + +	xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr); +	xfs_dir2_free_log_bests(tp, fbp, 0, freehdr.nvalid - 1);  	xfs_dir2_free_log_header(tp, fbp); -	xfs_dir2_free_log_bests(tp, fbp, 0, be32_to_cpu(free->hdr.nvalid) - 1); -	xfs_dir2_leafn_check(dp, lbp); + +	/* +	 * Converting the leaf to a leafnode is just a matter of changing the +	 * magic number and the ops. Do the change directly to the buffer as +	 * it's less work (and less code) than decoding the header to host +	 * format and back again. +	 */ +	if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) +		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); +	else +		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); +	lbp->b_ops = &xfs_dir3_leafn_buf_ops; +	xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); +	xfs_dir3_leaf_log_header(tp, lbp); +	xfs_dir3_leaf_check(mp, lbp);  	return 0;  } @@ -260,6 +431,8 @@ xfs_dir2_leafn_add(  	int			lowstale;	/* previous stale entry */  	xfs_mount_t		*mp;		/* filesystem mount point */  	xfs_trans_t		*tp;		/* transaction pointer */ +	struct xfs_dir3_icleaf_hdr leafhdr; +	struct xfs_dir2_leaf_entry *ents;  	trace_xfs_dir2_leafn_add(args, index); @@ -267,6 +440,8 @@ xfs_dir2_leafn_add(  	mp = dp->i_mount;  	tp = args->trans;  	leaf = bp->b_addr; +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); +	ents = xfs_dir3_leaf_ents_p(leaf);  	/*  	 * Quick check just to make sure we are not going to index @@ -282,15 +457,15 @@ xfs_dir2_leafn_add(  	 * a compact.  	 */ -	if (be16_to_cpu(leaf->hdr.count) == xfs_dir2_max_leaf_ents(mp)) { -		if (!leaf->hdr.stale) +	if (leafhdr.count == xfs_dir3_max_leaf_ents(mp, leaf)) { +		if (!leafhdr.stale)  			return XFS_ERROR(ENOSPC); -		compact = be16_to_cpu(leaf->hdr.stale) > 1; +		compact = leafhdr.stale > 1;  	} else  		compact = 0; -	ASSERT(index == 0 || be32_to_cpu(leaf->ents[index - 1].hashval) <= args->hashval); -	ASSERT(index == be16_to_cpu(leaf->hdr.count) || -	       be32_to_cpu(leaf->ents[index].hashval) >= args->hashval); +	ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); +	ASSERT(index == leafhdr.count || +	       be32_to_cpu(ents[index].hashval) >= args->hashval);  	if (args->op_flags & XFS_DA_OP_JUSTCHECK)  		return 0; @@ -299,61 +474,51 @@ xfs_dir2_leafn_add(  	 * Compact out all but one stale leaf entry.  Leaves behind  	 * the entry closest to index.  	 */ -	if (compact) { -		xfs_dir2_leaf_compact_x1(bp, &index, &lowstale, &highstale, -			&lfloglow, &lfloghigh); -	} -	/* -	 * Set impossible logging indices for this case. -	 */ -	else if (leaf->hdr.stale) { -		lfloglow = be16_to_cpu(leaf->hdr.count); +	if (compact) +		xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, +					 &highstale, &lfloglow, &lfloghigh); +	else if (leafhdr.stale) { +		/* +		 * Set impossible logging indices for this case. +		 */ +		lfloglow = leafhdr.count;  		lfloghigh = -1;  	}  	/*  	 * Insert the new entry, log everything.  	 */ -	lep = xfs_dir2_leaf_find_entry(leaf, index, compact, lowstale, +	lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale,  				       highstale, &lfloglow, &lfloghigh);  	lep->hashval = cpu_to_be32(args->hashval);  	lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp,  				args->blkno, args->index)); -	xfs_dir2_leaf_log_header(tp, bp); -	xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh); -	xfs_dir2_leafn_check(dp, bp); + +	xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); +	xfs_dir3_leaf_log_header(tp, bp); +	xfs_dir3_leaf_log_ents(tp, bp, lfloglow, lfloghigh); +	xfs_dir3_leaf_check(mp, bp);  	return 0;  }  #ifdef DEBUG -/* - * Check internal consistency of a leafn block. - */ -void -xfs_dir2_leafn_check( -	struct xfs_inode *dp, -	struct xfs_buf	*bp) +static void +xfs_dir2_free_hdr_check( +	struct xfs_mount *mp, +	struct xfs_buf	*bp, +	xfs_dir2_db_t	db)  { -	int		i;			/* leaf index */ -	xfs_dir2_leaf_t	*leaf;			/* leaf structure */ -	xfs_mount_t	*mp;			/* filesystem mount point */ -	int		stale;			/* count of stale leaves */ +	struct xfs_dir3_icfree_hdr hdr; -	leaf = bp->b_addr; -	mp = dp->i_mount; -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -	ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp)); -	for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) { -		if (i + 1 < be16_to_cpu(leaf->hdr.count)) { -			ASSERT(be32_to_cpu(leaf->ents[i].hashval) <= -			       be32_to_cpu(leaf->ents[i + 1].hashval)); -		} -		if (leaf->ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) -			stale++; -	} -	ASSERT(be16_to_cpu(leaf->hdr.stale) == stale); +	xfs_dir3_free_hdr_from_disk(&hdr, bp->b_addr); + +	ASSERT((hdr.firstdb % xfs_dir3_free_max_bests(mp)) == 0); +	ASSERT(hdr.firstdb <= db); +	ASSERT(db < hdr.firstdb + hdr.nvalid);  } +#else +#define xfs_dir2_free_hdr_check(mp, dp, db)  #endif	/* DEBUG */  /* @@ -365,15 +530,22 @@ xfs_dir2_leafn_lasthash(  	struct xfs_buf	*bp,			/* leaf buffer */  	int		*count)			/* count of entries in leaf */  { -	xfs_dir2_leaf_t	*leaf;			/* leaf structure */ +	struct xfs_dir2_leaf	*leaf = bp->b_addr; +	struct xfs_dir2_leaf_entry *ents; +	struct xfs_dir3_icleaf_hdr leafhdr; + +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); + +	ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || +	       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); -	leaf = bp->b_addr; -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));  	if (count) -		*count = be16_to_cpu(leaf->hdr.count); -	if (!leaf->hdr.count) +		*count = leafhdr.count; +	if (!leafhdr.count)  		return 0; -	return be32_to_cpu(leaf->ents[be16_to_cpu(leaf->hdr.count) - 1].hashval); + +	ents = xfs_dir3_leaf_ents_p(leaf); +	return be32_to_cpu(ents[leafhdr.count - 1].hashval);  }  /* @@ -402,16 +574,19 @@ xfs_dir2_leafn_lookup_for_addname(  	xfs_dir2_db_t		newdb;		/* new data block number */  	xfs_dir2_db_t		newfdb;		/* new free block number */  	xfs_trans_t		*tp;		/* transaction pointer */ +	struct xfs_dir2_leaf_entry *ents; +	struct xfs_dir3_icleaf_hdr leafhdr;  	dp = args->dp;  	tp = args->trans;  	mp = dp->i_mount;  	leaf = bp->b_addr; -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -#ifdef __KERNEL__ -	ASSERT(be16_to_cpu(leaf->hdr.count) > 0); -#endif -	xfs_dir2_leafn_check(dp, bp); +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); +	ents = xfs_dir3_leaf_ents_p(leaf); + +	xfs_dir3_leaf_check(mp, bp); +	ASSERT(leafhdr.count > 0); +  	/*  	 * Look up the hash value in the leaf entries.  	 */ @@ -424,15 +599,16 @@ xfs_dir2_leafn_lookup_for_addname(  		curbp = state->extrablk.bp;  		curfdb = state->extrablk.blkno;  		free = curbp->b_addr; -		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); +		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || +		       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));  	}  	length = xfs_dir2_data_entsize(args->namelen);  	/*  	 * Loop over leaf entries with the right hash value.  	 */ -	for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && -				be32_to_cpu(lep->hashval) == args->hashval; -				lep++, index++) { +	for (lep = &ents[index]; +	     index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; +	     lep++, index++) {  		/*  		 * Skip stale leaf entries.  		 */ @@ -451,6 +627,8 @@ xfs_dir2_leafn_lookup_for_addname(  		 * in hand, take a look at it.  		 */  		if (newdb != curdb) { +			__be16 *bests; +  			curdb = newdb;  			/*  			 * Convert the data block to the free block @@ -473,13 +651,8 @@ xfs_dir2_leafn_lookup_for_addname(  				if (error)  					return error;  				free = curbp->b_addr; -				ASSERT(be32_to_cpu(free->hdr.magic) == -					XFS_DIR2_FREE_MAGIC); -				ASSERT((be32_to_cpu(free->hdr.firstdb) % -					xfs_dir2_free_max_bests(mp)) == 0); -				ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb); -				ASSERT(curdb < be32_to_cpu(free->hdr.firstdb) + -					be32_to_cpu(free->hdr.nvalid)); + +				xfs_dir2_free_hdr_check(mp, curbp, curdb);  			}  			/*  			 * Get the index for our entry. @@ -488,8 +661,8 @@ xfs_dir2_leafn_lookup_for_addname(  			/*  			 * If it has room, return it.  			 */ -			if (unlikely(free->bests[fi] == -			    cpu_to_be16(NULLDATAOFF))) { +			bests = xfs_dir3_free_bests_p(mp, free); +			if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) {  				XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",  							XFS_ERRLEVEL_LOW, mp);  				if (curfdb != newfdb) @@ -497,7 +670,7 @@ xfs_dir2_leafn_lookup_for_addname(  				return XFS_ERROR(EFSCORRUPTED);  			}  			curfdb = newfdb; -			if (be16_to_cpu(free->bests[fi]) >= length) +			if (be16_to_cpu(bests[fi]) >= length)  				goto out;  		}  	} @@ -511,6 +684,12 @@ out:  		state->extrablk.bp = curbp;  		state->extrablk.index = fi;  		state->extrablk.blkno = curfdb; + +		/* +		 * Important: this magic number is not in the buffer - it's for +		 * buffer type information and therefore only the free/data type +		 * matters here, not whether CRCs are enabled or not. +		 */  		state->extrablk.magic = XFS_DIR2_FREE_MAGIC;  	} else {  		state->extravalid = 0; @@ -545,16 +724,19 @@ xfs_dir2_leafn_lookup_for_entry(  	xfs_dir2_db_t		newdb;		/* new data block number */  	xfs_trans_t		*tp;		/* transaction pointer */  	enum xfs_dacmp		cmp;		/* comparison result */ +	struct xfs_dir2_leaf_entry *ents; +	struct xfs_dir3_icleaf_hdr leafhdr;  	dp = args->dp;  	tp = args->trans;  	mp = dp->i_mount;  	leaf = bp->b_addr; -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -#ifdef __KERNEL__ -	ASSERT(be16_to_cpu(leaf->hdr.count) > 0); -#endif -	xfs_dir2_leafn_check(dp, bp); +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); +	ents = xfs_dir3_leaf_ents_p(leaf); + +	xfs_dir3_leaf_check(mp, bp); +	ASSERT(leafhdr.count > 0); +  	/*  	 * Look up the hash value in the leaf entries.  	 */ @@ -569,9 +751,9 @@ xfs_dir2_leafn_lookup_for_entry(  	/*  	 * Loop over leaf entries with the right hash value.  	 */ -	for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && -				be32_to_cpu(lep->hashval) == args->hashval; -				lep++, index++) { +	for (lep = &ents[index]; +	     index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; +	     lep++, index++) {  		/*  		 * Skip stale leaf entries.  		 */ @@ -604,13 +786,13 @@ xfs_dir2_leafn_lookup_for_entry(  				ASSERT(state->extravalid);  				curbp = state->extrablk.bp;  			} else { -				error = xfs_dir2_data_read(tp, dp, +				error = xfs_dir3_data_read(tp, dp,  						xfs_dir2_db_to_da(mp, newdb),  						-1, &curbp);  				if (error)  					return error;  			} -			xfs_dir2_data_check(dp, curbp); +			xfs_dir3_data_check(dp, curbp);  			curdb = newdb;  		}  		/* @@ -638,13 +820,13 @@ xfs_dir2_leafn_lookup_for_entry(  			state->extrablk.index = (int)((char *)dep -  							(char *)curbp->b_addr);  			state->extrablk.magic = XFS_DIR2_DATA_MAGIC; -			curbp->b_ops = &xfs_dir2_data_buf_ops; +			curbp->b_ops = &xfs_dir3_data_buf_ops; +			xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF);  			if (cmp == XFS_CMP_EXACT)  				return XFS_ERROR(EEXIST);  		}  	} -	ASSERT(index == be16_to_cpu(leaf->hdr.count) || -					(args->op_flags & XFS_DA_OP_OKNOENT)); +	ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT));  	if (curbp) {  		if (args->cmpresult == XFS_CMP_DIFFERENT) {  			/* Giving back last used data block. */ @@ -653,7 +835,8 @@ xfs_dir2_leafn_lookup_for_entry(  			state->extrablk.index = -1;  			state->extrablk.blkno = curdb;  			state->extrablk.magic = XFS_DIR2_DATA_MAGIC; -			curbp->b_ops = &xfs_dir2_data_buf_ops; +			curbp->b_ops = &xfs_dir3_data_buf_ops; +			xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF);  		} else {  			/* If the curbp is not the CI match block, drop it */  			if (state->extrablk.bp != curbp) @@ -689,52 +872,50 @@ xfs_dir2_leafn_lookup_int(   * Log entries and headers.  Stale entries are preserved.   */  static void -xfs_dir2_leafn_moveents( -	xfs_da_args_t	*args,			/* operation arguments */ -	struct xfs_buf	*bp_s,			/* source leaf buffer */ -	int		start_s,		/* source leaf index */ -	struct xfs_buf	*bp_d,			/* destination leaf buffer */ -	int		start_d,		/* destination leaf index */ -	int		count)			/* count of leaves to copy */ +xfs_dir3_leafn_moveents( +	xfs_da_args_t			*args,	/* operation arguments */ +	struct xfs_buf			*bp_s,	/* source */ +	struct xfs_dir3_icleaf_hdr	*shdr, +	struct xfs_dir2_leaf_entry	*sents, +	int				start_s,/* source leaf index */ +	struct xfs_buf			*bp_d,	/* destination */ +	struct xfs_dir3_icleaf_hdr	*dhdr, +	struct xfs_dir2_leaf_entry	*dents, +	int				start_d,/* destination leaf index */ +	int				count)	/* count of leaves to copy */  { -	xfs_dir2_leaf_t	*leaf_d;		/* destination leaf structure */ -	xfs_dir2_leaf_t	*leaf_s;		/* source leaf structure */ -	int		stale;			/* count stale leaves copied */ -	xfs_trans_t	*tp;			/* transaction pointer */ +	struct xfs_trans		*tp = args->trans; +	int				stale;	/* count stale leaves copied */  	trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count);  	/*  	 * Silently return if nothing to do.  	 */ -	if (count == 0) { +	if (count == 0)  		return; -	} -	tp = args->trans; -	leaf_s = bp_s->b_addr; -	leaf_d = bp_d->b_addr; +  	/*  	 * If the destination index is not the end of the current  	 * destination leaf entries, open up a hole in the destination  	 * to hold the new entries.  	 */ -	if (start_d < be16_to_cpu(leaf_d->hdr.count)) { -		memmove(&leaf_d->ents[start_d + count], &leaf_d->ents[start_d], -			(be16_to_cpu(leaf_d->hdr.count) - start_d) * -			sizeof(xfs_dir2_leaf_entry_t)); -		xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count, -			count + be16_to_cpu(leaf_d->hdr.count) - 1); +	if (start_d < dhdr->count) { +		memmove(&dents[start_d + count], &dents[start_d], +			(dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); +		xfs_dir3_leaf_log_ents(tp, bp_d, start_d + count, +				       count + dhdr->count - 1);  	}  	/*  	 * If the source has stale leaves, count the ones in the copy range  	 * so we can update the header correctly.  	 */ -	if (leaf_s->hdr.stale) { +	if (shdr->stale) {  		int	i;			/* temp leaf index */  		for (i = start_s, stale = 0; i < start_s + count; i++) { -			if (leaf_s->ents[i].address == -			    cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) +			if (sents[i].address == +					cpu_to_be32(XFS_DIR2_NULL_DATAPTR))  				stale++;  		}  	} else @@ -742,29 +923,27 @@ xfs_dir2_leafn_moveents(  	/*  	 * Copy the leaf entries from source to destination.  	 */ -	memcpy(&leaf_d->ents[start_d], &leaf_s->ents[start_s], +	memcpy(&dents[start_d], &sents[start_s],  		count * sizeof(xfs_dir2_leaf_entry_t)); -	xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); +	xfs_dir3_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); +  	/*  	 * If there are source entries after the ones we copied,  	 * delete the ones we copied by sliding the next ones down.  	 */ -	if (start_s + count < be16_to_cpu(leaf_s->hdr.count)) { -		memmove(&leaf_s->ents[start_s], &leaf_s->ents[start_s + count], +	if (start_s + count < shdr->count) { +		memmove(&sents[start_s], &sents[start_s + count],  			count * sizeof(xfs_dir2_leaf_entry_t)); -		xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); +		xfs_dir3_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1);  	} +  	/*  	 * Update the headers and log them.  	 */ -	be16_add_cpu(&leaf_s->hdr.count, -(count)); -	be16_add_cpu(&leaf_s->hdr.stale, -(stale)); -	be16_add_cpu(&leaf_d->hdr.count, count); -	be16_add_cpu(&leaf_d->hdr.stale, stale); -	xfs_dir2_leaf_log_header(tp, bp_s); -	xfs_dir2_leaf_log_header(tp, bp_d); -	xfs_dir2_leafn_check(args->dp, bp_s); -	xfs_dir2_leafn_check(args->dp, bp_d); +	shdr->count -= count; +	shdr->stale -= stale; +	dhdr->count += count; +	dhdr->stale += stale;  }  /* @@ -773,21 +952,25 @@ xfs_dir2_leafn_moveents(   */  int						/* sort order */  xfs_dir2_leafn_order( -	struct xfs_buf	*leaf1_bp,		/* leaf1 buffer */ -	struct xfs_buf	*leaf2_bp)		/* leaf2 buffer */ +	struct xfs_buf		*leaf1_bp,		/* leaf1 buffer */ +	struct xfs_buf		*leaf2_bp)		/* leaf2 buffer */  { -	xfs_dir2_leaf_t	*leaf1;			/* leaf1 structure */ -	xfs_dir2_leaf_t	*leaf2;			/* leaf2 structure */ - -	leaf1 = leaf1_bp->b_addr; -	leaf2 = leaf2_bp->b_addr; -	ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -	ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -	if (be16_to_cpu(leaf1->hdr.count) > 0 && -	    be16_to_cpu(leaf2->hdr.count) > 0 && -	    (be32_to_cpu(leaf2->ents[0].hashval) < be32_to_cpu(leaf1->ents[0].hashval) || -	     be32_to_cpu(leaf2->ents[be16_to_cpu(leaf2->hdr.count) - 1].hashval) < -	     be32_to_cpu(leaf1->ents[be16_to_cpu(leaf1->hdr.count) - 1].hashval))) +	struct xfs_dir2_leaf	*leaf1 = leaf1_bp->b_addr; +	struct xfs_dir2_leaf	*leaf2 = leaf2_bp->b_addr; +	struct xfs_dir2_leaf_entry *ents1; +	struct xfs_dir2_leaf_entry *ents2; +	struct xfs_dir3_icleaf_hdr hdr1; +	struct xfs_dir3_icleaf_hdr hdr2; + +	xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); +	xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); +	ents1 = xfs_dir3_leaf_ents_p(leaf1); +	ents2 = xfs_dir3_leaf_ents_p(leaf2); + +	if (hdr1.count > 0 && hdr2.count > 0 && +	    (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || +	     be32_to_cpu(ents2[hdr2.count - 1].hashval) < +				be32_to_cpu(ents1[hdr1.count - 1].hashval)))  		return 1;  	return 0;  } @@ -811,11 +994,15 @@ xfs_dir2_leafn_rebalance(  	xfs_dir2_leaf_t		*leaf1;		/* first leaf structure */  	xfs_dir2_leaf_t		*leaf2;		/* second leaf structure */  	int			mid;		/* midpoint leaf index */ -#ifdef DEBUG +#if defined(DEBUG) || defined(XFS_WARN)  	int			oldstale;	/* old count of stale leaves */  #endif  	int			oldsum;		/* old total leaf count */  	int			swap;		/* swapped leaf blocks */ +	struct xfs_dir2_leaf_entry *ents1; +	struct xfs_dir2_leaf_entry *ents2; +	struct xfs_dir3_icleaf_hdr hdr1; +	struct xfs_dir3_icleaf_hdr hdr2;  	args = state->args;  	/* @@ -830,11 +1017,17 @@ xfs_dir2_leafn_rebalance(  	}  	leaf1 = blk1->bp->b_addr;  	leaf2 = blk2->bp->b_addr; -	oldsum = be16_to_cpu(leaf1->hdr.count) + be16_to_cpu(leaf2->hdr.count); -#ifdef DEBUG -	oldstale = be16_to_cpu(leaf1->hdr.stale) + be16_to_cpu(leaf2->hdr.stale); +	xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); +	xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); +	ents1 = xfs_dir3_leaf_ents_p(leaf1); +	ents2 = xfs_dir3_leaf_ents_p(leaf2); + +	oldsum = hdr1.count + hdr2.count; +#if defined(DEBUG) || defined(XFS_WARN) +	oldstale = hdr1.stale + hdr2.stale;  #endif  	mid = oldsum >> 1; +  	/*  	 * If the old leaf count was odd then the new one will be even,  	 * so we need to divide the new count evenly. @@ -842,10 +1035,10 @@ xfs_dir2_leafn_rebalance(  	if (oldsum & 1) {  		xfs_dahash_t	midhash;	/* middle entry hash value */ -		if (mid >= be16_to_cpu(leaf1->hdr.count)) -			midhash = be32_to_cpu(leaf2->ents[mid - be16_to_cpu(leaf1->hdr.count)].hashval); +		if (mid >= hdr1.count) +			midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval);  		else -			midhash = be32_to_cpu(leaf1->ents[mid].hashval); +			midhash = be32_to_cpu(ents1[mid].hashval);  		isleft = args->hashval <= midhash;  	}  	/* @@ -859,30 +1052,42 @@ xfs_dir2_leafn_rebalance(  	 * Calculate moved entry count.  Positive means left-to-right,  	 * negative means right-to-left.  Then move the entries.  	 */ -	count = be16_to_cpu(leaf1->hdr.count) - mid + (isleft == 0); +	count = hdr1.count - mid + (isleft == 0);  	if (count > 0) -		xfs_dir2_leafn_moveents(args, blk1->bp, -			be16_to_cpu(leaf1->hdr.count) - count, blk2->bp, 0, count); +		xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, +					hdr1.count - count, blk2->bp, +					&hdr2, ents2, 0, count);  	else if (count < 0) -		xfs_dir2_leafn_moveents(args, blk2->bp, 0, blk1->bp, -			be16_to_cpu(leaf1->hdr.count), count); -	ASSERT(be16_to_cpu(leaf1->hdr.count) + be16_to_cpu(leaf2->hdr.count) == oldsum); -	ASSERT(be16_to_cpu(leaf1->hdr.stale) + be16_to_cpu(leaf2->hdr.stale) == oldstale); +		xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, +					blk1->bp, &hdr1, ents1, +					hdr1.count, count); + +	ASSERT(hdr1.count + hdr2.count == oldsum); +	ASSERT(hdr1.stale + hdr2.stale == oldstale); + +	/* log the changes made when moving the entries */ +	xfs_dir3_leaf_hdr_to_disk(leaf1, &hdr1); +	xfs_dir3_leaf_hdr_to_disk(leaf2, &hdr2); +	xfs_dir3_leaf_log_header(args->trans, blk1->bp); +	xfs_dir3_leaf_log_header(args->trans, blk2->bp); + +	xfs_dir3_leaf_check(args->dp->i_mount, blk1->bp); +	xfs_dir3_leaf_check(args->dp->i_mount, blk2->bp); +  	/*  	 * Mark whether we're inserting into the old or new leaf.  	 */ -	if (be16_to_cpu(leaf1->hdr.count) < be16_to_cpu(leaf2->hdr.count)) +	if (hdr1.count < hdr2.count)  		state->inleaf = swap; -	else if (be16_to_cpu(leaf1->hdr.count) > be16_to_cpu(leaf2->hdr.count)) +	else if (hdr1.count > hdr2.count)  		state->inleaf = !swap;  	else -		state->inleaf = -			swap ^ (blk1->index <= be16_to_cpu(leaf1->hdr.count)); +		state->inleaf = swap ^ (blk1->index <= hdr1.count);  	/*  	 * Adjust the expected index for insertion.  	 */  	if (!state->inleaf) -		blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); +		blk2->index = blk1->index - hdr1.count;  	/*  	 * Finally sanity check just to make sure we are not returning a @@ -898,7 +1103,7 @@ xfs_dir2_leafn_rebalance(  }  static int -xfs_dir2_data_block_free( +xfs_dir3_data_block_free(  	xfs_da_args_t		*args,  	struct xfs_dir2_data_hdr *hdr,  	struct xfs_dir2_free	*free, @@ -909,57 +1114,66 @@ xfs_dir2_data_block_free(  {  	struct xfs_trans	*tp = args->trans;  	int			logfree = 0; +	__be16			*bests; +	struct xfs_dir3_icfree_hdr freehdr; -	if (!hdr) { -		/* One less used entry in the free table.  */ -		be32_add_cpu(&free->hdr.nused, -1); -		xfs_dir2_free_log_header(tp, fbp); +	xfs_dir3_free_hdr_from_disk(&freehdr, free); +	bests = xfs_dir3_free_bests_p(tp->t_mountp, free); +	if (hdr) {  		/* -		 * If this was the last entry in the table, we can trim the -		 * table size back.  There might be other entries at the end -		 * referring to non-existent data blocks, get those too. +		 * Data block is not empty, just set the free entry to the new +		 * value.  		 */ -		if (findex == be32_to_cpu(free->hdr.nvalid) - 1) { -			int	i;		/* free entry index */ +		bests[findex] = cpu_to_be16(longest); +		xfs_dir2_free_log_bests(tp, fbp, findex, findex); +		return 0; +	} -			for (i = findex - 1; i >= 0; i--) { -				if (free->bests[i] != cpu_to_be16(NULLDATAOFF)) -					break; -			} -			free->hdr.nvalid = cpu_to_be32(i + 1); -			logfree = 0; -		} else { -			/* Not the last entry, just punch it out.  */ -			free->bests[findex] = cpu_to_be16(NULLDATAOFF); -			logfree = 1; -		} -		/* -		 * If there are no useful entries left in the block, -		 * get rid of the block if we can. -		 */ -		if (!free->hdr.nused) { -			int error; +	/* One less used entry in the free table. */ +	freehdr.nused--; -			error = xfs_dir2_shrink_inode(args, fdb, fbp); -			if (error == 0) { -				fbp = NULL; -				logfree = 0; -			} else if (error != ENOSPC || args->total != 0) -				return error; -			/* -			 * It's possible to get ENOSPC if there is no -			 * space reservation.  In this case some one -			 * else will eventually get rid of this block. -			 */ +	/* +	 * If this was the last entry in the table, we can trim the table size +	 * back.  There might be other entries at the end referring to +	 * non-existent data blocks, get those too. +	 */ +	if (findex == freehdr.nvalid - 1) { +		int	i;		/* free entry index */ + +		for (i = findex - 1; i >= 0; i--) { +			if (bests[i] != cpu_to_be16(NULLDATAOFF)) +				break;  		} +		freehdr.nvalid = i + 1; +		logfree = 0;  	} else { +		/* Not the last entry, just punch it out.  */ +		bests[findex] = cpu_to_be16(NULLDATAOFF); +		logfree = 1; +	} + +	xfs_dir3_free_hdr_to_disk(free, &freehdr); +	xfs_dir2_free_log_header(tp, fbp); + +	/* +	 * If there are no useful entries left in the block, get rid of the +	 * block if we can. +	 */ +	if (!freehdr.nused) { +		int error; + +		error = xfs_dir2_shrink_inode(args, fdb, fbp); +		if (error == 0) { +			fbp = NULL; +			logfree = 0; +		} else if (error != ENOSPC || args->total != 0) +			return error;  		/* -		 * Data block is not empty, just set the free entry to the new -		 * value. +		 * It's possible to get ENOSPC if there is no +		 * space reservation.  In this case some one +		 * else will eventually get rid of this block.  		 */ -		free->bests[findex] = cpu_to_be16(longest); -		logfree = 1;  	}  	/* Log the free entry that changed, unless we got rid of it.  */ @@ -994,6 +1208,9 @@ xfs_dir2_leafn_remove(  	int			needlog;	/* need to log data header */  	int			needscan;	/* need to rescan data frees */  	xfs_trans_t		*tp;		/* transaction pointer */ +	struct xfs_dir2_data_free *bf;		/* bestfree table */ +	struct xfs_dir3_icleaf_hdr leafhdr; +	struct xfs_dir2_leaf_entry *ents;  	trace_xfs_dir2_leafn_remove(args, index); @@ -1001,11 +1218,14 @@ xfs_dir2_leafn_remove(  	tp = args->trans;  	mp = dp->i_mount;  	leaf = bp->b_addr; -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); +	ents = xfs_dir3_leaf_ents_p(leaf); +  	/*  	 * Point to the entry we're removing.  	 */ -	lep = &leaf->ents[index]; +	lep = &ents[index]; +  	/*  	 * Extract the data block and offset from the entry.  	 */ @@ -1013,14 +1233,18 @@ xfs_dir2_leafn_remove(  	ASSERT(dblk->blkno == db);  	off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address));  	ASSERT(dblk->index == off); +  	/*  	 * Kill the leaf entry by marking it stale.  	 * Log the leaf block changes.  	 */ -	be16_add_cpu(&leaf->hdr.stale, 1); -	xfs_dir2_leaf_log_header(tp, bp); +	leafhdr.stale++; +	xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); +	xfs_dir3_leaf_log_header(tp, bp); +  	lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); -	xfs_dir2_leaf_log_ents(tp, bp, index, index); +	xfs_dir3_leaf_log_ents(tp, bp, index, index); +  	/*  	 * Make the data entry free.  Keep track of the longest freespace  	 * in the data block in case it changes. @@ -1028,7 +1252,8 @@ xfs_dir2_leafn_remove(  	dbp = dblk->bp;  	hdr = dbp->b_addr;  	dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); -	longest = be16_to_cpu(hdr->bestfree[0].length); +	bf = xfs_dir3_data_bestfree_p(hdr); +	longest = be16_to_cpu(bf[0].length);  	needlog = needscan = 0;  	xfs_dir2_data_make_free(tp, dbp, off,  		xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); @@ -1040,12 +1265,12 @@ xfs_dir2_leafn_remove(  		xfs_dir2_data_freescan(mp, hdr, &needlog);  	if (needlog)  		xfs_dir2_data_log_header(tp, dbp); -	xfs_dir2_data_check(dp, dbp); +	xfs_dir3_data_check(dp, dbp);  	/*  	 * If the longest data block freespace changes, need to update  	 * the corresponding freeblock entry.  	 */ -	if (longest < be16_to_cpu(hdr->bestfree[0].length)) { +	if (longest < be16_to_cpu(bf[0].length)) {  		int		error;		/* error return value */  		struct xfs_buf	*fbp;		/* freeblock buffer */  		xfs_dir2_db_t	fdb;		/* freeblock block number */ @@ -1062,20 +1287,25 @@ xfs_dir2_leafn_remove(  		if (error)  			return error;  		free = fbp->b_addr; -		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); -		ASSERT(be32_to_cpu(free->hdr.firstdb) == -		       xfs_dir2_free_max_bests(mp) * -		       (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); +#ifdef DEBUG +	{ +		struct xfs_dir3_icfree_hdr freehdr; +		xfs_dir3_free_hdr_from_disk(&freehdr, free); +		ASSERT(freehdr.firstdb == xfs_dir3_free_max_bests(mp) * +					  (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); +	} +#endif  		/*  		 * Calculate which entry we need to fix.  		 */  		findex = xfs_dir2_db_to_fdindex(mp, db); -		longest = be16_to_cpu(hdr->bestfree[0].length); +		longest = be16_to_cpu(bf[0].length);  		/*  		 * If the data block is now empty we can get rid of it  		 * (usually).  		 */ -		if (longest == mp->m_dirblksize - (uint)sizeof(*hdr)) { +		if (longest == mp->m_dirblksize - +			       xfs_dir3_data_entry_offset(hdr)) {  			/*  			 * Try to punch out the data block.  			 */ @@ -1096,21 +1326,19 @@ xfs_dir2_leafn_remove(  		 * If we got rid of the data block, we can eliminate that entry  		 * in the free block.  		 */ -		error = xfs_dir2_data_block_free(args, hdr, free, +		error = xfs_dir3_data_block_free(args, hdr, free,  						 fdb, findex, fbp, longest);  		if (error)  			return error;  	} -	xfs_dir2_leafn_check(dp, bp); +	xfs_dir3_leaf_check(mp, bp);  	/*  	 * Return indication of whether this leaf block is empty enough  	 * to justify trying to join it with a neighbor.  	 */ -	*rval = -		((uint)sizeof(leaf->hdr) + -		 (uint)sizeof(leaf->ents[0]) * -		 (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale))) < +	*rval = (xfs_dir3_leaf_hdr_size(leaf) + +		 (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) <  		mp->m_dir_magicpct;  	return 0;  } @@ -1143,11 +1371,11 @@ xfs_dir2_leafn_split(  	/*  	 * Initialize the new leaf block.  	 */ -	error = xfs_dir2_leaf_init(args, xfs_dir2_da_to_db(mp, blkno), -		&newblk->bp, XFS_DIR2_LEAFN_MAGIC); -	if (error) { +	error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(mp, blkno), +				      &newblk->bp, XFS_DIR2_LEAFN_MAGIC); +	if (error)  		return error; -	} +  	newblk->blkno = blkno;  	newblk->magic = XFS_DIR2_LEAFN_MAGIC;  	/* @@ -1155,7 +1383,7 @@ xfs_dir2_leafn_split(  	 * block into the leaves.  	 */  	xfs_dir2_leafn_rebalance(state, oldblk, newblk); -	error = xfs_da_blk_link(state, oldblk, newblk); +	error = xfs_da3_blk_link(state, oldblk, newblk);  	if (error) {  		return error;  	} @@ -1171,8 +1399,8 @@ xfs_dir2_leafn_split(  	 */  	oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL);  	newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); -	xfs_dir2_leafn_check(args->dp, oldblk->bp); -	xfs_dir2_leafn_check(args->dp, newblk->bp); +	xfs_dir3_leaf_check(mp, oldblk->bp); +	xfs_dir3_leaf_check(mp, newblk->bp);  	return error;  } @@ -1198,9 +1426,10 @@ xfs_dir2_leafn_toosmall(  	int			error;		/* error return value */  	int			forward;	/* sibling block direction */  	int			i;		/* sibling counter */ -	xfs_da_blkinfo_t	*info;		/* leaf block header */  	xfs_dir2_leaf_t		*leaf;		/* leaf structure */  	int			rval;		/* result from path_shift */ +	struct xfs_dir3_icleaf_hdr leafhdr; +	struct xfs_dir2_leaf_entry *ents;  	/*  	 * Check for the degenerate case of the block being over 50% full. @@ -1208,11 +1437,13 @@ xfs_dir2_leafn_toosmall(  	 * to coalesce with a sibling.  	 */  	blk = &state->path.blk[state->path.active - 1]; -	info = blk->bp->b_addr; -	ASSERT(info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -	leaf = (xfs_dir2_leaf_t *)info; -	count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale); -	bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]); +	leaf = blk->bp->b_addr; +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); +	ents = xfs_dir3_leaf_ents_p(leaf); +	xfs_dir3_leaf_check(state->args->dp->i_mount, blk->bp); + +	count = leafhdr.count - leafhdr.stale; +	bytes = xfs_dir3_leaf_hdr_size(leaf) + count * sizeof(ents[0]);  	if (bytes > (state->blocksize >> 1)) {  		/*  		 * Blk over 50%, don't try to join. @@ -1231,9 +1462,9 @@ xfs_dir2_leafn_toosmall(  		 * Make altpath point to the block we want to keep and  		 * path point to the block we want to drop (this one).  		 */ -		forward = (info->forw != 0); +		forward = (leafhdr.forw != 0);  		memcpy(&state->altpath, &state->path, sizeof(state->path)); -		error = xfs_da_path_shift(state, &state->altpath, forward, 0, +		error = xfs_da3_path_shift(state, &state->altpath, forward, 0,  			&rval);  		if (error)  			return error; @@ -1247,15 +1478,17 @@ xfs_dir2_leafn_toosmall(  	 * We prefer coalescing with the lower numbered sibling so as  	 * to shrink a directory over time.  	 */ -	forward = be32_to_cpu(info->forw) < be32_to_cpu(info->back); +	forward = leafhdr.forw < leafhdr.back;  	for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { -		blkno = forward ? be32_to_cpu(info->forw) : be32_to_cpu(info->back); +		struct xfs_dir3_icleaf_hdr hdr2; + +		blkno = forward ? leafhdr.forw : leafhdr.back;  		if (blkno == 0)  			continue;  		/*  		 * Read the sibling leaf block.  		 */ -		error = xfs_dir2_leafn_read(state->args->trans, state->args->dp, +		error = xfs_dir3_leafn_read(state->args->trans, state->args->dp,  					    blkno, -1, &bp);  		if (error)  			return error; @@ -1263,13 +1496,15 @@ xfs_dir2_leafn_toosmall(  		/*  		 * Count bytes in the two blocks combined.  		 */ -		leaf = (xfs_dir2_leaf_t *)info; -		count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale); +		count = leafhdr.count - leafhdr.stale;  		bytes = state->blocksize - (state->blocksize >> 2); +  		leaf = bp->b_addr; -		ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -		count += be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale); -		bytes -= count * (uint)sizeof(leaf->ents[0]); +		xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf); +		ents = xfs_dir3_leaf_ents_p(leaf); +		count += hdr2.count - hdr2.stale; +		bytes -= count * sizeof(ents[0]); +  		/*  		 * Fits with at least 25% to spare.  		 */ @@ -1291,10 +1526,10 @@ xfs_dir2_leafn_toosmall(  	 */  	memcpy(&state->altpath, &state->path, sizeof(state->path));  	if (blkno < blk->blkno) -		error = xfs_da_path_shift(state, &state->altpath, forward, 0, +		error = xfs_da3_path_shift(state, &state->altpath, forward, 0,  			&rval);  	else -		error = xfs_da_path_shift(state, &state->path, forward, 0, +		error = xfs_da3_path_shift(state, &state->path, forward, 0,  			&rval);  	if (error) {  		return error; @@ -1316,34 +1551,53 @@ xfs_dir2_leafn_unbalance(  	xfs_da_args_t		*args;		/* operation arguments */  	xfs_dir2_leaf_t		*drop_leaf;	/* dead leaf structure */  	xfs_dir2_leaf_t		*save_leaf;	/* surviving leaf structure */ +	struct xfs_dir3_icleaf_hdr savehdr; +	struct xfs_dir3_icleaf_hdr drophdr; +	struct xfs_dir2_leaf_entry *sents; +	struct xfs_dir2_leaf_entry *dents;  	args = state->args;  	ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);  	ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);  	drop_leaf = drop_blk->bp->b_addr;  	save_leaf = save_blk->bp->b_addr; -	ASSERT(drop_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); -	ASSERT(save_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)); + +	xfs_dir3_leaf_hdr_from_disk(&savehdr, save_leaf); +	xfs_dir3_leaf_hdr_from_disk(&drophdr, drop_leaf); +	sents = xfs_dir3_leaf_ents_p(save_leaf); +	dents = xfs_dir3_leaf_ents_p(drop_leaf); +  	/*  	 * If there are any stale leaf entries, take this opportunity  	 * to purge them.  	 */ -	if (drop_leaf->hdr.stale) -		xfs_dir2_leaf_compact(args, drop_blk->bp); -	if (save_leaf->hdr.stale) -		xfs_dir2_leaf_compact(args, save_blk->bp); +	if (drophdr.stale) +		xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); +	if (savehdr.stale) +		xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); +  	/*  	 * Move the entries from drop to the appropriate end of save.  	 */ -	drop_blk->hashval = be32_to_cpu(drop_leaf->ents[be16_to_cpu(drop_leaf->hdr.count) - 1].hashval); +	drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval);  	if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) -		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0, -			be16_to_cpu(drop_leaf->hdr.count)); +		xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, +					save_blk->bp, &savehdr, sents, 0, +					drophdr.count);  	else -		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, -			be16_to_cpu(save_leaf->hdr.count), be16_to_cpu(drop_leaf->hdr.count)); -	save_blk->hashval = be32_to_cpu(save_leaf->ents[be16_to_cpu(save_leaf->hdr.count) - 1].hashval); -	xfs_dir2_leafn_check(args->dp, save_blk->bp); +		xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, +					save_blk->bp, &savehdr, sents, +					savehdr.count, drophdr.count); +	save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); + +	/* log the changes made when moving the entries */ +	xfs_dir3_leaf_hdr_to_disk(save_leaf, &savehdr); +	xfs_dir3_leaf_hdr_to_disk(drop_leaf, &drophdr); +	xfs_dir3_leaf_log_header(args->trans, save_blk->bp); +	xfs_dir3_leaf_log_header(args->trans, drop_blk->bp); + +	xfs_dir3_leaf_check(args->dp->i_mount, save_blk->bp); +	xfs_dir3_leaf_check(args->dp->i_mount, drop_blk->bp);  }  /* @@ -1372,7 +1626,7 @@ xfs_dir2_node_addname(  	 * Look up the name.  We're not supposed to find it, but  	 * this gives us the insertion point.  	 */ -	error = xfs_da_node_lookup_int(state, &rval); +	error = xfs_da3_node_lookup_int(state, &rval);  	if (error)  		rval = error;  	if (rval != ENOENT) { @@ -1398,7 +1652,7 @@ xfs_dir2_node_addname(  		 * It worked, fix the hash values up the btree.  		 */  		if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) -			xfs_da_fixhashpath(state, &state->path); +			xfs_da3_fixhashpath(state, &state->path);  	} else {  		/*  		 * It didn't work, we need to split the leaf block. @@ -1410,7 +1664,7 @@ xfs_dir2_node_addname(  		/*  		 * Split the leaf block and insert the new entry.  		 */ -		rval = xfs_da_split(state); +		rval = xfs_da3_split(state);  	}  done:  	xfs_da_state_free(state); @@ -1447,6 +1701,9 @@ xfs_dir2_node_addname_int(  	int			needscan;	/* need to rescan data frees */  	__be16			*tagp;		/* data entry tag pointer */  	xfs_trans_t		*tp;		/* transaction pointer */ +	__be16			*bests; +	struct xfs_dir3_icfree_hdr freehdr; +	struct xfs_dir2_data_free *bf;  	dp = args->dp;  	mp = dp->i_mount; @@ -1464,36 +1721,37 @@ xfs_dir2_node_addname_int(  		 */  		ifbno = fblk->blkno;  		free = fbp->b_addr; -		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));  		findex = fblk->index; +		bests = xfs_dir3_free_bests_p(mp, free); +		xfs_dir3_free_hdr_from_disk(&freehdr, free); +  		/*  		 * This means the free entry showed that the data block had  		 * space for our entry, so we remembered it.  		 * Use that data block.  		 */  		if (findex >= 0) { -			ASSERT(findex < be32_to_cpu(free->hdr.nvalid)); -			ASSERT(be16_to_cpu(free->bests[findex]) != NULLDATAOFF); -			ASSERT(be16_to_cpu(free->bests[findex]) >= length); -			dbno = be32_to_cpu(free->hdr.firstdb) + findex; -		} -		/* -		 * The data block looked at didn't have enough room. -		 * We'll start at the beginning of the freespace entries. -		 */ -		else { +			ASSERT(findex < freehdr.nvalid); +			ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); +			ASSERT(be16_to_cpu(bests[findex]) >= length); +			dbno = freehdr.firstdb + findex; +		} else { +			/* +			 * The data block looked at didn't have enough room. +			 * We'll start at the beginning of the freespace entries. +			 */  			dbno = -1;  			findex = 0;  		} -	} -	/* -	 * Didn't come in with a freespace block, so don't have a data block. -	 */ -	else { +	} else { +		/* +		 * Didn't come in with a freespace block, so no data block. +		 */  		ifbno = dbno = -1;  		fbp = NULL;  		findex = 0;  	} +  	/*  	 * If we don't have a data block yet, we're going to scan the  	 * freespace blocks looking for one.  Figure out what the @@ -1547,20 +1805,26 @@ xfs_dir2_node_addname_int(  			if (!fbp)  				continue;  			free = fbp->b_addr; -			ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));  			findex = 0;  		}  		/*  		 * Look at the current free entry.  Is it good enough? +		 * +		 * The bests initialisation should be where the bufer is read in +		 * the above branch. But gcc is too stupid to realise that bests +		 * and the freehdr are actually initialised if they are placed +		 * there, so we have to do it here to avoid warnings. Blech.  		 */ -		if (be16_to_cpu(free->bests[findex]) != NULLDATAOFF && -		    be16_to_cpu(free->bests[findex]) >= length) -			dbno = be32_to_cpu(free->hdr.firstdb) + findex; +		bests = xfs_dir3_free_bests_p(mp, free); +		xfs_dir3_free_hdr_from_disk(&freehdr, free); +		if (be16_to_cpu(bests[findex]) != NULLDATAOFF && +		    be16_to_cpu(bests[findex]) >= length) +			dbno = freehdr.firstdb + findex;  		else {  			/*  			 * Are we done with the freeblock?  			 */ -			if (++findex == be32_to_cpu(free->hdr.nvalid)) { +			if (++findex == freehdr.nvalid) {  				/*  				 * Drop the block.  				 */ @@ -1588,7 +1852,7 @@ xfs_dir2_node_addname_int(  		if (unlikely((error = xfs_dir2_grow_inode(args,  							 XFS_DIR2_DATA_SPACE,  							 &dbno)) || -		    (error = xfs_dir2_data_init(args, dbno, &dbp)))) +		    (error = xfs_dir3_data_init(args, dbno, &dbp))))  			return error;  		/* @@ -1614,11 +1878,11 @@ xfs_dir2_node_addname_int(  		 * If there wasn't a freespace block, the read will  		 * return a NULL fbp.  Allocate and initialize a new one.  		 */ -		if( fbp == NULL ) { -			if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, -							&fbno))) { +		if (!fbp) { +			error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, +						    &fbno); +			if (error)  				return error; -			}  			if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) {  				xfs_alert(mp, @@ -1646,27 +1910,22 @@ xfs_dir2_node_addname_int(  			/*  			 * Get a buffer for the new block.  			 */ -			error = xfs_da_get_buf(tp, dp, -					       xfs_dir2_db_to_da(mp, fbno), -					       -1, &fbp, XFS_DATA_FORK); +			error = xfs_dir3_free_get_buf(tp, dp, fbno, &fbp);  			if (error)  				return error; -			fbp->b_ops = &xfs_dir2_free_buf_ops; +			free = fbp->b_addr; +			bests = xfs_dir3_free_bests_p(mp, free); +			xfs_dir3_free_hdr_from_disk(&freehdr, free);  			/* -			 * Initialize the new block to be empty, and remember -			 * its first slot as our empty slot. +			 * Remember the first slot as our empty slot.  			 */ -			free = fbp->b_addr; -			free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC); -			free->hdr.firstdb = cpu_to_be32( -				(fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * -				xfs_dir2_free_max_bests(mp)); -			free->hdr.nvalid = 0; -			free->hdr.nused = 0; +			freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * +					xfs_dir3_free_max_bests(mp);  		} else {  			free = fbp->b_addr; -			ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); +			bests = xfs_dir3_free_bests_p(mp, free); +			xfs_dir3_free_hdr_from_disk(&freehdr, free);  		}  		/* @@ -1677,20 +1936,21 @@ xfs_dir2_node_addname_int(  		 * If it's after the end of the current entries in the  		 * freespace block, extend that table.  		 */ -		if (findex >= be32_to_cpu(free->hdr.nvalid)) { -			ASSERT(findex < xfs_dir2_free_max_bests(mp)); -			free->hdr.nvalid = cpu_to_be32(findex + 1); +		if (findex >= freehdr.nvalid) { +			ASSERT(findex < xfs_dir3_free_max_bests(mp)); +			freehdr.nvalid = findex + 1;  			/*  			 * Tag new entry so nused will go up.  			 */ -			free->bests[findex] = cpu_to_be16(NULLDATAOFF); +			bests[findex] = cpu_to_be16(NULLDATAOFF);  		}  		/*  		 * If this entry was for an empty data block  		 * (this should always be true) then update the header.  		 */ -		if (free->bests[findex] == cpu_to_be16(NULLDATAOFF)) { -			be32_add_cpu(&free->hdr.nused, 1); +		if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { +			freehdr.nused++; +			xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr);  			xfs_dir2_free_log_header(tp, fbp);  		}  		/* @@ -1699,7 +1959,8 @@ xfs_dir2_node_addname_int(  		 * change again.  		 */  		hdr = dbp->b_addr; -		free->bests[findex] = hdr->bestfree[0].length; +		bf = xfs_dir3_data_bestfree_p(hdr); +		bests[findex] = bf[0].length;  		logfree = 1;  	}  	/* @@ -1715,19 +1976,20 @@ xfs_dir2_node_addname_int(  		/*  		 * Read the data block in.  		 */ -		error = xfs_dir2_data_read(tp, dp, xfs_dir2_db_to_da(mp, dbno), +		error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, dbno),  					   -1, &dbp);  		if (error)  			return error;  		hdr = dbp->b_addr; +		bf = xfs_dir3_data_bestfree_p(hdr);  		logfree = 0;  	} -	ASSERT(be16_to_cpu(hdr->bestfree[0].length) >= length); +	ASSERT(be16_to_cpu(bf[0].length) >= length);  	/*  	 * Point to the existing unused space.  	 */  	dup = (xfs_dir2_data_unused_t *) -	      ((char *)hdr + be16_to_cpu(hdr->bestfree[0].offset)); +	      ((char *)hdr + be16_to_cpu(bf[0].offset));  	needscan = needlog = 0;  	/*  	 * Mark the first part of the unused space, inuse for us. @@ -1758,8 +2020,9 @@ xfs_dir2_node_addname_int(  	/*  	 * If the freespace entry is now wrong, update it.  	 */ -	if (be16_to_cpu(free->bests[findex]) != be16_to_cpu(hdr->bestfree[0].length)) { -		free->bests[findex] = hdr->bestfree[0].length; +	bests = xfs_dir3_free_bests_p(mp, free); /* gcc is so stupid */ +	if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { +		bests[findex] = bf[0].length;  		logfree = 1;  	}  	/* @@ -1777,7 +2040,7 @@ xfs_dir2_node_addname_int(  /*   * Lookup an entry in a node-format directory. - * All the real work happens in xfs_da_node_lookup_int. + * All the real work happens in xfs_da3_node_lookup_int.   * The only real output is the inode number of the entry.   */  int						/* error */ @@ -1802,7 +2065,7 @@ xfs_dir2_node_lookup(  	/*  	 * Fill in the path to the entry in the cursor.  	 */ -	error = xfs_da_node_lookup_int(state, &rval); +	error = xfs_da3_node_lookup_int(state, &rval);  	if (error)  		rval = error;  	else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) { @@ -1857,7 +2120,7 @@ xfs_dir2_node_removename(  	/*  	 * Look up the entry we're deleting, set up the cursor.  	 */ -	error = xfs_da_node_lookup_int(state, &rval); +	error = xfs_da3_node_lookup_int(state, &rval);  	if (error)  		rval = error;  	/* @@ -1881,12 +2144,12 @@ xfs_dir2_node_removename(  	/*  	 * Fix the hash values up the btree.  	 */ -	xfs_da_fixhashpath(state, &state->path); +	xfs_da3_fixhashpath(state, &state->path);  	/*  	 * If we need to join leaf blocks, do it.  	 */  	if (rval && state->path.active > 1) -		error = xfs_da_join(state); +		error = xfs_da3_join(state);  	/*  	 * If no errors so far, try conversion to leaf format.  	 */ @@ -1928,7 +2191,7 @@ xfs_dir2_node_replace(  	/*  	 * Lookup the entry to change in the btree.  	 */ -	error = xfs_da_node_lookup_int(state, &rval); +	error = xfs_da3_node_lookup_int(state, &rval);  	if (error) {  		rval = error;  	} @@ -1937,19 +2200,22 @@ xfs_dir2_node_replace(  	 * and locked it.  But paranoia is good.  	 */  	if (rval == EEXIST) { +		struct xfs_dir2_leaf_entry *ents;  		/*  		 * Find the leaf entry.  		 */  		blk = &state->path.blk[state->path.active - 1];  		ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);  		leaf = blk->bp->b_addr; -		lep = &leaf->ents[blk->index]; +		ents = xfs_dir3_leaf_ents_p(leaf); +		lep = &ents[blk->index];  		ASSERT(state->extravalid);  		/*  		 * Point to the data entry.  		 */  		hdr = state->extrablk.bp->b_addr; -		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC)); +		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || +		       hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));  		dep = (xfs_dir2_data_entry_t *)  		      ((char *)hdr +  		       xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address))); @@ -1995,6 +2261,7 @@ xfs_dir2_node_trim_free(  	xfs_dir2_free_t		*free;		/* freespace structure */  	xfs_mount_t		*mp;		/* filesystem mount point */  	xfs_trans_t		*tp;		/* transaction pointer */ +	struct xfs_dir3_icfree_hdr freehdr;  	dp = args->dp;  	mp = dp->i_mount; @@ -2012,11 +2279,12 @@ xfs_dir2_node_trim_free(  	if (!bp)  		return 0;  	free = bp->b_addr; -	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)); +	xfs_dir3_free_hdr_from_disk(&freehdr, free); +  	/*  	 * If there are used entries, there's nothing to do.  	 */ -	if (be32_to_cpu(free->hdr.nused) > 0) { +	if (freehdr.nused > 0) {  		xfs_trans_brelse(tp, bp);  		*rvalp = 0;  		return 0; | 
