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_mount.h"
1462306a36Sopenharmony_ci#include "xfs_inode.h"
1562306a36Sopenharmony_ci#include "xfs_bmap.h"
1662306a36Sopenharmony_ci#include "xfs_dir2.h"
1762306a36Sopenharmony_ci#include "xfs_dir2_priv.h"
1862306a36Sopenharmony_ci#include "xfs_error.h"
1962306a36Sopenharmony_ci#include "xfs_trace.h"
2062306a36Sopenharmony_ci#include "xfs_trans.h"
2162306a36Sopenharmony_ci#include "xfs_buf_item.h"
2262306a36Sopenharmony_ci#include "xfs_log.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * Function declarations.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistatic int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args,
2862306a36Sopenharmony_ci			      int index);
2962306a36Sopenharmony_cistatic void xfs_dir2_leafn_rebalance(xfs_da_state_t *state,
3062306a36Sopenharmony_ci				     xfs_da_state_blk_t *blk1,
3162306a36Sopenharmony_ci				     xfs_da_state_blk_t *blk2);
3262306a36Sopenharmony_cistatic int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,
3362306a36Sopenharmony_ci				 int index, xfs_da_state_blk_t *dblk,
3462306a36Sopenharmony_ci				 int *rval);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * Convert data space db to the corresponding free db.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic xfs_dir2_db_t
4062306a36Sopenharmony_cixfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
4362306a36Sopenharmony_ci			(db / geo->free_max_bests);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/*
4762306a36Sopenharmony_ci * Convert data space db to the corresponding index in a free db.
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_cistatic int
5062306a36Sopenharmony_cixfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return db % geo->free_max_bests;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * Check internal consistency of a leafn block.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci#ifdef DEBUG
5962306a36Sopenharmony_cistatic xfs_failaddr_t
6062306a36Sopenharmony_cixfs_dir3_leafn_check(
6162306a36Sopenharmony_ci	struct xfs_inode	*dp,
6262306a36Sopenharmony_ci	struct xfs_buf		*bp)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct xfs_dir2_leaf	*leaf = bp->b_addr;
6562306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) {
7062306a36Sopenharmony_ci		struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
7162306a36Sopenharmony_ci		if (be64_to_cpu(leaf3->info.blkno) != xfs_buf_daddr(bp))
7262306a36Sopenharmony_ci			return __this_address;
7362306a36Sopenharmony_ci	} else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC)
7462306a36Sopenharmony_ci		return __this_address;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return xfs_dir3_leaf_check_int(dp->i_mount, &leafhdr, leaf, false);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic inline void
8062306a36Sopenharmony_cixfs_dir3_leaf_check(
8162306a36Sopenharmony_ci	struct xfs_inode	*dp,
8262306a36Sopenharmony_ci	struct xfs_buf		*bp)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	xfs_failaddr_t		fa;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	fa = xfs_dir3_leafn_check(dp, bp);
8762306a36Sopenharmony_ci	if (!fa)
8862306a36Sopenharmony_ci		return;
8962306a36Sopenharmony_ci	xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount,
9062306a36Sopenharmony_ci			bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__,
9162306a36Sopenharmony_ci			fa);
9262306a36Sopenharmony_ci	ASSERT(0);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci#else
9562306a36Sopenharmony_ci#define	xfs_dir3_leaf_check(dp, bp)
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic xfs_failaddr_t
9962306a36Sopenharmony_cixfs_dir3_free_verify(
10062306a36Sopenharmony_ci	struct xfs_buf		*bp)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
10362306a36Sopenharmony_ci	struct xfs_dir2_free_hdr *hdr = bp->b_addr;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (!xfs_verify_magic(bp, hdr->magic))
10662306a36Sopenharmony_ci		return __this_address;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
10962306a36Sopenharmony_ci		struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid))
11262306a36Sopenharmony_ci			return __this_address;
11362306a36Sopenharmony_ci		if (be64_to_cpu(hdr3->blkno) != xfs_buf_daddr(bp))
11462306a36Sopenharmony_ci			return __this_address;
11562306a36Sopenharmony_ci		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
11662306a36Sopenharmony_ci			return __this_address;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* XXX: should bounds check the xfs_dir3_icfree_hdr here */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return NULL;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void
12562306a36Sopenharmony_cixfs_dir3_free_read_verify(
12662306a36Sopenharmony_ci	struct xfs_buf	*bp)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
12962306a36Sopenharmony_ci	xfs_failaddr_t		fa;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (xfs_has_crc(mp) &&
13262306a36Sopenharmony_ci	    !xfs_buf_verify_cksum(bp, XFS_DIR3_FREE_CRC_OFF))
13362306a36Sopenharmony_ci		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
13462306a36Sopenharmony_ci	else {
13562306a36Sopenharmony_ci		fa = xfs_dir3_free_verify(bp);
13662306a36Sopenharmony_ci		if (fa)
13762306a36Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void
14262306a36Sopenharmony_cixfs_dir3_free_write_verify(
14362306a36Sopenharmony_ci	struct xfs_buf	*bp)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
14662306a36Sopenharmony_ci	struct xfs_buf_log_item	*bip = bp->b_log_item;
14762306a36Sopenharmony_ci	struct xfs_dir3_blk_hdr	*hdr3 = bp->b_addr;
14862306a36Sopenharmony_ci	xfs_failaddr_t		fa;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	fa = xfs_dir3_free_verify(bp);
15162306a36Sopenharmony_ci	if (fa) {
15262306a36Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
15362306a36Sopenharmony_ci		return;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (!xfs_has_crc(mp))
15762306a36Sopenharmony_ci		return;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (bip)
16062306a36Sopenharmony_ci		hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_dir3_free_buf_ops = {
16662306a36Sopenharmony_ci	.name = "xfs_dir3_free",
16762306a36Sopenharmony_ci	.magic = { cpu_to_be32(XFS_DIR2_FREE_MAGIC),
16862306a36Sopenharmony_ci		   cpu_to_be32(XFS_DIR3_FREE_MAGIC) },
16962306a36Sopenharmony_ci	.verify_read = xfs_dir3_free_read_verify,
17062306a36Sopenharmony_ci	.verify_write = xfs_dir3_free_write_verify,
17162306a36Sopenharmony_ci	.verify_struct = xfs_dir3_free_verify,
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/* Everything ok in the free block header? */
17562306a36Sopenharmony_cistatic xfs_failaddr_t
17662306a36Sopenharmony_cixfs_dir3_free_header_check(
17762306a36Sopenharmony_ci	struct xfs_inode	*dp,
17862306a36Sopenharmony_ci	xfs_dablk_t		fbno,
17962306a36Sopenharmony_ci	struct xfs_buf		*bp)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
18262306a36Sopenharmony_ci	int			maxbests = mp->m_dir_geo->free_max_bests;
18362306a36Sopenharmony_ci	unsigned int		firstdb;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	firstdb = (xfs_dir2_da_to_db(mp->m_dir_geo, fbno) -
18662306a36Sopenharmony_ci		   xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) *
18762306a36Sopenharmony_ci			maxbests;
18862306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
18962306a36Sopenharmony_ci		struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		if (be32_to_cpu(hdr3->firstdb) != firstdb)
19262306a36Sopenharmony_ci			return __this_address;
19362306a36Sopenharmony_ci		if (be32_to_cpu(hdr3->nvalid) > maxbests)
19462306a36Sopenharmony_ci			return __this_address;
19562306a36Sopenharmony_ci		if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused))
19662306a36Sopenharmony_ci			return __this_address;
19762306a36Sopenharmony_ci		if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
19862306a36Sopenharmony_ci			return __this_address;
19962306a36Sopenharmony_ci	} else {
20062306a36Sopenharmony_ci		struct xfs_dir2_free_hdr *hdr = bp->b_addr;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		if (be32_to_cpu(hdr->firstdb) != firstdb)
20362306a36Sopenharmony_ci			return __this_address;
20462306a36Sopenharmony_ci		if (be32_to_cpu(hdr->nvalid) > maxbests)
20562306a36Sopenharmony_ci			return __this_address;
20662306a36Sopenharmony_ci		if (be32_to_cpu(hdr->nvalid) < be32_to_cpu(hdr->nused))
20762306a36Sopenharmony_ci			return __this_address;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	return NULL;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int
21362306a36Sopenharmony_ci__xfs_dir3_free_read(
21462306a36Sopenharmony_ci	struct xfs_trans	*tp,
21562306a36Sopenharmony_ci	struct xfs_inode	*dp,
21662306a36Sopenharmony_ci	xfs_dablk_t		fbno,
21762306a36Sopenharmony_ci	unsigned int		flags,
21862306a36Sopenharmony_ci	struct xfs_buf		**bpp)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	xfs_failaddr_t		fa;
22162306a36Sopenharmony_ci	int			err;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	err = xfs_da_read_buf(tp, dp, fbno, flags, bpp, XFS_DATA_FORK,
22462306a36Sopenharmony_ci			&xfs_dir3_free_buf_ops);
22562306a36Sopenharmony_ci	if (err || !*bpp)
22662306a36Sopenharmony_ci		return err;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* Check things that we can't do in the verifier. */
22962306a36Sopenharmony_ci	fa = xfs_dir3_free_header_check(dp, fbno, *bpp);
23062306a36Sopenharmony_ci	if (fa) {
23162306a36Sopenharmony_ci		__xfs_buf_mark_corrupt(*bpp, fa);
23262306a36Sopenharmony_ci		xfs_trans_brelse(tp, *bpp);
23362306a36Sopenharmony_ci		*bpp = NULL;
23462306a36Sopenharmony_ci		return -EFSCORRUPTED;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* try read returns without an error or *bpp if it lands in a hole */
23862306a36Sopenharmony_ci	if (tp)
23962306a36Sopenharmony_ci		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_civoid
24562306a36Sopenharmony_cixfs_dir2_free_hdr_from_disk(
24662306a36Sopenharmony_ci	struct xfs_mount		*mp,
24762306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr	*to,
24862306a36Sopenharmony_ci	struct xfs_dir2_free		*from)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
25162306a36Sopenharmony_ci		struct xfs_dir3_free	*from3 = (struct xfs_dir3_free *)from;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		to->magic = be32_to_cpu(from3->hdr.hdr.magic);
25462306a36Sopenharmony_ci		to->firstdb = be32_to_cpu(from3->hdr.firstdb);
25562306a36Sopenharmony_ci		to->nvalid = be32_to_cpu(from3->hdr.nvalid);
25662306a36Sopenharmony_ci		to->nused = be32_to_cpu(from3->hdr.nused);
25762306a36Sopenharmony_ci		to->bests = from3->bests;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		ASSERT(to->magic == XFS_DIR3_FREE_MAGIC);
26062306a36Sopenharmony_ci	} else {
26162306a36Sopenharmony_ci		to->magic = be32_to_cpu(from->hdr.magic);
26262306a36Sopenharmony_ci		to->firstdb = be32_to_cpu(from->hdr.firstdb);
26362306a36Sopenharmony_ci		to->nvalid = be32_to_cpu(from->hdr.nvalid);
26462306a36Sopenharmony_ci		to->nused = be32_to_cpu(from->hdr.nused);
26562306a36Sopenharmony_ci		to->bests = from->bests;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		ASSERT(to->magic == XFS_DIR2_FREE_MAGIC);
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void
27262306a36Sopenharmony_cixfs_dir2_free_hdr_to_disk(
27362306a36Sopenharmony_ci	struct xfs_mount		*mp,
27462306a36Sopenharmony_ci	struct xfs_dir2_free		*to,
27562306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr	*from)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
27862306a36Sopenharmony_ci		struct xfs_dir3_free	*to3 = (struct xfs_dir3_free *)to;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		ASSERT(from->magic == XFS_DIR3_FREE_MAGIC);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		to3->hdr.hdr.magic = cpu_to_be32(from->magic);
28362306a36Sopenharmony_ci		to3->hdr.firstdb = cpu_to_be32(from->firstdb);
28462306a36Sopenharmony_ci		to3->hdr.nvalid = cpu_to_be32(from->nvalid);
28562306a36Sopenharmony_ci		to3->hdr.nused = cpu_to_be32(from->nused);
28662306a36Sopenharmony_ci	} else {
28762306a36Sopenharmony_ci		ASSERT(from->magic == XFS_DIR2_FREE_MAGIC);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		to->hdr.magic = cpu_to_be32(from->magic);
29062306a36Sopenharmony_ci		to->hdr.firstdb = cpu_to_be32(from->firstdb);
29162306a36Sopenharmony_ci		to->hdr.nvalid = cpu_to_be32(from->nvalid);
29262306a36Sopenharmony_ci		to->hdr.nused = cpu_to_be32(from->nused);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciint
29762306a36Sopenharmony_cixfs_dir2_free_read(
29862306a36Sopenharmony_ci	struct xfs_trans	*tp,
29962306a36Sopenharmony_ci	struct xfs_inode	*dp,
30062306a36Sopenharmony_ci	xfs_dablk_t		fbno,
30162306a36Sopenharmony_ci	struct xfs_buf		**bpp)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	return __xfs_dir3_free_read(tp, dp, fbno, 0, bpp);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic int
30762306a36Sopenharmony_cixfs_dir2_free_try_read(
30862306a36Sopenharmony_ci	struct xfs_trans	*tp,
30962306a36Sopenharmony_ci	struct xfs_inode	*dp,
31062306a36Sopenharmony_ci	xfs_dablk_t		fbno,
31162306a36Sopenharmony_ci	struct xfs_buf		**bpp)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic int
31762306a36Sopenharmony_cixfs_dir3_free_get_buf(
31862306a36Sopenharmony_ci	xfs_da_args_t		*args,
31962306a36Sopenharmony_ci	xfs_dir2_db_t		fbno,
32062306a36Sopenharmony_ci	struct xfs_buf		**bpp)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
32362306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
32462306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
32562306a36Sopenharmony_ci	struct xfs_buf		*bp;
32662306a36Sopenharmony_ci	int			error;
32762306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr hdr;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
33062306a36Sopenharmony_ci			&bp, XFS_DATA_FORK);
33162306a36Sopenharmony_ci	if (error)
33262306a36Sopenharmony_ci		return error;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF);
33562306a36Sopenharmony_ci	bp->b_ops = &xfs_dir3_free_buf_ops;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * Initialize the new block to be empty, and remember
33962306a36Sopenharmony_ci	 * its first slot as our empty slot.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr));
34262306a36Sopenharmony_ci	memset(&hdr, 0, sizeof(hdr));
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
34562306a36Sopenharmony_ci		struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci		hdr.magic = XFS_DIR3_FREE_MAGIC;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		hdr3->hdr.blkno = cpu_to_be64(xfs_buf_daddr(bp));
35062306a36Sopenharmony_ci		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
35162306a36Sopenharmony_ci		uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid);
35262306a36Sopenharmony_ci	} else
35362306a36Sopenharmony_ci		hdr.magic = XFS_DIR2_FREE_MAGIC;
35462306a36Sopenharmony_ci	xfs_dir2_free_hdr_to_disk(mp, bp->b_addr, &hdr);
35562306a36Sopenharmony_ci	*bpp = bp;
35662306a36Sopenharmony_ci	return 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/*
36062306a36Sopenharmony_ci * Log entries from a freespace block.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_ciSTATIC void
36362306a36Sopenharmony_cixfs_dir2_free_log_bests(
36462306a36Sopenharmony_ci	struct xfs_da_args	*args,
36562306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr *hdr,
36662306a36Sopenharmony_ci	struct xfs_buf		*bp,
36762306a36Sopenharmony_ci	int			first,		/* first entry to log */
36862306a36Sopenharmony_ci	int			last)		/* last entry to log */
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct xfs_dir2_free	*free = bp->b_addr;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
37362306a36Sopenharmony_ci	       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
37462306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, bp,
37562306a36Sopenharmony_ci			  (char *)&hdr->bests[first] - (char *)free,
37662306a36Sopenharmony_ci			  (char *)&hdr->bests[last] - (char *)free +
37762306a36Sopenharmony_ci			   sizeof(hdr->bests[0]) - 1);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/*
38162306a36Sopenharmony_ci * Log header from a freespace block.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic void
38462306a36Sopenharmony_cixfs_dir2_free_log_header(
38562306a36Sopenharmony_ci	struct xfs_da_args	*args,
38662306a36Sopenharmony_ci	struct xfs_buf		*bp)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci#ifdef DEBUG
38962306a36Sopenharmony_ci	xfs_dir2_free_t		*free;		/* freespace structure */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	free = bp->b_addr;
39262306a36Sopenharmony_ci	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
39362306a36Sopenharmony_ci	       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
39462306a36Sopenharmony_ci#endif
39562306a36Sopenharmony_ci	xfs_trans_log_buf(args->trans, bp, 0,
39662306a36Sopenharmony_ci			  args->geo->free_hdr_size - 1);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * Convert a leaf-format directory to a node-format directory.
40162306a36Sopenharmony_ci * We need to change the magic number of the leaf block, and copy
40262306a36Sopenharmony_ci * the freespace table out of the leaf block into its own block.
40362306a36Sopenharmony_ci */
40462306a36Sopenharmony_ciint						/* error */
40562306a36Sopenharmony_cixfs_dir2_leaf_to_node(
40662306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
40762306a36Sopenharmony_ci	struct xfs_buf		*lbp)		/* leaf buffer */
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
41062306a36Sopenharmony_ci	int			error;		/* error return value */
41162306a36Sopenharmony_ci	struct xfs_buf		*fbp;		/* freespace buffer */
41262306a36Sopenharmony_ci	xfs_dir2_db_t		fdb;		/* freespace block number */
41362306a36Sopenharmony_ci	__be16			*from;		/* pointer to freespace entry */
41462306a36Sopenharmony_ci	int			i;		/* leaf freespace index */
41562306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
41662306a36Sopenharmony_ci	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */
41762306a36Sopenharmony_ci	int			n;		/* count of live freespc ents */
41862306a36Sopenharmony_ci	xfs_dir2_data_off_t	off;		/* freespace entry value */
41962306a36Sopenharmony_ci	xfs_trans_t		*tp;		/* transaction pointer */
42062306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr freehdr;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	trace_xfs_dir2_leaf_to_node(args);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	dp = args->dp;
42562306a36Sopenharmony_ci	tp = args->trans;
42662306a36Sopenharmony_ci	/*
42762306a36Sopenharmony_ci	 * Add a freespace block to the directory.
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci	if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) {
43062306a36Sopenharmony_ci		return error;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	ASSERT(fdb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
43362306a36Sopenharmony_ci	/*
43462306a36Sopenharmony_ci	 * Get the buffer for the new freespace block.
43562306a36Sopenharmony_ci	 */
43662306a36Sopenharmony_ci	error = xfs_dir3_free_get_buf(args, fdb, &fbp);
43762306a36Sopenharmony_ci	if (error)
43862306a36Sopenharmony_ci		return error;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, fbp->b_addr);
44162306a36Sopenharmony_ci	leaf = lbp->b_addr;
44262306a36Sopenharmony_ci	ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
44362306a36Sopenharmony_ci	if (be32_to_cpu(ltp->bestcount) >
44462306a36Sopenharmony_ci				(uint)dp->i_disk_size / args->geo->blksize) {
44562306a36Sopenharmony_ci		xfs_buf_mark_corrupt(lbp);
44662306a36Sopenharmony_ci		return -EFSCORRUPTED;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * Copy freespace entries from the leaf block to the new block.
45162306a36Sopenharmony_ci	 * Count active entries.
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	from = xfs_dir2_leaf_bests_p(ltp);
45462306a36Sopenharmony_ci	for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++) {
45562306a36Sopenharmony_ci		off = be16_to_cpu(*from);
45662306a36Sopenharmony_ci		if (off != NULLDATAOFF)
45762306a36Sopenharmony_ci			n++;
45862306a36Sopenharmony_ci		freehdr.bests[i] = cpu_to_be16(off);
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/*
46262306a36Sopenharmony_ci	 * Now initialize the freespace block header.
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	freehdr.nused = n;
46562306a36Sopenharmony_ci	freehdr.nvalid = be32_to_cpu(ltp->bestcount);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	xfs_dir2_free_hdr_to_disk(dp->i_mount, fbp->b_addr, &freehdr);
46862306a36Sopenharmony_ci	xfs_dir2_free_log_bests(args, &freehdr, fbp, 0, freehdr.nvalid - 1);
46962306a36Sopenharmony_ci	xfs_dir2_free_log_header(args, fbp);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/*
47262306a36Sopenharmony_ci	 * Converting the leaf to a leafnode is just a matter of changing the
47362306a36Sopenharmony_ci	 * magic number and the ops. Do the change directly to the buffer as
47462306a36Sopenharmony_ci	 * it's less work (and less code) than decoding the header to host
47562306a36Sopenharmony_ci	 * format and back again.
47662306a36Sopenharmony_ci	 */
47762306a36Sopenharmony_ci	if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC))
47862306a36Sopenharmony_ci		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);
47962306a36Sopenharmony_ci	else
48062306a36Sopenharmony_ci		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
48162306a36Sopenharmony_ci	lbp->b_ops = &xfs_dir3_leafn_buf_ops;
48262306a36Sopenharmony_ci	xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF);
48362306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, lbp);
48462306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, lbp);
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/*
48962306a36Sopenharmony_ci * Add a leaf entry to a leaf block in a node-form directory.
49062306a36Sopenharmony_ci * The other work necessary is done from the caller.
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_cistatic int					/* error */
49362306a36Sopenharmony_cixfs_dir2_leafn_add(
49462306a36Sopenharmony_ci	struct xfs_buf		*bp,		/* leaf buffer */
49562306a36Sopenharmony_ci	struct xfs_da_args	*args,		/* operation arguments */
49662306a36Sopenharmony_ci	int			index)		/* insertion pt for new entry */
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
49962306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
50062306a36Sopenharmony_ci	struct xfs_dir2_leaf	*leaf = bp->b_addr;
50162306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *lep;
50262306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents;
50362306a36Sopenharmony_ci	int			compact;	/* compacting stale leaves */
50462306a36Sopenharmony_ci	int			highstale = 0;	/* next stale entry */
50562306a36Sopenharmony_ci	int			lfloghigh;	/* high leaf entry logging */
50662306a36Sopenharmony_ci	int			lfloglow;	/* low leaf entry logging */
50762306a36Sopenharmony_ci	int			lowstale = 0;	/* previous stale entry */
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	trace_xfs_dir2_leafn_add(args, index);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
51262306a36Sopenharmony_ci	ents = leafhdr.ents;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/*
51562306a36Sopenharmony_ci	 * Quick check just to make sure we are not going to index
51662306a36Sopenharmony_ci	 * into other peoples memory
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	if (index < 0) {
51962306a36Sopenharmony_ci		xfs_buf_mark_corrupt(bp);
52062306a36Sopenharmony_ci		return -EFSCORRUPTED;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/*
52462306a36Sopenharmony_ci	 * If there are already the maximum number of leaf entries in
52562306a36Sopenharmony_ci	 * the block, if there are no stale entries it won't fit.
52662306a36Sopenharmony_ci	 * Caller will do a split.  If there are stale entries we'll do
52762306a36Sopenharmony_ci	 * a compact.
52862306a36Sopenharmony_ci	 */
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (leafhdr.count == args->geo->leaf_max_ents) {
53162306a36Sopenharmony_ci		if (!leafhdr.stale)
53262306a36Sopenharmony_ci			return -ENOSPC;
53362306a36Sopenharmony_ci		compact = leafhdr.stale > 1;
53462306a36Sopenharmony_ci	} else
53562306a36Sopenharmony_ci		compact = 0;
53662306a36Sopenharmony_ci	ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval);
53762306a36Sopenharmony_ci	ASSERT(index == leafhdr.count ||
53862306a36Sopenharmony_ci	       be32_to_cpu(ents[index].hashval) >= args->hashval);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (args->op_flags & XFS_DA_OP_JUSTCHECK)
54162306a36Sopenharmony_ci		return 0;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/*
54462306a36Sopenharmony_ci	 * Compact out all but one stale leaf entry.  Leaves behind
54562306a36Sopenharmony_ci	 * the entry closest to index.
54662306a36Sopenharmony_ci	 */
54762306a36Sopenharmony_ci	if (compact)
54862306a36Sopenharmony_ci		xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale,
54962306a36Sopenharmony_ci					 &highstale, &lfloglow, &lfloghigh);
55062306a36Sopenharmony_ci	else if (leafhdr.stale) {
55162306a36Sopenharmony_ci		/*
55262306a36Sopenharmony_ci		 * Set impossible logging indices for this case.
55362306a36Sopenharmony_ci		 */
55462306a36Sopenharmony_ci		lfloglow = leafhdr.count;
55562306a36Sopenharmony_ci		lfloghigh = -1;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/*
55962306a36Sopenharmony_ci	 * Insert the new entry, log everything.
56062306a36Sopenharmony_ci	 */
56162306a36Sopenharmony_ci	lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale,
56262306a36Sopenharmony_ci				       highstale, &lfloglow, &lfloghigh);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	lep->hashval = cpu_to_be32(args->hashval);
56562306a36Sopenharmony_ci	lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo,
56662306a36Sopenharmony_ci				args->blkno, args->index));
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
56962306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, bp);
57062306a36Sopenharmony_ci	xfs_dir3_leaf_log_ents(args, &leafhdr, bp, lfloglow, lfloghigh);
57162306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, bp);
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci#ifdef DEBUG
57662306a36Sopenharmony_cistatic void
57762306a36Sopenharmony_cixfs_dir2_free_hdr_check(
57862306a36Sopenharmony_ci	struct xfs_inode *dp,
57962306a36Sopenharmony_ci	struct xfs_buf	*bp,
58062306a36Sopenharmony_ci	xfs_dir2_db_t	db)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr hdr;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	xfs_dir2_free_hdr_from_disk(dp->i_mount, &hdr, bp->b_addr);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	ASSERT((hdr.firstdb % dp->i_mount->m_dir_geo->free_max_bests) == 0);
58762306a36Sopenharmony_ci	ASSERT(hdr.firstdb <= db);
58862306a36Sopenharmony_ci	ASSERT(db < hdr.firstdb + hdr.nvalid);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci#else
59162306a36Sopenharmony_ci#define xfs_dir2_free_hdr_check(dp, bp, db)
59262306a36Sopenharmony_ci#endif	/* DEBUG */
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/*
59562306a36Sopenharmony_ci * Return the last hash value in the leaf.
59662306a36Sopenharmony_ci * Stale entries are ok.
59762306a36Sopenharmony_ci */
59862306a36Sopenharmony_cixfs_dahash_t					/* hash value */
59962306a36Sopenharmony_cixfs_dir2_leaf_lasthash(
60062306a36Sopenharmony_ci	struct xfs_inode *dp,
60162306a36Sopenharmony_ci	struct xfs_buf	*bp,			/* leaf buffer */
60262306a36Sopenharmony_ci	int		*count)			/* count of entries in leaf */
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, bp->b_addr);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
60962306a36Sopenharmony_ci	       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
61062306a36Sopenharmony_ci	       leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
61162306a36Sopenharmony_ci	       leafhdr.magic == XFS_DIR3_LEAF1_MAGIC);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (count)
61462306a36Sopenharmony_ci		*count = leafhdr.count;
61562306a36Sopenharmony_ci	if (!leafhdr.count)
61662306a36Sopenharmony_ci		return 0;
61762306a36Sopenharmony_ci	return be32_to_cpu(leafhdr.ents[leafhdr.count - 1].hashval);
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/*
62162306a36Sopenharmony_ci * Look up a leaf entry for space to add a name in a node-format leaf block.
62262306a36Sopenharmony_ci * The extrablk in state is a freespace block.
62362306a36Sopenharmony_ci */
62462306a36Sopenharmony_ciSTATIC int
62562306a36Sopenharmony_cixfs_dir2_leafn_lookup_for_addname(
62662306a36Sopenharmony_ci	struct xfs_buf		*bp,		/* leaf buffer */
62762306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
62862306a36Sopenharmony_ci	int			*indexp,	/* out: leaf entry index */
62962306a36Sopenharmony_ci	xfs_da_state_t		*state)		/* state to fill in */
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct xfs_buf		*curbp = NULL;	/* current data/free buffer */
63262306a36Sopenharmony_ci	xfs_dir2_db_t		curdb = -1;	/* current data block number */
63362306a36Sopenharmony_ci	xfs_dir2_db_t		curfdb = -1;	/* current free block number */
63462306a36Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
63562306a36Sopenharmony_ci	int			error;		/* error return value */
63662306a36Sopenharmony_ci	int			fi;		/* free entry index */
63762306a36Sopenharmony_ci	xfs_dir2_free_t		*free = NULL;	/* free block structure */
63862306a36Sopenharmony_ci	int			index;		/* leaf entry index */
63962306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
64062306a36Sopenharmony_ci	int			length;		/* length of new data entry */
64162306a36Sopenharmony_ci	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */
64262306a36Sopenharmony_ci	xfs_mount_t		*mp;		/* filesystem mount point */
64362306a36Sopenharmony_ci	xfs_dir2_db_t		newdb;		/* new data block number */
64462306a36Sopenharmony_ci	xfs_dir2_db_t		newfdb;		/* new free block number */
64562306a36Sopenharmony_ci	xfs_trans_t		*tp;		/* transaction pointer */
64662306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	dp = args->dp;
64962306a36Sopenharmony_ci	tp = args->trans;
65062306a36Sopenharmony_ci	mp = dp->i_mount;
65162306a36Sopenharmony_ci	leaf = bp->b_addr;
65262306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, bp);
65562306a36Sopenharmony_ci	ASSERT(leafhdr.count > 0);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/*
65862306a36Sopenharmony_ci	 * Look up the hash value in the leaf entries.
65962306a36Sopenharmony_ci	 */
66062306a36Sopenharmony_ci	index = xfs_dir2_leaf_search_hash(args, bp);
66162306a36Sopenharmony_ci	/*
66262306a36Sopenharmony_ci	 * Do we have a buffer coming in?
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	if (state->extravalid) {
66562306a36Sopenharmony_ci		/* If so, it's a free block buffer, get the block number. */
66662306a36Sopenharmony_ci		curbp = state->extrablk.bp;
66762306a36Sopenharmony_ci		curfdb = state->extrablk.blkno;
66862306a36Sopenharmony_ci		free = curbp->b_addr;
66962306a36Sopenharmony_ci		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
67062306a36Sopenharmony_ci		       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	length = xfs_dir2_data_entsize(mp, args->namelen);
67362306a36Sopenharmony_ci	/*
67462306a36Sopenharmony_ci	 * Loop over leaf entries with the right hash value.
67562306a36Sopenharmony_ci	 */
67662306a36Sopenharmony_ci	for (lep = &leafhdr.ents[index];
67762306a36Sopenharmony_ci	     index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
67862306a36Sopenharmony_ci	     lep++, index++) {
67962306a36Sopenharmony_ci		/*
68062306a36Sopenharmony_ci		 * Skip stale leaf entries.
68162306a36Sopenharmony_ci		 */
68262306a36Sopenharmony_ci		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
68362306a36Sopenharmony_ci			continue;
68462306a36Sopenharmony_ci		/*
68562306a36Sopenharmony_ci		 * Pull the data block number from the entry.
68662306a36Sopenharmony_ci		 */
68762306a36Sopenharmony_ci		newdb = xfs_dir2_dataptr_to_db(args->geo,
68862306a36Sopenharmony_ci					       be32_to_cpu(lep->address));
68962306a36Sopenharmony_ci		/*
69062306a36Sopenharmony_ci		 * For addname, we're looking for a place to put the new entry.
69162306a36Sopenharmony_ci		 * We want to use a data block with an entry of equal
69262306a36Sopenharmony_ci		 * hash value to ours if there is one with room.
69362306a36Sopenharmony_ci		 *
69462306a36Sopenharmony_ci		 * If this block isn't the data block we already have
69562306a36Sopenharmony_ci		 * in hand, take a look at it.
69662306a36Sopenharmony_ci		 */
69762306a36Sopenharmony_ci		if (newdb != curdb) {
69862306a36Sopenharmony_ci			struct xfs_dir3_icfree_hdr freehdr;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci			curdb = newdb;
70162306a36Sopenharmony_ci			/*
70262306a36Sopenharmony_ci			 * Convert the data block to the free block
70362306a36Sopenharmony_ci			 * holding its freespace information.
70462306a36Sopenharmony_ci			 */
70562306a36Sopenharmony_ci			newfdb = xfs_dir2_db_to_fdb(args->geo, newdb);
70662306a36Sopenharmony_ci			/*
70762306a36Sopenharmony_ci			 * If it's not the one we have in hand, read it in.
70862306a36Sopenharmony_ci			 */
70962306a36Sopenharmony_ci			if (newfdb != curfdb) {
71062306a36Sopenharmony_ci				/*
71162306a36Sopenharmony_ci				 * If we had one before, drop it.
71262306a36Sopenharmony_ci				 */
71362306a36Sopenharmony_ci				if (curbp)
71462306a36Sopenharmony_ci					xfs_trans_brelse(tp, curbp);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci				error = xfs_dir2_free_read(tp, dp,
71762306a36Sopenharmony_ci						xfs_dir2_db_to_da(args->geo,
71862306a36Sopenharmony_ci								  newfdb),
71962306a36Sopenharmony_ci						&curbp);
72062306a36Sopenharmony_ci				if (error)
72162306a36Sopenharmony_ci					return error;
72262306a36Sopenharmony_ci				free = curbp->b_addr;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci				xfs_dir2_free_hdr_check(dp, curbp, curdb);
72562306a36Sopenharmony_ci			}
72662306a36Sopenharmony_ci			/*
72762306a36Sopenharmony_ci			 * Get the index for our entry.
72862306a36Sopenharmony_ci			 */
72962306a36Sopenharmony_ci			fi = xfs_dir2_db_to_fdindex(args->geo, curdb);
73062306a36Sopenharmony_ci			/*
73162306a36Sopenharmony_ci			 * If it has room, return it.
73262306a36Sopenharmony_ci			 */
73362306a36Sopenharmony_ci			xfs_dir2_free_hdr_from_disk(mp, &freehdr, free);
73462306a36Sopenharmony_ci			if (XFS_IS_CORRUPT(mp,
73562306a36Sopenharmony_ci					   freehdr.bests[fi] ==
73662306a36Sopenharmony_ci					   cpu_to_be16(NULLDATAOFF))) {
73762306a36Sopenharmony_ci				if (curfdb != newfdb)
73862306a36Sopenharmony_ci					xfs_trans_brelse(tp, curbp);
73962306a36Sopenharmony_ci				return -EFSCORRUPTED;
74062306a36Sopenharmony_ci			}
74162306a36Sopenharmony_ci			curfdb = newfdb;
74262306a36Sopenharmony_ci			if (be16_to_cpu(freehdr.bests[fi]) >= length)
74362306a36Sopenharmony_ci				goto out;
74462306a36Sopenharmony_ci		}
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci	/* Didn't find any space */
74762306a36Sopenharmony_ci	fi = -1;
74862306a36Sopenharmony_ciout:
74962306a36Sopenharmony_ci	ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
75062306a36Sopenharmony_ci	if (curbp) {
75162306a36Sopenharmony_ci		/* Giving back a free block. */
75262306a36Sopenharmony_ci		state->extravalid = 1;
75362306a36Sopenharmony_ci		state->extrablk.bp = curbp;
75462306a36Sopenharmony_ci		state->extrablk.index = fi;
75562306a36Sopenharmony_ci		state->extrablk.blkno = curfdb;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		/*
75862306a36Sopenharmony_ci		 * Important: this magic number is not in the buffer - it's for
75962306a36Sopenharmony_ci		 * buffer type information and therefore only the free/data type
76062306a36Sopenharmony_ci		 * matters here, not whether CRCs are enabled or not.
76162306a36Sopenharmony_ci		 */
76262306a36Sopenharmony_ci		state->extrablk.magic = XFS_DIR2_FREE_MAGIC;
76362306a36Sopenharmony_ci	} else {
76462306a36Sopenharmony_ci		state->extravalid = 0;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	/*
76762306a36Sopenharmony_ci	 * Return the index, that will be the insertion point.
76862306a36Sopenharmony_ci	 */
76962306a36Sopenharmony_ci	*indexp = index;
77062306a36Sopenharmony_ci	return -ENOENT;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/*
77462306a36Sopenharmony_ci * Look up a leaf entry in a node-format leaf block.
77562306a36Sopenharmony_ci * The extrablk in state a data block.
77662306a36Sopenharmony_ci */
77762306a36Sopenharmony_ciSTATIC int
77862306a36Sopenharmony_cixfs_dir2_leafn_lookup_for_entry(
77962306a36Sopenharmony_ci	struct xfs_buf		*bp,		/* leaf buffer */
78062306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
78162306a36Sopenharmony_ci	int			*indexp,	/* out: leaf entry index */
78262306a36Sopenharmony_ci	xfs_da_state_t		*state)		/* state to fill in */
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct xfs_buf		*curbp = NULL;	/* current data/free buffer */
78562306a36Sopenharmony_ci	xfs_dir2_db_t		curdb = -1;	/* current data block number */
78662306a36Sopenharmony_ci	xfs_dir2_data_entry_t	*dep;		/* data block entry */
78762306a36Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
78862306a36Sopenharmony_ci	int			error;		/* error return value */
78962306a36Sopenharmony_ci	int			index;		/* leaf entry index */
79062306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
79162306a36Sopenharmony_ci	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */
79262306a36Sopenharmony_ci	xfs_mount_t		*mp;		/* filesystem mount point */
79362306a36Sopenharmony_ci	xfs_dir2_db_t		newdb;		/* new data block number */
79462306a36Sopenharmony_ci	xfs_trans_t		*tp;		/* transaction pointer */
79562306a36Sopenharmony_ci	enum xfs_dacmp		cmp;		/* comparison result */
79662306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	dp = args->dp;
79962306a36Sopenharmony_ci	tp = args->trans;
80062306a36Sopenharmony_ci	mp = dp->i_mount;
80162306a36Sopenharmony_ci	leaf = bp->b_addr;
80262306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, bp);
80562306a36Sopenharmony_ci	if (leafhdr.count <= 0) {
80662306a36Sopenharmony_ci		xfs_buf_mark_corrupt(bp);
80762306a36Sopenharmony_ci		return -EFSCORRUPTED;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/*
81162306a36Sopenharmony_ci	 * Look up the hash value in the leaf entries.
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	index = xfs_dir2_leaf_search_hash(args, bp);
81462306a36Sopenharmony_ci	/*
81562306a36Sopenharmony_ci	 * Do we have a buffer coming in?
81662306a36Sopenharmony_ci	 */
81762306a36Sopenharmony_ci	if (state->extravalid) {
81862306a36Sopenharmony_ci		curbp = state->extrablk.bp;
81962306a36Sopenharmony_ci		curdb = state->extrablk.blkno;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci	/*
82262306a36Sopenharmony_ci	 * Loop over leaf entries with the right hash value.
82362306a36Sopenharmony_ci	 */
82462306a36Sopenharmony_ci	for (lep = &leafhdr.ents[index];
82562306a36Sopenharmony_ci	     index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
82662306a36Sopenharmony_ci	     lep++, index++) {
82762306a36Sopenharmony_ci		/*
82862306a36Sopenharmony_ci		 * Skip stale leaf entries.
82962306a36Sopenharmony_ci		 */
83062306a36Sopenharmony_ci		if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
83162306a36Sopenharmony_ci			continue;
83262306a36Sopenharmony_ci		/*
83362306a36Sopenharmony_ci		 * Pull the data block number from the entry.
83462306a36Sopenharmony_ci		 */
83562306a36Sopenharmony_ci		newdb = xfs_dir2_dataptr_to_db(args->geo,
83662306a36Sopenharmony_ci					       be32_to_cpu(lep->address));
83762306a36Sopenharmony_ci		/*
83862306a36Sopenharmony_ci		 * Not adding a new entry, so we really want to find
83962306a36Sopenharmony_ci		 * the name given to us.
84062306a36Sopenharmony_ci		 *
84162306a36Sopenharmony_ci		 * If it's a different data block, go get it.
84262306a36Sopenharmony_ci		 */
84362306a36Sopenharmony_ci		if (newdb != curdb) {
84462306a36Sopenharmony_ci			/*
84562306a36Sopenharmony_ci			 * If we had a block before that we aren't saving
84662306a36Sopenharmony_ci			 * for a CI name, drop it
84762306a36Sopenharmony_ci			 */
84862306a36Sopenharmony_ci			if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT ||
84962306a36Sopenharmony_ci						curdb != state->extrablk.blkno))
85062306a36Sopenharmony_ci				xfs_trans_brelse(tp, curbp);
85162306a36Sopenharmony_ci			/*
85262306a36Sopenharmony_ci			 * If needing the block that is saved with a CI match,
85362306a36Sopenharmony_ci			 * use it otherwise read in the new data block.
85462306a36Sopenharmony_ci			 */
85562306a36Sopenharmony_ci			if (args->cmpresult != XFS_CMP_DIFFERENT &&
85662306a36Sopenharmony_ci					newdb == state->extrablk.blkno) {
85762306a36Sopenharmony_ci				ASSERT(state->extravalid);
85862306a36Sopenharmony_ci				curbp = state->extrablk.bp;
85962306a36Sopenharmony_ci			} else {
86062306a36Sopenharmony_ci				error = xfs_dir3_data_read(tp, dp,
86162306a36Sopenharmony_ci						xfs_dir2_db_to_da(args->geo,
86262306a36Sopenharmony_ci								  newdb),
86362306a36Sopenharmony_ci						0, &curbp);
86462306a36Sopenharmony_ci				if (error)
86562306a36Sopenharmony_ci					return error;
86662306a36Sopenharmony_ci			}
86762306a36Sopenharmony_ci			xfs_dir3_data_check(dp, curbp);
86862306a36Sopenharmony_ci			curdb = newdb;
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci		/*
87162306a36Sopenharmony_ci		 * Point to the data entry.
87262306a36Sopenharmony_ci		 */
87362306a36Sopenharmony_ci		dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr +
87462306a36Sopenharmony_ci			xfs_dir2_dataptr_to_off(args->geo,
87562306a36Sopenharmony_ci						be32_to_cpu(lep->address)));
87662306a36Sopenharmony_ci		/*
87762306a36Sopenharmony_ci		 * Compare the entry and if it's an exact match, return
87862306a36Sopenharmony_ci		 * EEXIST immediately. If it's the first case-insensitive
87962306a36Sopenharmony_ci		 * match, store the block & inode number and continue looking.
88062306a36Sopenharmony_ci		 */
88162306a36Sopenharmony_ci		cmp = xfs_dir2_compname(args, dep->name, dep->namelen);
88262306a36Sopenharmony_ci		if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
88362306a36Sopenharmony_ci			/* If there is a CI match block, drop it */
88462306a36Sopenharmony_ci			if (args->cmpresult != XFS_CMP_DIFFERENT &&
88562306a36Sopenharmony_ci						curdb != state->extrablk.blkno)
88662306a36Sopenharmony_ci				xfs_trans_brelse(tp, state->extrablk.bp);
88762306a36Sopenharmony_ci			args->cmpresult = cmp;
88862306a36Sopenharmony_ci			args->inumber = be64_to_cpu(dep->inumber);
88962306a36Sopenharmony_ci			args->filetype = xfs_dir2_data_get_ftype(mp, dep);
89062306a36Sopenharmony_ci			*indexp = index;
89162306a36Sopenharmony_ci			state->extravalid = 1;
89262306a36Sopenharmony_ci			state->extrablk.bp = curbp;
89362306a36Sopenharmony_ci			state->extrablk.blkno = curdb;
89462306a36Sopenharmony_ci			state->extrablk.index = (int)((char *)dep -
89562306a36Sopenharmony_ci							(char *)curbp->b_addr);
89662306a36Sopenharmony_ci			state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
89762306a36Sopenharmony_ci			curbp->b_ops = &xfs_dir3_data_buf_ops;
89862306a36Sopenharmony_ci			xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF);
89962306a36Sopenharmony_ci			if (cmp == XFS_CMP_EXACT)
90062306a36Sopenharmony_ci				return -EEXIST;
90162306a36Sopenharmony_ci		}
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci	ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT));
90462306a36Sopenharmony_ci	if (curbp) {
90562306a36Sopenharmony_ci		if (args->cmpresult == XFS_CMP_DIFFERENT) {
90662306a36Sopenharmony_ci			/* Giving back last used data block. */
90762306a36Sopenharmony_ci			state->extravalid = 1;
90862306a36Sopenharmony_ci			state->extrablk.bp = curbp;
90962306a36Sopenharmony_ci			state->extrablk.index = -1;
91062306a36Sopenharmony_ci			state->extrablk.blkno = curdb;
91162306a36Sopenharmony_ci			state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
91262306a36Sopenharmony_ci			curbp->b_ops = &xfs_dir3_data_buf_ops;
91362306a36Sopenharmony_ci			xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF);
91462306a36Sopenharmony_ci		} else {
91562306a36Sopenharmony_ci			/* If the curbp is not the CI match block, drop it */
91662306a36Sopenharmony_ci			if (state->extrablk.bp != curbp)
91762306a36Sopenharmony_ci				xfs_trans_brelse(tp, curbp);
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci	} else {
92062306a36Sopenharmony_ci		state->extravalid = 0;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci	*indexp = index;
92362306a36Sopenharmony_ci	return -ENOENT;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci/*
92762306a36Sopenharmony_ci * Look up a leaf entry in a node-format leaf block.
92862306a36Sopenharmony_ci * If this is an addname then the extrablk in state is a freespace block,
92962306a36Sopenharmony_ci * otherwise it's a data block.
93062306a36Sopenharmony_ci */
93162306a36Sopenharmony_ciint
93262306a36Sopenharmony_cixfs_dir2_leafn_lookup_int(
93362306a36Sopenharmony_ci	struct xfs_buf		*bp,		/* leaf buffer */
93462306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
93562306a36Sopenharmony_ci	int			*indexp,	/* out: leaf entry index */
93662306a36Sopenharmony_ci	xfs_da_state_t		*state)		/* state to fill in */
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	if (args->op_flags & XFS_DA_OP_ADDNAME)
93962306a36Sopenharmony_ci		return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp,
94062306a36Sopenharmony_ci							state);
94162306a36Sopenharmony_ci	return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci/*
94562306a36Sopenharmony_ci * Move count leaf entries from source to destination leaf.
94662306a36Sopenharmony_ci * Log entries and headers.  Stale entries are preserved.
94762306a36Sopenharmony_ci */
94862306a36Sopenharmony_cistatic void
94962306a36Sopenharmony_cixfs_dir3_leafn_moveents(
95062306a36Sopenharmony_ci	xfs_da_args_t			*args,	/* operation arguments */
95162306a36Sopenharmony_ci	struct xfs_buf			*bp_s,	/* source */
95262306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr	*shdr,
95362306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry	*sents,
95462306a36Sopenharmony_ci	int				start_s,/* source leaf index */
95562306a36Sopenharmony_ci	struct xfs_buf			*bp_d,	/* destination */
95662306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr	*dhdr,
95762306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry	*dents,
95862306a36Sopenharmony_ci	int				start_d,/* destination leaf index */
95962306a36Sopenharmony_ci	int				count)	/* count of leaves to copy */
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	int				stale;	/* count stale leaves copied */
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/*
96662306a36Sopenharmony_ci	 * Silently return if nothing to do.
96762306a36Sopenharmony_ci	 */
96862306a36Sopenharmony_ci	if (count == 0)
96962306a36Sopenharmony_ci		return;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/*
97262306a36Sopenharmony_ci	 * If the destination index is not the end of the current
97362306a36Sopenharmony_ci	 * destination leaf entries, open up a hole in the destination
97462306a36Sopenharmony_ci	 * to hold the new entries.
97562306a36Sopenharmony_ci	 */
97662306a36Sopenharmony_ci	if (start_d < dhdr->count) {
97762306a36Sopenharmony_ci		memmove(&dents[start_d + count], &dents[start_d],
97862306a36Sopenharmony_ci			(dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t));
97962306a36Sopenharmony_ci		xfs_dir3_leaf_log_ents(args, dhdr, bp_d, start_d + count,
98062306a36Sopenharmony_ci				       count + dhdr->count - 1);
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci	/*
98362306a36Sopenharmony_ci	 * If the source has stale leaves, count the ones in the copy range
98462306a36Sopenharmony_ci	 * so we can update the header correctly.
98562306a36Sopenharmony_ci	 */
98662306a36Sopenharmony_ci	if (shdr->stale) {
98762306a36Sopenharmony_ci		int	i;			/* temp leaf index */
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci		for (i = start_s, stale = 0; i < start_s + count; i++) {
99062306a36Sopenharmony_ci			if (sents[i].address ==
99162306a36Sopenharmony_ci					cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
99262306a36Sopenharmony_ci				stale++;
99362306a36Sopenharmony_ci		}
99462306a36Sopenharmony_ci	} else
99562306a36Sopenharmony_ci		stale = 0;
99662306a36Sopenharmony_ci	/*
99762306a36Sopenharmony_ci	 * Copy the leaf entries from source to destination.
99862306a36Sopenharmony_ci	 */
99962306a36Sopenharmony_ci	memcpy(&dents[start_d], &sents[start_s],
100062306a36Sopenharmony_ci		count * sizeof(xfs_dir2_leaf_entry_t));
100162306a36Sopenharmony_ci	xfs_dir3_leaf_log_ents(args, dhdr, bp_d, start_d, start_d + count - 1);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	/*
100462306a36Sopenharmony_ci	 * If there are source entries after the ones we copied,
100562306a36Sopenharmony_ci	 * delete the ones we copied by sliding the next ones down.
100662306a36Sopenharmony_ci	 */
100762306a36Sopenharmony_ci	if (start_s + count < shdr->count) {
100862306a36Sopenharmony_ci		memmove(&sents[start_s], &sents[start_s + count],
100962306a36Sopenharmony_ci			count * sizeof(xfs_dir2_leaf_entry_t));
101062306a36Sopenharmony_ci		xfs_dir3_leaf_log_ents(args, shdr, bp_s, start_s,
101162306a36Sopenharmony_ci				       start_s + count - 1);
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/*
101562306a36Sopenharmony_ci	 * Update the headers and log them.
101662306a36Sopenharmony_ci	 */
101762306a36Sopenharmony_ci	shdr->count -= count;
101862306a36Sopenharmony_ci	shdr->stale -= stale;
101962306a36Sopenharmony_ci	dhdr->count += count;
102062306a36Sopenharmony_ci	dhdr->stale += stale;
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci/*
102462306a36Sopenharmony_ci * Determine the sort order of two leaf blocks.
102562306a36Sopenharmony_ci * Returns 1 if both are valid and leaf2 should be before leaf1, else 0.
102662306a36Sopenharmony_ci */
102762306a36Sopenharmony_ciint						/* sort order */
102862306a36Sopenharmony_cixfs_dir2_leafn_order(
102962306a36Sopenharmony_ci	struct xfs_inode	*dp,
103062306a36Sopenharmony_ci	struct xfs_buf		*leaf1_bp,		/* leaf1 buffer */
103162306a36Sopenharmony_ci	struct xfs_buf		*leaf2_bp)		/* leaf2 buffer */
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct xfs_dir2_leaf	*leaf1 = leaf1_bp->b_addr;
103462306a36Sopenharmony_ci	struct xfs_dir2_leaf	*leaf2 = leaf2_bp->b_addr;
103562306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents1;
103662306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents2;
103762306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr hdr1;
103862306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr hdr2;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr1, leaf1);
104162306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf2);
104262306a36Sopenharmony_ci	ents1 = hdr1.ents;
104362306a36Sopenharmony_ci	ents2 = hdr2.ents;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	if (hdr1.count > 0 && hdr2.count > 0 &&
104662306a36Sopenharmony_ci	    (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) ||
104762306a36Sopenharmony_ci	     be32_to_cpu(ents2[hdr2.count - 1].hashval) <
104862306a36Sopenharmony_ci				be32_to_cpu(ents1[hdr1.count - 1].hashval)))
104962306a36Sopenharmony_ci		return 1;
105062306a36Sopenharmony_ci	return 0;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci/*
105462306a36Sopenharmony_ci * Rebalance leaf entries between two leaf blocks.
105562306a36Sopenharmony_ci * This is actually only called when the second block is new,
105662306a36Sopenharmony_ci * though the code deals with the general case.
105762306a36Sopenharmony_ci * A new entry will be inserted in one of the blocks, and that
105862306a36Sopenharmony_ci * entry is taken into account when balancing.
105962306a36Sopenharmony_ci */
106062306a36Sopenharmony_cistatic void
106162306a36Sopenharmony_cixfs_dir2_leafn_rebalance(
106262306a36Sopenharmony_ci	xfs_da_state_t		*state,		/* btree cursor */
106362306a36Sopenharmony_ci	xfs_da_state_blk_t	*blk1,		/* first btree block */
106462306a36Sopenharmony_ci	xfs_da_state_blk_t	*blk2)		/* second btree block */
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	xfs_da_args_t		*args;		/* operation arguments */
106762306a36Sopenharmony_ci	int			count;		/* count (& direction) leaves */
106862306a36Sopenharmony_ci	int			isleft;		/* new goes in left leaf */
106962306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf1;		/* first leaf structure */
107062306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf2;		/* second leaf structure */
107162306a36Sopenharmony_ci	int			mid;		/* midpoint leaf index */
107262306a36Sopenharmony_ci#if defined(DEBUG) || defined(XFS_WARN)
107362306a36Sopenharmony_ci	int			oldstale;	/* old count of stale leaves */
107462306a36Sopenharmony_ci#endif
107562306a36Sopenharmony_ci	int			oldsum;		/* old total leaf count */
107662306a36Sopenharmony_ci	int			swap_blocks;	/* swapped leaf blocks */
107762306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents1;
107862306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents2;
107962306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr hdr1;
108062306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr hdr2;
108162306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	args = state->args;
108462306a36Sopenharmony_ci	/*
108562306a36Sopenharmony_ci	 * If the block order is wrong, swap the arguments.
108662306a36Sopenharmony_ci	 */
108762306a36Sopenharmony_ci	swap_blocks = xfs_dir2_leafn_order(dp, blk1->bp, blk2->bp);
108862306a36Sopenharmony_ci	if (swap_blocks)
108962306a36Sopenharmony_ci		swap(blk1, blk2);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	leaf1 = blk1->bp->b_addr;
109262306a36Sopenharmony_ci	leaf2 = blk2->bp->b_addr;
109362306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr1, leaf1);
109462306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf2);
109562306a36Sopenharmony_ci	ents1 = hdr1.ents;
109662306a36Sopenharmony_ci	ents2 = hdr2.ents;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	oldsum = hdr1.count + hdr2.count;
109962306a36Sopenharmony_ci#if defined(DEBUG) || defined(XFS_WARN)
110062306a36Sopenharmony_ci	oldstale = hdr1.stale + hdr2.stale;
110162306a36Sopenharmony_ci#endif
110262306a36Sopenharmony_ci	mid = oldsum >> 1;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/*
110562306a36Sopenharmony_ci	 * If the old leaf count was odd then the new one will be even,
110662306a36Sopenharmony_ci	 * so we need to divide the new count evenly.
110762306a36Sopenharmony_ci	 */
110862306a36Sopenharmony_ci	if (oldsum & 1) {
110962306a36Sopenharmony_ci		xfs_dahash_t	midhash;	/* middle entry hash value */
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		if (mid >= hdr1.count)
111262306a36Sopenharmony_ci			midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval);
111362306a36Sopenharmony_ci		else
111462306a36Sopenharmony_ci			midhash = be32_to_cpu(ents1[mid].hashval);
111562306a36Sopenharmony_ci		isleft = args->hashval <= midhash;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci	/*
111862306a36Sopenharmony_ci	 * If the old count is even then the new count is odd, so there's
111962306a36Sopenharmony_ci	 * no preferred side for the new entry.
112062306a36Sopenharmony_ci	 * Pick the left one.
112162306a36Sopenharmony_ci	 */
112262306a36Sopenharmony_ci	else
112362306a36Sopenharmony_ci		isleft = 1;
112462306a36Sopenharmony_ci	/*
112562306a36Sopenharmony_ci	 * Calculate moved entry count.  Positive means left-to-right,
112662306a36Sopenharmony_ci	 * negative means right-to-left.  Then move the entries.
112762306a36Sopenharmony_ci	 */
112862306a36Sopenharmony_ci	count = hdr1.count - mid + (isleft == 0);
112962306a36Sopenharmony_ci	if (count > 0)
113062306a36Sopenharmony_ci		xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1,
113162306a36Sopenharmony_ci					hdr1.count - count, blk2->bp,
113262306a36Sopenharmony_ci					&hdr2, ents2, 0, count);
113362306a36Sopenharmony_ci	else if (count < 0)
113462306a36Sopenharmony_ci		xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0,
113562306a36Sopenharmony_ci					blk1->bp, &hdr1, ents1,
113662306a36Sopenharmony_ci					hdr1.count, count);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	ASSERT(hdr1.count + hdr2.count == oldsum);
113962306a36Sopenharmony_ci	ASSERT(hdr1.stale + hdr2.stale == oldstale);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* log the changes made when moving the entries */
114262306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf1, &hdr1);
114362306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf2, &hdr2);
114462306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, blk1->bp);
114562306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, blk2->bp);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, blk1->bp);
114862306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, blk2->bp);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/*
115162306a36Sopenharmony_ci	 * Mark whether we're inserting into the old or new leaf.
115262306a36Sopenharmony_ci	 */
115362306a36Sopenharmony_ci	if (hdr1.count < hdr2.count)
115462306a36Sopenharmony_ci		state->inleaf = swap_blocks;
115562306a36Sopenharmony_ci	else if (hdr1.count > hdr2.count)
115662306a36Sopenharmony_ci		state->inleaf = !swap_blocks;
115762306a36Sopenharmony_ci	else
115862306a36Sopenharmony_ci		state->inleaf = swap_blocks ^ (blk1->index <= hdr1.count);
115962306a36Sopenharmony_ci	/*
116062306a36Sopenharmony_ci	 * Adjust the expected index for insertion.
116162306a36Sopenharmony_ci	 */
116262306a36Sopenharmony_ci	if (!state->inleaf)
116362306a36Sopenharmony_ci		blk2->index = blk1->index - hdr1.count;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/*
116662306a36Sopenharmony_ci	 * Finally sanity check just to make sure we are not returning a
116762306a36Sopenharmony_ci	 * negative index
116862306a36Sopenharmony_ci	 */
116962306a36Sopenharmony_ci	if (blk2->index < 0) {
117062306a36Sopenharmony_ci		state->inleaf = 1;
117162306a36Sopenharmony_ci		blk2->index = 0;
117262306a36Sopenharmony_ci		xfs_alert(dp->i_mount,
117362306a36Sopenharmony_ci	"%s: picked the wrong leaf? reverting original leaf: blk1->index %d",
117462306a36Sopenharmony_ci			__func__, blk1->index);
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_cistatic int
117962306a36Sopenharmony_cixfs_dir3_data_block_free(
118062306a36Sopenharmony_ci	xfs_da_args_t		*args,
118162306a36Sopenharmony_ci	struct xfs_dir2_data_hdr *hdr,
118262306a36Sopenharmony_ci	struct xfs_dir2_free	*free,
118362306a36Sopenharmony_ci	xfs_dir2_db_t		fdb,
118462306a36Sopenharmony_ci	int			findex,
118562306a36Sopenharmony_ci	struct xfs_buf		*fbp,
118662306a36Sopenharmony_ci	int			longest)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	int			logfree = 0;
118962306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr freehdr;
119062306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
119362306a36Sopenharmony_ci	if (hdr) {
119462306a36Sopenharmony_ci		/*
119562306a36Sopenharmony_ci		 * Data block is not empty, just set the free entry to the new
119662306a36Sopenharmony_ci		 * value.
119762306a36Sopenharmony_ci		 */
119862306a36Sopenharmony_ci		freehdr.bests[findex] = cpu_to_be16(longest);
119962306a36Sopenharmony_ci		xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
120062306a36Sopenharmony_ci		return 0;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* One less used entry in the free table. */
120462306a36Sopenharmony_ci	freehdr.nused--;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/*
120762306a36Sopenharmony_ci	 * If this was the last entry in the table, we can trim the table size
120862306a36Sopenharmony_ci	 * back.  There might be other entries at the end referring to
120962306a36Sopenharmony_ci	 * non-existent data blocks, get those too.
121062306a36Sopenharmony_ci	 */
121162306a36Sopenharmony_ci	if (findex == freehdr.nvalid - 1) {
121262306a36Sopenharmony_ci		int	i;		/* free entry index */
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		for (i = findex - 1; i >= 0; i--) {
121562306a36Sopenharmony_ci			if (freehdr.bests[i] != cpu_to_be16(NULLDATAOFF))
121662306a36Sopenharmony_ci				break;
121762306a36Sopenharmony_ci		}
121862306a36Sopenharmony_ci		freehdr.nvalid = i + 1;
121962306a36Sopenharmony_ci		logfree = 0;
122062306a36Sopenharmony_ci	} else {
122162306a36Sopenharmony_ci		/* Not the last entry, just punch it out.  */
122262306a36Sopenharmony_ci		freehdr.bests[findex] = cpu_to_be16(NULLDATAOFF);
122362306a36Sopenharmony_ci		logfree = 1;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	xfs_dir2_free_hdr_to_disk(dp->i_mount, free, &freehdr);
122762306a36Sopenharmony_ci	xfs_dir2_free_log_header(args, fbp);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	/*
123062306a36Sopenharmony_ci	 * If there are no useful entries left in the block, get rid of the
123162306a36Sopenharmony_ci	 * block if we can.
123262306a36Sopenharmony_ci	 */
123362306a36Sopenharmony_ci	if (!freehdr.nused) {
123462306a36Sopenharmony_ci		int error;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		error = xfs_dir2_shrink_inode(args, fdb, fbp);
123762306a36Sopenharmony_ci		if (error == 0) {
123862306a36Sopenharmony_ci			fbp = NULL;
123962306a36Sopenharmony_ci			logfree = 0;
124062306a36Sopenharmony_ci		} else if (error != -ENOSPC || args->total != 0)
124162306a36Sopenharmony_ci			return error;
124262306a36Sopenharmony_ci		/*
124362306a36Sopenharmony_ci		 * It's possible to get ENOSPC if there is no
124462306a36Sopenharmony_ci		 * space reservation.  In this case some one
124562306a36Sopenharmony_ci		 * else will eventually get rid of this block.
124662306a36Sopenharmony_ci		 */
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* Log the free entry that changed, unless we got rid of it.  */
125062306a36Sopenharmony_ci	if (logfree)
125162306a36Sopenharmony_ci		xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
125262306a36Sopenharmony_ci	return 0;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci/*
125662306a36Sopenharmony_ci * Remove an entry from a node directory.
125762306a36Sopenharmony_ci * This removes the leaf entry and the data entry,
125862306a36Sopenharmony_ci * and updates the free block if necessary.
125962306a36Sopenharmony_ci */
126062306a36Sopenharmony_cistatic int					/* error */
126162306a36Sopenharmony_cixfs_dir2_leafn_remove(
126262306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
126362306a36Sopenharmony_ci	struct xfs_buf		*bp,		/* leaf buffer */
126462306a36Sopenharmony_ci	int			index,		/* leaf entry index */
126562306a36Sopenharmony_ci	xfs_da_state_blk_t	*dblk,		/* data block */
126662306a36Sopenharmony_ci	int			*rval)		/* resulting block needs join */
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct xfs_da_geometry	*geo = args->geo;
126962306a36Sopenharmony_ci	xfs_dir2_data_hdr_t	*hdr;		/* data block header */
127062306a36Sopenharmony_ci	xfs_dir2_db_t		db;		/* data block number */
127162306a36Sopenharmony_ci	struct xfs_buf		*dbp;		/* data block buffer */
127262306a36Sopenharmony_ci	xfs_dir2_data_entry_t	*dep;		/* data block entry */
127362306a36Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
127462306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
127562306a36Sopenharmony_ci	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */
127662306a36Sopenharmony_ci	int			longest;	/* longest data free entry */
127762306a36Sopenharmony_ci	int			off;		/* data block entry offset */
127862306a36Sopenharmony_ci	int			needlog;	/* need to log data header */
127962306a36Sopenharmony_ci	int			needscan;	/* need to rescan data frees */
128062306a36Sopenharmony_ci	xfs_trans_t		*tp;		/* transaction pointer */
128162306a36Sopenharmony_ci	struct xfs_dir2_data_free *bf;		/* bestfree table */
128262306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	trace_xfs_dir2_leafn_remove(args, index);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	dp = args->dp;
128762306a36Sopenharmony_ci	tp = args->trans;
128862306a36Sopenharmony_ci	leaf = bp->b_addr;
128962306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/*
129262306a36Sopenharmony_ci	 * Point to the entry we're removing.
129362306a36Sopenharmony_ci	 */
129462306a36Sopenharmony_ci	lep = &leafhdr.ents[index];
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/*
129762306a36Sopenharmony_ci	 * Extract the data block and offset from the entry.
129862306a36Sopenharmony_ci	 */
129962306a36Sopenharmony_ci	db = xfs_dir2_dataptr_to_db(geo, be32_to_cpu(lep->address));
130062306a36Sopenharmony_ci	ASSERT(dblk->blkno == db);
130162306a36Sopenharmony_ci	off = xfs_dir2_dataptr_to_off(geo, be32_to_cpu(lep->address));
130262306a36Sopenharmony_ci	ASSERT(dblk->index == off);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/*
130562306a36Sopenharmony_ci	 * Kill the leaf entry by marking it stale.
130662306a36Sopenharmony_ci	 * Log the leaf block changes.
130762306a36Sopenharmony_ci	 */
130862306a36Sopenharmony_ci	leafhdr.stale++;
130962306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, leaf, &leafhdr);
131062306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, bp);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
131362306a36Sopenharmony_ci	xfs_dir3_leaf_log_ents(args, &leafhdr, bp, index, index);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/*
131662306a36Sopenharmony_ci	 * Make the data entry free.  Keep track of the longest freespace
131762306a36Sopenharmony_ci	 * in the data block in case it changes.
131862306a36Sopenharmony_ci	 */
131962306a36Sopenharmony_ci	dbp = dblk->bp;
132062306a36Sopenharmony_ci	hdr = dbp->b_addr;
132162306a36Sopenharmony_ci	dep = (xfs_dir2_data_entry_t *)((char *)hdr + off);
132262306a36Sopenharmony_ci	bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
132362306a36Sopenharmony_ci	longest = be16_to_cpu(bf[0].length);
132462306a36Sopenharmony_ci	needlog = needscan = 0;
132562306a36Sopenharmony_ci	xfs_dir2_data_make_free(args, dbp, off,
132662306a36Sopenharmony_ci		xfs_dir2_data_entsize(dp->i_mount, dep->namelen), &needlog,
132762306a36Sopenharmony_ci		&needscan);
132862306a36Sopenharmony_ci	/*
132962306a36Sopenharmony_ci	 * Rescan the data block freespaces for bestfree.
133062306a36Sopenharmony_ci	 * Log the data block header if needed.
133162306a36Sopenharmony_ci	 */
133262306a36Sopenharmony_ci	if (needscan)
133362306a36Sopenharmony_ci		xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
133462306a36Sopenharmony_ci	if (needlog)
133562306a36Sopenharmony_ci		xfs_dir2_data_log_header(args, dbp);
133662306a36Sopenharmony_ci	xfs_dir3_data_check(dp, dbp);
133762306a36Sopenharmony_ci	/*
133862306a36Sopenharmony_ci	 * If the longest data block freespace changes, need to update
133962306a36Sopenharmony_ci	 * the corresponding freeblock entry.
134062306a36Sopenharmony_ci	 */
134162306a36Sopenharmony_ci	if (longest < be16_to_cpu(bf[0].length)) {
134262306a36Sopenharmony_ci		int		error;		/* error return value */
134362306a36Sopenharmony_ci		struct xfs_buf	*fbp;		/* freeblock buffer */
134462306a36Sopenharmony_ci		xfs_dir2_db_t	fdb;		/* freeblock block number */
134562306a36Sopenharmony_ci		int		findex;		/* index in freeblock entries */
134662306a36Sopenharmony_ci		xfs_dir2_free_t	*free;		/* freeblock structure */
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		/*
134962306a36Sopenharmony_ci		 * Convert the data block number to a free block,
135062306a36Sopenharmony_ci		 * read in the free block.
135162306a36Sopenharmony_ci		 */
135262306a36Sopenharmony_ci		fdb = xfs_dir2_db_to_fdb(geo, db);
135362306a36Sopenharmony_ci		error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(geo, fdb),
135462306a36Sopenharmony_ci					   &fbp);
135562306a36Sopenharmony_ci		if (error)
135662306a36Sopenharmony_ci			return error;
135762306a36Sopenharmony_ci		free = fbp->b_addr;
135862306a36Sopenharmony_ci#ifdef DEBUG
135962306a36Sopenharmony_ci	{
136062306a36Sopenharmony_ci		struct xfs_dir3_icfree_hdr freehdr;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
136362306a36Sopenharmony_ci		ASSERT(freehdr.firstdb == geo->free_max_bests *
136462306a36Sopenharmony_ci			(fdb - xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET)));
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci#endif
136762306a36Sopenharmony_ci		/*
136862306a36Sopenharmony_ci		 * Calculate which entry we need to fix.
136962306a36Sopenharmony_ci		 */
137062306a36Sopenharmony_ci		findex = xfs_dir2_db_to_fdindex(geo, db);
137162306a36Sopenharmony_ci		longest = be16_to_cpu(bf[0].length);
137262306a36Sopenharmony_ci		/*
137362306a36Sopenharmony_ci		 * If the data block is now empty we can get rid of it
137462306a36Sopenharmony_ci		 * (usually).
137562306a36Sopenharmony_ci		 */
137662306a36Sopenharmony_ci		if (longest == geo->blksize - geo->data_entry_offset) {
137762306a36Sopenharmony_ci			/*
137862306a36Sopenharmony_ci			 * Try to punch out the data block.
137962306a36Sopenharmony_ci			 */
138062306a36Sopenharmony_ci			error = xfs_dir2_shrink_inode(args, db, dbp);
138162306a36Sopenharmony_ci			if (error == 0) {
138262306a36Sopenharmony_ci				dblk->bp = NULL;
138362306a36Sopenharmony_ci				hdr = NULL;
138462306a36Sopenharmony_ci			}
138562306a36Sopenharmony_ci			/*
138662306a36Sopenharmony_ci			 * We can get ENOSPC if there's no space reservation.
138762306a36Sopenharmony_ci			 * In this case just drop the buffer and some one else
138862306a36Sopenharmony_ci			 * will eventually get rid of the empty block.
138962306a36Sopenharmony_ci			 */
139062306a36Sopenharmony_ci			else if (!(error == -ENOSPC && args->total == 0))
139162306a36Sopenharmony_ci				return error;
139262306a36Sopenharmony_ci		}
139362306a36Sopenharmony_ci		/*
139462306a36Sopenharmony_ci		 * If we got rid of the data block, we can eliminate that entry
139562306a36Sopenharmony_ci		 * in the free block.
139662306a36Sopenharmony_ci		 */
139762306a36Sopenharmony_ci		error = xfs_dir3_data_block_free(args, hdr, free,
139862306a36Sopenharmony_ci						 fdb, findex, fbp, longest);
139962306a36Sopenharmony_ci		if (error)
140062306a36Sopenharmony_ci			return error;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, bp);
140462306a36Sopenharmony_ci	/*
140562306a36Sopenharmony_ci	 * Return indication of whether this leaf block is empty enough
140662306a36Sopenharmony_ci	 * to justify trying to join it with a neighbor.
140762306a36Sopenharmony_ci	 */
140862306a36Sopenharmony_ci	*rval = (geo->leaf_hdr_size +
140962306a36Sopenharmony_ci		 (uint)sizeof(leafhdr.ents) * (leafhdr.count - leafhdr.stale)) <
141062306a36Sopenharmony_ci		geo->magicpct;
141162306a36Sopenharmony_ci	return 0;
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci/*
141562306a36Sopenharmony_ci * Split the leaf entries in the old block into old and new blocks.
141662306a36Sopenharmony_ci */
141762306a36Sopenharmony_ciint						/* error */
141862306a36Sopenharmony_cixfs_dir2_leafn_split(
141962306a36Sopenharmony_ci	xfs_da_state_t		*state,		/* btree cursor */
142062306a36Sopenharmony_ci	xfs_da_state_blk_t	*oldblk,	/* original block */
142162306a36Sopenharmony_ci	xfs_da_state_blk_t	*newblk)	/* newly created block */
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	xfs_da_args_t		*args;		/* operation arguments */
142462306a36Sopenharmony_ci	xfs_dablk_t		blkno;		/* new leaf block number */
142562306a36Sopenharmony_ci	int			error;		/* error return value */
142662306a36Sopenharmony_ci	struct xfs_inode	*dp;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	/*
142962306a36Sopenharmony_ci	 * Allocate space for a new leaf node.
143062306a36Sopenharmony_ci	 */
143162306a36Sopenharmony_ci	args = state->args;
143262306a36Sopenharmony_ci	dp = args->dp;
143362306a36Sopenharmony_ci	ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC);
143462306a36Sopenharmony_ci	error = xfs_da_grow_inode(args, &blkno);
143562306a36Sopenharmony_ci	if (error) {
143662306a36Sopenharmony_ci		return error;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci	/*
143962306a36Sopenharmony_ci	 * Initialize the new leaf block.
144062306a36Sopenharmony_ci	 */
144162306a36Sopenharmony_ci	error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(args->geo, blkno),
144262306a36Sopenharmony_ci				      &newblk->bp, XFS_DIR2_LEAFN_MAGIC);
144362306a36Sopenharmony_ci	if (error)
144462306a36Sopenharmony_ci		return error;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	newblk->blkno = blkno;
144762306a36Sopenharmony_ci	newblk->magic = XFS_DIR2_LEAFN_MAGIC;
144862306a36Sopenharmony_ci	/*
144962306a36Sopenharmony_ci	 * Rebalance the entries across the two leaves, link the new
145062306a36Sopenharmony_ci	 * block into the leaves.
145162306a36Sopenharmony_ci	 */
145262306a36Sopenharmony_ci	xfs_dir2_leafn_rebalance(state, oldblk, newblk);
145362306a36Sopenharmony_ci	error = xfs_da3_blk_link(state, oldblk, newblk);
145462306a36Sopenharmony_ci	if (error) {
145562306a36Sopenharmony_ci		return error;
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci	/*
145862306a36Sopenharmony_ci	 * Insert the new entry in the correct block.
145962306a36Sopenharmony_ci	 */
146062306a36Sopenharmony_ci	if (state->inleaf)
146162306a36Sopenharmony_ci		error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index);
146262306a36Sopenharmony_ci	else
146362306a36Sopenharmony_ci		error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index);
146462306a36Sopenharmony_ci	/*
146562306a36Sopenharmony_ci	 * Update last hashval in each block since we added the name.
146662306a36Sopenharmony_ci	 */
146762306a36Sopenharmony_ci	oldblk->hashval = xfs_dir2_leaf_lasthash(dp, oldblk->bp, NULL);
146862306a36Sopenharmony_ci	newblk->hashval = xfs_dir2_leaf_lasthash(dp, newblk->bp, NULL);
146962306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, oldblk->bp);
147062306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, newblk->bp);
147162306a36Sopenharmony_ci	return error;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci/*
147562306a36Sopenharmony_ci * Check a leaf block and its neighbors to see if the block should be
147662306a36Sopenharmony_ci * collapsed into one or the other neighbor.  Always keep the block
147762306a36Sopenharmony_ci * with the smaller block number.
147862306a36Sopenharmony_ci * If the current block is over 50% full, don't try to join it, return 0.
147962306a36Sopenharmony_ci * If the block is empty, fill in the state structure and return 2.
148062306a36Sopenharmony_ci * If it can be collapsed, fill in the state structure and return 1.
148162306a36Sopenharmony_ci * If nothing can be done, return 0.
148262306a36Sopenharmony_ci */
148362306a36Sopenharmony_ciint						/* error */
148462306a36Sopenharmony_cixfs_dir2_leafn_toosmall(
148562306a36Sopenharmony_ci	xfs_da_state_t		*state,		/* btree cursor */
148662306a36Sopenharmony_ci	int			*action)	/* resulting action to take */
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	xfs_da_state_blk_t	*blk;		/* leaf block */
148962306a36Sopenharmony_ci	xfs_dablk_t		blkno;		/* leaf block number */
149062306a36Sopenharmony_ci	struct xfs_buf		*bp;		/* leaf buffer */
149162306a36Sopenharmony_ci	int			bytes;		/* bytes in use */
149262306a36Sopenharmony_ci	int			count;		/* leaf live entry count */
149362306a36Sopenharmony_ci	int			error;		/* error return value */
149462306a36Sopenharmony_ci	int			forward;	/* sibling block direction */
149562306a36Sopenharmony_ci	int			i;		/* sibling counter */
149662306a36Sopenharmony_ci	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
149762306a36Sopenharmony_ci	int			rval;		/* result from path_shift */
149862306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr leafhdr;
149962306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *ents;
150062306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	/*
150362306a36Sopenharmony_ci	 * Check for the degenerate case of the block being over 50% full.
150462306a36Sopenharmony_ci	 * If so, it's not worth even looking to see if we might be able
150562306a36Sopenharmony_ci	 * to coalesce with a sibling.
150662306a36Sopenharmony_ci	 */
150762306a36Sopenharmony_ci	blk = &state->path.blk[state->path.active - 1];
150862306a36Sopenharmony_ci	leaf = blk->bp->b_addr;
150962306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &leafhdr, leaf);
151062306a36Sopenharmony_ci	ents = leafhdr.ents;
151162306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, blk->bp);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	count = leafhdr.count - leafhdr.stale;
151462306a36Sopenharmony_ci	bytes = state->args->geo->leaf_hdr_size + count * sizeof(ents[0]);
151562306a36Sopenharmony_ci	if (bytes > (state->args->geo->blksize >> 1)) {
151662306a36Sopenharmony_ci		/*
151762306a36Sopenharmony_ci		 * Blk over 50%, don't try to join.
151862306a36Sopenharmony_ci		 */
151962306a36Sopenharmony_ci		*action = 0;
152062306a36Sopenharmony_ci		return 0;
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci	/*
152362306a36Sopenharmony_ci	 * Check for the degenerate case of the block being empty.
152462306a36Sopenharmony_ci	 * If the block is empty, we'll simply delete it, no need to
152562306a36Sopenharmony_ci	 * coalesce it with a sibling block.  We choose (arbitrarily)
152662306a36Sopenharmony_ci	 * to merge with the forward block unless it is NULL.
152762306a36Sopenharmony_ci	 */
152862306a36Sopenharmony_ci	if (count == 0) {
152962306a36Sopenharmony_ci		/*
153062306a36Sopenharmony_ci		 * Make altpath point to the block we want to keep and
153162306a36Sopenharmony_ci		 * path point to the block we want to drop (this one).
153262306a36Sopenharmony_ci		 */
153362306a36Sopenharmony_ci		forward = (leafhdr.forw != 0);
153462306a36Sopenharmony_ci		memcpy(&state->altpath, &state->path, sizeof(state->path));
153562306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->altpath, forward, 0,
153662306a36Sopenharmony_ci			&rval);
153762306a36Sopenharmony_ci		if (error)
153862306a36Sopenharmony_ci			return error;
153962306a36Sopenharmony_ci		*action = rval ? 2 : 0;
154062306a36Sopenharmony_ci		return 0;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci	/*
154362306a36Sopenharmony_ci	 * Examine each sibling block to see if we can coalesce with
154462306a36Sopenharmony_ci	 * at least 25% free space to spare.  We need to figure out
154562306a36Sopenharmony_ci	 * whether to merge with the forward or the backward block.
154662306a36Sopenharmony_ci	 * We prefer coalescing with the lower numbered sibling so as
154762306a36Sopenharmony_ci	 * to shrink a directory over time.
154862306a36Sopenharmony_ci	 */
154962306a36Sopenharmony_ci	forward = leafhdr.forw < leafhdr.back;
155062306a36Sopenharmony_ci	for (i = 0, bp = NULL; i < 2; forward = !forward, i++) {
155162306a36Sopenharmony_ci		struct xfs_dir3_icleaf_hdr hdr2;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		blkno = forward ? leafhdr.forw : leafhdr.back;
155462306a36Sopenharmony_ci		if (blkno == 0)
155562306a36Sopenharmony_ci			continue;
155662306a36Sopenharmony_ci		/*
155762306a36Sopenharmony_ci		 * Read the sibling leaf block.
155862306a36Sopenharmony_ci		 */
155962306a36Sopenharmony_ci		error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, &bp);
156062306a36Sopenharmony_ci		if (error)
156162306a36Sopenharmony_ci			return error;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci		/*
156462306a36Sopenharmony_ci		 * Count bytes in the two blocks combined.
156562306a36Sopenharmony_ci		 */
156662306a36Sopenharmony_ci		count = leafhdr.count - leafhdr.stale;
156762306a36Sopenharmony_ci		bytes = state->args->geo->blksize -
156862306a36Sopenharmony_ci			(state->args->geo->blksize >> 2);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci		leaf = bp->b_addr;
157162306a36Sopenharmony_ci		xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &hdr2, leaf);
157262306a36Sopenharmony_ci		ents = hdr2.ents;
157362306a36Sopenharmony_ci		count += hdr2.count - hdr2.stale;
157462306a36Sopenharmony_ci		bytes -= count * sizeof(ents[0]);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		/*
157762306a36Sopenharmony_ci		 * Fits with at least 25% to spare.
157862306a36Sopenharmony_ci		 */
157962306a36Sopenharmony_ci		if (bytes >= 0)
158062306a36Sopenharmony_ci			break;
158162306a36Sopenharmony_ci		xfs_trans_brelse(state->args->trans, bp);
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci	/*
158462306a36Sopenharmony_ci	 * Didn't like either block, give up.
158562306a36Sopenharmony_ci	 */
158662306a36Sopenharmony_ci	if (i >= 2) {
158762306a36Sopenharmony_ci		*action = 0;
158862306a36Sopenharmony_ci		return 0;
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/*
159262306a36Sopenharmony_ci	 * Make altpath point to the block we want to keep (the lower
159362306a36Sopenharmony_ci	 * numbered block) and path point to the block we want to drop.
159462306a36Sopenharmony_ci	 */
159562306a36Sopenharmony_ci	memcpy(&state->altpath, &state->path, sizeof(state->path));
159662306a36Sopenharmony_ci	if (blkno < blk->blkno)
159762306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->altpath, forward, 0,
159862306a36Sopenharmony_ci			&rval);
159962306a36Sopenharmony_ci	else
160062306a36Sopenharmony_ci		error = xfs_da3_path_shift(state, &state->path, forward, 0,
160162306a36Sopenharmony_ci			&rval);
160262306a36Sopenharmony_ci	if (error) {
160362306a36Sopenharmony_ci		return error;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci	*action = rval ? 0 : 1;
160662306a36Sopenharmony_ci	return 0;
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci/*
161062306a36Sopenharmony_ci * Move all the leaf entries from drop_blk to save_blk.
161162306a36Sopenharmony_ci * This is done as part of a join operation.
161262306a36Sopenharmony_ci */
161362306a36Sopenharmony_civoid
161462306a36Sopenharmony_cixfs_dir2_leafn_unbalance(
161562306a36Sopenharmony_ci	xfs_da_state_t		*state,		/* cursor */
161662306a36Sopenharmony_ci	xfs_da_state_blk_t	*drop_blk,	/* dead block */
161762306a36Sopenharmony_ci	xfs_da_state_blk_t	*save_blk)	/* surviving block */
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	xfs_da_args_t		*args;		/* operation arguments */
162062306a36Sopenharmony_ci	xfs_dir2_leaf_t		*drop_leaf;	/* dead leaf structure */
162162306a36Sopenharmony_ci	xfs_dir2_leaf_t		*save_leaf;	/* surviving leaf structure */
162262306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr savehdr;
162362306a36Sopenharmony_ci	struct xfs_dir3_icleaf_hdr drophdr;
162462306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *sents;
162562306a36Sopenharmony_ci	struct xfs_dir2_leaf_entry *dents;
162662306a36Sopenharmony_ci	struct xfs_inode	*dp = state->args->dp;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	args = state->args;
162962306a36Sopenharmony_ci	ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
163062306a36Sopenharmony_ci	ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);
163162306a36Sopenharmony_ci	drop_leaf = drop_blk->bp->b_addr;
163262306a36Sopenharmony_ci	save_leaf = save_blk->bp->b_addr;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &savehdr, save_leaf);
163562306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_from_disk(dp->i_mount, &drophdr, drop_leaf);
163662306a36Sopenharmony_ci	sents = savehdr.ents;
163762306a36Sopenharmony_ci	dents = drophdr.ents;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/*
164062306a36Sopenharmony_ci	 * If there are any stale leaf entries, take this opportunity
164162306a36Sopenharmony_ci	 * to purge them.
164262306a36Sopenharmony_ci	 */
164362306a36Sopenharmony_ci	if (drophdr.stale)
164462306a36Sopenharmony_ci		xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp);
164562306a36Sopenharmony_ci	if (savehdr.stale)
164662306a36Sopenharmony_ci		xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * Move the entries from drop to the appropriate end of save.
165062306a36Sopenharmony_ci	 */
165162306a36Sopenharmony_ci	drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval);
165262306a36Sopenharmony_ci	if (xfs_dir2_leafn_order(dp, save_blk->bp, drop_blk->bp))
165362306a36Sopenharmony_ci		xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0,
165462306a36Sopenharmony_ci					save_blk->bp, &savehdr, sents, 0,
165562306a36Sopenharmony_ci					drophdr.count);
165662306a36Sopenharmony_ci	else
165762306a36Sopenharmony_ci		xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0,
165862306a36Sopenharmony_ci					save_blk->bp, &savehdr, sents,
165962306a36Sopenharmony_ci					savehdr.count, drophdr.count);
166062306a36Sopenharmony_ci	save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	/* log the changes made when moving the entries */
166362306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, save_leaf, &savehdr);
166462306a36Sopenharmony_ci	xfs_dir2_leaf_hdr_to_disk(dp->i_mount, drop_leaf, &drophdr);
166562306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, save_blk->bp);
166662306a36Sopenharmony_ci	xfs_dir3_leaf_log_header(args, drop_blk->bp);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, save_blk->bp);
166962306a36Sopenharmony_ci	xfs_dir3_leaf_check(dp, drop_blk->bp);
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci/*
167362306a36Sopenharmony_ci * Add a new data block to the directory at the free space index that the caller
167462306a36Sopenharmony_ci * has specified.
167562306a36Sopenharmony_ci */
167662306a36Sopenharmony_cistatic int
167762306a36Sopenharmony_cixfs_dir2_node_add_datablk(
167862306a36Sopenharmony_ci	struct xfs_da_args	*args,
167962306a36Sopenharmony_ci	struct xfs_da_state_blk	*fblk,
168062306a36Sopenharmony_ci	xfs_dir2_db_t		*dbno,
168162306a36Sopenharmony_ci	struct xfs_buf		**dbpp,
168262306a36Sopenharmony_ci	struct xfs_buf		**fbpp,
168362306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr *hdr,
168462306a36Sopenharmony_ci	int			*findex)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
168762306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
168862306a36Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
168962306a36Sopenharmony_ci	struct xfs_dir2_data_free *bf;
169062306a36Sopenharmony_ci	xfs_dir2_db_t		fbno;
169162306a36Sopenharmony_ci	struct xfs_buf		*fbp;
169262306a36Sopenharmony_ci	struct xfs_buf		*dbp;
169362306a36Sopenharmony_ci	int			error;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	/* Not allowed to allocate, return failure. */
169662306a36Sopenharmony_ci	if (args->total == 0)
169762306a36Sopenharmony_ci		return -ENOSPC;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/* Allocate and initialize the new data block.  */
170062306a36Sopenharmony_ci	error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, dbno);
170162306a36Sopenharmony_ci	if (error)
170262306a36Sopenharmony_ci		return error;
170362306a36Sopenharmony_ci	error = xfs_dir3_data_init(args, *dbno, &dbp);
170462306a36Sopenharmony_ci	if (error)
170562306a36Sopenharmony_ci		return error;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	/*
170862306a36Sopenharmony_ci	 * Get the freespace block corresponding to the data block
170962306a36Sopenharmony_ci	 * that was just allocated.
171062306a36Sopenharmony_ci	 */
171162306a36Sopenharmony_ci	fbno = xfs_dir2_db_to_fdb(args->geo, *dbno);
171262306a36Sopenharmony_ci	error = xfs_dir2_free_try_read(tp, dp,
171362306a36Sopenharmony_ci			       xfs_dir2_db_to_da(args->geo, fbno), &fbp);
171462306a36Sopenharmony_ci	if (error)
171562306a36Sopenharmony_ci		return error;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	/*
171862306a36Sopenharmony_ci	 * If there wasn't a freespace block, the read will
171962306a36Sopenharmony_ci	 * return a NULL fbp.  Allocate and initialize a new one.
172062306a36Sopenharmony_ci	 */
172162306a36Sopenharmony_ci	if (!fbp) {
172262306a36Sopenharmony_ci		error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fbno);
172362306a36Sopenharmony_ci		if (error)
172462306a36Sopenharmony_ci			return error;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci		if (XFS_IS_CORRUPT(mp,
172762306a36Sopenharmony_ci				   xfs_dir2_db_to_fdb(args->geo, *dbno) !=
172862306a36Sopenharmony_ci				   fbno)) {
172962306a36Sopenharmony_ci			xfs_alert(mp,
173062306a36Sopenharmony_ci"%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld",
173162306a36Sopenharmony_ci				__func__, (unsigned long long)dp->i_ino,
173262306a36Sopenharmony_ci				(long long)xfs_dir2_db_to_fdb(args->geo, *dbno),
173362306a36Sopenharmony_ci				(long long)*dbno, (long long)fbno);
173462306a36Sopenharmony_ci			if (fblk) {
173562306a36Sopenharmony_ci				xfs_alert(mp,
173662306a36Sopenharmony_ci			" fblk "PTR_FMT" blkno %llu index %d magic 0x%x",
173762306a36Sopenharmony_ci					fblk, (unsigned long long)fblk->blkno,
173862306a36Sopenharmony_ci					fblk->index, fblk->magic);
173962306a36Sopenharmony_ci			} else {
174062306a36Sopenharmony_ci				xfs_alert(mp, " ... fblk is NULL");
174162306a36Sopenharmony_ci			}
174262306a36Sopenharmony_ci			return -EFSCORRUPTED;
174362306a36Sopenharmony_ci		}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci		/* Get a buffer for the new block. */
174662306a36Sopenharmony_ci		error = xfs_dir3_free_get_buf(args, fbno, &fbp);
174762306a36Sopenharmony_ci		if (error)
174862306a36Sopenharmony_ci			return error;
174962306a36Sopenharmony_ci		xfs_dir2_free_hdr_from_disk(mp, hdr, fbp->b_addr);
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci		/* Remember the first slot as our empty slot. */
175262306a36Sopenharmony_ci		hdr->firstdb = (fbno - xfs_dir2_byte_to_db(args->geo,
175362306a36Sopenharmony_ci							XFS_DIR2_FREE_OFFSET)) *
175462306a36Sopenharmony_ci				args->geo->free_max_bests;
175562306a36Sopenharmony_ci	} else {
175662306a36Sopenharmony_ci		xfs_dir2_free_hdr_from_disk(mp, hdr, fbp->b_addr);
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	/* Set the freespace block index from the data block number. */
176062306a36Sopenharmony_ci	*findex = xfs_dir2_db_to_fdindex(args->geo, *dbno);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* Extend the freespace table if the new data block is off the end. */
176362306a36Sopenharmony_ci	if (*findex >= hdr->nvalid) {
176462306a36Sopenharmony_ci		ASSERT(*findex < args->geo->free_max_bests);
176562306a36Sopenharmony_ci		hdr->nvalid = *findex + 1;
176662306a36Sopenharmony_ci		hdr->bests[*findex] = cpu_to_be16(NULLDATAOFF);
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	/*
177062306a36Sopenharmony_ci	 * If this entry was for an empty data block (this should always be
177162306a36Sopenharmony_ci	 * true) then update the header.
177262306a36Sopenharmony_ci	 */
177362306a36Sopenharmony_ci	if (hdr->bests[*findex] == cpu_to_be16(NULLDATAOFF)) {
177462306a36Sopenharmony_ci		hdr->nused++;
177562306a36Sopenharmony_ci		xfs_dir2_free_hdr_to_disk(mp, fbp->b_addr, hdr);
177662306a36Sopenharmony_ci		xfs_dir2_free_log_header(args, fbp);
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	/* Update the freespace value for the new block in the table. */
178062306a36Sopenharmony_ci	bf = xfs_dir2_data_bestfree_p(mp, dbp->b_addr);
178162306a36Sopenharmony_ci	hdr->bests[*findex] = bf[0].length;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	*dbpp = dbp;
178462306a36Sopenharmony_ci	*fbpp = fbp;
178562306a36Sopenharmony_ci	return 0;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_cistatic int
178962306a36Sopenharmony_cixfs_dir2_node_find_freeblk(
179062306a36Sopenharmony_ci	struct xfs_da_args	*args,
179162306a36Sopenharmony_ci	struct xfs_da_state_blk	*fblk,
179262306a36Sopenharmony_ci	xfs_dir2_db_t		*dbnop,
179362306a36Sopenharmony_ci	struct xfs_buf		**fbpp,
179462306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr *hdr,
179562306a36Sopenharmony_ci	int			*findexp,
179662306a36Sopenharmony_ci	int			length)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
179962306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
180062306a36Sopenharmony_ci	struct xfs_buf		*fbp = NULL;
180162306a36Sopenharmony_ci	xfs_dir2_db_t		firstfbno;
180262306a36Sopenharmony_ci	xfs_dir2_db_t		lastfbno;
180362306a36Sopenharmony_ci	xfs_dir2_db_t		ifbno = -1;
180462306a36Sopenharmony_ci	xfs_dir2_db_t		dbno = -1;
180562306a36Sopenharmony_ci	xfs_dir2_db_t		fbno;
180662306a36Sopenharmony_ci	xfs_fileoff_t		fo;
180762306a36Sopenharmony_ci	int			findex = 0;
180862306a36Sopenharmony_ci	int			error;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	/*
181162306a36Sopenharmony_ci	 * If we came in with a freespace block that means that lookup
181262306a36Sopenharmony_ci	 * found an entry with our hash value.  This is the freespace
181362306a36Sopenharmony_ci	 * block for that data entry.
181462306a36Sopenharmony_ci	 */
181562306a36Sopenharmony_ci	if (fblk) {
181662306a36Sopenharmony_ci		fbp = fblk->bp;
181762306a36Sopenharmony_ci		findex = fblk->index;
181862306a36Sopenharmony_ci		xfs_dir2_free_hdr_from_disk(dp->i_mount, hdr, fbp->b_addr);
181962306a36Sopenharmony_ci		if (findex >= 0) {
182062306a36Sopenharmony_ci			/* caller already found the freespace for us. */
182162306a36Sopenharmony_ci			ASSERT(findex < hdr->nvalid);
182262306a36Sopenharmony_ci			ASSERT(be16_to_cpu(hdr->bests[findex]) != NULLDATAOFF);
182362306a36Sopenharmony_ci			ASSERT(be16_to_cpu(hdr->bests[findex]) >= length);
182462306a36Sopenharmony_ci			dbno = hdr->firstdb + findex;
182562306a36Sopenharmony_ci			goto found_block;
182662306a36Sopenharmony_ci		}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		/*
182962306a36Sopenharmony_ci		 * The data block looked at didn't have enough room.
183062306a36Sopenharmony_ci		 * We'll start at the beginning of the freespace entries.
183162306a36Sopenharmony_ci		 */
183262306a36Sopenharmony_ci		ifbno = fblk->blkno;
183362306a36Sopenharmony_ci		xfs_trans_brelse(tp, fbp);
183462306a36Sopenharmony_ci		fbp = NULL;
183562306a36Sopenharmony_ci		fblk->bp = NULL;
183662306a36Sopenharmony_ci	}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/*
183962306a36Sopenharmony_ci	 * If we don't have a data block yet, we're going to scan the freespace
184062306a36Sopenharmony_ci	 * data for a data block with enough free space in it.
184162306a36Sopenharmony_ci	 */
184262306a36Sopenharmony_ci	error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK);
184362306a36Sopenharmony_ci	if (error)
184462306a36Sopenharmony_ci		return error;
184562306a36Sopenharmony_ci	lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo);
184662306a36Sopenharmony_ci	firstfbno = xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	for (fbno = lastfbno - 1; fbno >= firstfbno; fbno--) {
184962306a36Sopenharmony_ci		/* If it's ifbno we already looked at it. */
185062306a36Sopenharmony_ci		if (fbno == ifbno)
185162306a36Sopenharmony_ci			continue;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci		/*
185462306a36Sopenharmony_ci		 * Read the block.  There can be holes in the freespace blocks,
185562306a36Sopenharmony_ci		 * so this might not succeed.  This should be really rare, so
185662306a36Sopenharmony_ci		 * there's no reason to avoid it.
185762306a36Sopenharmony_ci		 */
185862306a36Sopenharmony_ci		error = xfs_dir2_free_try_read(tp, dp,
185962306a36Sopenharmony_ci				xfs_dir2_db_to_da(args->geo, fbno),
186062306a36Sopenharmony_ci				&fbp);
186162306a36Sopenharmony_ci		if (error)
186262306a36Sopenharmony_ci			return error;
186362306a36Sopenharmony_ci		if (!fbp)
186462306a36Sopenharmony_ci			continue;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci		xfs_dir2_free_hdr_from_disk(dp->i_mount, hdr, fbp->b_addr);
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci		/* Scan the free entry array for a large enough free space. */
186962306a36Sopenharmony_ci		for (findex = hdr->nvalid - 1; findex >= 0; findex--) {
187062306a36Sopenharmony_ci			if (be16_to_cpu(hdr->bests[findex]) != NULLDATAOFF &&
187162306a36Sopenharmony_ci			    be16_to_cpu(hdr->bests[findex]) >= length) {
187262306a36Sopenharmony_ci				dbno = hdr->firstdb + findex;
187362306a36Sopenharmony_ci				goto found_block;
187462306a36Sopenharmony_ci			}
187562306a36Sopenharmony_ci		}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci		/* Didn't find free space, go on to next free block */
187862306a36Sopenharmony_ci		xfs_trans_brelse(tp, fbp);
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_cifound_block:
188262306a36Sopenharmony_ci	*dbnop = dbno;
188362306a36Sopenharmony_ci	*fbpp = fbp;
188462306a36Sopenharmony_ci	*findexp = findex;
188562306a36Sopenharmony_ci	return 0;
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci/*
188962306a36Sopenharmony_ci * Add the data entry for a node-format directory name addition.
189062306a36Sopenharmony_ci * The leaf entry is added in xfs_dir2_leafn_add.
189162306a36Sopenharmony_ci * We may enter with a freespace block that the lookup found.
189262306a36Sopenharmony_ci */
189362306a36Sopenharmony_cistatic int
189462306a36Sopenharmony_cixfs_dir2_node_addname_int(
189562306a36Sopenharmony_ci	struct xfs_da_args	*args,		/* operation arguments */
189662306a36Sopenharmony_ci	struct xfs_da_state_blk	*fblk)		/* optional freespace block */
189762306a36Sopenharmony_ci{
189862306a36Sopenharmony_ci	struct xfs_dir2_data_unused *dup;	/* data unused entry pointer */
189962306a36Sopenharmony_ci	struct xfs_dir2_data_entry *dep;	/* data entry pointer */
190062306a36Sopenharmony_ci	struct xfs_dir2_data_hdr *hdr;		/* data block header */
190162306a36Sopenharmony_ci	struct xfs_dir2_data_free *bf;
190262306a36Sopenharmony_ci	struct xfs_trans	*tp = args->trans;
190362306a36Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
190462306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr freehdr;
190562306a36Sopenharmony_ci	struct xfs_buf		*dbp;		/* data block buffer */
190662306a36Sopenharmony_ci	struct xfs_buf		*fbp;		/* freespace buffer */
190762306a36Sopenharmony_ci	xfs_dir2_data_aoff_t	aoff;
190862306a36Sopenharmony_ci	xfs_dir2_db_t		dbno;		/* data block number */
190962306a36Sopenharmony_ci	int			error;		/* error return value */
191062306a36Sopenharmony_ci	int			findex;		/* freespace entry index */
191162306a36Sopenharmony_ci	int			length;		/* length of the new entry */
191262306a36Sopenharmony_ci	int			logfree = 0;	/* need to log free entry */
191362306a36Sopenharmony_ci	int			needlog = 0;	/* need to log data header */
191462306a36Sopenharmony_ci	int			needscan = 0;	/* need to rescan data frees */
191562306a36Sopenharmony_ci	__be16			*tagp;		/* data entry tag pointer */
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	length = xfs_dir2_data_entsize(dp->i_mount, args->namelen);
191862306a36Sopenharmony_ci	error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &freehdr,
191962306a36Sopenharmony_ci					   &findex, length);
192062306a36Sopenharmony_ci	if (error)
192162306a36Sopenharmony_ci		return error;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	/*
192462306a36Sopenharmony_ci	 * Now we know if we must allocate blocks, so if we are checking whether
192562306a36Sopenharmony_ci	 * we can insert without allocation then we can return now.
192662306a36Sopenharmony_ci	 */
192762306a36Sopenharmony_ci	if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
192862306a36Sopenharmony_ci		if (dbno == -1)
192962306a36Sopenharmony_ci			return -ENOSPC;
193062306a36Sopenharmony_ci		return 0;
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	/*
193462306a36Sopenharmony_ci	 * If we don't have a data block, we need to allocate one and make
193562306a36Sopenharmony_ci	 * the freespace entries refer to it.
193662306a36Sopenharmony_ci	 */
193762306a36Sopenharmony_ci	if (dbno == -1) {
193862306a36Sopenharmony_ci		/* we're going to have to log the free block index later */
193962306a36Sopenharmony_ci		logfree = 1;
194062306a36Sopenharmony_ci		error = xfs_dir2_node_add_datablk(args, fblk, &dbno, &dbp, &fbp,
194162306a36Sopenharmony_ci						  &freehdr, &findex);
194262306a36Sopenharmony_ci	} else {
194362306a36Sopenharmony_ci		/* Read the data block in. */
194462306a36Sopenharmony_ci		error = xfs_dir3_data_read(tp, dp,
194562306a36Sopenharmony_ci					   xfs_dir2_db_to_da(args->geo, dbno),
194662306a36Sopenharmony_ci					   0, &dbp);
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci	if (error)
194962306a36Sopenharmony_ci		return error;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	/* setup for data block up now */
195262306a36Sopenharmony_ci	hdr = dbp->b_addr;
195362306a36Sopenharmony_ci	bf = xfs_dir2_data_bestfree_p(dp->i_mount, hdr);
195462306a36Sopenharmony_ci	ASSERT(be16_to_cpu(bf[0].length) >= length);
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/* Point to the existing unused space. */
195762306a36Sopenharmony_ci	dup = (xfs_dir2_data_unused_t *)
195862306a36Sopenharmony_ci	      ((char *)hdr + be16_to_cpu(bf[0].offset));
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	/* Mark the first part of the unused space, inuse for us. */
196162306a36Sopenharmony_ci	aoff = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
196262306a36Sopenharmony_ci	error = xfs_dir2_data_use_free(args, dbp, dup, aoff, length,
196362306a36Sopenharmony_ci			&needlog, &needscan);
196462306a36Sopenharmony_ci	if (error) {
196562306a36Sopenharmony_ci		xfs_trans_brelse(tp, dbp);
196662306a36Sopenharmony_ci		return error;
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	/* Fill in the new entry and log it. */
197062306a36Sopenharmony_ci	dep = (xfs_dir2_data_entry_t *)dup;
197162306a36Sopenharmony_ci	dep->inumber = cpu_to_be64(args->inumber);
197262306a36Sopenharmony_ci	dep->namelen = args->namelen;
197362306a36Sopenharmony_ci	memcpy(dep->name, args->name, dep->namelen);
197462306a36Sopenharmony_ci	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
197562306a36Sopenharmony_ci	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, dep);
197662306a36Sopenharmony_ci	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
197762306a36Sopenharmony_ci	xfs_dir2_data_log_entry(args, dbp, dep);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	/* Rescan the freespace and log the data block if needed. */
198062306a36Sopenharmony_ci	if (needscan)
198162306a36Sopenharmony_ci		xfs_dir2_data_freescan(dp->i_mount, hdr, &needlog);
198262306a36Sopenharmony_ci	if (needlog)
198362306a36Sopenharmony_ci		xfs_dir2_data_log_header(args, dbp);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	/* If the freespace block entry is now wrong, update it. */
198662306a36Sopenharmony_ci	if (freehdr.bests[findex] != bf[0].length) {
198762306a36Sopenharmony_ci		freehdr.bests[findex] = bf[0].length;
198862306a36Sopenharmony_ci		logfree = 1;
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	/* Log the freespace entry if needed. */
199262306a36Sopenharmony_ci	if (logfree)
199362306a36Sopenharmony_ci		xfs_dir2_free_log_bests(args, &freehdr, fbp, findex, findex);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	/* Return the data block and offset in args. */
199662306a36Sopenharmony_ci	args->blkno = (xfs_dablk_t)dbno;
199762306a36Sopenharmony_ci	args->index = be16_to_cpu(*tagp);
199862306a36Sopenharmony_ci	return 0;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci/*
200262306a36Sopenharmony_ci * Top-level node form directory addname routine.
200362306a36Sopenharmony_ci */
200462306a36Sopenharmony_ciint						/* error */
200562306a36Sopenharmony_cixfs_dir2_node_addname(
200662306a36Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
200762306a36Sopenharmony_ci{
200862306a36Sopenharmony_ci	xfs_da_state_blk_t	*blk;		/* leaf block for insert */
200962306a36Sopenharmony_ci	int			error;		/* error return value */
201062306a36Sopenharmony_ci	int			rval;		/* sub-return value */
201162306a36Sopenharmony_ci	xfs_da_state_t		*state;		/* btree cursor */
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	trace_xfs_dir2_node_addname(args);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/*
201662306a36Sopenharmony_ci	 * Allocate and initialize the state (btree cursor).
201762306a36Sopenharmony_ci	 */
201862306a36Sopenharmony_ci	state = xfs_da_state_alloc(args);
201962306a36Sopenharmony_ci	/*
202062306a36Sopenharmony_ci	 * Look up the name.  We're not supposed to find it, but
202162306a36Sopenharmony_ci	 * this gives us the insertion point.
202262306a36Sopenharmony_ci	 */
202362306a36Sopenharmony_ci	error = xfs_da3_node_lookup_int(state, &rval);
202462306a36Sopenharmony_ci	if (error)
202562306a36Sopenharmony_ci		rval = error;
202662306a36Sopenharmony_ci	if (rval != -ENOENT) {
202762306a36Sopenharmony_ci		goto done;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci	/*
203062306a36Sopenharmony_ci	 * Add the data entry to a data block.
203162306a36Sopenharmony_ci	 * Extravalid is set to a freeblock found by lookup.
203262306a36Sopenharmony_ci	 */
203362306a36Sopenharmony_ci	rval = xfs_dir2_node_addname_int(args,
203462306a36Sopenharmony_ci		state->extravalid ? &state->extrablk : NULL);
203562306a36Sopenharmony_ci	if (rval) {
203662306a36Sopenharmony_ci		goto done;
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci	blk = &state->path.blk[state->path.active - 1];
203962306a36Sopenharmony_ci	ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);
204062306a36Sopenharmony_ci	/*
204162306a36Sopenharmony_ci	 * Add the new leaf entry.
204262306a36Sopenharmony_ci	 */
204362306a36Sopenharmony_ci	rval = xfs_dir2_leafn_add(blk->bp, args, blk->index);
204462306a36Sopenharmony_ci	if (rval == 0) {
204562306a36Sopenharmony_ci		/*
204662306a36Sopenharmony_ci		 * It worked, fix the hash values up the btree.
204762306a36Sopenharmony_ci		 */
204862306a36Sopenharmony_ci		if (!(args->op_flags & XFS_DA_OP_JUSTCHECK))
204962306a36Sopenharmony_ci			xfs_da3_fixhashpath(state, &state->path);
205062306a36Sopenharmony_ci	} else {
205162306a36Sopenharmony_ci		/*
205262306a36Sopenharmony_ci		 * It didn't work, we need to split the leaf block.
205362306a36Sopenharmony_ci		 */
205462306a36Sopenharmony_ci		if (args->total == 0) {
205562306a36Sopenharmony_ci			ASSERT(rval == -ENOSPC);
205662306a36Sopenharmony_ci			goto done;
205762306a36Sopenharmony_ci		}
205862306a36Sopenharmony_ci		/*
205962306a36Sopenharmony_ci		 * Split the leaf block and insert the new entry.
206062306a36Sopenharmony_ci		 */
206162306a36Sopenharmony_ci		rval = xfs_da3_split(state);
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_cidone:
206462306a36Sopenharmony_ci	xfs_da_state_free(state);
206562306a36Sopenharmony_ci	return rval;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci/*
206962306a36Sopenharmony_ci * Lookup an entry in a node-format directory.
207062306a36Sopenharmony_ci * All the real work happens in xfs_da3_node_lookup_int.
207162306a36Sopenharmony_ci * The only real output is the inode number of the entry.
207262306a36Sopenharmony_ci */
207362306a36Sopenharmony_ciint						/* error */
207462306a36Sopenharmony_cixfs_dir2_node_lookup(
207562306a36Sopenharmony_ci	xfs_da_args_t	*args)			/* operation arguments */
207662306a36Sopenharmony_ci{
207762306a36Sopenharmony_ci	int		error;			/* error return value */
207862306a36Sopenharmony_ci	int		i;			/* btree level */
207962306a36Sopenharmony_ci	int		rval;			/* operation return value */
208062306a36Sopenharmony_ci	xfs_da_state_t	*state;			/* btree cursor */
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	trace_xfs_dir2_node_lookup(args);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/*
208562306a36Sopenharmony_ci	 * Allocate and initialize the btree cursor.
208662306a36Sopenharmony_ci	 */
208762306a36Sopenharmony_ci	state = xfs_da_state_alloc(args);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	/*
209062306a36Sopenharmony_ci	 * Fill in the path to the entry in the cursor.
209162306a36Sopenharmony_ci	 */
209262306a36Sopenharmony_ci	error = xfs_da3_node_lookup_int(state, &rval);
209362306a36Sopenharmony_ci	if (error)
209462306a36Sopenharmony_ci		rval = error;
209562306a36Sopenharmony_ci	else if (rval == -ENOENT && args->cmpresult == XFS_CMP_CASE) {
209662306a36Sopenharmony_ci		/* If a CI match, dup the actual name and return -EEXIST */
209762306a36Sopenharmony_ci		xfs_dir2_data_entry_t	*dep;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci		dep = (xfs_dir2_data_entry_t *)
210062306a36Sopenharmony_ci			((char *)state->extrablk.bp->b_addr +
210162306a36Sopenharmony_ci						 state->extrablk.index);
210262306a36Sopenharmony_ci		rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci	/*
210562306a36Sopenharmony_ci	 * Release the btree blocks and leaf block.
210662306a36Sopenharmony_ci	 */
210762306a36Sopenharmony_ci	for (i = 0; i < state->path.active; i++) {
210862306a36Sopenharmony_ci		xfs_trans_brelse(args->trans, state->path.blk[i].bp);
210962306a36Sopenharmony_ci		state->path.blk[i].bp = NULL;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci	/*
211262306a36Sopenharmony_ci	 * Release the data block if we have it.
211362306a36Sopenharmony_ci	 */
211462306a36Sopenharmony_ci	if (state->extravalid && state->extrablk.bp) {
211562306a36Sopenharmony_ci		xfs_trans_brelse(args->trans, state->extrablk.bp);
211662306a36Sopenharmony_ci		state->extrablk.bp = NULL;
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci	xfs_da_state_free(state);
211962306a36Sopenharmony_ci	return rval;
212062306a36Sopenharmony_ci}
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci/*
212362306a36Sopenharmony_ci * Remove an entry from a node-format directory.
212462306a36Sopenharmony_ci */
212562306a36Sopenharmony_ciint						/* error */
212662306a36Sopenharmony_cixfs_dir2_node_removename(
212762306a36Sopenharmony_ci	struct xfs_da_args	*args)		/* operation arguments */
212862306a36Sopenharmony_ci{
212962306a36Sopenharmony_ci	struct xfs_da_state_blk	*blk;		/* leaf block */
213062306a36Sopenharmony_ci	int			error;		/* error return value */
213162306a36Sopenharmony_ci	int			rval;		/* operation return value */
213262306a36Sopenharmony_ci	struct xfs_da_state	*state;		/* btree cursor */
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	trace_xfs_dir2_node_removename(args);
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	/*
213762306a36Sopenharmony_ci	 * Allocate and initialize the btree cursor.
213862306a36Sopenharmony_ci	 */
213962306a36Sopenharmony_ci	state = xfs_da_state_alloc(args);
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	/* Look up the entry we're deleting, set up the cursor. */
214262306a36Sopenharmony_ci	error = xfs_da3_node_lookup_int(state, &rval);
214362306a36Sopenharmony_ci	if (error)
214462306a36Sopenharmony_ci		goto out_free;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	/* Didn't find it, upper layer screwed up. */
214762306a36Sopenharmony_ci	if (rval != -EEXIST) {
214862306a36Sopenharmony_ci		error = rval;
214962306a36Sopenharmony_ci		goto out_free;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	blk = &state->path.blk[state->path.active - 1];
215362306a36Sopenharmony_ci	ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);
215462306a36Sopenharmony_ci	ASSERT(state->extravalid);
215562306a36Sopenharmony_ci	/*
215662306a36Sopenharmony_ci	 * Remove the leaf and data entries.
215762306a36Sopenharmony_ci	 * Extrablk refers to the data block.
215862306a36Sopenharmony_ci	 */
215962306a36Sopenharmony_ci	error = xfs_dir2_leafn_remove(args, blk->bp, blk->index,
216062306a36Sopenharmony_ci		&state->extrablk, &rval);
216162306a36Sopenharmony_ci	if (error)
216262306a36Sopenharmony_ci		goto out_free;
216362306a36Sopenharmony_ci	/*
216462306a36Sopenharmony_ci	 * Fix the hash values up the btree.
216562306a36Sopenharmony_ci	 */
216662306a36Sopenharmony_ci	xfs_da3_fixhashpath(state, &state->path);
216762306a36Sopenharmony_ci	/*
216862306a36Sopenharmony_ci	 * If we need to join leaf blocks, do it.
216962306a36Sopenharmony_ci	 */
217062306a36Sopenharmony_ci	if (rval && state->path.active > 1)
217162306a36Sopenharmony_ci		error = xfs_da3_join(state);
217262306a36Sopenharmony_ci	/*
217362306a36Sopenharmony_ci	 * If no errors so far, try conversion to leaf format.
217462306a36Sopenharmony_ci	 */
217562306a36Sopenharmony_ci	if (!error)
217662306a36Sopenharmony_ci		error = xfs_dir2_node_to_leaf(state);
217762306a36Sopenharmony_ciout_free:
217862306a36Sopenharmony_ci	xfs_da_state_free(state);
217962306a36Sopenharmony_ci	return error;
218062306a36Sopenharmony_ci}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci/*
218362306a36Sopenharmony_ci * Replace an entry's inode number in a node-format directory.
218462306a36Sopenharmony_ci */
218562306a36Sopenharmony_ciint						/* error */
218662306a36Sopenharmony_cixfs_dir2_node_replace(
218762306a36Sopenharmony_ci	xfs_da_args_t		*args)		/* operation arguments */
218862306a36Sopenharmony_ci{
218962306a36Sopenharmony_ci	xfs_da_state_blk_t	*blk;		/* leaf block */
219062306a36Sopenharmony_ci	xfs_dir2_data_hdr_t	*hdr;		/* data block header */
219162306a36Sopenharmony_ci	xfs_dir2_data_entry_t	*dep;		/* data entry changed */
219262306a36Sopenharmony_ci	int			error;		/* error return value */
219362306a36Sopenharmony_ci	int			i;		/* btree level */
219462306a36Sopenharmony_ci	xfs_ino_t		inum;		/* new inode number */
219562306a36Sopenharmony_ci	int			ftype;		/* new file type */
219662306a36Sopenharmony_ci	int			rval;		/* internal return value */
219762306a36Sopenharmony_ci	xfs_da_state_t		*state;		/* btree cursor */
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	trace_xfs_dir2_node_replace(args);
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	/*
220262306a36Sopenharmony_ci	 * Allocate and initialize the btree cursor.
220362306a36Sopenharmony_ci	 */
220462306a36Sopenharmony_ci	state = xfs_da_state_alloc(args);
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/*
220762306a36Sopenharmony_ci	 * We have to save new inode number and ftype since
220862306a36Sopenharmony_ci	 * xfs_da3_node_lookup_int() is going to overwrite them
220962306a36Sopenharmony_ci	 */
221062306a36Sopenharmony_ci	inum = args->inumber;
221162306a36Sopenharmony_ci	ftype = args->filetype;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	/*
221462306a36Sopenharmony_ci	 * Lookup the entry to change in the btree.
221562306a36Sopenharmony_ci	 */
221662306a36Sopenharmony_ci	error = xfs_da3_node_lookup_int(state, &rval);
221762306a36Sopenharmony_ci	if (error) {
221862306a36Sopenharmony_ci		rval = error;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci	/*
222162306a36Sopenharmony_ci	 * It should be found, since the vnodeops layer has looked it up
222262306a36Sopenharmony_ci	 * and locked it.  But paranoia is good.
222362306a36Sopenharmony_ci	 */
222462306a36Sopenharmony_ci	if (rval == -EEXIST) {
222562306a36Sopenharmony_ci		struct xfs_dir3_icleaf_hdr	leafhdr;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci		/*
222862306a36Sopenharmony_ci		 * Find the leaf entry.
222962306a36Sopenharmony_ci		 */
223062306a36Sopenharmony_ci		blk = &state->path.blk[state->path.active - 1];
223162306a36Sopenharmony_ci		ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);
223262306a36Sopenharmony_ci		ASSERT(state->extravalid);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		xfs_dir2_leaf_hdr_from_disk(state->mp, &leafhdr,
223562306a36Sopenharmony_ci					    blk->bp->b_addr);
223662306a36Sopenharmony_ci		/*
223762306a36Sopenharmony_ci		 * Point to the data entry.
223862306a36Sopenharmony_ci		 */
223962306a36Sopenharmony_ci		hdr = state->extrablk.bp->b_addr;
224062306a36Sopenharmony_ci		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
224162306a36Sopenharmony_ci		       hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
224262306a36Sopenharmony_ci		dep = (xfs_dir2_data_entry_t *)
224362306a36Sopenharmony_ci		      ((char *)hdr +
224462306a36Sopenharmony_ci		       xfs_dir2_dataptr_to_off(args->geo,
224562306a36Sopenharmony_ci				be32_to_cpu(leafhdr.ents[blk->index].address)));
224662306a36Sopenharmony_ci		ASSERT(inum != be64_to_cpu(dep->inumber));
224762306a36Sopenharmony_ci		/*
224862306a36Sopenharmony_ci		 * Fill in the new inode number and log the entry.
224962306a36Sopenharmony_ci		 */
225062306a36Sopenharmony_ci		dep->inumber = cpu_to_be64(inum);
225162306a36Sopenharmony_ci		xfs_dir2_data_put_ftype(state->mp, dep, ftype);
225262306a36Sopenharmony_ci		xfs_dir2_data_log_entry(args, state->extrablk.bp, dep);
225362306a36Sopenharmony_ci		rval = 0;
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci	/*
225662306a36Sopenharmony_ci	 * Didn't find it, and we're holding a data block.  Drop it.
225762306a36Sopenharmony_ci	 */
225862306a36Sopenharmony_ci	else if (state->extravalid) {
225962306a36Sopenharmony_ci		xfs_trans_brelse(args->trans, state->extrablk.bp);
226062306a36Sopenharmony_ci		state->extrablk.bp = NULL;
226162306a36Sopenharmony_ci	}
226262306a36Sopenharmony_ci	/*
226362306a36Sopenharmony_ci	 * Release all the buffers in the cursor.
226462306a36Sopenharmony_ci	 */
226562306a36Sopenharmony_ci	for (i = 0; i < state->path.active; i++) {
226662306a36Sopenharmony_ci		xfs_trans_brelse(args->trans, state->path.blk[i].bp);
226762306a36Sopenharmony_ci		state->path.blk[i].bp = NULL;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci	xfs_da_state_free(state);
227062306a36Sopenharmony_ci	return rval;
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci/*
227462306a36Sopenharmony_ci * Trim off a trailing empty freespace block.
227562306a36Sopenharmony_ci * Return (in rvalp) 1 if we did it, 0 if not.
227662306a36Sopenharmony_ci */
227762306a36Sopenharmony_ciint						/* error */
227862306a36Sopenharmony_cixfs_dir2_node_trim_free(
227962306a36Sopenharmony_ci	xfs_da_args_t		*args,		/* operation arguments */
228062306a36Sopenharmony_ci	xfs_fileoff_t		fo,		/* free block number */
228162306a36Sopenharmony_ci	int			*rvalp)		/* out: did something */
228262306a36Sopenharmony_ci{
228362306a36Sopenharmony_ci	struct xfs_buf		*bp;		/* freespace buffer */
228462306a36Sopenharmony_ci	xfs_inode_t		*dp;		/* incore directory inode */
228562306a36Sopenharmony_ci	int			error;		/* error return code */
228662306a36Sopenharmony_ci	xfs_dir2_free_t		*free;		/* freespace structure */
228762306a36Sopenharmony_ci	xfs_trans_t		*tp;		/* transaction pointer */
228862306a36Sopenharmony_ci	struct xfs_dir3_icfree_hdr freehdr;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	dp = args->dp;
229162306a36Sopenharmony_ci	tp = args->trans;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	*rvalp = 0;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	/*
229662306a36Sopenharmony_ci	 * Read the freespace block.
229762306a36Sopenharmony_ci	 */
229862306a36Sopenharmony_ci	error = xfs_dir2_free_try_read(tp, dp, fo, &bp);
229962306a36Sopenharmony_ci	if (error)
230062306a36Sopenharmony_ci		return error;
230162306a36Sopenharmony_ci	/*
230262306a36Sopenharmony_ci	 * There can be holes in freespace.  If fo is a hole, there's
230362306a36Sopenharmony_ci	 * nothing to do.
230462306a36Sopenharmony_ci	 */
230562306a36Sopenharmony_ci	if (!bp)
230662306a36Sopenharmony_ci		return 0;
230762306a36Sopenharmony_ci	free = bp->b_addr;
230862306a36Sopenharmony_ci	xfs_dir2_free_hdr_from_disk(dp->i_mount, &freehdr, free);
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	/*
231162306a36Sopenharmony_ci	 * If there are used entries, there's nothing to do.
231262306a36Sopenharmony_ci	 */
231362306a36Sopenharmony_ci	if (freehdr.nused > 0) {
231462306a36Sopenharmony_ci		xfs_trans_brelse(tp, bp);
231562306a36Sopenharmony_ci		return 0;
231662306a36Sopenharmony_ci	}
231762306a36Sopenharmony_ci	/*
231862306a36Sopenharmony_ci	 * Blow the block away.
231962306a36Sopenharmony_ci	 */
232062306a36Sopenharmony_ci	error = xfs_dir2_shrink_inode(args,
232162306a36Sopenharmony_ci			xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo), bp);
232262306a36Sopenharmony_ci	if (error) {
232362306a36Sopenharmony_ci		/*
232462306a36Sopenharmony_ci		 * Can't fail with ENOSPC since that only happens with no
232562306a36Sopenharmony_ci		 * space reservation, when breaking up an extent into two
232662306a36Sopenharmony_ci		 * pieces.  This is the last block of an extent.
232762306a36Sopenharmony_ci		 */
232862306a36Sopenharmony_ci		ASSERT(error != -ENOSPC);
232962306a36Sopenharmony_ci		xfs_trans_brelse(tp, bp);
233062306a36Sopenharmony_ci		return error;
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci	/*
233362306a36Sopenharmony_ci	 * Return that we succeeded.
233462306a36Sopenharmony_ci	 */
233562306a36Sopenharmony_ci	*rvalp = 1;
233662306a36Sopenharmony_ci	return 0;
233762306a36Sopenharmony_ci}
2338