162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * Copyright (c) 2013 Red Hat, Inc.
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include "xfs.h"
862306a36Sopenharmony_ci#include "xfs_fs.h"
962306a36Sopenharmony_ci#include "xfs_shared.h"
1062306a36Sopenharmony_ci#include "xfs_format.h"
1162306a36Sopenharmony_ci#include "xfs_log_format.h"
1262306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1362306a36Sopenharmony_ci#include "xfs_bit.h"
1462306a36Sopenharmony_ci#include "xfs_mount.h"
1562306a36Sopenharmony_ci#include "xfs_inode.h"
1662306a36Sopenharmony_ci#include "xfs_dir2.h"
1762306a36Sopenharmony_ci#include "xfs_dir2_priv.h"
1862306a36Sopenharmony_ci#include "xfs_trans.h"
1962306a36Sopenharmony_ci#include "xfs_bmap.h"
2062306a36Sopenharmony_ci#include "xfs_attr_leaf.h"
2162306a36Sopenharmony_ci#include "xfs_error.h"
2262306a36Sopenharmony_ci#include "xfs_trace.h"
2362306a36Sopenharmony_ci#include "xfs_buf_item.h"
2462306a36Sopenharmony_ci#include "xfs_log.h"
2562306a36Sopenharmony_ci#include "xfs_errortag.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * xfs_da_btree.c
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Routines to implement directories as Btrees of hashed names.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*========================================================================
3462306a36Sopenharmony_ci * Function prototypes for the kernel.
3562306a36Sopenharmony_ci *========================================================================*/
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * Routines used for growing the Btree.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ciSTATIC int xfs_da3_root_split(xfs_da_state_t *state,
4162306a36Sopenharmony_ci					    xfs_da_state_blk_t *existing_root,
4262306a36Sopenharmony_ci					    xfs_da_state_blk_t *new_child);
4362306a36Sopenharmony_ciSTATIC int xfs_da3_node_split(xfs_da_state_t *state,
4462306a36Sopenharmony_ci					    xfs_da_state_blk_t *existing_blk,
4562306a36Sopenharmony_ci					    xfs_da_state_blk_t *split_blk,
4662306a36Sopenharmony_ci					    xfs_da_state_blk_t *blk_to_add,
4762306a36Sopenharmony_ci					    int treelevel,
4862306a36Sopenharmony_ci					    int *result);
4962306a36Sopenharmony_ciSTATIC void xfs_da3_node_rebalance(xfs_da_state_t *state,
5062306a36Sopenharmony_ci					 xfs_da_state_blk_t *node_blk_1,
5162306a36Sopenharmony_ci					 xfs_da_state_blk_t *node_blk_2);
5262306a36Sopenharmony_ciSTATIC void xfs_da3_node_add(xfs_da_state_t *state,
5362306a36Sopenharmony_ci				   xfs_da_state_blk_t *old_node_blk,
5462306a36Sopenharmony_ci				   xfs_da_state_blk_t *new_node_blk);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * Routines used for shrinking the Btree.
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ciSTATIC int xfs_da3_root_join(xfs_da_state_t *state,
6062306a36Sopenharmony_ci					   xfs_da_state_blk_t *root_blk);
6162306a36Sopenharmony_ciSTATIC int xfs_da3_node_toosmall(xfs_da_state_t *state, int *retval);
6262306a36Sopenharmony_ciSTATIC void xfs_da3_node_remove(xfs_da_state_t *state,
6362306a36Sopenharmony_ci					      xfs_da_state_blk_t *drop_blk);
6462306a36Sopenharmony_ciSTATIC void xfs_da3_node_unbalance(xfs_da_state_t *state,
6562306a36Sopenharmony_ci					 xfs_da_state_blk_t *src_node_blk,
6662306a36Sopenharmony_ci					 xfs_da_state_blk_t *dst_node_blk);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * Utility routines.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ciSTATIC int	xfs_da3_blk_unlink(xfs_da_state_t *state,
7262306a36Sopenharmony_ci				  xfs_da_state_blk_t *drop_blk,
7362306a36Sopenharmony_ci				  xfs_da_state_blk_t *save_blk);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistruct kmem_cache	*xfs_da_state_cache;	/* anchor for dir/attr state */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/*
7962306a36Sopenharmony_ci * Allocate a dir-state structure.
8062306a36Sopenharmony_ci * We don't put them on the stack since they're large.
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cistruct xfs_da_state *
8362306a36Sopenharmony_cixfs_da_state_alloc(
8462306a36Sopenharmony_ci	struct xfs_da_args	*args)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct xfs_da_state	*state;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	state = kmem_cache_zalloc(xfs_da_state_cache, GFP_NOFS | __GFP_NOFAIL);
8962306a36Sopenharmony_ci	state->args = args;
9062306a36Sopenharmony_ci	state->mp = args->dp->i_mount;
9162306a36Sopenharmony_ci	return state;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * Kill the altpath contents of a da-state structure.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_ciSTATIC void
9862306a36Sopenharmony_cixfs_da_state_kill_altpath(xfs_da_state_t *state)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	int	i;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	for (i = 0; i < state->altpath.active; i++)
10362306a36Sopenharmony_ci		state->altpath.blk[i].bp = NULL;
10462306a36Sopenharmony_ci	state->altpath.active = 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/*
10862306a36Sopenharmony_ci * Free a da-state structure.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_civoid
11162306a36Sopenharmony_cixfs_da_state_free(xfs_da_state_t *state)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	xfs_da_state_kill_altpath(state);
11462306a36Sopenharmony_ci#ifdef DEBUG
11562306a36Sopenharmony_ci	memset((char *)state, 0, sizeof(*state));
11662306a36Sopenharmony_ci#endif /* DEBUG */
11762306a36Sopenharmony_ci	kmem_cache_free(xfs_da_state_cache, state);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_civoid
12162306a36Sopenharmony_cixfs_da_state_reset(
12262306a36Sopenharmony_ci	struct xfs_da_state	*state,
12362306a36Sopenharmony_ci	struct xfs_da_args	*args)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	xfs_da_state_kill_altpath(state);
12662306a36Sopenharmony_ci	memset(state, 0, sizeof(struct xfs_da_state));
12762306a36Sopenharmony_ci	state->args = args;
12862306a36Sopenharmony_ci	state->mp = state->args->dp->i_mount;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	if (whichfork == XFS_DATA_FORK)
13462306a36Sopenharmony_ci		return mp->m_dir_geo->fsbcount;
13562306a36Sopenharmony_ci	return mp->m_attr_geo->fsbcount;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_civoid
13962306a36Sopenharmony_cixfs_da3_node_hdr_from_disk(
14062306a36Sopenharmony_ci	struct xfs_mount		*mp,
14162306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr	*to,
14262306a36Sopenharmony_ci	struct xfs_da_intnode		*from)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
14562306a36Sopenharmony_ci		struct xfs_da3_intnode	*from3 = (struct xfs_da3_intnode *)from;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		to->forw = be32_to_cpu(from3->hdr.info.hdr.forw);
14862306a36Sopenharmony_ci		to->back = be32_to_cpu(from3->hdr.info.hdr.back);
14962306a36Sopenharmony_ci		to->magic = be16_to_cpu(from3->hdr.info.hdr.magic);
15062306a36Sopenharmony_ci		to->count = be16_to_cpu(from3->hdr.__count);
15162306a36Sopenharmony_ci		to->level = be16_to_cpu(from3->hdr.__level);
15262306a36Sopenharmony_ci		to->btree = from3->__btree;
15362306a36Sopenharmony_ci		ASSERT(to->magic == XFS_DA3_NODE_MAGIC);
15462306a36Sopenharmony_ci	} else {
15562306a36Sopenharmony_ci		to->forw = be32_to_cpu(from->hdr.info.forw);
15662306a36Sopenharmony_ci		to->back = be32_to_cpu(from->hdr.info.back);
15762306a36Sopenharmony_ci		to->magic = be16_to_cpu(from->hdr.info.magic);
15862306a36Sopenharmony_ci		to->count = be16_to_cpu(from->hdr.__count);
15962306a36Sopenharmony_ci		to->level = be16_to_cpu(from->hdr.__level);
16062306a36Sopenharmony_ci		to->btree = from->__btree;
16162306a36Sopenharmony_ci		ASSERT(to->magic == XFS_DA_NODE_MAGIC);
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_civoid
16662306a36Sopenharmony_cixfs_da3_node_hdr_to_disk(
16762306a36Sopenharmony_ci	struct xfs_mount		*mp,
16862306a36Sopenharmony_ci	struct xfs_da_intnode		*to,
16962306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr	*from)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
17262306a36Sopenharmony_ci		struct xfs_da3_intnode	*to3 = (struct xfs_da3_intnode *)to;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		ASSERT(from->magic == XFS_DA3_NODE_MAGIC);
17562306a36Sopenharmony_ci		to3->hdr.info.hdr.forw = cpu_to_be32(from->forw);
17662306a36Sopenharmony_ci		to3->hdr.info.hdr.back = cpu_to_be32(from->back);
17762306a36Sopenharmony_ci		to3->hdr.info.hdr.magic = cpu_to_be16(from->magic);
17862306a36Sopenharmony_ci		to3->hdr.__count = cpu_to_be16(from->count);
17962306a36Sopenharmony_ci		to3->hdr.__level = cpu_to_be16(from->level);
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		ASSERT(from->magic == XFS_DA_NODE_MAGIC);
18262306a36Sopenharmony_ci		to->hdr.info.forw = cpu_to_be32(from->forw);
18362306a36Sopenharmony_ci		to->hdr.info.back = cpu_to_be32(from->back);
18462306a36Sopenharmony_ci		to->hdr.info.magic = cpu_to_be16(from->magic);
18562306a36Sopenharmony_ci		to->hdr.__count = cpu_to_be16(from->count);
18662306a36Sopenharmony_ci		to->hdr.__level = cpu_to_be16(from->level);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/*
19162306a36Sopenharmony_ci * Verify an xfs_da3_blkinfo structure. Note that the da3 fields are only
19262306a36Sopenharmony_ci * accessible on v5 filesystems. This header format is common across da node,
19362306a36Sopenharmony_ci * attr leaf and dir leaf blocks.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cixfs_failaddr_t
19662306a36Sopenharmony_cixfs_da3_blkinfo_verify(
19762306a36Sopenharmony_ci	struct xfs_buf		*bp,
19862306a36Sopenharmony_ci	struct xfs_da3_blkinfo	*hdr3)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
20162306a36Sopenharmony_ci	struct xfs_da_blkinfo	*hdr = &hdr3->hdr;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (!xfs_verify_magic16(bp, hdr->magic))
20462306a36Sopenharmony_ci		return __this_address;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
20762306a36Sopenharmony_ci		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
20862306a36Sopenharmony_ci			return __this_address;
20962306a36Sopenharmony_ci		if (be64_to_cpu(hdr3->blkno) != xfs_buf_daddr(bp))
21062306a36Sopenharmony_ci			return __this_address;
21162306a36Sopenharmony_ci		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
21262306a36Sopenharmony_ci			return __this_address;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return NULL;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic xfs_failaddr_t
21962306a36Sopenharmony_cixfs_da3_node_verify(
22062306a36Sopenharmony_ci	struct xfs_buf		*bp)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
22362306a36Sopenharmony_ci	struct xfs_da_intnode	*hdr = bp->b_addr;
22462306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr ichdr;
22562306a36Sopenharmony_ci	xfs_failaddr_t		fa;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(mp, &ichdr, hdr);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	fa = xfs_da3_blkinfo_verify(bp, bp->b_addr);
23062306a36Sopenharmony_ci	if (fa)
23162306a36Sopenharmony_ci		return fa;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (ichdr.level == 0)
23462306a36Sopenharmony_ci		return __this_address;
23562306a36Sopenharmony_ci	if (ichdr.level > XFS_DA_NODE_MAXDEPTH)
23662306a36Sopenharmony_ci		return __this_address;
23762306a36Sopenharmony_ci	if (ichdr.count == 0)
23862306a36Sopenharmony_ci		return __this_address;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/*
24162306a36Sopenharmony_ci	 * we don't know if the node is for and attribute or directory tree,
24262306a36Sopenharmony_ci	 * so only fail if the count is outside both bounds
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	if (ichdr.count > mp->m_dir_geo->node_ents &&
24562306a36Sopenharmony_ci	    ichdr.count > mp->m_attr_geo->node_ents)
24662306a36Sopenharmony_ci		return __this_address;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* XXX: hash order check? */
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return NULL;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void
25462306a36Sopenharmony_cixfs_da3_node_write_verify(
25562306a36Sopenharmony_ci	struct xfs_buf	*bp)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
25862306a36Sopenharmony_ci	struct xfs_buf_log_item	*bip = bp->b_log_item;
25962306a36Sopenharmony_ci	struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
26062306a36Sopenharmony_ci	xfs_failaddr_t		fa;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	fa = xfs_da3_node_verify(bp);
26362306a36Sopenharmony_ci	if (fa) {
26462306a36Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
26562306a36Sopenharmony_ci		return;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (!xfs_has_crc(mp))
26962306a36Sopenharmony_ci		return;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (bip)
27262306a36Sopenharmony_ci		hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/*
27862306a36Sopenharmony_ci * leaf/node format detection on trees is sketchy, so a node read can be done on
27962306a36Sopenharmony_ci * leaf level blocks when detection identifies the tree as a node format tree
28062306a36Sopenharmony_ci * incorrectly. In this case, we need to swap the verifier to match the correct
28162306a36Sopenharmony_ci * format of the block being read.
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cistatic void
28462306a36Sopenharmony_cixfs_da3_node_read_verify(
28562306a36Sopenharmony_ci	struct xfs_buf		*bp)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct xfs_da_blkinfo	*info = bp->b_addr;
28862306a36Sopenharmony_ci	xfs_failaddr_t		fa;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	switch (be16_to_cpu(info->magic)) {
29162306a36Sopenharmony_ci		case XFS_DA3_NODE_MAGIC:
29262306a36Sopenharmony_ci			if (!xfs_buf_verify_cksum(bp, XFS_DA3_NODE_CRC_OFF)) {
29362306a36Sopenharmony_ci				xfs_verifier_error(bp, -EFSBADCRC,
29462306a36Sopenharmony_ci						__this_address);
29562306a36Sopenharmony_ci				break;
29662306a36Sopenharmony_ci			}
29762306a36Sopenharmony_ci			fallthrough;
29862306a36Sopenharmony_ci		case XFS_DA_NODE_MAGIC:
29962306a36Sopenharmony_ci			fa = xfs_da3_node_verify(bp);
30062306a36Sopenharmony_ci			if (fa)
30162306a36Sopenharmony_ci				xfs_verifier_error(bp, -EFSCORRUPTED, fa);
30262306a36Sopenharmony_ci			return;
30362306a36Sopenharmony_ci		case XFS_ATTR_LEAF_MAGIC:
30462306a36Sopenharmony_ci		case XFS_ATTR3_LEAF_MAGIC:
30562306a36Sopenharmony_ci			bp->b_ops = &xfs_attr3_leaf_buf_ops;
30662306a36Sopenharmony_ci			bp->b_ops->verify_read(bp);
30762306a36Sopenharmony_ci			return;
30862306a36Sopenharmony_ci		case XFS_DIR2_LEAFN_MAGIC:
30962306a36Sopenharmony_ci		case XFS_DIR3_LEAFN_MAGIC:
31062306a36Sopenharmony_ci			bp->b_ops = &xfs_dir3_leafn_buf_ops;
31162306a36Sopenharmony_ci			bp->b_ops->verify_read(bp);
31262306a36Sopenharmony_ci			return;
31362306a36Sopenharmony_ci		default:
31462306a36Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
31562306a36Sopenharmony_ci			break;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/* Verify the structure of a da3 block. */
32062306a36Sopenharmony_cistatic xfs_failaddr_t
32162306a36Sopenharmony_cixfs_da3_node_verify_struct(
32262306a36Sopenharmony_ci	struct xfs_buf		*bp)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct xfs_da_blkinfo	*info = bp->b_addr;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	switch (be16_to_cpu(info->magic)) {
32762306a36Sopenharmony_ci	case XFS_DA3_NODE_MAGIC:
32862306a36Sopenharmony_ci	case XFS_DA_NODE_MAGIC:
32962306a36Sopenharmony_ci		return xfs_da3_node_verify(bp);
33062306a36Sopenharmony_ci	case XFS_ATTR_LEAF_MAGIC:
33162306a36Sopenharmony_ci	case XFS_ATTR3_LEAF_MAGIC:
33262306a36Sopenharmony_ci		bp->b_ops = &xfs_attr3_leaf_buf_ops;
33362306a36Sopenharmony_ci		return bp->b_ops->verify_struct(bp);
33462306a36Sopenharmony_ci	case XFS_DIR2_LEAFN_MAGIC:
33562306a36Sopenharmony_ci	case XFS_DIR3_LEAFN_MAGIC:
33662306a36Sopenharmony_ci		bp->b_ops = &xfs_dir3_leafn_buf_ops;
33762306a36Sopenharmony_ci		return bp->b_ops->verify_struct(bp);
33862306a36Sopenharmony_ci	default:
33962306a36Sopenharmony_ci		return __this_address;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_da3_node_buf_ops = {
34462306a36Sopenharmony_ci	.name = "xfs_da3_node",
34562306a36Sopenharmony_ci	.magic16 = { cpu_to_be16(XFS_DA_NODE_MAGIC),
34662306a36Sopenharmony_ci		     cpu_to_be16(XFS_DA3_NODE_MAGIC) },
34762306a36Sopenharmony_ci	.verify_read = xfs_da3_node_read_verify,
34862306a36Sopenharmony_ci	.verify_write = xfs_da3_node_write_verify,
34962306a36Sopenharmony_ci	.verify_struct = xfs_da3_node_verify_struct,
35062306a36Sopenharmony_ci};
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int
35362306a36Sopenharmony_cixfs_da3_node_set_type(
35462306a36Sopenharmony_ci	struct xfs_trans	*tp,
35562306a36Sopenharmony_ci	struct xfs_buf		*bp)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct xfs_da_blkinfo	*info = bp->b_addr;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	switch (be16_to_cpu(info->magic)) {
36062306a36Sopenharmony_ci	case XFS_DA_NODE_MAGIC:
36162306a36Sopenharmony_ci	case XFS_DA3_NODE_MAGIC:
36262306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
36362306a36Sopenharmony_ci		return 0;
36462306a36Sopenharmony_ci	case XFS_ATTR_LEAF_MAGIC:
36562306a36Sopenharmony_ci	case XFS_ATTR3_LEAF_MAGIC:
36662306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_ATTR_LEAF_BUF);
36762306a36Sopenharmony_ci		return 0;
36862306a36Sopenharmony_ci	case XFS_DIR2_LEAFN_MAGIC:
36962306a36Sopenharmony_ci	case XFS_DIR3_LEAFN_MAGIC:
37062306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF);
37162306a36Sopenharmony_ci		return 0;
37262306a36Sopenharmony_ci	default:
37362306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, tp->t_mountp,
37462306a36Sopenharmony_ci				info, sizeof(*info));
37562306a36Sopenharmony_ci		xfs_trans_brelse(tp, bp);
37662306a36Sopenharmony_ci		return -EFSCORRUPTED;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciint
38162306a36Sopenharmony_cixfs_da3_node_read(
38262306a36Sopenharmony_ci	struct xfs_trans	*tp,
38362306a36Sopenharmony_ci	struct xfs_inode	*dp,
38462306a36Sopenharmony_ci	xfs_dablk_t		bno,
38562306a36Sopenharmony_ci	struct xfs_buf		**bpp,
38662306a36Sopenharmony_ci	int			whichfork)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	int			error;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	error = xfs_da_read_buf(tp, dp, bno, 0, bpp, whichfork,
39162306a36Sopenharmony_ci			&xfs_da3_node_buf_ops);
39262306a36Sopenharmony_ci	if (error || !*bpp || !tp)
39362306a36Sopenharmony_ci		return error;
39462306a36Sopenharmony_ci	return xfs_da3_node_set_type(tp, *bpp);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciint
39862306a36Sopenharmony_cixfs_da3_node_read_mapped(
39962306a36Sopenharmony_ci	struct xfs_trans	*tp,
40062306a36Sopenharmony_ci	struct xfs_inode	*dp,
40162306a36Sopenharmony_ci	xfs_daddr_t		mappedbno,
40262306a36Sopenharmony_ci	struct xfs_buf		**bpp,
40362306a36Sopenharmony_ci	int			whichfork)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
40662306a36Sopenharmony_ci	int			error;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, mappedbno,
40962306a36Sopenharmony_ci			XFS_FSB_TO_BB(mp, xfs_dabuf_nfsb(mp, whichfork)), 0,
41062306a36Sopenharmony_ci			bpp, &xfs_da3_node_buf_ops);
41162306a36Sopenharmony_ci	if (error || !*bpp)
41262306a36Sopenharmony_ci		return error;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (whichfork == XFS_ATTR_FORK)
41562306a36Sopenharmony_ci		xfs_buf_set_ref(*bpp, XFS_ATTR_BTREE_REF);
41662306a36Sopenharmony_ci	else
41762306a36Sopenharmony_ci		xfs_buf_set_ref(*bpp, XFS_DIR_BTREE_REF);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (!tp)
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci	return xfs_da3_node_set_type(tp, *bpp);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/*========================================================================
42562306a36Sopenharmony_ci * Routines used for growing the Btree.
42662306a36Sopenharmony_ci *========================================================================*/
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/*
42962306a36Sopenharmony_ci * Create the initial contents of an intermediate node.
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_ciint
43262306a36Sopenharmony_cixfs_da3_node_create(
43362306a36Sopenharmony_ci	struct xfs_da_args	*args,
43462306a36Sopenharmony_ci	xfs_dablk_t		blkno,
43562306a36Sopenharmony_ci	int			level,
43662306a36Sopenharmony_ci	struct xfs_buf		**bpp,
43762306a36Sopenharmony_ci	int			whichfork)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
44062306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
44162306a36Sopenharmony_ci	struct xfs_mount	*mp = tp->t_mountp;
44262306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr ichdr = {0};
44362306a36Sopenharmony_ci	struct xfs_buf		*bp;
44462306a36Sopenharmony_ci	int			error;
44562306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	trace_xfs_da_node_create(args);
44862306a36Sopenharmony_ci	ASSERT(level <= XFS_DA_NODE_MAXDEPTH);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	error = xfs_da_get_buf(tp, dp, blkno, &bp, whichfork);
45162306a36Sopenharmony_ci	if (error)
45262306a36Sopenharmony_ci		return error;
45362306a36Sopenharmony_ci	bp->b_ops = &xfs_da3_node_buf_ops;
45462306a36Sopenharmony_ci	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
45562306a36Sopenharmony_ci	node = bp->b_addr;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
45862306a36Sopenharmony_ci		struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));
46162306a36Sopenharmony_ci		ichdr.magic = XFS_DA3_NODE_MAGIC;
46262306a36Sopenharmony_ci		hdr3->info.blkno = cpu_to_be64(xfs_buf_daddr(bp));
46362306a36Sopenharmony_ci		hdr3->info.owner = cpu_to_be64(args->dp->i_ino);
46462306a36Sopenharmony_ci		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
46562306a36Sopenharmony_ci	} else {
46662306a36Sopenharmony_ci		ichdr.magic = XFS_DA_NODE_MAGIC;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci	ichdr.level = level;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node, &ichdr);
47162306a36Sopenharmony_ci	xfs_trans_log_buf(tp, bp,
47262306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node, &node->hdr, args->geo->node_hdr_size));
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	*bpp = bp;
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/*
47962306a36Sopenharmony_ci * Split a leaf node, rebalance, then possibly split
48062306a36Sopenharmony_ci * intermediate nodes, rebalance, etc.
48162306a36Sopenharmony_ci */
48262306a36Sopenharmony_ciint							/* error */
48362306a36Sopenharmony_cixfs_da3_split(
48462306a36Sopenharmony_ci	struct xfs_da_state	*state)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct xfs_da_state_blk	*oldblk;
48762306a36Sopenharmony_ci	struct xfs_da_state_blk	*newblk;
48862306a36Sopenharmony_ci	struct xfs_da_state_blk	*addblk;
48962306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
49062306a36Sopenharmony_ci	int			max;
49162306a36Sopenharmony_ci	int			action = 0;
49262306a36Sopenharmony_ci	int			error;
49362306a36Sopenharmony_ci	int			i;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	trace_xfs_da_split(state->args);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (XFS_TEST_ERROR(false, state->mp, XFS_ERRTAG_DA_LEAF_SPLIT))
49862306a36Sopenharmony_ci		return -EIO;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/*
50162306a36Sopenharmony_ci	 * Walk back up the tree splitting/inserting/adjusting as necessary.
50262306a36Sopenharmony_ci	 * If we need to insert and there isn't room, split the node, then
50362306a36Sopenharmony_ci	 * decide which fragment to insert the new block from below into.
50462306a36Sopenharmony_ci	 * Note that we may split the root this way, but we need more fixup.
50562306a36Sopenharmony_ci	 */
50662306a36Sopenharmony_ci	max = state->path.active - 1;
50762306a36Sopenharmony_ci	ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH));
50862306a36Sopenharmony_ci	ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC ||
50962306a36Sopenharmony_ci	       state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	addblk = &state->path.blk[max];		/* initial dummy value */
51262306a36Sopenharmony_ci	for (i = max; (i >= 0) && addblk; state->path.active--, i--) {
51362306a36Sopenharmony_ci		oldblk = &state->path.blk[i];
51462306a36Sopenharmony_ci		newblk = &state->altpath.blk[i];
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		/*
51762306a36Sopenharmony_ci		 * If a leaf node then
51862306a36Sopenharmony_ci		 *     Allocate a new leaf node, then rebalance across them.
51962306a36Sopenharmony_ci		 * else if an intermediate node then
52062306a36Sopenharmony_ci		 *     We split on the last layer, must we split the node?
52162306a36Sopenharmony_ci		 */
52262306a36Sopenharmony_ci		switch (oldblk->magic) {
52362306a36Sopenharmony_ci		case XFS_ATTR_LEAF_MAGIC:
52462306a36Sopenharmony_ci			error = xfs_attr3_leaf_split(state, oldblk, newblk);
52562306a36Sopenharmony_ci			if ((error != 0) && (error != -ENOSPC)) {
52662306a36Sopenharmony_ci				return error;	/* GROT: attr is inconsistent */
52762306a36Sopenharmony_ci			}
52862306a36Sopenharmony_ci			if (!error) {
52962306a36Sopenharmony_ci				addblk = newblk;
53062306a36Sopenharmony_ci				break;
53162306a36Sopenharmony_ci			}
53262306a36Sopenharmony_ci			/*
53362306a36Sopenharmony_ci			 * Entry wouldn't fit, split the leaf again. The new
53462306a36Sopenharmony_ci			 * extrablk will be consumed by xfs_da3_node_split if
53562306a36Sopenharmony_ci			 * the node is split.
53662306a36Sopenharmony_ci			 */
53762306a36Sopenharmony_ci			state->extravalid = 1;
53862306a36Sopenharmony_ci			if (state->inleaf) {
53962306a36Sopenharmony_ci				state->extraafter = 0;	/* before newblk */
54062306a36Sopenharmony_ci				trace_xfs_attr_leaf_split_before(state->args);
54162306a36Sopenharmony_ci				error = xfs_attr3_leaf_split(state, oldblk,
54262306a36Sopenharmony_ci							    &state->extrablk);
54362306a36Sopenharmony_ci			} else {
54462306a36Sopenharmony_ci				state->extraafter = 1;	/* after newblk */
54562306a36Sopenharmony_ci				trace_xfs_attr_leaf_split_after(state->args);
54662306a36Sopenharmony_ci				error = xfs_attr3_leaf_split(state, newblk,
54762306a36Sopenharmony_ci							    &state->extrablk);
54862306a36Sopenharmony_ci			}
54962306a36Sopenharmony_ci			if (error)
55062306a36Sopenharmony_ci				return error;	/* GROT: attr inconsistent */
55162306a36Sopenharmony_ci			addblk = newblk;
55262306a36Sopenharmony_ci			break;
55362306a36Sopenharmony_ci		case XFS_DIR2_LEAFN_MAGIC:
55462306a36Sopenharmony_ci			error = xfs_dir2_leafn_split(state, oldblk, newblk);
55562306a36Sopenharmony_ci			if (error)
55662306a36Sopenharmony_ci				return error;
55762306a36Sopenharmony_ci			addblk = newblk;
55862306a36Sopenharmony_ci			break;
55962306a36Sopenharmony_ci		case XFS_DA_NODE_MAGIC:
56062306a36Sopenharmony_ci			error = xfs_da3_node_split(state, oldblk, newblk, addblk,
56162306a36Sopenharmony_ci							 max - i, &action);
56262306a36Sopenharmony_ci			addblk->bp = NULL;
56362306a36Sopenharmony_ci			if (error)
56462306a36Sopenharmony_ci				return error;	/* GROT: dir is inconsistent */
56562306a36Sopenharmony_ci			/*
56662306a36Sopenharmony_ci			 * Record the newly split block for the next time thru?
56762306a36Sopenharmony_ci			 */
56862306a36Sopenharmony_ci			if (action)
56962306a36Sopenharmony_ci				addblk = newblk;
57062306a36Sopenharmony_ci			else
57162306a36Sopenharmony_ci				addblk = NULL;
57262306a36Sopenharmony_ci			break;
57362306a36Sopenharmony_ci		}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		/*
57662306a36Sopenharmony_ci		 * Update the btree to show the new hashval for this child.
57762306a36Sopenharmony_ci		 */
57862306a36Sopenharmony_ci		xfs_da3_fixhashpath(state, &state->path);
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci	if (!addblk)
58162306a36Sopenharmony_ci		return 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/*
58462306a36Sopenharmony_ci	 * xfs_da3_node_split() should have consumed any extra blocks we added
58562306a36Sopenharmony_ci	 * during a double leaf split in the attr fork. This is guaranteed as
58662306a36Sopenharmony_ci	 * we can't be here if the attr fork only has a single leaf block.
58762306a36Sopenharmony_ci	 */
58862306a36Sopenharmony_ci	ASSERT(state->extravalid == 0 ||
58962306a36Sopenharmony_ci	       state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * Split the root node.
59362306a36Sopenharmony_ci	 */
59462306a36Sopenharmony_ci	ASSERT(state->path.active == 0);
59562306a36Sopenharmony_ci	oldblk = &state->path.blk[0];
59662306a36Sopenharmony_ci	error = xfs_da3_root_split(state, oldblk, addblk);
59762306a36Sopenharmony_ci	if (error)
59862306a36Sopenharmony_ci		goto out;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * Update pointers to the node which used to be block 0 and just got
60262306a36Sopenharmony_ci	 * bumped because of the addition of a new root node.  Note that the
60362306a36Sopenharmony_ci	 * original block 0 could be at any position in the list of blocks in
60462306a36Sopenharmony_ci	 * the tree.
60562306a36Sopenharmony_ci	 *
60662306a36Sopenharmony_ci	 * Note: the magic numbers and sibling pointers are in the same physical
60762306a36Sopenharmony_ci	 * place for both v2 and v3 headers (by design). Hence it doesn't matter
60862306a36Sopenharmony_ci	 * which version of the xfs_da_intnode structure we use here as the
60962306a36Sopenharmony_ci	 * result will be the same using either structure.
61062306a36Sopenharmony_ci	 */
61162306a36Sopenharmony_ci	node = oldblk->bp->b_addr;
61262306a36Sopenharmony_ci	if (node->hdr.info.forw) {
61362306a36Sopenharmony_ci		if (be32_to_cpu(node->hdr.info.forw) != addblk->blkno) {
61462306a36Sopenharmony_ci			xfs_buf_mark_corrupt(oldblk->bp);
61562306a36Sopenharmony_ci			error = -EFSCORRUPTED;
61662306a36Sopenharmony_ci			goto out;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci		node = addblk->bp->b_addr;
61962306a36Sopenharmony_ci		node->hdr.info.back = cpu_to_be32(oldblk->blkno);
62062306a36Sopenharmony_ci		xfs_trans_log_buf(state->args->trans, addblk->bp,
62162306a36Sopenharmony_ci				  XFS_DA_LOGRANGE(node, &node->hdr.info,
62262306a36Sopenharmony_ci				  sizeof(node->hdr.info)));
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci	node = oldblk->bp->b_addr;
62562306a36Sopenharmony_ci	if (node->hdr.info.back) {
62662306a36Sopenharmony_ci		if (be32_to_cpu(node->hdr.info.back) != addblk->blkno) {
62762306a36Sopenharmony_ci			xfs_buf_mark_corrupt(oldblk->bp);
62862306a36Sopenharmony_ci			error = -EFSCORRUPTED;
62962306a36Sopenharmony_ci			goto out;
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci		node = addblk->bp->b_addr;
63262306a36Sopenharmony_ci		node->hdr.info.forw = cpu_to_be32(oldblk->blkno);
63362306a36Sopenharmony_ci		xfs_trans_log_buf(state->args->trans, addblk->bp,
63462306a36Sopenharmony_ci				  XFS_DA_LOGRANGE(node, &node->hdr.info,
63562306a36Sopenharmony_ci				  sizeof(node->hdr.info)));
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ciout:
63862306a36Sopenharmony_ci	addblk->bp = NULL;
63962306a36Sopenharmony_ci	return error;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/*
64362306a36Sopenharmony_ci * Split the root.  We have to create a new root and point to the two
64462306a36Sopenharmony_ci * parts (the split old root) that we just created.  Copy block zero to
64562306a36Sopenharmony_ci * the EOF, extending the inode in process.
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_ciSTATIC int						/* error */
64862306a36Sopenharmony_cixfs_da3_root_split(
64962306a36Sopenharmony_ci	struct xfs_da_state	*state,
65062306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk1,
65162306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk2)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
65462306a36Sopenharmony_ci	struct xfs_da_intnode	*oldroot;
65562306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
65662306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
65762306a36Sopenharmony_ci	struct xfs_da_args	*args;
65862306a36Sopenharmony_ci	struct xfs_buf		*bp;
65962306a36Sopenharmony_ci	struct xfs_inode	*dp;
66062306a36Sopenharmony_ci	struct xfs_trans	*tp;
66162306a36Sopenharmony_ci	struct xfs_dir2_leaf	*leaf;
66262306a36Sopenharmony_ci	xfs_dablk_t		blkno;
66362306a36Sopenharmony_ci	int			level;
66462306a36Sopenharmony_ci	int			error;
66562306a36Sopenharmony_ci	int			size;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	trace_xfs_da_root_split(state->args);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/*
67062306a36Sopenharmony_ci	 * Copy the existing (incorrect) block from the root node position
67162306a36Sopenharmony_ci	 * to a free space somewhere.
67262306a36Sopenharmony_ci	 */
67362306a36Sopenharmony_ci	args = state->args;
67462306a36Sopenharmony_ci	error = xfs_da_grow_inode(args, &blkno);
67562306a36Sopenharmony_ci	if (error)
67662306a36Sopenharmony_ci		return error;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	dp = args->dp;
67962306a36Sopenharmony_ci	tp = args->trans;
68062306a36Sopenharmony_ci	error = xfs_da_get_buf(tp, dp, blkno, &bp, args->whichfork);
68162306a36Sopenharmony_ci	if (error)
68262306a36Sopenharmony_ci		return error;
68362306a36Sopenharmony_ci	node = bp->b_addr;
68462306a36Sopenharmony_ci	oldroot = blk1->bp->b_addr;
68562306a36Sopenharmony_ci	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
68662306a36Sopenharmony_ci	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) {
68762306a36Sopenharmony_ci		struct xfs_da3_icnode_hdr icnodehdr;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &icnodehdr, oldroot);
69062306a36Sopenharmony_ci		btree = icnodehdr.btree;
69162306a36Sopenharmony_ci		size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot);
69262306a36Sopenharmony_ci		level = icnodehdr.level;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		/*
69562306a36Sopenharmony_ci		 * we are about to copy oldroot to bp, so set up the type
69662306a36Sopenharmony_ci		 * of bp while we know exactly what it will be.
69762306a36Sopenharmony_ci		 */
69862306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
69962306a36Sopenharmony_ci	} else {
70062306a36Sopenharmony_ci		struct xfs_dir3_icleaf_hdr leafhdr;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		leaf = (xfs_dir2_leaf_t *)oldroot;
70362306a36Sopenharmony_ci		xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
70662306a36Sopenharmony_ci		       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
70762306a36Sopenharmony_ci		size = (int)((char *)&leafhdr.ents[leafhdr.count] -
70862306a36Sopenharmony_ci			(char *)leaf);
70962306a36Sopenharmony_ci		level = 0;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		/*
71262306a36Sopenharmony_ci		 * we are about to copy oldroot to bp, so set up the type
71362306a36Sopenharmony_ci		 * of bp while we know exactly what it will be.
71462306a36Sopenharmony_ci		 */
71562306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF);
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/*
71962306a36Sopenharmony_ci	 * we can copy most of the information in the node from one block to
72062306a36Sopenharmony_ci	 * another, but for CRC enabled headers we have to make sure that the
72162306a36Sopenharmony_ci	 * block specific identifiers are kept intact. We update the buffer
72262306a36Sopenharmony_ci	 * directly for this.
72362306a36Sopenharmony_ci	 */
72462306a36Sopenharmony_ci	memcpy(node, oldroot, size);
72562306a36Sopenharmony_ci	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) ||
72662306a36Sopenharmony_ci	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
72762306a36Sopenharmony_ci		struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		node3->hdr.info.blkno = cpu_to_be64(xfs_buf_daddr(bp));
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci	xfs_trans_log_buf(tp, bp, 0, size - 1);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	bp->b_ops = blk1->bp->b_ops;
73462306a36Sopenharmony_ci	xfs_trans_buf_copy_type(bp, blk1->bp);
73562306a36Sopenharmony_ci	blk1->bp = bp;
73662306a36Sopenharmony_ci	blk1->blkno = blkno;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/*
73962306a36Sopenharmony_ci	 * Set up the new root node.
74062306a36Sopenharmony_ci	 */
74162306a36Sopenharmony_ci	error = xfs_da3_node_create(args,
74262306a36Sopenharmony_ci		(args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0,
74362306a36Sopenharmony_ci		level + 1, &bp, args->whichfork);
74462306a36Sopenharmony_ci	if (error)
74562306a36Sopenharmony_ci		return error;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	node = bp->b_addr;
74862306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
74962306a36Sopenharmony_ci	btree = nodehdr.btree;
75062306a36Sopenharmony_ci	btree[0].hashval = cpu_to_be32(blk1->hashval);
75162306a36Sopenharmony_ci	btree[0].before = cpu_to_be32(blk1->blkno);
75262306a36Sopenharmony_ci	btree[1].hashval = cpu_to_be32(blk2->hashval);
75362306a36Sopenharmony_ci	btree[1].before = cpu_to_be32(blk2->blkno);
75462306a36Sopenharmony_ci	nodehdr.count = 2;
75562306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci#ifdef DEBUG
75862306a36Sopenharmony_ci	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
75962306a36Sopenharmony_ci	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
76062306a36Sopenharmony_ci		ASSERT(blk1->blkno >= args->geo->leafblk &&
76162306a36Sopenharmony_ci		       blk1->blkno < args->geo->freeblk);
76262306a36Sopenharmony_ci		ASSERT(blk2->blkno >= args->geo->leafblk &&
76362306a36Sopenharmony_ci		       blk2->blkno < args->geo->freeblk);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci#endif
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	/* Header is already logged by xfs_da_node_create */
76862306a36Sopenharmony_ci	xfs_trans_log_buf(tp, bp,
76962306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node, btree, sizeof(xfs_da_node_entry_t) * 2));
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci/*
77562306a36Sopenharmony_ci * Split the node, rebalance, then add the new entry.
77662306a36Sopenharmony_ci */
77762306a36Sopenharmony_ciSTATIC int						/* error */
77862306a36Sopenharmony_cixfs_da3_node_split(
77962306a36Sopenharmony_ci	struct xfs_da_state	*state,
78062306a36Sopenharmony_ci	struct xfs_da_state_blk	*oldblk,
78162306a36Sopenharmony_ci	struct xfs_da_state_blk	*newblk,
78262306a36Sopenharmony_ci	struct xfs_da_state_blk	*addblk,
78362306a36Sopenharmony_ci	int			treelevel,
78462306a36Sopenharmony_ci	int			*result)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
78762306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
78862306a36Sopenharmony_ci	xfs_dablk_t		blkno;
78962306a36Sopenharmony_ci	int			newcount;
79062306a36Sopenharmony_ci	int			error;
79162306a36Sopenharmony_ci	int			useextra;
79262306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	trace_xfs_da_node_split(state->args);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	node = oldblk->bp->b_addr;
79762306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	/*
80062306a36Sopenharmony_ci	 * With V2 dirs the extra block is data or freespace.
80162306a36Sopenharmony_ci	 */
80262306a36Sopenharmony_ci	useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK;
80362306a36Sopenharmony_ci	newcount = 1 + useextra;
80462306a36Sopenharmony_ci	/*
80562306a36Sopenharmony_ci	 * Do we have to split the node?
80662306a36Sopenharmony_ci	 */
80762306a36Sopenharmony_ci	if (nodehdr.count + newcount > state->args->geo->node_ents) {
80862306a36Sopenharmony_ci		/*
80962306a36Sopenharmony_ci		 * Allocate a new node, add to the doubly linked chain of
81062306a36Sopenharmony_ci		 * nodes, then move some of our excess entries into it.
81162306a36Sopenharmony_ci		 */
81262306a36Sopenharmony_ci		error = xfs_da_grow_inode(state->args, &blkno);
81362306a36Sopenharmony_ci		if (error)
81462306a36Sopenharmony_ci			return error;	/* GROT: dir is inconsistent */
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		error = xfs_da3_node_create(state->args, blkno, treelevel,
81762306a36Sopenharmony_ci					   &newblk->bp, state->args->whichfork);
81862306a36Sopenharmony_ci		if (error)
81962306a36Sopenharmony_ci			return error;	/* GROT: dir is inconsistent */
82062306a36Sopenharmony_ci		newblk->blkno = blkno;
82162306a36Sopenharmony_ci		newblk->magic = XFS_DA_NODE_MAGIC;
82262306a36Sopenharmony_ci		xfs_da3_node_rebalance(state, oldblk, newblk);
82362306a36Sopenharmony_ci		error = xfs_da3_blk_link(state, oldblk, newblk);
82462306a36Sopenharmony_ci		if (error)
82562306a36Sopenharmony_ci			return error;
82662306a36Sopenharmony_ci		*result = 1;
82762306a36Sopenharmony_ci	} else {
82862306a36Sopenharmony_ci		*result = 0;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/*
83262306a36Sopenharmony_ci	 * Insert the new entry(s) into the correct block
83362306a36Sopenharmony_ci	 * (updating last hashval in the process).
83462306a36Sopenharmony_ci	 *
83562306a36Sopenharmony_ci	 * xfs_da3_node_add() inserts BEFORE the given index,
83662306a36Sopenharmony_ci	 * and as a result of using node_lookup_int() we always
83762306a36Sopenharmony_ci	 * point to a valid entry (not after one), but a split
83862306a36Sopenharmony_ci	 * operation always results in a new block whose hashvals
83962306a36Sopenharmony_ci	 * FOLLOW the current block.
84062306a36Sopenharmony_ci	 *
84162306a36Sopenharmony_ci	 * If we had double-split op below us, then add the extra block too.
84262306a36Sopenharmony_ci	 */
84362306a36Sopenharmony_ci	node = oldblk->bp->b_addr;
84462306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
84562306a36Sopenharmony_ci	if (oldblk->index <= nodehdr.count) {
84662306a36Sopenharmony_ci		oldblk->index++;
84762306a36Sopenharmony_ci		xfs_da3_node_add(state, oldblk, addblk);
84862306a36Sopenharmony_ci		if (useextra) {
84962306a36Sopenharmony_ci			if (state->extraafter)
85062306a36Sopenharmony_ci				oldblk->index++;
85162306a36Sopenharmony_ci			xfs_da3_node_add(state, oldblk, &state->extrablk);
85262306a36Sopenharmony_ci			state->extravalid = 0;
85362306a36Sopenharmony_ci		}
85462306a36Sopenharmony_ci	} else {
85562306a36Sopenharmony_ci		newblk->index++;
85662306a36Sopenharmony_ci		xfs_da3_node_add(state, newblk, addblk);
85762306a36Sopenharmony_ci		if (useextra) {
85862306a36Sopenharmony_ci			if (state->extraafter)
85962306a36Sopenharmony_ci				newblk->index++;
86062306a36Sopenharmony_ci			xfs_da3_node_add(state, newblk, &state->extrablk);
86162306a36Sopenharmony_ci			state->extravalid = 0;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return 0;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/*
86962306a36Sopenharmony_ci * Balance the btree elements between two intermediate nodes,
87062306a36Sopenharmony_ci * usually one full and one empty.
87162306a36Sopenharmony_ci *
87262306a36Sopenharmony_ci * NOTE: if blk2 is empty, then it will get the upper half of blk1.
87362306a36Sopenharmony_ci */
87462306a36Sopenharmony_ciSTATIC void
87562306a36Sopenharmony_cixfs_da3_node_rebalance(
87662306a36Sopenharmony_ci	struct xfs_da_state	*state,
87762306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk1,
87862306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk2)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	struct xfs_da_intnode	*node1;
88162306a36Sopenharmony_ci	struct xfs_da_intnode	*node2;
88262306a36Sopenharmony_ci	struct xfs_da_node_entry *btree1;
88362306a36Sopenharmony_ci	struct xfs_da_node_entry *btree2;
88462306a36Sopenharmony_ci	struct xfs_da_node_entry *btree_s;
88562306a36Sopenharmony_ci	struct xfs_da_node_entry *btree_d;
88662306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr1;
88762306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr2;
88862306a36Sopenharmony_ci	struct xfs_trans	*tp;
88962306a36Sopenharmony_ci	int			count;
89062306a36Sopenharmony_ci	int			tmp;
89162306a36Sopenharmony_ci	int			swap = 0;
89262306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	trace_xfs_da_node_rebalance(state->args);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	node1 = blk1->bp->b_addr;
89762306a36Sopenharmony_ci	node2 = blk2->bp->b_addr;
89862306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
89962306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
90062306a36Sopenharmony_ci	btree1 = nodehdr1.btree;
90162306a36Sopenharmony_ci	btree2 = nodehdr2.btree;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/*
90462306a36Sopenharmony_ci	 * Figure out how many entries need to move, and in which direction.
90562306a36Sopenharmony_ci	 * Swap the nodes around if that makes it simpler.
90662306a36Sopenharmony_ci	 */
90762306a36Sopenharmony_ci	if (nodehdr1.count > 0 && nodehdr2.count > 0 &&
90862306a36Sopenharmony_ci	    ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) ||
90962306a36Sopenharmony_ci	     (be32_to_cpu(btree2[nodehdr2.count - 1].hashval) <
91062306a36Sopenharmony_ci			be32_to_cpu(btree1[nodehdr1.count - 1].hashval)))) {
91162306a36Sopenharmony_ci		swap(node1, node2);
91262306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
91362306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
91462306a36Sopenharmony_ci		btree1 = nodehdr1.btree;
91562306a36Sopenharmony_ci		btree2 = nodehdr2.btree;
91662306a36Sopenharmony_ci		swap = 1;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	count = (nodehdr1.count - nodehdr2.count) / 2;
92062306a36Sopenharmony_ci	if (count == 0)
92162306a36Sopenharmony_ci		return;
92262306a36Sopenharmony_ci	tp = state->args->trans;
92362306a36Sopenharmony_ci	/*
92462306a36Sopenharmony_ci	 * Two cases: high-to-low and low-to-high.
92562306a36Sopenharmony_ci	 */
92662306a36Sopenharmony_ci	if (count > 0) {
92762306a36Sopenharmony_ci		/*
92862306a36Sopenharmony_ci		 * Move elements in node2 up to make a hole.
92962306a36Sopenharmony_ci		 */
93062306a36Sopenharmony_ci		tmp = nodehdr2.count;
93162306a36Sopenharmony_ci		if (tmp > 0) {
93262306a36Sopenharmony_ci			tmp *= (uint)sizeof(xfs_da_node_entry_t);
93362306a36Sopenharmony_ci			btree_s = &btree2[0];
93462306a36Sopenharmony_ci			btree_d = &btree2[count];
93562306a36Sopenharmony_ci			memmove(btree_d, btree_s, tmp);
93662306a36Sopenharmony_ci		}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		/*
93962306a36Sopenharmony_ci		 * Move the req'd B-tree elements from high in node1 to
94062306a36Sopenharmony_ci		 * low in node2.
94162306a36Sopenharmony_ci		 */
94262306a36Sopenharmony_ci		nodehdr2.count += count;
94362306a36Sopenharmony_ci		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
94462306a36Sopenharmony_ci		btree_s = &btree1[nodehdr1.count - count];
94562306a36Sopenharmony_ci		btree_d = &btree2[0];
94662306a36Sopenharmony_ci		memcpy(btree_d, btree_s, tmp);
94762306a36Sopenharmony_ci		nodehdr1.count -= count;
94862306a36Sopenharmony_ci	} else {
94962306a36Sopenharmony_ci		/*
95062306a36Sopenharmony_ci		 * Move the req'd B-tree elements from low in node2 to
95162306a36Sopenharmony_ci		 * high in node1.
95262306a36Sopenharmony_ci		 */
95362306a36Sopenharmony_ci		count = -count;
95462306a36Sopenharmony_ci		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
95562306a36Sopenharmony_ci		btree_s = &btree2[0];
95662306a36Sopenharmony_ci		btree_d = &btree1[nodehdr1.count];
95762306a36Sopenharmony_ci		memcpy(btree_d, btree_s, tmp);
95862306a36Sopenharmony_ci		nodehdr1.count += count;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci		xfs_trans_log_buf(tp, blk1->bp,
96162306a36Sopenharmony_ci			XFS_DA_LOGRANGE(node1, btree_d, tmp));
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		/*
96462306a36Sopenharmony_ci		 * Move elements in node2 down to fill the hole.
96562306a36Sopenharmony_ci		 */
96662306a36Sopenharmony_ci		tmp  = nodehdr2.count - count;
96762306a36Sopenharmony_ci		tmp *= (uint)sizeof(xfs_da_node_entry_t);
96862306a36Sopenharmony_ci		btree_s = &btree2[count];
96962306a36Sopenharmony_ci		btree_d = &btree2[0];
97062306a36Sopenharmony_ci		memmove(btree_d, btree_s, tmp);
97162306a36Sopenharmony_ci		nodehdr2.count -= count;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/*
97562306a36Sopenharmony_ci	 * Log header of node 1 and all current bits of node 2.
97662306a36Sopenharmony_ci	 */
97762306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node1, &nodehdr1);
97862306a36Sopenharmony_ci	xfs_trans_log_buf(tp, blk1->bp,
97962306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node1, &node1->hdr,
98062306a36Sopenharmony_ci				state->args->geo->node_hdr_size));
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node2, &nodehdr2);
98362306a36Sopenharmony_ci	xfs_trans_log_buf(tp, blk2->bp,
98462306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node2, &node2->hdr,
98562306a36Sopenharmony_ci				state->args->geo->node_hdr_size +
98662306a36Sopenharmony_ci				(sizeof(btree2[0]) * nodehdr2.count)));
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	/*
98962306a36Sopenharmony_ci	 * Record the last hashval from each block for upward propagation.
99062306a36Sopenharmony_ci	 * (note: don't use the swapped node pointers)
99162306a36Sopenharmony_ci	 */
99262306a36Sopenharmony_ci	if (swap) {
99362306a36Sopenharmony_ci		node1 = blk1->bp->b_addr;
99462306a36Sopenharmony_ci		node2 = blk2->bp->b_addr;
99562306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr1, node1);
99662306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr2, node2);
99762306a36Sopenharmony_ci		btree1 = nodehdr1.btree;
99862306a36Sopenharmony_ci		btree2 = nodehdr2.btree;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci	blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval);
100162306a36Sopenharmony_ci	blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/*
100462306a36Sopenharmony_ci	 * Adjust the expected index for insertion.
100562306a36Sopenharmony_ci	 */
100662306a36Sopenharmony_ci	if (blk1->index >= nodehdr1.count) {
100762306a36Sopenharmony_ci		blk2->index = blk1->index - nodehdr1.count;
100862306a36Sopenharmony_ci		blk1->index = nodehdr1.count + 1;	/* make it invalid */
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/*
101362306a36Sopenharmony_ci * Add a new entry to an intermediate node.
101462306a36Sopenharmony_ci */
101562306a36Sopenharmony_ciSTATIC void
101662306a36Sopenharmony_cixfs_da3_node_add(
101762306a36Sopenharmony_ci	struct xfs_da_state	*state,
101862306a36Sopenharmony_ci	struct xfs_da_state_blk	*oldblk,
101962306a36Sopenharmony_ci	struct xfs_da_state_blk	*newblk)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
102262306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
102362306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
102462306a36Sopenharmony_ci	int			tmp;
102562306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	trace_xfs_da_node_add(state->args);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	node = oldblk->bp->b_addr;
103062306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
103162306a36Sopenharmony_ci	btree = nodehdr.btree;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count);
103462306a36Sopenharmony_ci	ASSERT(newblk->blkno != 0);
103562306a36Sopenharmony_ci	if (state->args->whichfork == XFS_DATA_FORK)
103662306a36Sopenharmony_ci		ASSERT(newblk->blkno >= state->args->geo->leafblk &&
103762306a36Sopenharmony_ci		       newblk->blkno < state->args->geo->freeblk);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/*
104062306a36Sopenharmony_ci	 * We may need to make some room before we insert the new node.
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	tmp = 0;
104362306a36Sopenharmony_ci	if (oldblk->index < nodehdr.count) {
104462306a36Sopenharmony_ci		tmp = (nodehdr.count - oldblk->index) * (uint)sizeof(*btree);
104562306a36Sopenharmony_ci		memmove(&btree[oldblk->index + 1], &btree[oldblk->index], tmp);
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci	btree[oldblk->index].hashval = cpu_to_be32(newblk->hashval);
104862306a36Sopenharmony_ci	btree[oldblk->index].before = cpu_to_be32(newblk->blkno);
104962306a36Sopenharmony_ci	xfs_trans_log_buf(state->args->trans, oldblk->bp,
105062306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node, &btree[oldblk->index],
105162306a36Sopenharmony_ci				tmp + sizeof(*btree)));
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	nodehdr.count += 1;
105462306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
105562306a36Sopenharmony_ci	xfs_trans_log_buf(state->args->trans, oldblk->bp,
105662306a36Sopenharmony_ci		XFS_DA_LOGRANGE(node, &node->hdr,
105762306a36Sopenharmony_ci				state->args->geo->node_hdr_size));
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/*
106062306a36Sopenharmony_ci	 * Copy the last hash value from the oldblk to propagate upwards.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	oldblk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci/*========================================================================
106662306a36Sopenharmony_ci * Routines used for shrinking the Btree.
106762306a36Sopenharmony_ci *========================================================================*/
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci/*
107062306a36Sopenharmony_ci * Deallocate an empty leaf node, remove it from its parent,
107162306a36Sopenharmony_ci * possibly deallocating that block, etc...
107262306a36Sopenharmony_ci */
107362306a36Sopenharmony_ciint
107462306a36Sopenharmony_cixfs_da3_join(
107562306a36Sopenharmony_ci	struct xfs_da_state	*state)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct xfs_da_state_blk	*drop_blk;
107862306a36Sopenharmony_ci	struct xfs_da_state_blk	*save_blk;
107962306a36Sopenharmony_ci	int			action = 0;
108062306a36Sopenharmony_ci	int			error;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	trace_xfs_da_join(state->args);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	drop_blk = &state->path.blk[ state->path.active-1 ];
108562306a36Sopenharmony_ci	save_blk = &state->altpath.blk[ state->path.active-1 ];
108662306a36Sopenharmony_ci	ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC);
108762306a36Sopenharmony_ci	ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC ||
108862306a36Sopenharmony_ci	       drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/*
109162306a36Sopenharmony_ci	 * Walk back up the tree joining/deallocating as necessary.
109262306a36Sopenharmony_ci	 * When we stop dropping blocks, break out.
109362306a36Sopenharmony_ci	 */
109462306a36Sopenharmony_ci	for (  ; state->path.active >= 2; drop_blk--, save_blk--,
109562306a36Sopenharmony_ci		 state->path.active--) {
109662306a36Sopenharmony_ci		/*
109762306a36Sopenharmony_ci		 * See if we can combine the block with a neighbor.
109862306a36Sopenharmony_ci		 *   (action == 0) => no options, just leave
109962306a36Sopenharmony_ci		 *   (action == 1) => coalesce, then unlink
110062306a36Sopenharmony_ci		 *   (action == 2) => block empty, unlink it
110162306a36Sopenharmony_ci		 */
110262306a36Sopenharmony_ci		switch (drop_blk->magic) {
110362306a36Sopenharmony_ci		case XFS_ATTR_LEAF_MAGIC:
110462306a36Sopenharmony_ci			error = xfs_attr3_leaf_toosmall(state, &action);
110562306a36Sopenharmony_ci			if (error)
110662306a36Sopenharmony_ci				return error;
110762306a36Sopenharmony_ci			if (action == 0)
110862306a36Sopenharmony_ci				return 0;
110962306a36Sopenharmony_ci			xfs_attr3_leaf_unbalance(state, drop_blk, save_blk);
111062306a36Sopenharmony_ci			break;
111162306a36Sopenharmony_ci		case XFS_DIR2_LEAFN_MAGIC:
111262306a36Sopenharmony_ci			error = xfs_dir2_leafn_toosmall(state, &action);
111362306a36Sopenharmony_ci			if (error)
111462306a36Sopenharmony_ci				return error;
111562306a36Sopenharmony_ci			if (action == 0)
111662306a36Sopenharmony_ci				return 0;
111762306a36Sopenharmony_ci			xfs_dir2_leafn_unbalance(state, drop_blk, save_blk);
111862306a36Sopenharmony_ci			break;
111962306a36Sopenharmony_ci		case XFS_DA_NODE_MAGIC:
112062306a36Sopenharmony_ci			/*
112162306a36Sopenharmony_ci			 * Remove the offending node, fixup hashvals,
112262306a36Sopenharmony_ci			 * check for a toosmall neighbor.
112362306a36Sopenharmony_ci			 */
112462306a36Sopenharmony_ci			xfs_da3_node_remove(state, drop_blk);
112562306a36Sopenharmony_ci			xfs_da3_fixhashpath(state, &state->path);
112662306a36Sopenharmony_ci			error = xfs_da3_node_toosmall(state, &action);
112762306a36Sopenharmony_ci			if (error)
112862306a36Sopenharmony_ci				return error;
112962306a36Sopenharmony_ci			if (action == 0)
113062306a36Sopenharmony_ci				return 0;
113162306a36Sopenharmony_ci			xfs_da3_node_unbalance(state, drop_blk, save_blk);
113262306a36Sopenharmony_ci			break;
113362306a36Sopenharmony_ci		}
113462306a36Sopenharmony_ci		xfs_da3_fixhashpath(state, &state->altpath);
113562306a36Sopenharmony_ci		error = xfs_da3_blk_unlink(state, drop_blk, save_blk);
113662306a36Sopenharmony_ci		xfs_da_state_kill_altpath(state);
113762306a36Sopenharmony_ci		if (error)
113862306a36Sopenharmony_ci			return error;
113962306a36Sopenharmony_ci		error = xfs_da_shrink_inode(state->args, drop_blk->blkno,
114062306a36Sopenharmony_ci							 drop_blk->bp);
114162306a36Sopenharmony_ci		drop_blk->bp = NULL;
114262306a36Sopenharmony_ci		if (error)
114362306a36Sopenharmony_ci			return error;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci	/*
114662306a36Sopenharmony_ci	 * We joined all the way to the top.  If it turns out that
114762306a36Sopenharmony_ci	 * we only have one entry in the root, make the child block
114862306a36Sopenharmony_ci	 * the new root.
114962306a36Sopenharmony_ci	 */
115062306a36Sopenharmony_ci	xfs_da3_node_remove(state, drop_blk);
115162306a36Sopenharmony_ci	xfs_da3_fixhashpath(state, &state->path);
115262306a36Sopenharmony_ci	error = xfs_da3_root_join(state, &state->path.blk[0]);
115362306a36Sopenharmony_ci	return error;
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci#ifdef	DEBUG
115762306a36Sopenharmony_cistatic void
115862306a36Sopenharmony_cixfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	__be16	magic = blkinfo->magic;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (level == 1) {
116362306a36Sopenharmony_ci		ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
116462306a36Sopenharmony_ci		       magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
116562306a36Sopenharmony_ci		       magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
116662306a36Sopenharmony_ci		       magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
116762306a36Sopenharmony_ci	} else {
116862306a36Sopenharmony_ci		ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
116962306a36Sopenharmony_ci		       magic == cpu_to_be16(XFS_DA3_NODE_MAGIC));
117062306a36Sopenharmony_ci	}
117162306a36Sopenharmony_ci	ASSERT(!blkinfo->forw);
117262306a36Sopenharmony_ci	ASSERT(!blkinfo->back);
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci#else	/* !DEBUG */
117562306a36Sopenharmony_ci#define	xfs_da_blkinfo_onlychild_validate(blkinfo, level)
117662306a36Sopenharmony_ci#endif	/* !DEBUG */
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci/*
117962306a36Sopenharmony_ci * We have only one entry in the root.  Copy the only remaining child of
118062306a36Sopenharmony_ci * the old root to block 0 as the new root node.
118162306a36Sopenharmony_ci */
118262306a36Sopenharmony_ciSTATIC int
118362306a36Sopenharmony_cixfs_da3_root_join(
118462306a36Sopenharmony_ci	struct xfs_da_state	*state,
118562306a36Sopenharmony_ci	struct xfs_da_state_blk	*root_blk)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	struct xfs_da_intnode	*oldroot;
118862306a36Sopenharmony_ci	struct xfs_da_args	*args;
118962306a36Sopenharmony_ci	xfs_dablk_t		child;
119062306a36Sopenharmony_ci	struct xfs_buf		*bp;
119162306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr oldroothdr;
119262306a36Sopenharmony_ci	int			error;
119362306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	trace_xfs_da_root_join(state->args);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	args = state->args;
120062306a36Sopenharmony_ci	oldroot = root_blk->bp->b_addr;
120162306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &oldroothdr, oldroot);
120262306a36Sopenharmony_ci	ASSERT(oldroothdr.forw == 0);
120362306a36Sopenharmony_ci	ASSERT(oldroothdr.back == 0);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/*
120662306a36Sopenharmony_ci	 * If the root has more than one child, then don't do anything.
120762306a36Sopenharmony_ci	 */
120862306a36Sopenharmony_ci	if (oldroothdr.count > 1)
120962306a36Sopenharmony_ci		return 0;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/*
121262306a36Sopenharmony_ci	 * Read in the (only) child block, then copy those bytes into
121362306a36Sopenharmony_ci	 * the root block's buffer and free the original child block.
121462306a36Sopenharmony_ci	 */
121562306a36Sopenharmony_ci	child = be32_to_cpu(oldroothdr.btree[0].before);
121662306a36Sopenharmony_ci	ASSERT(child != 0);
121762306a36Sopenharmony_ci	error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork);
121862306a36Sopenharmony_ci	if (error)
121962306a36Sopenharmony_ci		return error;
122062306a36Sopenharmony_ci	xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	/*
122362306a36Sopenharmony_ci	 * This could be copying a leaf back into the root block in the case of
122462306a36Sopenharmony_ci	 * there only being a single leaf block left in the tree. Hence we have
122562306a36Sopenharmony_ci	 * to update the b_ops pointer as well to match the buffer type change
122662306a36Sopenharmony_ci	 * that could occur. For dir3 blocks we also need to update the block
122762306a36Sopenharmony_ci	 * number in the buffer header.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize);
123062306a36Sopenharmony_ci	root_blk->bp->b_ops = bp->b_ops;
123162306a36Sopenharmony_ci	xfs_trans_buf_copy_type(root_blk->bp, bp);
123262306a36Sopenharmony_ci	if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) {
123362306a36Sopenharmony_ci		struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr;
123462306a36Sopenharmony_ci		da3->blkno = cpu_to_be64(xfs_buf_daddr(root_blk->bp));
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, root_blk->bp, 0,
123762306a36Sopenharmony_ci			  args->geo->blksize - 1);
123862306a36Sopenharmony_ci	error = xfs_da_shrink_inode(args, child, bp);
123962306a36Sopenharmony_ci	return error;
124062306a36Sopenharmony_ci}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci/*
124362306a36Sopenharmony_ci * Check a node block and its neighbors to see if the block should be
124462306a36Sopenharmony_ci * collapsed into one or the other neighbor.  Always keep the block
124562306a36Sopenharmony_ci * with the smaller block number.
124662306a36Sopenharmony_ci * If the current block is over 50% full, don't try to join it, return 0.
124762306a36Sopenharmony_ci * If the block is empty, fill in the state structure and return 2.
124862306a36Sopenharmony_ci * If it can be collapsed, fill in the state structure and return 1.
124962306a36Sopenharmony_ci * If nothing can be done, return 0.
125062306a36Sopenharmony_ci */
125162306a36Sopenharmony_ciSTATIC int
125262306a36Sopenharmony_cixfs_da3_node_toosmall(
125362306a36Sopenharmony_ci	struct xfs_da_state	*state,
125462306a36Sopenharmony_ci	int			*action)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
125762306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk;
125862306a36Sopenharmony_ci	struct xfs_da_blkinfo	*info;
125962306a36Sopenharmony_ci	xfs_dablk_t		blkno;
126062306a36Sopenharmony_ci	struct xfs_buf		*bp;
126162306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
126262306a36Sopenharmony_ci	int			count;
126362306a36Sopenharmony_ci	int			forward;
126462306a36Sopenharmony_ci	int			error;
126562306a36Sopenharmony_ci	int			retval;
126662306a36Sopenharmony_ci	int			i;
126762306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	trace_xfs_da_node_toosmall(state->args);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	/*
127262306a36Sopenharmony_ci	 * Check for the degenerate case of the block being over 50% full.
127362306a36Sopenharmony_ci	 * If so, it's not worth even looking to see if we might be able
127462306a36Sopenharmony_ci	 * to coalesce with a sibling.
127562306a36Sopenharmony_ci	 */
127662306a36Sopenharmony_ci	blk = &state->path.blk[ state->path.active-1 ];
127762306a36Sopenharmony_ci	info = blk->bp->b_addr;
127862306a36Sopenharmony_ci	node = (xfs_da_intnode_t *)info;
127962306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
128062306a36Sopenharmony_ci	if (nodehdr.count > (state->args->geo->node_ents >> 1)) {
128162306a36Sopenharmony_ci		*action = 0;	/* blk over 50%, don't try to join */
128262306a36Sopenharmony_ci		return 0;	/* blk over 50%, don't try to join */
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/*
128662306a36Sopenharmony_ci	 * Check for the degenerate case of the block being empty.
128762306a36Sopenharmony_ci	 * If the block is empty, we'll simply delete it, no need to
128862306a36Sopenharmony_ci	 * coalesce it with a sibling block.  We choose (arbitrarily)
128962306a36Sopenharmony_ci	 * to merge with the forward block unless it is NULL.
129062306a36Sopenharmony_ci	 */
129162306a36Sopenharmony_ci	if (nodehdr.count == 0) {
129262306a36Sopenharmony_ci		/*
129362306a36Sopenharmony_ci		 * Make altpath point to the block we want to keep and
129462306a36Sopenharmony_ci		 * path point to the block we want to drop (this one).
129562306a36Sopenharmony_ci		 */
129662306a36Sopenharmony_ci		forward = (info->forw != 0);
129762306a36Sopenharmony_ci		memcpy(&state->altpath, &state->path, sizeof(state->path));
129862306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->altpath, forward,
129962306a36Sopenharmony_ci						 0, &retval);
130062306a36Sopenharmony_ci		if (error)
130162306a36Sopenharmony_ci			return error;
130262306a36Sopenharmony_ci		if (retval) {
130362306a36Sopenharmony_ci			*action = 0;
130462306a36Sopenharmony_ci		} else {
130562306a36Sopenharmony_ci			*action = 2;
130662306a36Sopenharmony_ci		}
130762306a36Sopenharmony_ci		return 0;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	/*
131162306a36Sopenharmony_ci	 * Examine each sibling block to see if we can coalesce with
131262306a36Sopenharmony_ci	 * at least 25% free space to spare.  We need to figure out
131362306a36Sopenharmony_ci	 * whether to merge with the forward or the backward block.
131462306a36Sopenharmony_ci	 * We prefer coalescing with the lower numbered sibling so as
131562306a36Sopenharmony_ci	 * to shrink a directory over time.
131662306a36Sopenharmony_ci	 */
131762306a36Sopenharmony_ci	count  = state->args->geo->node_ents;
131862306a36Sopenharmony_ci	count -= state->args->geo->node_ents >> 2;
131962306a36Sopenharmony_ci	count -= nodehdr.count;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* start with smaller blk num */
132262306a36Sopenharmony_ci	forward = nodehdr.forw < nodehdr.back;
132362306a36Sopenharmony_ci	for (i = 0; i < 2; forward = !forward, i++) {
132462306a36Sopenharmony_ci		struct xfs_da3_icnode_hdr thdr;
132562306a36Sopenharmony_ci		if (forward)
132662306a36Sopenharmony_ci			blkno = nodehdr.forw;
132762306a36Sopenharmony_ci		else
132862306a36Sopenharmony_ci			blkno = nodehdr.back;
132962306a36Sopenharmony_ci		if (blkno == 0)
133062306a36Sopenharmony_ci			continue;
133162306a36Sopenharmony_ci		error = xfs_da3_node_read(state->args->trans, dp, blkno, &bp,
133262306a36Sopenharmony_ci				state->args->whichfork);
133362306a36Sopenharmony_ci		if (error)
133462306a36Sopenharmony_ci			return error;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		node = bp->b_addr;
133762306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node);
133862306a36Sopenharmony_ci		xfs_trans_brelse(state->args->trans, bp);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		if (count - thdr.count >= 0)
134162306a36Sopenharmony_ci			break;	/* fits with at least 25% to spare */
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci	if (i >= 2) {
134462306a36Sopenharmony_ci		*action = 0;
134562306a36Sopenharmony_ci		return 0;
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	/*
134962306a36Sopenharmony_ci	 * Make altpath point to the block we want to keep (the lower
135062306a36Sopenharmony_ci	 * numbered block) and path point to the block we want to drop.
135162306a36Sopenharmony_ci	 */
135262306a36Sopenharmony_ci	memcpy(&state->altpath, &state->path, sizeof(state->path));
135362306a36Sopenharmony_ci	if (blkno < blk->blkno) {
135462306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->altpath, forward,
135562306a36Sopenharmony_ci						 0, &retval);
135662306a36Sopenharmony_ci	} else {
135762306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->path, forward,
135862306a36Sopenharmony_ci						 0, &retval);
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci	if (error)
136162306a36Sopenharmony_ci		return error;
136262306a36Sopenharmony_ci	if (retval) {
136362306a36Sopenharmony_ci		*action = 0;
136462306a36Sopenharmony_ci		return 0;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci	*action = 1;
136762306a36Sopenharmony_ci	return 0;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci/*
137162306a36Sopenharmony_ci * Pick up the last hashvalue from an intermediate node.
137262306a36Sopenharmony_ci */
137362306a36Sopenharmony_ciSTATIC uint
137462306a36Sopenharmony_cixfs_da3_node_lasthash(
137562306a36Sopenharmony_ci	struct xfs_inode	*dp,
137662306a36Sopenharmony_ci	struct xfs_buf		*bp,
137762306a36Sopenharmony_ci	int			*count)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, bp->b_addr);
138262306a36Sopenharmony_ci	if (count)
138362306a36Sopenharmony_ci		*count = nodehdr.count;
138462306a36Sopenharmony_ci	if (!nodehdr.count)
138562306a36Sopenharmony_ci		return 0;
138662306a36Sopenharmony_ci	return be32_to_cpu(nodehdr.btree[nodehdr.count - 1].hashval);
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci/*
139062306a36Sopenharmony_ci * Walk back up the tree adjusting hash values as necessary,
139162306a36Sopenharmony_ci * when we stop making changes, return.
139262306a36Sopenharmony_ci */
139362306a36Sopenharmony_civoid
139462306a36Sopenharmony_cixfs_da3_fixhashpath(
139562306a36Sopenharmony_ci	struct xfs_da_state	*state,
139662306a36Sopenharmony_ci	struct xfs_da_state_path *path)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk;
139962306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
140062306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
140162306a36Sopenharmony_ci	xfs_dahash_t		lasthash=0;
140262306a36Sopenharmony_ci	int			level;
140362306a36Sopenharmony_ci	int			count;
140462306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	trace_xfs_da_fixhashpath(state->args);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	level = path->active-1;
140962306a36Sopenharmony_ci	blk = &path->blk[ level ];
141062306a36Sopenharmony_ci	switch (blk->magic) {
141162306a36Sopenharmony_ci	case XFS_ATTR_LEAF_MAGIC:
141262306a36Sopenharmony_ci		lasthash = xfs_attr_leaf_lasthash(blk->bp, &count);
141362306a36Sopenharmony_ci		if (count == 0)
141462306a36Sopenharmony_ci			return;
141562306a36Sopenharmony_ci		break;
141662306a36Sopenharmony_ci	case XFS_DIR2_LEAFN_MAGIC:
141762306a36Sopenharmony_ci		lasthash = xfs_dir2_leaf_lasthash(dp, blk->bp, &count);
141862306a36Sopenharmony_ci		if (count == 0)
141962306a36Sopenharmony_ci			return;
142062306a36Sopenharmony_ci		break;
142162306a36Sopenharmony_ci	case XFS_DA_NODE_MAGIC:
142262306a36Sopenharmony_ci		lasthash = xfs_da3_node_lasthash(dp, blk->bp, &count);
142362306a36Sopenharmony_ci		if (count == 0)
142462306a36Sopenharmony_ci			return;
142562306a36Sopenharmony_ci		break;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci	for (blk--, level--; level >= 0; blk--, level--) {
142862306a36Sopenharmony_ci		struct xfs_da3_icnode_hdr nodehdr;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		node = blk->bp->b_addr;
143162306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
143262306a36Sopenharmony_ci		btree = nodehdr.btree;
143362306a36Sopenharmony_ci		if (be32_to_cpu(btree[blk->index].hashval) == lasthash)
143462306a36Sopenharmony_ci			break;
143562306a36Sopenharmony_ci		blk->hashval = lasthash;
143662306a36Sopenharmony_ci		btree[blk->index].hashval = cpu_to_be32(lasthash);
143762306a36Sopenharmony_ci		xfs_trans_log_buf(state->args->trans, blk->bp,
143862306a36Sopenharmony_ci				  XFS_DA_LOGRANGE(node, &btree[blk->index],
143962306a36Sopenharmony_ci						  sizeof(*btree)));
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		lasthash = be32_to_cpu(btree[nodehdr.count - 1].hashval);
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci/*
144662306a36Sopenharmony_ci * Remove an entry from an intermediate node.
144762306a36Sopenharmony_ci */
144862306a36Sopenharmony_ciSTATIC void
144962306a36Sopenharmony_cixfs_da3_node_remove(
145062306a36Sopenharmony_ci	struct xfs_da_state	*state,
145162306a36Sopenharmony_ci	struct xfs_da_state_blk	*drop_blk)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
145462306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
145562306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
145662306a36Sopenharmony_ci	int			index;
145762306a36Sopenharmony_ci	int			tmp;
145862306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	trace_xfs_da_node_remove(state->args);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	node = drop_blk->bp->b_addr;
146362306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
146462306a36Sopenharmony_ci	ASSERT(drop_blk->index < nodehdr.count);
146562306a36Sopenharmony_ci	ASSERT(drop_blk->index >= 0);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/*
146862306a36Sopenharmony_ci	 * Copy over the offending entry, or just zero it out.
146962306a36Sopenharmony_ci	 */
147062306a36Sopenharmony_ci	index = drop_blk->index;
147162306a36Sopenharmony_ci	btree = nodehdr.btree;
147262306a36Sopenharmony_ci	if (index < nodehdr.count - 1) {
147362306a36Sopenharmony_ci		tmp  = nodehdr.count - index - 1;
147462306a36Sopenharmony_ci		tmp *= (uint)sizeof(xfs_da_node_entry_t);
147562306a36Sopenharmony_ci		memmove(&btree[index], &btree[index + 1], tmp);
147662306a36Sopenharmony_ci		xfs_trans_log_buf(state->args->trans, drop_blk->bp,
147762306a36Sopenharmony_ci		    XFS_DA_LOGRANGE(node, &btree[index], tmp));
147862306a36Sopenharmony_ci		index = nodehdr.count - 1;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci	memset(&btree[index], 0, sizeof(xfs_da_node_entry_t));
148162306a36Sopenharmony_ci	xfs_trans_log_buf(state->args->trans, drop_blk->bp,
148262306a36Sopenharmony_ci	    XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index])));
148362306a36Sopenharmony_ci	nodehdr.count -= 1;
148462306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
148562306a36Sopenharmony_ci	xfs_trans_log_buf(state->args->trans, drop_blk->bp,
148662306a36Sopenharmony_ci	    XFS_DA_LOGRANGE(node, &node->hdr, state->args->geo->node_hdr_size));
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/*
148962306a36Sopenharmony_ci	 * Copy the last hash value from the block to propagate upwards.
149062306a36Sopenharmony_ci	 */
149162306a36Sopenharmony_ci	drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval);
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci/*
149562306a36Sopenharmony_ci * Unbalance the elements between two intermediate nodes,
149662306a36Sopenharmony_ci * move all Btree elements from one node into another.
149762306a36Sopenharmony_ci */
149862306a36Sopenharmony_ciSTATIC void
149962306a36Sopenharmony_cixfs_da3_node_unbalance(
150062306a36Sopenharmony_ci	struct xfs_da_state	*state,
150162306a36Sopenharmony_ci	struct xfs_da_state_blk	*drop_blk,
150262306a36Sopenharmony_ci	struct xfs_da_state_blk	*save_blk)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	struct xfs_da_intnode	*drop_node;
150562306a36Sopenharmony_ci	struct xfs_da_intnode	*save_node;
150662306a36Sopenharmony_ci	struct xfs_da_node_entry *drop_btree;
150762306a36Sopenharmony_ci	struct xfs_da_node_entry *save_btree;
150862306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr drop_hdr;
150962306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr save_hdr;
151062306a36Sopenharmony_ci	struct xfs_trans	*tp;
151162306a36Sopenharmony_ci	int			sindex;
151262306a36Sopenharmony_ci	int			tmp;
151362306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	trace_xfs_da_node_unbalance(state->args);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	drop_node = drop_blk->bp->b_addr;
151862306a36Sopenharmony_ci	save_node = save_blk->bp->b_addr;
151962306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &drop_hdr, drop_node);
152062306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &save_hdr, save_node);
152162306a36Sopenharmony_ci	drop_btree = drop_hdr.btree;
152262306a36Sopenharmony_ci	save_btree = save_hdr.btree;
152362306a36Sopenharmony_ci	tp = state->args->trans;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	/*
152662306a36Sopenharmony_ci	 * If the dying block has lower hashvals, then move all the
152762306a36Sopenharmony_ci	 * elements in the remaining block up to make a hole.
152862306a36Sopenharmony_ci	 */
152962306a36Sopenharmony_ci	if ((be32_to_cpu(drop_btree[0].hashval) <
153062306a36Sopenharmony_ci			be32_to_cpu(save_btree[0].hashval)) ||
153162306a36Sopenharmony_ci	    (be32_to_cpu(drop_btree[drop_hdr.count - 1].hashval) <
153262306a36Sopenharmony_ci			be32_to_cpu(save_btree[save_hdr.count - 1].hashval))) {
153362306a36Sopenharmony_ci		/* XXX: check this - is memmove dst correct? */
153462306a36Sopenharmony_ci		tmp = save_hdr.count * sizeof(xfs_da_node_entry_t);
153562306a36Sopenharmony_ci		memmove(&save_btree[drop_hdr.count], &save_btree[0], tmp);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci		sindex = 0;
153862306a36Sopenharmony_ci		xfs_trans_log_buf(tp, save_blk->bp,
153962306a36Sopenharmony_ci			XFS_DA_LOGRANGE(save_node, &save_btree[0],
154062306a36Sopenharmony_ci				(save_hdr.count + drop_hdr.count) *
154162306a36Sopenharmony_ci						sizeof(xfs_da_node_entry_t)));
154262306a36Sopenharmony_ci	} else {
154362306a36Sopenharmony_ci		sindex = save_hdr.count;
154462306a36Sopenharmony_ci		xfs_trans_log_buf(tp, save_blk->bp,
154562306a36Sopenharmony_ci			XFS_DA_LOGRANGE(save_node, &save_btree[sindex],
154662306a36Sopenharmony_ci				drop_hdr.count * sizeof(xfs_da_node_entry_t)));
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/*
155062306a36Sopenharmony_ci	 * Move all the B-tree elements from drop_blk to save_blk.
155162306a36Sopenharmony_ci	 */
155262306a36Sopenharmony_ci	tmp = drop_hdr.count * (uint)sizeof(xfs_da_node_entry_t);
155362306a36Sopenharmony_ci	memcpy(&save_btree[sindex], &drop_btree[0], tmp);
155462306a36Sopenharmony_ci	save_hdr.count += drop_hdr.count;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	xfs_da3_node_hdr_to_disk(dp->i_mount, save_node, &save_hdr);
155762306a36Sopenharmony_ci	xfs_trans_log_buf(tp, save_blk->bp,
155862306a36Sopenharmony_ci		XFS_DA_LOGRANGE(save_node, &save_node->hdr,
155962306a36Sopenharmony_ci				state->args->geo->node_hdr_size));
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/*
156262306a36Sopenharmony_ci	 * Save the last hashval in the remaining block for upward propagation.
156362306a36Sopenharmony_ci	 */
156462306a36Sopenharmony_ci	save_blk->hashval = be32_to_cpu(save_btree[save_hdr.count - 1].hashval);
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci/*========================================================================
156862306a36Sopenharmony_ci * Routines used for finding things in the Btree.
156962306a36Sopenharmony_ci *========================================================================*/
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci/*
157262306a36Sopenharmony_ci * Walk down the Btree looking for a particular filename, filling
157362306a36Sopenharmony_ci * in the state structure as we go.
157462306a36Sopenharmony_ci *
157562306a36Sopenharmony_ci * We will set the state structure to point to each of the elements
157662306a36Sopenharmony_ci * in each of the nodes where either the hashval is or should be.
157762306a36Sopenharmony_ci *
157862306a36Sopenharmony_ci * We support duplicate hashval's so for each entry in the current
157962306a36Sopenharmony_ci * node that could contain the desired hashval, descend.  This is a
158062306a36Sopenharmony_ci * pruned depth-first tree search.
158162306a36Sopenharmony_ci */
158262306a36Sopenharmony_ciint							/* error */
158362306a36Sopenharmony_cixfs_da3_node_lookup_int(
158462306a36Sopenharmony_ci	struct xfs_da_state	*state,
158562306a36Sopenharmony_ci	int			*result)
158662306a36Sopenharmony_ci{
158762306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk;
158862306a36Sopenharmony_ci	struct xfs_da_blkinfo	*curr;
158962306a36Sopenharmony_ci	struct xfs_da_intnode	*node;
159062306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
159162306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
159262306a36Sopenharmony_ci	struct xfs_da_args	*args;
159362306a36Sopenharmony_ci	xfs_dablk_t		blkno;
159462306a36Sopenharmony_ci	xfs_dahash_t		hashval;
159562306a36Sopenharmony_ci	xfs_dahash_t		btreehashval;
159662306a36Sopenharmony_ci	int			probe;
159762306a36Sopenharmony_ci	int			span;
159862306a36Sopenharmony_ci	int			max;
159962306a36Sopenharmony_ci	int			error;
160062306a36Sopenharmony_ci	int			retval;
160162306a36Sopenharmony_ci	unsigned int		expected_level = 0;
160262306a36Sopenharmony_ci	uint16_t		magic;
160362306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	args = state->args;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	/*
160862306a36Sopenharmony_ci	 * Descend thru the B-tree searching each level for the right
160962306a36Sopenharmony_ci	 * node to use, until the right hashval is found.
161062306a36Sopenharmony_ci	 */
161162306a36Sopenharmony_ci	blkno = args->geo->leafblk;
161262306a36Sopenharmony_ci	for (blk = &state->path.blk[0], state->path.active = 1;
161362306a36Sopenharmony_ci			 state->path.active <= XFS_DA_NODE_MAXDEPTH;
161462306a36Sopenharmony_ci			 blk++, state->path.active++) {
161562306a36Sopenharmony_ci		/*
161662306a36Sopenharmony_ci		 * Read the next node down in the tree.
161762306a36Sopenharmony_ci		 */
161862306a36Sopenharmony_ci		blk->blkno = blkno;
161962306a36Sopenharmony_ci		error = xfs_da3_node_read(args->trans, args->dp, blkno,
162062306a36Sopenharmony_ci					&blk->bp, args->whichfork);
162162306a36Sopenharmony_ci		if (error) {
162262306a36Sopenharmony_ci			blk->blkno = 0;
162362306a36Sopenharmony_ci			state->path.active--;
162462306a36Sopenharmony_ci			return error;
162562306a36Sopenharmony_ci		}
162662306a36Sopenharmony_ci		curr = blk->bp->b_addr;
162762306a36Sopenharmony_ci		magic = be16_to_cpu(curr->magic);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		if (magic == XFS_ATTR_LEAF_MAGIC ||
163062306a36Sopenharmony_ci		    magic == XFS_ATTR3_LEAF_MAGIC) {
163162306a36Sopenharmony_ci			blk->magic = XFS_ATTR_LEAF_MAGIC;
163262306a36Sopenharmony_ci			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
163362306a36Sopenharmony_ci			break;
163462306a36Sopenharmony_ci		}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		if (magic == XFS_DIR2_LEAFN_MAGIC ||
163762306a36Sopenharmony_ci		    magic == XFS_DIR3_LEAFN_MAGIC) {
163862306a36Sopenharmony_ci			blk->magic = XFS_DIR2_LEAFN_MAGIC;
163962306a36Sopenharmony_ci			blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
164062306a36Sopenharmony_ci							      blk->bp, NULL);
164162306a36Sopenharmony_ci			break;
164262306a36Sopenharmony_ci		}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci		if (magic != XFS_DA_NODE_MAGIC && magic != XFS_DA3_NODE_MAGIC) {
164562306a36Sopenharmony_ci			xfs_buf_mark_corrupt(blk->bp);
164662306a36Sopenharmony_ci			return -EFSCORRUPTED;
164762306a36Sopenharmony_ci		}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		blk->magic = XFS_DA_NODE_MAGIC;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		/*
165262306a36Sopenharmony_ci		 * Search an intermediate node for a match.
165362306a36Sopenharmony_ci		 */
165462306a36Sopenharmony_ci		node = blk->bp->b_addr;
165562306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
165662306a36Sopenharmony_ci		btree = nodehdr.btree;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci		/* Tree taller than we can handle; bail out! */
165962306a36Sopenharmony_ci		if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
166062306a36Sopenharmony_ci			xfs_buf_mark_corrupt(blk->bp);
166162306a36Sopenharmony_ci			return -EFSCORRUPTED;
166262306a36Sopenharmony_ci		}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci		/* Check the level from the root. */
166562306a36Sopenharmony_ci		if (blkno == args->geo->leafblk)
166662306a36Sopenharmony_ci			expected_level = nodehdr.level - 1;
166762306a36Sopenharmony_ci		else if (expected_level != nodehdr.level) {
166862306a36Sopenharmony_ci			xfs_buf_mark_corrupt(blk->bp);
166962306a36Sopenharmony_ci			return -EFSCORRUPTED;
167062306a36Sopenharmony_ci		} else
167162306a36Sopenharmony_ci			expected_level--;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci		max = nodehdr.count;
167462306a36Sopenharmony_ci		blk->hashval = be32_to_cpu(btree[max - 1].hashval);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci		/*
167762306a36Sopenharmony_ci		 * Binary search.  (note: small blocks will skip loop)
167862306a36Sopenharmony_ci		 */
167962306a36Sopenharmony_ci		probe = span = max / 2;
168062306a36Sopenharmony_ci		hashval = args->hashval;
168162306a36Sopenharmony_ci		while (span > 4) {
168262306a36Sopenharmony_ci			span /= 2;
168362306a36Sopenharmony_ci			btreehashval = be32_to_cpu(btree[probe].hashval);
168462306a36Sopenharmony_ci			if (btreehashval < hashval)
168562306a36Sopenharmony_ci				probe += span;
168662306a36Sopenharmony_ci			else if (btreehashval > hashval)
168762306a36Sopenharmony_ci				probe -= span;
168862306a36Sopenharmony_ci			else
168962306a36Sopenharmony_ci				break;
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci		ASSERT((probe >= 0) && (probe < max));
169262306a36Sopenharmony_ci		ASSERT((span <= 4) ||
169362306a36Sopenharmony_ci			(be32_to_cpu(btree[probe].hashval) == hashval));
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci		/*
169662306a36Sopenharmony_ci		 * Since we may have duplicate hashval's, find the first
169762306a36Sopenharmony_ci		 * matching hashval in the node.
169862306a36Sopenharmony_ci		 */
169962306a36Sopenharmony_ci		while (probe > 0 &&
170062306a36Sopenharmony_ci		       be32_to_cpu(btree[probe].hashval) >= hashval) {
170162306a36Sopenharmony_ci			probe--;
170262306a36Sopenharmony_ci		}
170362306a36Sopenharmony_ci		while (probe < max &&
170462306a36Sopenharmony_ci		       be32_to_cpu(btree[probe].hashval) < hashval) {
170562306a36Sopenharmony_ci			probe++;
170662306a36Sopenharmony_ci		}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		/*
170962306a36Sopenharmony_ci		 * Pick the right block to descend on.
171062306a36Sopenharmony_ci		 */
171162306a36Sopenharmony_ci		if (probe == max) {
171262306a36Sopenharmony_ci			blk->index = max - 1;
171362306a36Sopenharmony_ci			blkno = be32_to_cpu(btree[max - 1].before);
171462306a36Sopenharmony_ci		} else {
171562306a36Sopenharmony_ci			blk->index = probe;
171662306a36Sopenharmony_ci			blkno = be32_to_cpu(btree[probe].before);
171762306a36Sopenharmony_ci		}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		/* We can't point back to the root. */
172062306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(dp->i_mount, blkno == args->geo->leafblk))
172162306a36Sopenharmony_ci			return -EFSCORRUPTED;
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(dp->i_mount, expected_level != 0))
172562306a36Sopenharmony_ci		return -EFSCORRUPTED;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/*
172862306a36Sopenharmony_ci	 * A leaf block that ends in the hashval that we are interested in
172962306a36Sopenharmony_ci	 * (final hashval == search hashval) means that the next block may
173062306a36Sopenharmony_ci	 * contain more entries with the same hashval, shift upward to the
173162306a36Sopenharmony_ci	 * next leaf and keep searching.
173262306a36Sopenharmony_ci	 */
173362306a36Sopenharmony_ci	for (;;) {
173462306a36Sopenharmony_ci		if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
173562306a36Sopenharmony_ci			retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
173662306a36Sopenharmony_ci							&blk->index, state);
173762306a36Sopenharmony_ci		} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
173862306a36Sopenharmony_ci			retval = xfs_attr3_leaf_lookup_int(blk->bp, args);
173962306a36Sopenharmony_ci			blk->index = args->index;
174062306a36Sopenharmony_ci			args->blkno = blk->blkno;
174162306a36Sopenharmony_ci		} else {
174262306a36Sopenharmony_ci			ASSERT(0);
174362306a36Sopenharmony_ci			return -EFSCORRUPTED;
174462306a36Sopenharmony_ci		}
174562306a36Sopenharmony_ci		if (((retval == -ENOENT) || (retval == -ENOATTR)) &&
174662306a36Sopenharmony_ci		    (blk->hashval == args->hashval)) {
174762306a36Sopenharmony_ci			error = xfs_da3_path_shift(state, &state->path, 1, 1,
174862306a36Sopenharmony_ci							 &retval);
174962306a36Sopenharmony_ci			if (error)
175062306a36Sopenharmony_ci				return error;
175162306a36Sopenharmony_ci			if (retval == 0) {
175262306a36Sopenharmony_ci				continue;
175362306a36Sopenharmony_ci			} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
175462306a36Sopenharmony_ci				/* path_shift() gives ENOENT */
175562306a36Sopenharmony_ci				retval = -ENOATTR;
175662306a36Sopenharmony_ci			}
175762306a36Sopenharmony_ci		}
175862306a36Sopenharmony_ci		break;
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci	*result = retval;
176162306a36Sopenharmony_ci	return 0;
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci/*========================================================================
176562306a36Sopenharmony_ci * Utility routines.
176662306a36Sopenharmony_ci *========================================================================*/
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci/*
176962306a36Sopenharmony_ci * Compare two intermediate nodes for "order".
177062306a36Sopenharmony_ci */
177162306a36Sopenharmony_ciSTATIC int
177262306a36Sopenharmony_cixfs_da3_node_order(
177362306a36Sopenharmony_ci	struct xfs_inode *dp,
177462306a36Sopenharmony_ci	struct xfs_buf	*node1_bp,
177562306a36Sopenharmony_ci	struct xfs_buf	*node2_bp)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	struct xfs_da_intnode	*node1;
177862306a36Sopenharmony_ci	struct xfs_da_intnode	*node2;
177962306a36Sopenharmony_ci	struct xfs_da_node_entry *btree1;
178062306a36Sopenharmony_ci	struct xfs_da_node_entry *btree2;
178162306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr node1hdr;
178262306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr node2hdr;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	node1 = node1_bp->b_addr;
178562306a36Sopenharmony_ci	node2 = node2_bp->b_addr;
178662306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &node1hdr, node1);
178762306a36Sopenharmony_ci	xfs_da3_node_hdr_from_disk(dp->i_mount, &node2hdr, node2);
178862306a36Sopenharmony_ci	btree1 = node1hdr.btree;
178962306a36Sopenharmony_ci	btree2 = node2hdr.btree;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (node1hdr.count > 0 && node2hdr.count > 0 &&
179262306a36Sopenharmony_ci	    ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) ||
179362306a36Sopenharmony_ci	     (be32_to_cpu(btree2[node2hdr.count - 1].hashval) <
179462306a36Sopenharmony_ci	      be32_to_cpu(btree1[node1hdr.count - 1].hashval)))) {
179562306a36Sopenharmony_ci		return 1;
179662306a36Sopenharmony_ci	}
179762306a36Sopenharmony_ci	return 0;
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci/*
180162306a36Sopenharmony_ci * Link a new block into a doubly linked list of blocks (of whatever type).
180262306a36Sopenharmony_ci */
180362306a36Sopenharmony_ciint							/* error */
180462306a36Sopenharmony_cixfs_da3_blk_link(
180562306a36Sopenharmony_ci	struct xfs_da_state	*state,
180662306a36Sopenharmony_ci	struct xfs_da_state_blk	*old_blk,
180762306a36Sopenharmony_ci	struct xfs_da_state_blk	*new_blk)
180862306a36Sopenharmony_ci{
180962306a36Sopenharmony_ci	struct xfs_da_blkinfo	*old_info;
181062306a36Sopenharmony_ci	struct xfs_da_blkinfo	*new_info;
181162306a36Sopenharmony_ci	struct xfs_da_blkinfo	*tmp_info;
181262306a36Sopenharmony_ci	struct xfs_da_args	*args;
181362306a36Sopenharmony_ci	struct xfs_buf		*bp;
181462306a36Sopenharmony_ci	int			before = 0;
181562306a36Sopenharmony_ci	int			error;
181662306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	/*
181962306a36Sopenharmony_ci	 * Set up environment.
182062306a36Sopenharmony_ci	 */
182162306a36Sopenharmony_ci	args = state->args;
182262306a36Sopenharmony_ci	ASSERT(args != NULL);
182362306a36Sopenharmony_ci	old_info = old_blk->bp->b_addr;
182462306a36Sopenharmony_ci	new_info = new_blk->bp->b_addr;
182562306a36Sopenharmony_ci	ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
182662306a36Sopenharmony_ci	       old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
182762306a36Sopenharmony_ci	       old_blk->magic == XFS_ATTR_LEAF_MAGIC);
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	switch (old_blk->magic) {
183062306a36Sopenharmony_ci	case XFS_ATTR_LEAF_MAGIC:
183162306a36Sopenharmony_ci		before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp);
183262306a36Sopenharmony_ci		break;
183362306a36Sopenharmony_ci	case XFS_DIR2_LEAFN_MAGIC:
183462306a36Sopenharmony_ci		before = xfs_dir2_leafn_order(dp, old_blk->bp, new_blk->bp);
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci	case XFS_DA_NODE_MAGIC:
183762306a36Sopenharmony_ci		before = xfs_da3_node_order(dp, old_blk->bp, new_blk->bp);
183862306a36Sopenharmony_ci		break;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/*
184262306a36Sopenharmony_ci	 * Link blocks in appropriate order.
184362306a36Sopenharmony_ci	 */
184462306a36Sopenharmony_ci	if (before) {
184562306a36Sopenharmony_ci		/*
184662306a36Sopenharmony_ci		 * Link new block in before existing block.
184762306a36Sopenharmony_ci		 */
184862306a36Sopenharmony_ci		trace_xfs_da_link_before(args);
184962306a36Sopenharmony_ci		new_info->forw = cpu_to_be32(old_blk->blkno);
185062306a36Sopenharmony_ci		new_info->back = old_info->back;
185162306a36Sopenharmony_ci		if (old_info->back) {
185262306a36Sopenharmony_ci			error = xfs_da3_node_read(args->trans, dp,
185362306a36Sopenharmony_ci						be32_to_cpu(old_info->back),
185462306a36Sopenharmony_ci						&bp, args->whichfork);
185562306a36Sopenharmony_ci			if (error)
185662306a36Sopenharmony_ci				return error;
185762306a36Sopenharmony_ci			ASSERT(bp != NULL);
185862306a36Sopenharmony_ci			tmp_info = bp->b_addr;
185962306a36Sopenharmony_ci			ASSERT(tmp_info->magic == old_info->magic);
186062306a36Sopenharmony_ci			ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno);
186162306a36Sopenharmony_ci			tmp_info->forw = cpu_to_be32(new_blk->blkno);
186262306a36Sopenharmony_ci			xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
186362306a36Sopenharmony_ci		}
186462306a36Sopenharmony_ci		old_info->back = cpu_to_be32(new_blk->blkno);
186562306a36Sopenharmony_ci	} else {
186662306a36Sopenharmony_ci		/*
186762306a36Sopenharmony_ci		 * Link new block in after existing block.
186862306a36Sopenharmony_ci		 */
186962306a36Sopenharmony_ci		trace_xfs_da_link_after(args);
187062306a36Sopenharmony_ci		new_info->forw = old_info->forw;
187162306a36Sopenharmony_ci		new_info->back = cpu_to_be32(old_blk->blkno);
187262306a36Sopenharmony_ci		if (old_info->forw) {
187362306a36Sopenharmony_ci			error = xfs_da3_node_read(args->trans, dp,
187462306a36Sopenharmony_ci						be32_to_cpu(old_info->forw),
187562306a36Sopenharmony_ci						&bp, args->whichfork);
187662306a36Sopenharmony_ci			if (error)
187762306a36Sopenharmony_ci				return error;
187862306a36Sopenharmony_ci			ASSERT(bp != NULL);
187962306a36Sopenharmony_ci			tmp_info = bp->b_addr;
188062306a36Sopenharmony_ci			ASSERT(tmp_info->magic == old_info->magic);
188162306a36Sopenharmony_ci			ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno);
188262306a36Sopenharmony_ci			tmp_info->back = cpu_to_be32(new_blk->blkno);
188362306a36Sopenharmony_ci			xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
188462306a36Sopenharmony_ci		}
188562306a36Sopenharmony_ci		old_info->forw = cpu_to_be32(new_blk->blkno);
188662306a36Sopenharmony_ci	}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);
188962306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1);
189062306a36Sopenharmony_ci	return 0;
189162306a36Sopenharmony_ci}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci/*
189462306a36Sopenharmony_ci * Unlink a block from a doubly linked list of blocks.
189562306a36Sopenharmony_ci */
189662306a36Sopenharmony_ciSTATIC int						/* error */
189762306a36Sopenharmony_cixfs_da3_blk_unlink(
189862306a36Sopenharmony_ci	struct xfs_da_state	*state,
189962306a36Sopenharmony_ci	struct xfs_da_state_blk	*drop_blk,
190062306a36Sopenharmony_ci	struct xfs_da_state_blk	*save_blk)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	struct xfs_da_blkinfo	*drop_info;
190362306a36Sopenharmony_ci	struct xfs_da_blkinfo	*save_info;
190462306a36Sopenharmony_ci	struct xfs_da_blkinfo	*tmp_info;
190562306a36Sopenharmony_ci	struct xfs_da_args	*args;
190662306a36Sopenharmony_ci	struct xfs_buf		*bp;
190762306a36Sopenharmony_ci	int			error;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/*
191062306a36Sopenharmony_ci	 * Set up environment.
191162306a36Sopenharmony_ci	 */
191262306a36Sopenharmony_ci	args = state->args;
191362306a36Sopenharmony_ci	ASSERT(args != NULL);
191462306a36Sopenharmony_ci	save_info = save_blk->bp->b_addr;
191562306a36Sopenharmony_ci	drop_info = drop_blk->bp->b_addr;
191662306a36Sopenharmony_ci	ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
191762306a36Sopenharmony_ci	       save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
191862306a36Sopenharmony_ci	       save_blk->magic == XFS_ATTR_LEAF_MAGIC);
191962306a36Sopenharmony_ci	ASSERT(save_blk->magic == drop_blk->magic);
192062306a36Sopenharmony_ci	ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) ||
192162306a36Sopenharmony_ci	       (be32_to_cpu(save_info->back) == drop_blk->blkno));
192262306a36Sopenharmony_ci	ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) ||
192362306a36Sopenharmony_ci	       (be32_to_cpu(drop_info->back) == save_blk->blkno));
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	/*
192662306a36Sopenharmony_ci	 * Unlink the leaf block from the doubly linked chain of leaves.
192762306a36Sopenharmony_ci	 */
192862306a36Sopenharmony_ci	if (be32_to_cpu(save_info->back) == drop_blk->blkno) {
192962306a36Sopenharmony_ci		trace_xfs_da_unlink_back(args);
193062306a36Sopenharmony_ci		save_info->back = drop_info->back;
193162306a36Sopenharmony_ci		if (drop_info->back) {
193262306a36Sopenharmony_ci			error = xfs_da3_node_read(args->trans, args->dp,
193362306a36Sopenharmony_ci						be32_to_cpu(drop_info->back),
193462306a36Sopenharmony_ci						&bp, args->whichfork);
193562306a36Sopenharmony_ci			if (error)
193662306a36Sopenharmony_ci				return error;
193762306a36Sopenharmony_ci			ASSERT(bp != NULL);
193862306a36Sopenharmony_ci			tmp_info = bp->b_addr;
193962306a36Sopenharmony_ci			ASSERT(tmp_info->magic == save_info->magic);
194062306a36Sopenharmony_ci			ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno);
194162306a36Sopenharmony_ci			tmp_info->forw = cpu_to_be32(save_blk->blkno);
194262306a36Sopenharmony_ci			xfs_trans_log_buf(args->trans, bp, 0,
194362306a36Sopenharmony_ci						    sizeof(*tmp_info) - 1);
194462306a36Sopenharmony_ci		}
194562306a36Sopenharmony_ci	} else {
194662306a36Sopenharmony_ci		trace_xfs_da_unlink_forward(args);
194762306a36Sopenharmony_ci		save_info->forw = drop_info->forw;
194862306a36Sopenharmony_ci		if (drop_info->forw) {
194962306a36Sopenharmony_ci			error = xfs_da3_node_read(args->trans, args->dp,
195062306a36Sopenharmony_ci						be32_to_cpu(drop_info->forw),
195162306a36Sopenharmony_ci						&bp, args->whichfork);
195262306a36Sopenharmony_ci			if (error)
195362306a36Sopenharmony_ci				return error;
195462306a36Sopenharmony_ci			ASSERT(bp != NULL);
195562306a36Sopenharmony_ci			tmp_info = bp->b_addr;
195662306a36Sopenharmony_ci			ASSERT(tmp_info->magic == save_info->magic);
195762306a36Sopenharmony_ci			ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno);
195862306a36Sopenharmony_ci			tmp_info->back = cpu_to_be32(save_blk->blkno);
195962306a36Sopenharmony_ci			xfs_trans_log_buf(args->trans, bp, 0,
196062306a36Sopenharmony_ci						    sizeof(*tmp_info) - 1);
196162306a36Sopenharmony_ci		}
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1);
196562306a36Sopenharmony_ci	return 0;
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci/*
196962306a36Sopenharmony_ci * Move a path "forward" or "!forward" one block at the current level.
197062306a36Sopenharmony_ci *
197162306a36Sopenharmony_ci * This routine will adjust a "path" to point to the next block
197262306a36Sopenharmony_ci * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the
197362306a36Sopenharmony_ci * Btree, including updating pointers to the intermediate nodes between
197462306a36Sopenharmony_ci * the new bottom and the root.
197562306a36Sopenharmony_ci */
197662306a36Sopenharmony_ciint							/* error */
197762306a36Sopenharmony_cixfs_da3_path_shift(
197862306a36Sopenharmony_ci	struct xfs_da_state	*state,
197962306a36Sopenharmony_ci	struct xfs_da_state_path *path,
198062306a36Sopenharmony_ci	int			forward,
198162306a36Sopenharmony_ci	int			release,
198262306a36Sopenharmony_ci	int			*result)
198362306a36Sopenharmony_ci{
198462306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk;
198562306a36Sopenharmony_ci	struct xfs_da_blkinfo	*info;
198662306a36Sopenharmony_ci	struct xfs_da_args	*args;
198762306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
198862306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr nodehdr;
198962306a36Sopenharmony_ci	struct xfs_buf		*bp;
199062306a36Sopenharmony_ci	xfs_dablk_t		blkno = 0;
199162306a36Sopenharmony_ci	int			level;
199262306a36Sopenharmony_ci	int			error;
199362306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	trace_xfs_da_path_shift(state->args);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	/*
199862306a36Sopenharmony_ci	 * Roll up the Btree looking for the first block where our
199962306a36Sopenharmony_ci	 * current index is not at the edge of the block.  Note that
200062306a36Sopenharmony_ci	 * we skip the bottom layer because we want the sibling block.
200162306a36Sopenharmony_ci	 */
200262306a36Sopenharmony_ci	args = state->args;
200362306a36Sopenharmony_ci	ASSERT(args != NULL);
200462306a36Sopenharmony_ci	ASSERT(path != NULL);
200562306a36Sopenharmony_ci	ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
200662306a36Sopenharmony_ci	level = (path->active-1) - 1;	/* skip bottom layer in path */
200762306a36Sopenharmony_ci	for (; level >= 0; level--) {
200862306a36Sopenharmony_ci		blk = &path->blk[level];
200962306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
201062306a36Sopenharmony_ci					   blk->bp->b_addr);
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci		if (forward && (blk->index < nodehdr.count - 1)) {
201362306a36Sopenharmony_ci			blk->index++;
201462306a36Sopenharmony_ci			blkno = be32_to_cpu(nodehdr.btree[blk->index].before);
201562306a36Sopenharmony_ci			break;
201662306a36Sopenharmony_ci		} else if (!forward && (blk->index > 0)) {
201762306a36Sopenharmony_ci			blk->index--;
201862306a36Sopenharmony_ci			blkno = be32_to_cpu(nodehdr.btree[blk->index].before);
201962306a36Sopenharmony_ci			break;
202062306a36Sopenharmony_ci		}
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci	if (level < 0) {
202362306a36Sopenharmony_ci		*result = -ENOENT;	/* we're out of our tree */
202462306a36Sopenharmony_ci		ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
202562306a36Sopenharmony_ci		return 0;
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	/*
202962306a36Sopenharmony_ci	 * Roll down the edge of the subtree until we reach the
203062306a36Sopenharmony_ci	 * same depth we were at originally.
203162306a36Sopenharmony_ci	 */
203262306a36Sopenharmony_ci	for (blk++, level++; level < path->active; blk++, level++) {
203362306a36Sopenharmony_ci		/*
203462306a36Sopenharmony_ci		 * Read the next child block into a local buffer.
203562306a36Sopenharmony_ci		 */
203662306a36Sopenharmony_ci		error = xfs_da3_node_read(args->trans, dp, blkno, &bp,
203762306a36Sopenharmony_ci					  args->whichfork);
203862306a36Sopenharmony_ci		if (error)
203962306a36Sopenharmony_ci			return error;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci		/*
204262306a36Sopenharmony_ci		 * Release the old block (if it's dirty, the trans doesn't
204362306a36Sopenharmony_ci		 * actually let go) and swap the local buffer into the path
204462306a36Sopenharmony_ci		 * structure. This ensures failure of the above read doesn't set
204562306a36Sopenharmony_ci		 * a NULL buffer in an active slot in the path.
204662306a36Sopenharmony_ci		 */
204762306a36Sopenharmony_ci		if (release)
204862306a36Sopenharmony_ci			xfs_trans_brelse(args->trans, blk->bp);
204962306a36Sopenharmony_ci		blk->blkno = blkno;
205062306a36Sopenharmony_ci		blk->bp = bp;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci		info = blk->bp->b_addr;
205362306a36Sopenharmony_ci		ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
205462306a36Sopenharmony_ci		       info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) ||
205562306a36Sopenharmony_ci		       info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
205662306a36Sopenharmony_ci		       info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
205762306a36Sopenharmony_ci		       info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
205862306a36Sopenharmony_ci		       info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci		/*
206262306a36Sopenharmony_ci		 * Note: we flatten the magic number to a single type so we
206362306a36Sopenharmony_ci		 * don't have to compare against crc/non-crc types elsewhere.
206462306a36Sopenharmony_ci		 */
206562306a36Sopenharmony_ci		switch (be16_to_cpu(info->magic)) {
206662306a36Sopenharmony_ci		case XFS_DA_NODE_MAGIC:
206762306a36Sopenharmony_ci		case XFS_DA3_NODE_MAGIC:
206862306a36Sopenharmony_ci			blk->magic = XFS_DA_NODE_MAGIC;
206962306a36Sopenharmony_ci			xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
207062306a36Sopenharmony_ci						   bp->b_addr);
207162306a36Sopenharmony_ci			btree = nodehdr.btree;
207262306a36Sopenharmony_ci			blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval);
207362306a36Sopenharmony_ci			if (forward)
207462306a36Sopenharmony_ci				blk->index = 0;
207562306a36Sopenharmony_ci			else
207662306a36Sopenharmony_ci				blk->index = nodehdr.count - 1;
207762306a36Sopenharmony_ci			blkno = be32_to_cpu(btree[blk->index].before);
207862306a36Sopenharmony_ci			break;
207962306a36Sopenharmony_ci		case XFS_ATTR_LEAF_MAGIC:
208062306a36Sopenharmony_ci		case XFS_ATTR3_LEAF_MAGIC:
208162306a36Sopenharmony_ci			blk->magic = XFS_ATTR_LEAF_MAGIC;
208262306a36Sopenharmony_ci			ASSERT(level == path->active-1);
208362306a36Sopenharmony_ci			blk->index = 0;
208462306a36Sopenharmony_ci			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
208562306a36Sopenharmony_ci			break;
208662306a36Sopenharmony_ci		case XFS_DIR2_LEAFN_MAGIC:
208762306a36Sopenharmony_ci		case XFS_DIR3_LEAFN_MAGIC:
208862306a36Sopenharmony_ci			blk->magic = XFS_DIR2_LEAFN_MAGIC;
208962306a36Sopenharmony_ci			ASSERT(level == path->active-1);
209062306a36Sopenharmony_ci			blk->index = 0;
209162306a36Sopenharmony_ci			blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
209262306a36Sopenharmony_ci							      blk->bp, NULL);
209362306a36Sopenharmony_ci			break;
209462306a36Sopenharmony_ci		default:
209562306a36Sopenharmony_ci			ASSERT(0);
209662306a36Sopenharmony_ci			break;
209762306a36Sopenharmony_ci		}
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci	*result = 0;
210062306a36Sopenharmony_ci	return 0;
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci/*========================================================================
210562306a36Sopenharmony_ci * Utility routines.
210662306a36Sopenharmony_ci *========================================================================*/
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci/*
210962306a36Sopenharmony_ci * Implement a simple hash on a character string.
211062306a36Sopenharmony_ci * Rotate the hash value by 7 bits, then XOR each character in.
211162306a36Sopenharmony_ci * This is implemented with some source-level loop unrolling.
211262306a36Sopenharmony_ci */
211362306a36Sopenharmony_cixfs_dahash_t
211462306a36Sopenharmony_cixfs_da_hashname(const uint8_t *name, int namelen)
211562306a36Sopenharmony_ci{
211662306a36Sopenharmony_ci	xfs_dahash_t hash;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	/*
211962306a36Sopenharmony_ci	 * Do four characters at a time as long as we can.
212062306a36Sopenharmony_ci	 */
212162306a36Sopenharmony_ci	for (hash = 0; namelen >= 4; namelen -= 4, name += 4)
212262306a36Sopenharmony_ci		hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
212362306a36Sopenharmony_ci		       (name[3] << 0) ^ rol32(hash, 7 * 4);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	/*
212662306a36Sopenharmony_ci	 * Now do the rest of the characters.
212762306a36Sopenharmony_ci	 */
212862306a36Sopenharmony_ci	switch (namelen) {
212962306a36Sopenharmony_ci	case 3:
213062306a36Sopenharmony_ci		return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
213162306a36Sopenharmony_ci		       rol32(hash, 7 * 3);
213262306a36Sopenharmony_ci	case 2:
213362306a36Sopenharmony_ci		return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
213462306a36Sopenharmony_ci	case 1:
213562306a36Sopenharmony_ci		return (name[0] << 0) ^ rol32(hash, 7 * 1);
213662306a36Sopenharmony_ci	default: /* case 0: */
213762306a36Sopenharmony_ci		return hash;
213862306a36Sopenharmony_ci	}
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cienum xfs_dacmp
214262306a36Sopenharmony_cixfs_da_compname(
214362306a36Sopenharmony_ci	struct xfs_da_args *args,
214462306a36Sopenharmony_ci	const unsigned char *name,
214562306a36Sopenharmony_ci	int		len)
214662306a36Sopenharmony_ci{
214762306a36Sopenharmony_ci	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
214862306a36Sopenharmony_ci					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
214962306a36Sopenharmony_ci}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ciint
215262306a36Sopenharmony_cixfs_da_grow_inode_int(
215362306a36Sopenharmony_ci	struct xfs_da_args	*args,
215462306a36Sopenharmony_ci	xfs_fileoff_t		*bno,
215562306a36Sopenharmony_ci	int			count)
215662306a36Sopenharmony_ci{
215762306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
215862306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
215962306a36Sopenharmony_ci	int			w = args->whichfork;
216062306a36Sopenharmony_ci	xfs_rfsblock_t		nblks = dp->i_nblocks;
216162306a36Sopenharmony_ci	struct xfs_bmbt_irec	map, *mapp;
216262306a36Sopenharmony_ci	int			nmap, error, got, i, mapi;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/*
216562306a36Sopenharmony_ci	 * Find a spot in the file space to put the new block.
216662306a36Sopenharmony_ci	 */
216762306a36Sopenharmony_ci	error = xfs_bmap_first_unused(tp, dp, count, bno, w);
216862306a36Sopenharmony_ci	if (error)
216962306a36Sopenharmony_ci		return error;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/*
217262306a36Sopenharmony_ci	 * Try mapping it in one filesystem block.
217362306a36Sopenharmony_ci	 */
217462306a36Sopenharmony_ci	nmap = 1;
217562306a36Sopenharmony_ci	error = xfs_bmapi_write(tp, dp, *bno, count,
217662306a36Sopenharmony_ci			xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
217762306a36Sopenharmony_ci			args->total, &map, &nmap);
217862306a36Sopenharmony_ci	if (error)
217962306a36Sopenharmony_ci		return error;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	ASSERT(nmap <= 1);
218262306a36Sopenharmony_ci	if (nmap == 1) {
218362306a36Sopenharmony_ci		mapp = &map;
218462306a36Sopenharmony_ci		mapi = 1;
218562306a36Sopenharmony_ci	} else if (nmap == 0 && count > 1) {
218662306a36Sopenharmony_ci		xfs_fileoff_t		b;
218762306a36Sopenharmony_ci		int			c;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci		/*
219062306a36Sopenharmony_ci		 * If we didn't get it and the block might work if fragmented,
219162306a36Sopenharmony_ci		 * try without the CONTIG flag.  Loop until we get it all.
219262306a36Sopenharmony_ci		 */
219362306a36Sopenharmony_ci		mapp = kmem_alloc(sizeof(*mapp) * count, 0);
219462306a36Sopenharmony_ci		for (b = *bno, mapi = 0; b < *bno + count; ) {
219562306a36Sopenharmony_ci			c = (int)(*bno + count - b);
219662306a36Sopenharmony_ci			nmap = min(XFS_BMAP_MAX_NMAP, c);
219762306a36Sopenharmony_ci			error = xfs_bmapi_write(tp, dp, b, c,
219862306a36Sopenharmony_ci					xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
219962306a36Sopenharmony_ci					args->total, &mapp[mapi], &nmap);
220062306a36Sopenharmony_ci			if (error)
220162306a36Sopenharmony_ci				goto out_free_map;
220262306a36Sopenharmony_ci			if (nmap < 1)
220362306a36Sopenharmony_ci				break;
220462306a36Sopenharmony_ci			mapi += nmap;
220562306a36Sopenharmony_ci			b = mapp[mapi - 1].br_startoff +
220662306a36Sopenharmony_ci			    mapp[mapi - 1].br_blockcount;
220762306a36Sopenharmony_ci		}
220862306a36Sopenharmony_ci	} else {
220962306a36Sopenharmony_ci		mapi = 0;
221062306a36Sopenharmony_ci		mapp = NULL;
221162306a36Sopenharmony_ci	}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	/*
221462306a36Sopenharmony_ci	 * Count the blocks we got, make sure it matches the total.
221562306a36Sopenharmony_ci	 */
221662306a36Sopenharmony_ci	for (i = 0, got = 0; i < mapi; i++)
221762306a36Sopenharmony_ci		got += mapp[i].br_blockcount;
221862306a36Sopenharmony_ci	if (got != count || mapp[0].br_startoff != *bno ||
221962306a36Sopenharmony_ci	    mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
222062306a36Sopenharmony_ci	    *bno + count) {
222162306a36Sopenharmony_ci		error = -ENOSPC;
222262306a36Sopenharmony_ci		goto out_free_map;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	/* account for newly allocated blocks in reserved blocks total */
222662306a36Sopenharmony_ci	args->total -= dp->i_nblocks - nblks;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ciout_free_map:
222962306a36Sopenharmony_ci	if (mapp != &map)
223062306a36Sopenharmony_ci		kmem_free(mapp);
223162306a36Sopenharmony_ci	return error;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci/*
223562306a36Sopenharmony_ci * Add a block to the btree ahead of the file.
223662306a36Sopenharmony_ci * Return the new block number to the caller.
223762306a36Sopenharmony_ci */
223862306a36Sopenharmony_ciint
223962306a36Sopenharmony_cixfs_da_grow_inode(
224062306a36Sopenharmony_ci	struct xfs_da_args	*args,
224162306a36Sopenharmony_ci	xfs_dablk_t		*new_blkno)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	xfs_fileoff_t		bno;
224462306a36Sopenharmony_ci	int			error;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	trace_xfs_da_grow_inode(args);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	bno = args->geo->leafblk;
224962306a36Sopenharmony_ci	error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount);
225062306a36Sopenharmony_ci	if (!error)
225162306a36Sopenharmony_ci		*new_blkno = (xfs_dablk_t)bno;
225262306a36Sopenharmony_ci	return error;
225362306a36Sopenharmony_ci}
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci/*
225662306a36Sopenharmony_ci * Ick.  We need to always be able to remove a btree block, even
225762306a36Sopenharmony_ci * if there's no space reservation because the filesystem is full.
225862306a36Sopenharmony_ci * This is called if xfs_bunmapi on a btree block fails due to ENOSPC.
225962306a36Sopenharmony_ci * It swaps the target block with the last block in the file.  The
226062306a36Sopenharmony_ci * last block in the file can always be removed since it can't cause
226162306a36Sopenharmony_ci * a bmap btree split to do that.
226262306a36Sopenharmony_ci */
226362306a36Sopenharmony_ciSTATIC int
226462306a36Sopenharmony_cixfs_da3_swap_lastblock(
226562306a36Sopenharmony_ci	struct xfs_da_args	*args,
226662306a36Sopenharmony_ci	xfs_dablk_t		*dead_blknop,
226762306a36Sopenharmony_ci	struct xfs_buf		**dead_bufp)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	struct xfs_da_blkinfo	*dead_info;
227062306a36Sopenharmony_ci	struct xfs_da_blkinfo	*sib_info;
227162306a36Sopenharmony_ci	struct xfs_da_intnode	*par_node;
227262306a36Sopenharmony_ci	struct xfs_da_intnode	*dead_node;
227362306a36Sopenharmony_ci	struct xfs_dir2_leaf	*dead_leaf2;
227462306a36Sopenharmony_ci	struct xfs_da_node_entry *btree;
227562306a36Sopenharmony_ci	struct xfs_da3_icnode_hdr par_hdr;
227662306a36Sopenharmony_ci	struct xfs_inode	*dp;
227762306a36Sopenharmony_ci	struct xfs_trans	*tp;
227862306a36Sopenharmony_ci	struct xfs_mount	*mp;
227962306a36Sopenharmony_ci	struct xfs_buf		*dead_buf;
228062306a36Sopenharmony_ci	struct xfs_buf		*last_buf;
228162306a36Sopenharmony_ci	struct xfs_buf		*sib_buf;
228262306a36Sopenharmony_ci	struct xfs_buf		*par_buf;
228362306a36Sopenharmony_ci	xfs_dahash_t		dead_hash;
228462306a36Sopenharmony_ci	xfs_fileoff_t		lastoff;
228562306a36Sopenharmony_ci	xfs_dablk_t		dead_blkno;
228662306a36Sopenharmony_ci	xfs_dablk_t		last_blkno;
228762306a36Sopenharmony_ci	xfs_dablk_t		sib_blkno;
228862306a36Sopenharmony_ci	xfs_dablk_t		par_blkno;
228962306a36Sopenharmony_ci	int			error;
229062306a36Sopenharmony_ci	int			w;
229162306a36Sopenharmony_ci	int			entno;
229262306a36Sopenharmony_ci	int			level;
229362306a36Sopenharmony_ci	int			dead_level;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	trace_xfs_da_swap_lastblock(args);
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	dead_buf = *dead_bufp;
229862306a36Sopenharmony_ci	dead_blkno = *dead_blknop;
229962306a36Sopenharmony_ci	tp = args->trans;
230062306a36Sopenharmony_ci	dp = args->dp;
230162306a36Sopenharmony_ci	w = args->whichfork;
230262306a36Sopenharmony_ci	ASSERT(w == XFS_DATA_FORK);
230362306a36Sopenharmony_ci	mp = dp->i_mount;
230462306a36Sopenharmony_ci	lastoff = args->geo->freeblk;
230562306a36Sopenharmony_ci	error = xfs_bmap_last_before(tp, dp, &lastoff, w);
230662306a36Sopenharmony_ci	if (error)
230762306a36Sopenharmony_ci		return error;
230862306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, lastoff == 0))
230962306a36Sopenharmony_ci		return -EFSCORRUPTED;
231062306a36Sopenharmony_ci	/*
231162306a36Sopenharmony_ci	 * Read the last block in the btree space.
231262306a36Sopenharmony_ci	 */
231362306a36Sopenharmony_ci	last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount;
231462306a36Sopenharmony_ci	error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
231562306a36Sopenharmony_ci	if (error)
231662306a36Sopenharmony_ci		return error;
231762306a36Sopenharmony_ci	/*
231862306a36Sopenharmony_ci	 * Copy the last block into the dead buffer and log it.
231962306a36Sopenharmony_ci	 */
232062306a36Sopenharmony_ci	memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize);
232162306a36Sopenharmony_ci	xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1);
232262306a36Sopenharmony_ci	dead_info = dead_buf->b_addr;
232362306a36Sopenharmony_ci	/*
232462306a36Sopenharmony_ci	 * Get values from the moved block.
232562306a36Sopenharmony_ci	 */
232662306a36Sopenharmony_ci	if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
232762306a36Sopenharmony_ci	    dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
232862306a36Sopenharmony_ci		struct xfs_dir3_icleaf_hdr leafhdr;
232962306a36Sopenharmony_ci		struct xfs_dir2_leaf_entry *ents;
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci		dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
233262306a36Sopenharmony_ci		xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr,
233362306a36Sopenharmony_ci					    dead_leaf2);
233462306a36Sopenharmony_ci		ents = leafhdr.ents;
233562306a36Sopenharmony_ci		dead_level = 0;
233662306a36Sopenharmony_ci		dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval);
233762306a36Sopenharmony_ci	} else {
233862306a36Sopenharmony_ci		struct xfs_da3_icnode_hdr deadhdr;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci		dead_node = (xfs_da_intnode_t *)dead_info;
234162306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &deadhdr, dead_node);
234262306a36Sopenharmony_ci		btree = deadhdr.btree;
234362306a36Sopenharmony_ci		dead_level = deadhdr.level;
234462306a36Sopenharmony_ci		dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval);
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci	sib_buf = par_buf = NULL;
234762306a36Sopenharmony_ci	/*
234862306a36Sopenharmony_ci	 * If the moved block has a left sibling, fix up the pointers.
234962306a36Sopenharmony_ci	 */
235062306a36Sopenharmony_ci	if ((sib_blkno = be32_to_cpu(dead_info->back))) {
235162306a36Sopenharmony_ci		error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
235262306a36Sopenharmony_ci		if (error)
235362306a36Sopenharmony_ci			goto done;
235462306a36Sopenharmony_ci		sib_info = sib_buf->b_addr;
235562306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp,
235662306a36Sopenharmony_ci				   be32_to_cpu(sib_info->forw) != last_blkno ||
235762306a36Sopenharmony_ci				   sib_info->magic != dead_info->magic)) {
235862306a36Sopenharmony_ci			error = -EFSCORRUPTED;
235962306a36Sopenharmony_ci			goto done;
236062306a36Sopenharmony_ci		}
236162306a36Sopenharmony_ci		sib_info->forw = cpu_to_be32(dead_blkno);
236262306a36Sopenharmony_ci		xfs_trans_log_buf(tp, sib_buf,
236362306a36Sopenharmony_ci			XFS_DA_LOGRANGE(sib_info, &sib_info->forw,
236462306a36Sopenharmony_ci					sizeof(sib_info->forw)));
236562306a36Sopenharmony_ci		sib_buf = NULL;
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci	/*
236862306a36Sopenharmony_ci	 * If the moved block has a right sibling, fix up the pointers.
236962306a36Sopenharmony_ci	 */
237062306a36Sopenharmony_ci	if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
237162306a36Sopenharmony_ci		error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
237262306a36Sopenharmony_ci		if (error)
237362306a36Sopenharmony_ci			goto done;
237462306a36Sopenharmony_ci		sib_info = sib_buf->b_addr;
237562306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp,
237662306a36Sopenharmony_ci				   be32_to_cpu(sib_info->back) != last_blkno ||
237762306a36Sopenharmony_ci				   sib_info->magic != dead_info->magic)) {
237862306a36Sopenharmony_ci			error = -EFSCORRUPTED;
237962306a36Sopenharmony_ci			goto done;
238062306a36Sopenharmony_ci		}
238162306a36Sopenharmony_ci		sib_info->back = cpu_to_be32(dead_blkno);
238262306a36Sopenharmony_ci		xfs_trans_log_buf(tp, sib_buf,
238362306a36Sopenharmony_ci			XFS_DA_LOGRANGE(sib_info, &sib_info->back,
238462306a36Sopenharmony_ci					sizeof(sib_info->back)));
238562306a36Sopenharmony_ci		sib_buf = NULL;
238662306a36Sopenharmony_ci	}
238762306a36Sopenharmony_ci	par_blkno = args->geo->leafblk;
238862306a36Sopenharmony_ci	level = -1;
238962306a36Sopenharmony_ci	/*
239062306a36Sopenharmony_ci	 * Walk down the tree looking for the parent of the moved block.
239162306a36Sopenharmony_ci	 */
239262306a36Sopenharmony_ci	for (;;) {
239362306a36Sopenharmony_ci		error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
239462306a36Sopenharmony_ci		if (error)
239562306a36Sopenharmony_ci			goto done;
239662306a36Sopenharmony_ci		par_node = par_buf->b_addr;
239762306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
239862306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp,
239962306a36Sopenharmony_ci				   level >= 0 && level != par_hdr.level + 1)) {
240062306a36Sopenharmony_ci			error = -EFSCORRUPTED;
240162306a36Sopenharmony_ci			goto done;
240262306a36Sopenharmony_ci		}
240362306a36Sopenharmony_ci		level = par_hdr.level;
240462306a36Sopenharmony_ci		btree = par_hdr.btree;
240562306a36Sopenharmony_ci		for (entno = 0;
240662306a36Sopenharmony_ci		     entno < par_hdr.count &&
240762306a36Sopenharmony_ci		     be32_to_cpu(btree[entno].hashval) < dead_hash;
240862306a36Sopenharmony_ci		     entno++)
240962306a36Sopenharmony_ci			continue;
241062306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp, entno == par_hdr.count)) {
241162306a36Sopenharmony_ci			error = -EFSCORRUPTED;
241262306a36Sopenharmony_ci			goto done;
241362306a36Sopenharmony_ci		}
241462306a36Sopenharmony_ci		par_blkno = be32_to_cpu(btree[entno].before);
241562306a36Sopenharmony_ci		if (level == dead_level + 1)
241662306a36Sopenharmony_ci			break;
241762306a36Sopenharmony_ci		xfs_trans_brelse(tp, par_buf);
241862306a36Sopenharmony_ci		par_buf = NULL;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci	/*
242162306a36Sopenharmony_ci	 * We're in the right parent block.
242262306a36Sopenharmony_ci	 * Look for the right entry.
242362306a36Sopenharmony_ci	 */
242462306a36Sopenharmony_ci	for (;;) {
242562306a36Sopenharmony_ci		for (;
242662306a36Sopenharmony_ci		     entno < par_hdr.count &&
242762306a36Sopenharmony_ci		     be32_to_cpu(btree[entno].before) != last_blkno;
242862306a36Sopenharmony_ci		     entno++)
242962306a36Sopenharmony_ci			continue;
243062306a36Sopenharmony_ci		if (entno < par_hdr.count)
243162306a36Sopenharmony_ci			break;
243262306a36Sopenharmony_ci		par_blkno = par_hdr.forw;
243362306a36Sopenharmony_ci		xfs_trans_brelse(tp, par_buf);
243462306a36Sopenharmony_ci		par_buf = NULL;
243562306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp, par_blkno == 0)) {
243662306a36Sopenharmony_ci			error = -EFSCORRUPTED;
243762306a36Sopenharmony_ci			goto done;
243862306a36Sopenharmony_ci		}
243962306a36Sopenharmony_ci		error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
244062306a36Sopenharmony_ci		if (error)
244162306a36Sopenharmony_ci			goto done;
244262306a36Sopenharmony_ci		par_node = par_buf->b_addr;
244362306a36Sopenharmony_ci		xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
244462306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) {
244562306a36Sopenharmony_ci			error = -EFSCORRUPTED;
244662306a36Sopenharmony_ci			goto done;
244762306a36Sopenharmony_ci		}
244862306a36Sopenharmony_ci		btree = par_hdr.btree;
244962306a36Sopenharmony_ci		entno = 0;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci	/*
245262306a36Sopenharmony_ci	 * Update the parent entry pointing to the moved block.
245362306a36Sopenharmony_ci	 */
245462306a36Sopenharmony_ci	btree[entno].before = cpu_to_be32(dead_blkno);
245562306a36Sopenharmony_ci	xfs_trans_log_buf(tp, par_buf,
245662306a36Sopenharmony_ci		XFS_DA_LOGRANGE(par_node, &btree[entno].before,
245762306a36Sopenharmony_ci				sizeof(btree[entno].before)));
245862306a36Sopenharmony_ci	*dead_blknop = last_blkno;
245962306a36Sopenharmony_ci	*dead_bufp = last_buf;
246062306a36Sopenharmony_ci	return 0;
246162306a36Sopenharmony_cidone:
246262306a36Sopenharmony_ci	if (par_buf)
246362306a36Sopenharmony_ci		xfs_trans_brelse(tp, par_buf);
246462306a36Sopenharmony_ci	if (sib_buf)
246562306a36Sopenharmony_ci		xfs_trans_brelse(tp, sib_buf);
246662306a36Sopenharmony_ci	xfs_trans_brelse(tp, last_buf);
246762306a36Sopenharmony_ci	return error;
246862306a36Sopenharmony_ci}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci/*
247162306a36Sopenharmony_ci * Remove a btree block from a directory or attribute.
247262306a36Sopenharmony_ci */
247362306a36Sopenharmony_ciint
247462306a36Sopenharmony_cixfs_da_shrink_inode(
247562306a36Sopenharmony_ci	struct xfs_da_args	*args,
247662306a36Sopenharmony_ci	xfs_dablk_t		dead_blkno,
247762306a36Sopenharmony_ci	struct xfs_buf		*dead_buf)
247862306a36Sopenharmony_ci{
247962306a36Sopenharmony_ci	struct xfs_inode	*dp;
248062306a36Sopenharmony_ci	int			done, error, w, count;
248162306a36Sopenharmony_ci	struct xfs_trans	*tp;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	trace_xfs_da_shrink_inode(args);
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	dp = args->dp;
248662306a36Sopenharmony_ci	w = args->whichfork;
248762306a36Sopenharmony_ci	tp = args->trans;
248862306a36Sopenharmony_ci	count = args->geo->fsbcount;
248962306a36Sopenharmony_ci	for (;;) {
249062306a36Sopenharmony_ci		/*
249162306a36Sopenharmony_ci		 * Remove extents.  If we get ENOSPC for a dir we have to move
249262306a36Sopenharmony_ci		 * the last block to the place we want to kill.
249362306a36Sopenharmony_ci		 */
249462306a36Sopenharmony_ci		error = xfs_bunmapi(tp, dp, dead_blkno, count,
249562306a36Sopenharmony_ci				    xfs_bmapi_aflag(w), 0, &done);
249662306a36Sopenharmony_ci		if (error == -ENOSPC) {
249762306a36Sopenharmony_ci			if (w != XFS_DATA_FORK)
249862306a36Sopenharmony_ci				break;
249962306a36Sopenharmony_ci			error = xfs_da3_swap_lastblock(args, &dead_blkno,
250062306a36Sopenharmony_ci						      &dead_buf);
250162306a36Sopenharmony_ci			if (error)
250262306a36Sopenharmony_ci				break;
250362306a36Sopenharmony_ci		} else {
250462306a36Sopenharmony_ci			break;
250562306a36Sopenharmony_ci		}
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci	xfs_trans_binval(tp, dead_buf);
250862306a36Sopenharmony_ci	return error;
250962306a36Sopenharmony_ci}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_cistatic int
251262306a36Sopenharmony_cixfs_dabuf_map(
251362306a36Sopenharmony_ci	struct xfs_inode	*dp,
251462306a36Sopenharmony_ci	xfs_dablk_t		bno,
251562306a36Sopenharmony_ci	unsigned int		flags,
251662306a36Sopenharmony_ci	int			whichfork,
251762306a36Sopenharmony_ci	struct xfs_buf_map	**mapp,
251862306a36Sopenharmony_ci	int			*nmaps)
251962306a36Sopenharmony_ci{
252062306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
252162306a36Sopenharmony_ci	int			nfsb = xfs_dabuf_nfsb(mp, whichfork);
252262306a36Sopenharmony_ci	struct xfs_bmbt_irec	irec, *irecs = &irec;
252362306a36Sopenharmony_ci	struct xfs_buf_map	*map = *mapp;
252462306a36Sopenharmony_ci	xfs_fileoff_t		off = bno;
252562306a36Sopenharmony_ci	int			error = 0, nirecs, i;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (nfsb > 1)
252862306a36Sopenharmony_ci		irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_NOFS);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	nirecs = nfsb;
253162306a36Sopenharmony_ci	error = xfs_bmapi_read(dp, bno, nfsb, irecs, &nirecs,
253262306a36Sopenharmony_ci			xfs_bmapi_aflag(whichfork));
253362306a36Sopenharmony_ci	if (error)
253462306a36Sopenharmony_ci		goto out_free_irecs;
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	/*
253762306a36Sopenharmony_ci	 * Use the caller provided map for the single map case, else allocate a
253862306a36Sopenharmony_ci	 * larger one that needs to be free by the caller.
253962306a36Sopenharmony_ci	 */
254062306a36Sopenharmony_ci	if (nirecs > 1) {
254162306a36Sopenharmony_ci		map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_NOFS);
254262306a36Sopenharmony_ci		if (!map) {
254362306a36Sopenharmony_ci			error = -ENOMEM;
254462306a36Sopenharmony_ci			goto out_free_irecs;
254562306a36Sopenharmony_ci		}
254662306a36Sopenharmony_ci		*mapp = map;
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	for (i = 0; i < nirecs; i++) {
255062306a36Sopenharmony_ci		if (irecs[i].br_startblock == HOLESTARTBLOCK ||
255162306a36Sopenharmony_ci		    irecs[i].br_startblock == DELAYSTARTBLOCK)
255262306a36Sopenharmony_ci			goto invalid_mapping;
255362306a36Sopenharmony_ci		if (off != irecs[i].br_startoff)
255462306a36Sopenharmony_ci			goto invalid_mapping;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci		map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock);
255762306a36Sopenharmony_ci		map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount);
255862306a36Sopenharmony_ci		off += irecs[i].br_blockcount;
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	if (off != bno + nfsb)
256262306a36Sopenharmony_ci		goto invalid_mapping;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	*nmaps = nirecs;
256562306a36Sopenharmony_ciout_free_irecs:
256662306a36Sopenharmony_ci	if (irecs != &irec)
256762306a36Sopenharmony_ci		kmem_free(irecs);
256862306a36Sopenharmony_ci	return error;
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ciinvalid_mapping:
257162306a36Sopenharmony_ci	/* Caller ok with no mapping. */
257262306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, !(flags & XFS_DABUF_MAP_HOLE_OK))) {
257362306a36Sopenharmony_ci		error = -EFSCORRUPTED;
257462306a36Sopenharmony_ci		if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
257562306a36Sopenharmony_ci			xfs_alert(mp, "%s: bno %u inode %llu",
257662306a36Sopenharmony_ci					__func__, bno, dp->i_ino);
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci			for (i = 0; i < nirecs; i++) {
257962306a36Sopenharmony_ci				xfs_alert(mp,
258062306a36Sopenharmony_ci"[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
258162306a36Sopenharmony_ci					i, irecs[i].br_startoff,
258262306a36Sopenharmony_ci					irecs[i].br_startblock,
258362306a36Sopenharmony_ci					irecs[i].br_blockcount,
258462306a36Sopenharmony_ci					irecs[i].br_state);
258562306a36Sopenharmony_ci			}
258662306a36Sopenharmony_ci		}
258762306a36Sopenharmony_ci	} else {
258862306a36Sopenharmony_ci		*nmaps = 0;
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci	goto out_free_irecs;
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci/*
259462306a36Sopenharmony_ci * Get a buffer for the dir/attr block.
259562306a36Sopenharmony_ci */
259662306a36Sopenharmony_ciint
259762306a36Sopenharmony_cixfs_da_get_buf(
259862306a36Sopenharmony_ci	struct xfs_trans	*tp,
259962306a36Sopenharmony_ci	struct xfs_inode	*dp,
260062306a36Sopenharmony_ci	xfs_dablk_t		bno,
260162306a36Sopenharmony_ci	struct xfs_buf		**bpp,
260262306a36Sopenharmony_ci	int			whichfork)
260362306a36Sopenharmony_ci{
260462306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
260562306a36Sopenharmony_ci	struct xfs_buf		*bp;
260662306a36Sopenharmony_ci	struct xfs_buf_map	map, *mapp = &map;
260762306a36Sopenharmony_ci	int			nmap = 1;
260862306a36Sopenharmony_ci	int			error;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	*bpp = NULL;
261162306a36Sopenharmony_ci	error = xfs_dabuf_map(dp, bno, 0, whichfork, &mapp, &nmap);
261262306a36Sopenharmony_ci	if (error || nmap == 0)
261362306a36Sopenharmony_ci		goto out_free;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	error = xfs_trans_get_buf_map(tp, mp->m_ddev_targp, mapp, nmap, 0, &bp);
261662306a36Sopenharmony_ci	if (error)
261762306a36Sopenharmony_ci		goto out_free;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	*bpp = bp;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ciout_free:
262262306a36Sopenharmony_ci	if (mapp != &map)
262362306a36Sopenharmony_ci		kmem_free(mapp);
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	return error;
262662306a36Sopenharmony_ci}
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci/*
262962306a36Sopenharmony_ci * Get a buffer for the dir/attr block, fill in the contents.
263062306a36Sopenharmony_ci */
263162306a36Sopenharmony_ciint
263262306a36Sopenharmony_cixfs_da_read_buf(
263362306a36Sopenharmony_ci	struct xfs_trans	*tp,
263462306a36Sopenharmony_ci	struct xfs_inode	*dp,
263562306a36Sopenharmony_ci	xfs_dablk_t		bno,
263662306a36Sopenharmony_ci	unsigned int		flags,
263762306a36Sopenharmony_ci	struct xfs_buf		**bpp,
263862306a36Sopenharmony_ci	int			whichfork,
263962306a36Sopenharmony_ci	const struct xfs_buf_ops *ops)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
264262306a36Sopenharmony_ci	struct xfs_buf		*bp;
264362306a36Sopenharmony_ci	struct xfs_buf_map	map, *mapp = &map;
264462306a36Sopenharmony_ci	int			nmap = 1;
264562306a36Sopenharmony_ci	int			error;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	*bpp = NULL;
264862306a36Sopenharmony_ci	error = xfs_dabuf_map(dp, bno, flags, whichfork, &mapp, &nmap);
264962306a36Sopenharmony_ci	if (error || !nmap)
265062306a36Sopenharmony_ci		goto out_free;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	error = xfs_trans_read_buf_map(mp, tp, mp->m_ddev_targp, mapp, nmap, 0,
265362306a36Sopenharmony_ci			&bp, ops);
265462306a36Sopenharmony_ci	if (error)
265562306a36Sopenharmony_ci		goto out_free;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	if (whichfork == XFS_ATTR_FORK)
265862306a36Sopenharmony_ci		xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
265962306a36Sopenharmony_ci	else
266062306a36Sopenharmony_ci		xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
266162306a36Sopenharmony_ci	*bpp = bp;
266262306a36Sopenharmony_ciout_free:
266362306a36Sopenharmony_ci	if (mapp != &map)
266462306a36Sopenharmony_ci		kmem_free(mapp);
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	return error;
266762306a36Sopenharmony_ci}
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci/*
267062306a36Sopenharmony_ci * Readahead the dir/attr block.
267162306a36Sopenharmony_ci */
267262306a36Sopenharmony_ciint
267362306a36Sopenharmony_cixfs_da_reada_buf(
267462306a36Sopenharmony_ci	struct xfs_inode	*dp,
267562306a36Sopenharmony_ci	xfs_dablk_t		bno,
267662306a36Sopenharmony_ci	unsigned int		flags,
267762306a36Sopenharmony_ci	int			whichfork,
267862306a36Sopenharmony_ci	const struct xfs_buf_ops *ops)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	struct xfs_buf_map	map;
268162306a36Sopenharmony_ci	struct xfs_buf_map	*mapp;
268262306a36Sopenharmony_ci	int			nmap;
268362306a36Sopenharmony_ci	int			error;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	mapp = &map;
268662306a36Sopenharmony_ci	nmap = 1;
268762306a36Sopenharmony_ci	error = xfs_dabuf_map(dp, bno, flags, whichfork, &mapp, &nmap);
268862306a36Sopenharmony_ci	if (error || !nmap)
268962306a36Sopenharmony_ci		goto out_free;
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops);
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ciout_free:
269462306a36Sopenharmony_ci	if (mapp != &map)
269562306a36Sopenharmony_ci		kmem_free(mapp);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	return error;
269862306a36Sopenharmony_ci}
2699