162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_bit.h"
1362306a36Sopenharmony_ci#include "xfs_mount.h"
1462306a36Sopenharmony_ci#include "xfs_inode.h"
1562306a36Sopenharmony_ci#include "xfs_trans.h"
1662306a36Sopenharmony_ci#include "xfs_alloc.h"
1762306a36Sopenharmony_ci#include "xfs_btree.h"
1862306a36Sopenharmony_ci#include "xfs_bmap_btree.h"
1962306a36Sopenharmony_ci#include "xfs_bmap.h"
2062306a36Sopenharmony_ci#include "xfs_error.h"
2162306a36Sopenharmony_ci#include "xfs_quota.h"
2262306a36Sopenharmony_ci#include "xfs_trace.h"
2362306a36Sopenharmony_ci#include "xfs_rmap.h"
2462306a36Sopenharmony_ci#include "xfs_ag.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic struct kmem_cache	*xfs_bmbt_cur_cache;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * Convert on-disk form of btree root to in-memory form.
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_civoid
3262306a36Sopenharmony_cixfs_bmdr_to_bmbt(
3362306a36Sopenharmony_ci	struct xfs_inode	*ip,
3462306a36Sopenharmony_ci	xfs_bmdr_block_t	*dblock,
3562306a36Sopenharmony_ci	int			dblocklen,
3662306a36Sopenharmony_ci	struct xfs_btree_block	*rblock,
3762306a36Sopenharmony_ci	int			rblocklen)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct xfs_mount	*mp = ip->i_mount;
4062306a36Sopenharmony_ci	int			dmxr;
4162306a36Sopenharmony_ci	xfs_bmbt_key_t		*fkp;
4262306a36Sopenharmony_ci	__be64			*fpp;
4362306a36Sopenharmony_ci	xfs_bmbt_key_t		*tkp;
4462306a36Sopenharmony_ci	__be64			*tpp;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
4762306a36Sopenharmony_ci				 XFS_BTNUM_BMAP, 0, 0, ip->i_ino,
4862306a36Sopenharmony_ci				 XFS_BTREE_LONG_PTRS);
4962306a36Sopenharmony_ci	rblock->bb_level = dblock->bb_level;
5062306a36Sopenharmony_ci	ASSERT(be16_to_cpu(rblock->bb_level) > 0);
5162306a36Sopenharmony_ci	rblock->bb_numrecs = dblock->bb_numrecs;
5262306a36Sopenharmony_ci	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
5362306a36Sopenharmony_ci	fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
5462306a36Sopenharmony_ci	tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
5562306a36Sopenharmony_ci	fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
5662306a36Sopenharmony_ci	tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
5762306a36Sopenharmony_ci	dmxr = be16_to_cpu(dblock->bb_numrecs);
5862306a36Sopenharmony_ci	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
5962306a36Sopenharmony_ci	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_civoid
6362306a36Sopenharmony_cixfs_bmbt_disk_get_all(
6462306a36Sopenharmony_ci	const struct xfs_bmbt_rec *rec,
6562306a36Sopenharmony_ci	struct xfs_bmbt_irec	*irec)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	uint64_t		l0 = get_unaligned_be64(&rec->l0);
6862306a36Sopenharmony_ci	uint64_t		l1 = get_unaligned_be64(&rec->l1);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	irec->br_startoff = (l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
7162306a36Sopenharmony_ci	irec->br_startblock = ((l0 & xfs_mask64lo(9)) << 43) | (l1 >> 21);
7262306a36Sopenharmony_ci	irec->br_blockcount = l1 & xfs_mask64lo(21);
7362306a36Sopenharmony_ci	if (l0 >> (64 - BMBT_EXNTFLAG_BITLEN))
7462306a36Sopenharmony_ci		irec->br_state = XFS_EXT_UNWRITTEN;
7562306a36Sopenharmony_ci	else
7662306a36Sopenharmony_ci		irec->br_state = XFS_EXT_NORM;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * Extract the blockcount field from an on disk bmap extent record.
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cixfs_filblks_t
8362306a36Sopenharmony_cixfs_bmbt_disk_get_blockcount(
8462306a36Sopenharmony_ci	const struct xfs_bmbt_rec	*r)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21));
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * Extract the startoff field from a disk format bmap extent record.
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_cixfs_fileoff_t
9362306a36Sopenharmony_cixfs_bmbt_disk_get_startoff(
9462306a36Sopenharmony_ci	const struct xfs_bmbt_rec	*r)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	return ((xfs_fileoff_t)be64_to_cpu(r->l0) &
9762306a36Sopenharmony_ci		 xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * Set all the fields in a bmap extent record from the uncompressed form.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_civoid
10462306a36Sopenharmony_cixfs_bmbt_disk_set_all(
10562306a36Sopenharmony_ci	struct xfs_bmbt_rec	*r,
10662306a36Sopenharmony_ci	struct xfs_bmbt_irec	*s)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	int			extent_flag = (s->br_state != XFS_EXT_NORM);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ASSERT(s->br_state == XFS_EXT_NORM || s->br_state == XFS_EXT_UNWRITTEN);
11162306a36Sopenharmony_ci	ASSERT(!(s->br_startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)));
11262306a36Sopenharmony_ci	ASSERT(!(s->br_blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)));
11362306a36Sopenharmony_ci	ASSERT(!(s->br_startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)));
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	put_unaligned_be64(
11662306a36Sopenharmony_ci		((xfs_bmbt_rec_base_t)extent_flag << 63) |
11762306a36Sopenharmony_ci		 ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
11862306a36Sopenharmony_ci		 ((xfs_bmbt_rec_base_t)s->br_startblock >> 43), &r->l0);
11962306a36Sopenharmony_ci	put_unaligned_be64(
12062306a36Sopenharmony_ci		((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
12162306a36Sopenharmony_ci		 ((xfs_bmbt_rec_base_t)s->br_blockcount &
12262306a36Sopenharmony_ci		  (xfs_bmbt_rec_base_t)xfs_mask64lo(21)), &r->l1);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * Convert in-memory form of btree root to on-disk form.
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_civoid
12962306a36Sopenharmony_cixfs_bmbt_to_bmdr(
13062306a36Sopenharmony_ci	struct xfs_mount	*mp,
13162306a36Sopenharmony_ci	struct xfs_btree_block	*rblock,
13262306a36Sopenharmony_ci	int			rblocklen,
13362306a36Sopenharmony_ci	xfs_bmdr_block_t	*dblock,
13462306a36Sopenharmony_ci	int			dblocklen)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	int			dmxr;
13762306a36Sopenharmony_ci	xfs_bmbt_key_t		*fkp;
13862306a36Sopenharmony_ci	__be64			*fpp;
13962306a36Sopenharmony_ci	xfs_bmbt_key_t		*tkp;
14062306a36Sopenharmony_ci	__be64			*tpp;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
14362306a36Sopenharmony_ci		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
14462306a36Sopenharmony_ci		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
14562306a36Sopenharmony_ci		       &mp->m_sb.sb_meta_uuid));
14662306a36Sopenharmony_ci		ASSERT(rblock->bb_u.l.bb_blkno ==
14762306a36Sopenharmony_ci		       cpu_to_be64(XFS_BUF_DADDR_NULL));
14862306a36Sopenharmony_ci	} else
14962306a36Sopenharmony_ci		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC));
15062306a36Sopenharmony_ci	ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK));
15162306a36Sopenharmony_ci	ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK));
15262306a36Sopenharmony_ci	ASSERT(rblock->bb_level != 0);
15362306a36Sopenharmony_ci	dblock->bb_level = rblock->bb_level;
15462306a36Sopenharmony_ci	dblock->bb_numrecs = rblock->bb_numrecs;
15562306a36Sopenharmony_ci	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
15662306a36Sopenharmony_ci	fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
15762306a36Sopenharmony_ci	tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
15862306a36Sopenharmony_ci	fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
15962306a36Sopenharmony_ci	tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
16062306a36Sopenharmony_ci	dmxr = be16_to_cpu(dblock->bb_numrecs);
16162306a36Sopenharmony_ci	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
16262306a36Sopenharmony_ci	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciSTATIC struct xfs_btree_cur *
16662306a36Sopenharmony_cixfs_bmbt_dup_cursor(
16762306a36Sopenharmony_ci	struct xfs_btree_cur	*cur)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct xfs_btree_cur	*new;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp,
17262306a36Sopenharmony_ci			cur->bc_ino.ip, cur->bc_ino.whichfork);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/*
17562306a36Sopenharmony_ci	 * Copy the firstblock, dfops, and flags values,
17662306a36Sopenharmony_ci	 * since init cursor doesn't get them.
17762306a36Sopenharmony_ci	 */
17862306a36Sopenharmony_ci	new->bc_ino.flags = cur->bc_ino.flags;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return new;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ciSTATIC void
18462306a36Sopenharmony_cixfs_bmbt_update_cursor(
18562306a36Sopenharmony_ci	struct xfs_btree_cur	*src,
18662306a36Sopenharmony_ci	struct xfs_btree_cur	*dst)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	ASSERT((dst->bc_tp->t_highest_agno != NULLAGNUMBER) ||
18962306a36Sopenharmony_ci	       (dst->bc_ino.ip->i_diflags & XFS_DIFLAG_REALTIME));
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	dst->bc_ino.allocated += src->bc_ino.allocated;
19262306a36Sopenharmony_ci	dst->bc_tp->t_highest_agno = src->bc_tp->t_highest_agno;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	src->bc_ino.allocated = 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciSTATIC int
19862306a36Sopenharmony_cixfs_bmbt_alloc_block(
19962306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
20062306a36Sopenharmony_ci	const union xfs_btree_ptr	*start,
20162306a36Sopenharmony_ci	union xfs_btree_ptr		*new,
20262306a36Sopenharmony_ci	int				*stat)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct xfs_alloc_arg	args;
20562306a36Sopenharmony_ci	int			error;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
20862306a36Sopenharmony_ci	args.tp = cur->bc_tp;
20962306a36Sopenharmony_ci	args.mp = cur->bc_mp;
21062306a36Sopenharmony_ci	xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_ino.ip->i_ino,
21162306a36Sopenharmony_ci			cur->bc_ino.whichfork);
21262306a36Sopenharmony_ci	args.minlen = args.maxlen = args.prod = 1;
21362306a36Sopenharmony_ci	args.wasdel = cur->bc_ino.flags & XFS_BTCUR_BMBT_WASDEL;
21462306a36Sopenharmony_ci	if (!args.wasdel && args.tp->t_blk_res == 0)
21562306a36Sopenharmony_ci		return -ENOSPC;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/*
21862306a36Sopenharmony_ci	 * If we are coming here from something like unwritten extent
21962306a36Sopenharmony_ci	 * conversion, there has been no data extent allocation already done, so
22062306a36Sopenharmony_ci	 * we have to ensure that we attempt to locate the entire set of bmbt
22162306a36Sopenharmony_ci	 * allocations in the same AG, as xfs_bmapi_write() would have reserved.
22262306a36Sopenharmony_ci	 */
22362306a36Sopenharmony_ci	if (cur->bc_tp->t_highest_agno == NULLAGNUMBER)
22462306a36Sopenharmony_ci		args.minleft = xfs_bmapi_minleft(cur->bc_tp, cur->bc_ino.ip,
22562306a36Sopenharmony_ci					cur->bc_ino.whichfork);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	error = xfs_alloc_vextent_start_ag(&args, be64_to_cpu(start->l));
22862306a36Sopenharmony_ci	if (error)
22962306a36Sopenharmony_ci		return error;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (args.fsbno == NULLFSBLOCK && args.minleft) {
23262306a36Sopenharmony_ci		/*
23362306a36Sopenharmony_ci		 * Could not find an AG with enough free space to satisfy
23462306a36Sopenharmony_ci		 * a full btree split.  Try again and if
23562306a36Sopenharmony_ci		 * successful activate the lowspace algorithm.
23662306a36Sopenharmony_ci		 */
23762306a36Sopenharmony_ci		args.minleft = 0;
23862306a36Sopenharmony_ci		error = xfs_alloc_vextent_start_ag(&args, 0);
23962306a36Sopenharmony_ci		if (error)
24062306a36Sopenharmony_ci			return error;
24162306a36Sopenharmony_ci		cur->bc_tp->t_flags |= XFS_TRANS_LOWMODE;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
24462306a36Sopenharmony_ci		*stat = 0;
24562306a36Sopenharmony_ci		return 0;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ASSERT(args.len == 1);
24962306a36Sopenharmony_ci	cur->bc_ino.allocated++;
25062306a36Sopenharmony_ci	cur->bc_ino.ip->i_nblocks++;
25162306a36Sopenharmony_ci	xfs_trans_log_inode(args.tp, cur->bc_ino.ip, XFS_ILOG_CORE);
25262306a36Sopenharmony_ci	xfs_trans_mod_dquot_byino(args.tp, cur->bc_ino.ip,
25362306a36Sopenharmony_ci			XFS_TRANS_DQ_BCOUNT, 1L);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	new->l = cpu_to_be64(args.fsbno);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	*stat = 1;
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ciSTATIC int
26262306a36Sopenharmony_cixfs_bmbt_free_block(
26362306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
26462306a36Sopenharmony_ci	struct xfs_buf		*bp)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct xfs_mount	*mp = cur->bc_mp;
26762306a36Sopenharmony_ci	struct xfs_inode	*ip = cur->bc_ino.ip;
26862306a36Sopenharmony_ci	struct xfs_trans	*tp = cur->bc_tp;
26962306a36Sopenharmony_ci	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
27062306a36Sopenharmony_ci	struct xfs_owner_info	oinfo;
27162306a36Sopenharmony_ci	int			error;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
27462306a36Sopenharmony_ci	error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo,
27562306a36Sopenharmony_ci			XFS_AG_RESV_NONE);
27662306a36Sopenharmony_ci	if (error)
27762306a36Sopenharmony_ci		return error;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ip->i_nblocks--;
28062306a36Sopenharmony_ci	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
28162306a36Sopenharmony_ci	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
28262306a36Sopenharmony_ci	return 0;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ciSTATIC int
28662306a36Sopenharmony_cixfs_bmbt_get_minrecs(
28762306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
28862306a36Sopenharmony_ci	int			level)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	if (level == cur->bc_nlevels - 1) {
29162306a36Sopenharmony_ci		struct xfs_ifork	*ifp;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		ifp = xfs_ifork_ptr(cur->bc_ino.ip,
29462306a36Sopenharmony_ci				    cur->bc_ino.whichfork);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		return xfs_bmbt_maxrecs(cur->bc_mp,
29762306a36Sopenharmony_ci					ifp->if_broot_bytes, level == 0) / 2;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return cur->bc_mp->m_bmap_dmnr[level != 0];
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ciint
30462306a36Sopenharmony_cixfs_bmbt_get_maxrecs(
30562306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
30662306a36Sopenharmony_ci	int			level)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	if (level == cur->bc_nlevels - 1) {
30962306a36Sopenharmony_ci		struct xfs_ifork	*ifp;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		ifp = xfs_ifork_ptr(cur->bc_ino.ip,
31262306a36Sopenharmony_ci				    cur->bc_ino.whichfork);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		return xfs_bmbt_maxrecs(cur->bc_mp,
31562306a36Sopenharmony_ci					ifp->if_broot_bytes, level == 0);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return cur->bc_mp->m_bmap_dmxr[level != 0];
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/*
32362306a36Sopenharmony_ci * Get the maximum records we could store in the on-disk format.
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but
32662306a36Sopenharmony_ci * for the root node this checks the available space in the dinode fork
32762306a36Sopenharmony_ci * so that we can resize the in-memory buffer to match it.  After a
32862306a36Sopenharmony_ci * resize to the maximum size this function returns the same value
32962306a36Sopenharmony_ci * as xfs_bmbt_get_maxrecs for the root node, too.
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_ciSTATIC int
33262306a36Sopenharmony_cixfs_bmbt_get_dmaxrecs(
33362306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
33462306a36Sopenharmony_ci	int			level)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	if (level != cur->bc_nlevels - 1)
33762306a36Sopenharmony_ci		return cur->bc_mp->m_bmap_dmxr[level != 0];
33862306a36Sopenharmony_ci	return xfs_bmdr_maxrecs(cur->bc_ino.forksize, level == 0);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ciSTATIC void
34262306a36Sopenharmony_cixfs_bmbt_init_key_from_rec(
34362306a36Sopenharmony_ci	union xfs_btree_key		*key,
34462306a36Sopenharmony_ci	const union xfs_btree_rec	*rec)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	key->bmbt.br_startoff =
34762306a36Sopenharmony_ci		cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt));
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciSTATIC void
35162306a36Sopenharmony_cixfs_bmbt_init_high_key_from_rec(
35262306a36Sopenharmony_ci	union xfs_btree_key		*key,
35362306a36Sopenharmony_ci	const union xfs_btree_rec	*rec)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	key->bmbt.br_startoff = cpu_to_be64(
35662306a36Sopenharmony_ci			xfs_bmbt_disk_get_startoff(&rec->bmbt) +
35762306a36Sopenharmony_ci			xfs_bmbt_disk_get_blockcount(&rec->bmbt) - 1);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciSTATIC void
36162306a36Sopenharmony_cixfs_bmbt_init_rec_from_cur(
36262306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
36362306a36Sopenharmony_ci	union xfs_btree_rec	*rec)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ciSTATIC void
36962306a36Sopenharmony_cixfs_bmbt_init_ptr_from_cur(
37062306a36Sopenharmony_ci	struct xfs_btree_cur	*cur,
37162306a36Sopenharmony_ci	union xfs_btree_ptr	*ptr)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	ptr->l = 0;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ciSTATIC int64_t
37762306a36Sopenharmony_cixfs_bmbt_key_diff(
37862306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
37962306a36Sopenharmony_ci	const union xfs_btree_key	*key)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	return (int64_t)be64_to_cpu(key->bmbt.br_startoff) -
38262306a36Sopenharmony_ci				      cur->bc_rec.b.br_startoff;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ciSTATIC int64_t
38662306a36Sopenharmony_cixfs_bmbt_diff_two_keys(
38762306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
38862306a36Sopenharmony_ci	const union xfs_btree_key	*k1,
38962306a36Sopenharmony_ci	const union xfs_btree_key	*k2,
39062306a36Sopenharmony_ci	const union xfs_btree_key	*mask)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	uint64_t			a = be64_to_cpu(k1->bmbt.br_startoff);
39362306a36Sopenharmony_ci	uint64_t			b = be64_to_cpu(k2->bmbt.br_startoff);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	ASSERT(!mask || mask->bmbt.br_startoff);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * Note: This routine previously casted a and b to int64 and subtracted
39962306a36Sopenharmony_ci	 * them to generate a result.  This lead to problems if b was the
40062306a36Sopenharmony_ci	 * "maximum" key value (all ones) being signed incorrectly, hence this
40162306a36Sopenharmony_ci	 * somewhat less efficient version.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	if (a > b)
40462306a36Sopenharmony_ci		return 1;
40562306a36Sopenharmony_ci	if (b > a)
40662306a36Sopenharmony_ci		return -1;
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic xfs_failaddr_t
41162306a36Sopenharmony_cixfs_bmbt_verify(
41262306a36Sopenharmony_ci	struct xfs_buf		*bp)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct xfs_mount	*mp = bp->b_mount;
41562306a36Sopenharmony_ci	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
41662306a36Sopenharmony_ci	xfs_failaddr_t		fa;
41762306a36Sopenharmony_ci	unsigned int		level;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (!xfs_verify_magic(bp, block->bb_magic))
42062306a36Sopenharmony_ci		return __this_address;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
42362306a36Sopenharmony_ci		/*
42462306a36Sopenharmony_ci		 * XXX: need a better way of verifying the owner here. Right now
42562306a36Sopenharmony_ci		 * just make sure there has been one set.
42662306a36Sopenharmony_ci		 */
42762306a36Sopenharmony_ci		fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
42862306a36Sopenharmony_ci		if (fa)
42962306a36Sopenharmony_ci			return fa;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/*
43362306a36Sopenharmony_ci	 * numrecs and level verification.
43462306a36Sopenharmony_ci	 *
43562306a36Sopenharmony_ci	 * We don't know what fork we belong to, so just verify that the level
43662306a36Sopenharmony_ci	 * is less than the maximum of the two. Later checks will be more
43762306a36Sopenharmony_ci	 * precise.
43862306a36Sopenharmony_ci	 */
43962306a36Sopenharmony_ci	level = be16_to_cpu(block->bb_level);
44062306a36Sopenharmony_ci	if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]))
44162306a36Sopenharmony_ci		return __this_address;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return xfs_btree_lblock_verify(bp, mp->m_bmap_dmxr[level != 0]);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic void
44762306a36Sopenharmony_cixfs_bmbt_read_verify(
44862306a36Sopenharmony_ci	struct xfs_buf	*bp)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	xfs_failaddr_t	fa;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!xfs_btree_lblock_verify_crc(bp))
45362306a36Sopenharmony_ci		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
45462306a36Sopenharmony_ci	else {
45562306a36Sopenharmony_ci		fa = xfs_bmbt_verify(bp);
45662306a36Sopenharmony_ci		if (fa)
45762306a36Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (bp->b_error)
46162306a36Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void
46562306a36Sopenharmony_cixfs_bmbt_write_verify(
46662306a36Sopenharmony_ci	struct xfs_buf	*bp)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	xfs_failaddr_t	fa;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	fa = xfs_bmbt_verify(bp);
47162306a36Sopenharmony_ci	if (fa) {
47262306a36Sopenharmony_ci		trace_xfs_btree_corrupt(bp, _RET_IP_);
47362306a36Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
47462306a36Sopenharmony_ci		return;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	xfs_btree_lblock_calc_crc(bp);
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_bmbt_buf_ops = {
48062306a36Sopenharmony_ci	.name = "xfs_bmbt",
48162306a36Sopenharmony_ci	.magic = { cpu_to_be32(XFS_BMAP_MAGIC),
48262306a36Sopenharmony_ci		   cpu_to_be32(XFS_BMAP_CRC_MAGIC) },
48362306a36Sopenharmony_ci	.verify_read = xfs_bmbt_read_verify,
48462306a36Sopenharmony_ci	.verify_write = xfs_bmbt_write_verify,
48562306a36Sopenharmony_ci	.verify_struct = xfs_bmbt_verify,
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ciSTATIC int
49062306a36Sopenharmony_cixfs_bmbt_keys_inorder(
49162306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
49262306a36Sopenharmony_ci	const union xfs_btree_key	*k1,
49362306a36Sopenharmony_ci	const union xfs_btree_key	*k2)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	return be64_to_cpu(k1->bmbt.br_startoff) <
49662306a36Sopenharmony_ci		be64_to_cpu(k2->bmbt.br_startoff);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ciSTATIC int
50062306a36Sopenharmony_cixfs_bmbt_recs_inorder(
50162306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
50262306a36Sopenharmony_ci	const union xfs_btree_rec	*r1,
50362306a36Sopenharmony_ci	const union xfs_btree_rec	*r2)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	return xfs_bmbt_disk_get_startoff(&r1->bmbt) +
50662306a36Sopenharmony_ci		xfs_bmbt_disk_get_blockcount(&r1->bmbt) <=
50762306a36Sopenharmony_ci		xfs_bmbt_disk_get_startoff(&r2->bmbt);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ciSTATIC enum xbtree_key_contig
51162306a36Sopenharmony_cixfs_bmbt_keys_contiguous(
51262306a36Sopenharmony_ci	struct xfs_btree_cur		*cur,
51362306a36Sopenharmony_ci	const union xfs_btree_key	*key1,
51462306a36Sopenharmony_ci	const union xfs_btree_key	*key2,
51562306a36Sopenharmony_ci	const union xfs_btree_key	*mask)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	ASSERT(!mask || mask->bmbt.br_startoff);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return xbtree_key_contig(be64_to_cpu(key1->bmbt.br_startoff),
52062306a36Sopenharmony_ci				 be64_to_cpu(key2->bmbt.br_startoff));
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic const struct xfs_btree_ops xfs_bmbt_ops = {
52462306a36Sopenharmony_ci	.rec_len		= sizeof(xfs_bmbt_rec_t),
52562306a36Sopenharmony_ci	.key_len		= sizeof(xfs_bmbt_key_t),
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	.dup_cursor		= xfs_bmbt_dup_cursor,
52862306a36Sopenharmony_ci	.update_cursor		= xfs_bmbt_update_cursor,
52962306a36Sopenharmony_ci	.alloc_block		= xfs_bmbt_alloc_block,
53062306a36Sopenharmony_ci	.free_block		= xfs_bmbt_free_block,
53162306a36Sopenharmony_ci	.get_maxrecs		= xfs_bmbt_get_maxrecs,
53262306a36Sopenharmony_ci	.get_minrecs		= xfs_bmbt_get_minrecs,
53362306a36Sopenharmony_ci	.get_dmaxrecs		= xfs_bmbt_get_dmaxrecs,
53462306a36Sopenharmony_ci	.init_key_from_rec	= xfs_bmbt_init_key_from_rec,
53562306a36Sopenharmony_ci	.init_high_key_from_rec	= xfs_bmbt_init_high_key_from_rec,
53662306a36Sopenharmony_ci	.init_rec_from_cur	= xfs_bmbt_init_rec_from_cur,
53762306a36Sopenharmony_ci	.init_ptr_from_cur	= xfs_bmbt_init_ptr_from_cur,
53862306a36Sopenharmony_ci	.key_diff		= xfs_bmbt_key_diff,
53962306a36Sopenharmony_ci	.diff_two_keys		= xfs_bmbt_diff_two_keys,
54062306a36Sopenharmony_ci	.buf_ops		= &xfs_bmbt_buf_ops,
54162306a36Sopenharmony_ci	.keys_inorder		= xfs_bmbt_keys_inorder,
54262306a36Sopenharmony_ci	.recs_inorder		= xfs_bmbt_recs_inorder,
54362306a36Sopenharmony_ci	.keys_contiguous	= xfs_bmbt_keys_contiguous,
54462306a36Sopenharmony_ci};
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/*
54762306a36Sopenharmony_ci * Allocate a new bmap btree cursor.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_cistruct xfs_btree_cur *				/* new bmap btree cursor */
55062306a36Sopenharmony_cixfs_bmbt_init_cursor(
55162306a36Sopenharmony_ci	struct xfs_mount	*mp,		/* file system mount point */
55262306a36Sopenharmony_ci	struct xfs_trans	*tp,		/* transaction pointer */
55362306a36Sopenharmony_ci	struct xfs_inode	*ip,		/* inode owning the btree */
55462306a36Sopenharmony_ci	int			whichfork)	/* data or attr fork */
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, whichfork);
55762306a36Sopenharmony_ci	struct xfs_btree_cur	*cur;
55862306a36Sopenharmony_ci	ASSERT(whichfork != XFS_COW_FORK);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_BMAP,
56162306a36Sopenharmony_ci			mp->m_bm_maxlevels[whichfork], xfs_bmbt_cur_cache);
56262306a36Sopenharmony_ci	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
56362306a36Sopenharmony_ci	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	cur->bc_ops = &xfs_bmbt_ops;
56662306a36Sopenharmony_ci	cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
56762306a36Sopenharmony_ci	if (xfs_has_crc(mp))
56862306a36Sopenharmony_ci		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	cur->bc_ino.forksize = xfs_inode_fork_size(ip, whichfork);
57162306a36Sopenharmony_ci	cur->bc_ino.ip = ip;
57262306a36Sopenharmony_ci	cur->bc_ino.allocated = 0;
57362306a36Sopenharmony_ci	cur->bc_ino.flags = 0;
57462306a36Sopenharmony_ci	cur->bc_ino.whichfork = whichfork;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return cur;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci/* Calculate number of records in a block mapping btree block. */
58062306a36Sopenharmony_cistatic inline unsigned int
58162306a36Sopenharmony_cixfs_bmbt_block_maxrecs(
58262306a36Sopenharmony_ci	unsigned int		blocklen,
58362306a36Sopenharmony_ci	bool			leaf)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	if (leaf)
58662306a36Sopenharmony_ci		return blocklen / sizeof(xfs_bmbt_rec_t);
58762306a36Sopenharmony_ci	return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t));
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/*
59162306a36Sopenharmony_ci * Calculate number of records in a bmap btree block.
59262306a36Sopenharmony_ci */
59362306a36Sopenharmony_ciint
59462306a36Sopenharmony_cixfs_bmbt_maxrecs(
59562306a36Sopenharmony_ci	struct xfs_mount	*mp,
59662306a36Sopenharmony_ci	int			blocklen,
59762306a36Sopenharmony_ci	int			leaf)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	blocklen -= XFS_BMBT_BLOCK_LEN(mp);
60062306a36Sopenharmony_ci	return xfs_bmbt_block_maxrecs(blocklen, leaf);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/*
60462306a36Sopenharmony_ci * Calculate the maximum possible height of the btree that the on-disk format
60562306a36Sopenharmony_ci * supports. This is used for sizing structures large enough to support every
60662306a36Sopenharmony_ci * possible configuration of a filesystem that might get mounted.
60762306a36Sopenharmony_ci */
60862306a36Sopenharmony_ciunsigned int
60962306a36Sopenharmony_cixfs_bmbt_maxlevels_ondisk(void)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	unsigned int		minrecs[2];
61262306a36Sopenharmony_ci	unsigned int		blocklen;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN,
61562306a36Sopenharmony_ci		       XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	minrecs[0] = xfs_bmbt_block_maxrecs(blocklen, true) / 2;
61862306a36Sopenharmony_ci	minrecs[1] = xfs_bmbt_block_maxrecs(blocklen, false) / 2;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* One extra level for the inode root. */
62162306a36Sopenharmony_ci	return xfs_btree_compute_maxlevels(minrecs,
62262306a36Sopenharmony_ci			XFS_MAX_EXTCNT_DATA_FORK_LARGE) + 1;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/*
62662306a36Sopenharmony_ci * Calculate number of records in a bmap btree inode root.
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ciint
62962306a36Sopenharmony_cixfs_bmdr_maxrecs(
63062306a36Sopenharmony_ci	int			blocklen,
63162306a36Sopenharmony_ci	int			leaf)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	blocklen -= sizeof(xfs_bmdr_block_t);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (leaf)
63662306a36Sopenharmony_ci		return blocklen / sizeof(xfs_bmdr_rec_t);
63762306a36Sopenharmony_ci	return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/*
64162306a36Sopenharmony_ci * Change the owner of a btree format fork fo the inode passed in. Change it to
64262306a36Sopenharmony_ci * the owner of that is passed in so that we can change owners before or after
64362306a36Sopenharmony_ci * we switch forks between inodes. The operation that the caller is doing will
64462306a36Sopenharmony_ci * determine whether is needs to change owner before or after the switch.
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * For demand paged transactional modification, the fork switch should be done
64762306a36Sopenharmony_ci * after reading in all the blocks, modifying them and pinning them in the
64862306a36Sopenharmony_ci * transaction. For modification when the buffers are already pinned in memory,
64962306a36Sopenharmony_ci * the fork switch can be done before changing the owner as we won't need to
65062306a36Sopenharmony_ci * validate the owner until the btree buffers are unpinned and writes can occur
65162306a36Sopenharmony_ci * again.
65262306a36Sopenharmony_ci *
65362306a36Sopenharmony_ci * For recovery based ownership change, there is no transactional context and
65462306a36Sopenharmony_ci * so a buffer list must be supplied so that we can record the buffers that we
65562306a36Sopenharmony_ci * modified for the caller to issue IO on.
65662306a36Sopenharmony_ci */
65762306a36Sopenharmony_ciint
65862306a36Sopenharmony_cixfs_bmbt_change_owner(
65962306a36Sopenharmony_ci	struct xfs_trans	*tp,
66062306a36Sopenharmony_ci	struct xfs_inode	*ip,
66162306a36Sopenharmony_ci	int			whichfork,
66262306a36Sopenharmony_ci	xfs_ino_t		new_owner,
66362306a36Sopenharmony_ci	struct list_head	*buffer_list)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct xfs_btree_cur	*cur;
66662306a36Sopenharmony_ci	int			error;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	ASSERT(tp || buffer_list);
66962306a36Sopenharmony_ci	ASSERT(!(tp && buffer_list));
67062306a36Sopenharmony_ci	ASSERT(xfs_ifork_ptr(ip, whichfork)->if_format == XFS_DINODE_FMT_BTREE);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
67362306a36Sopenharmony_ci	cur->bc_ino.flags |= XFS_BTCUR_BMBT_INVALID_OWNER;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	error = xfs_btree_change_owner(cur, new_owner, buffer_list);
67662306a36Sopenharmony_ci	xfs_btree_del_cursor(cur, error);
67762306a36Sopenharmony_ci	return error;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/* Calculate the bmap btree size for some records. */
68162306a36Sopenharmony_ciunsigned long long
68262306a36Sopenharmony_cixfs_bmbt_calc_size(
68362306a36Sopenharmony_ci	struct xfs_mount	*mp,
68462306a36Sopenharmony_ci	unsigned long long	len)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	return xfs_btree_calc_size(mp->m_bmap_dmnr, len);
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ciint __init
69062306a36Sopenharmony_cixfs_bmbt_init_cur_cache(void)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	xfs_bmbt_cur_cache = kmem_cache_create("xfs_bmbt_cur",
69362306a36Sopenharmony_ci			xfs_btree_cur_sizeof(xfs_bmbt_maxlevels_ondisk()),
69462306a36Sopenharmony_ci			0, 0, NULL);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (!xfs_bmbt_cur_cache)
69762306a36Sopenharmony_ci		return -ENOMEM;
69862306a36Sopenharmony_ci	return 0;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_civoid
70262306a36Sopenharmony_cixfs_bmbt_destroy_cur_cache(void)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	kmem_cache_destroy(xfs_bmbt_cur_cache);
70562306a36Sopenharmony_ci	xfs_bmbt_cur_cache = NULL;
70662306a36Sopenharmony_ci}
707