10b61f8a4SDave Chinner// SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds/*
37b718769SNathan Scott * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
47b718769SNathan Scott * All Rights Reserved.
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds#include "xfs.h"
7a844f451SNathan Scott#include "xfs_fs.h"
8632b89e8SDave Chinner#include "xfs_shared.h"
96ca1c906SDave Chinner#include "xfs_format.h"
10239880efSDave Chinner#include "xfs_log_format.h"
11239880efSDave Chinner#include "xfs_trans_resv.h"
12a844f451SNathan Scott#include "xfs_bit.h"
131da177e4SLinus Torvalds#include "xfs_mount.h"
141da177e4SLinus Torvalds#include "xfs_inode.h"
15239880efSDave Chinner#include "xfs_trans.h"
161da177e4SLinus Torvalds#include "xfs_alloc.h"
17a844f451SNathan Scott#include "xfs_btree.h"
18a4fbe6abSDave Chinner#include "xfs_bmap_btree.h"
191da177e4SLinus Torvalds#include "xfs_bmap.h"
201da177e4SLinus Torvalds#include "xfs_error.h"
211da177e4SLinus Torvalds#include "xfs_quota.h"
223d3e6f64SDave Chinner#include "xfs_trace.h"
23340785ccSDarrick J. Wong#include "xfs_rmap.h"
241da177e4SLinus Torvalds
25e7720afaSDarrick J. Wongstatic struct kmem_cache	*xfs_bmbt_cur_cache;
269fa47bdcSDarrick J. Wong
271da177e4SLinus Torvalds/*
281da177e4SLinus Torvalds * Convert on-disk form of btree root to in-memory form.
291da177e4SLinus Torvalds */
301da177e4SLinus Torvaldsvoid
311da177e4SLinus Torvaldsxfs_bmdr_to_bmbt(
32ee1a47abSChristoph Hellwig	struct xfs_inode	*ip,
331da177e4SLinus Torvalds	xfs_bmdr_block_t	*dblock,
341da177e4SLinus Torvalds	int			dblocklen,
357cc95a82SChristoph Hellwig	struct xfs_btree_block	*rblock,
361da177e4SLinus Torvalds	int			rblocklen)
371da177e4SLinus Torvalds{
38ee1a47abSChristoph Hellwig	struct xfs_mount	*mp = ip->i_mount;
391da177e4SLinus Torvalds	int			dmxr;
401da177e4SLinus Torvalds	xfs_bmbt_key_t		*fkp;
41576039cfSChristoph Hellwig	__be64			*fpp;
421da177e4SLinus Torvalds	xfs_bmbt_key_t		*tkp;
43576039cfSChristoph Hellwig	__be64			*tpp;
441da177e4SLinus Torvalds
45b6f41e44SEric Sandeen	xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL,
46b6f41e44SEric Sandeen				 XFS_BTNUM_BMAP, 0, 0, ip->i_ino,
47f88ae46bSEric Sandeen				 XFS_BTREE_LONG_PTRS);
4816259e7dSChristoph Hellwig	rblock->bb_level = dblock->bb_level;
4916259e7dSChristoph Hellwig	ASSERT(be16_to_cpu(rblock->bb_level) > 0);
5016259e7dSChristoph Hellwig	rblock->bb_numrecs = dblock->bb_numrecs;
51152d93b7SEric Sandeen	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
52136341b4SChristoph Hellwig	fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
53136341b4SChristoph Hellwig	tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
54136341b4SChristoph Hellwig	fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
5560197e8dSChristoph Hellwig	tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
5616259e7dSChristoph Hellwig	dmxr = be16_to_cpu(dblock->bb_numrecs);
571da177e4SLinus Torvalds	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
58576039cfSChristoph Hellwig	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
591da177e4SLinus Torvalds}
601da177e4SLinus Torvalds
611da177e4SLinus Torvaldsvoid
626bdcf26aSChristoph Hellwigxfs_bmbt_disk_get_all(
6322ece4e8SDarrick J. Wong	const struct xfs_bmbt_rec *rec,
646bdcf26aSChristoph Hellwig	struct xfs_bmbt_irec	*irec)
651da177e4SLinus Torvalds{
666bdcf26aSChristoph Hellwig	uint64_t		l0 = get_unaligned_be64(&rec->l0);
676bdcf26aSChristoph Hellwig	uint64_t		l1 = get_unaligned_be64(&rec->l1);
681da177e4SLinus Torvalds
696bdcf26aSChristoph Hellwig	irec->br_startoff = (l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
706bdcf26aSChristoph Hellwig	irec->br_startblock = ((l0 & xfs_mask64lo(9)) << 43) | (l1 >> 21);
716bdcf26aSChristoph Hellwig	irec->br_blockcount = l1 & xfs_mask64lo(21);
726bdcf26aSChristoph Hellwig	if (l0 >> (64 - BMBT_EXNTFLAG_BITLEN))
736bdcf26aSChristoph Hellwig		irec->br_state = XFS_EXT_UNWRITTEN;
746bdcf26aSChristoph Hellwig	else
756bdcf26aSChristoph Hellwig		irec->br_state = XFS_EXT_NORM;
761da177e4SLinus Torvalds}
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds/*
791da177e4SLinus Torvalds * Extract the blockcount field from an on disk bmap extent record.
801da177e4SLinus Torvalds */
811da177e4SLinus Torvaldsxfs_filblks_t
821da177e4SLinus Torvaldsxfs_bmbt_disk_get_blockcount(
8323825cd1SDarrick J. Wong	const struct xfs_bmbt_rec	*r)
841da177e4SLinus Torvalds{
85fb82557fSEric Sandeen	return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21));
861da177e4SLinus Torvalds}
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds/*
891da177e4SLinus Torvalds * Extract the startoff field from a disk format bmap extent record.
901da177e4SLinus Torvalds */
911da177e4SLinus Torvaldsxfs_fileoff_t
921da177e4SLinus Torvaldsxfs_bmbt_disk_get_startoff(
9323825cd1SDarrick J. Wong	const struct xfs_bmbt_rec	*r)
941da177e4SLinus Torvalds{
95cd8b0a97SChristoph Hellwig	return ((xfs_fileoff_t)be64_to_cpu(r->l0) &
96fb82557fSEric Sandeen		 xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
971da177e4SLinus Torvalds}
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds/*
100a67d00a5SChristoph Hellwig * Set all the fields in a bmap extent record from the uncompressed form.
1011da177e4SLinus Torvalds */
1021da177e4SLinus Torvaldsvoid
103a67d00a5SChristoph Hellwigxfs_bmbt_disk_set_all(
104a67d00a5SChristoph Hellwig	struct xfs_bmbt_rec	*r,
105a67d00a5SChristoph Hellwig	struct xfs_bmbt_irec	*s)
1061da177e4SLinus Torvalds{
107a67d00a5SChristoph Hellwig	int			extent_flag = (s->br_state != XFS_EXT_NORM);
1088cba4344SChristoph Hellwig
109a67d00a5SChristoph Hellwig	ASSERT(s->br_state == XFS_EXT_NORM || s->br_state == XFS_EXT_UNWRITTEN);
110a67d00a5SChristoph Hellwig	ASSERT(!(s->br_startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)));
111a67d00a5SChristoph Hellwig	ASSERT(!(s->br_blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)));
112a67d00a5SChristoph Hellwig	ASSERT(!(s->br_startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)));
1138cba4344SChristoph Hellwig
114135dcc10SChristoph Hellwig	put_unaligned_be64(
1158cba4344SChristoph Hellwig		((xfs_bmbt_rec_base_t)extent_flag << 63) |
116a67d00a5SChristoph Hellwig		 ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
117135dcc10SChristoph Hellwig		 ((xfs_bmbt_rec_base_t)s->br_startblock >> 43), &r->l0);
118135dcc10SChristoph Hellwig	put_unaligned_be64(
119a67d00a5SChristoph Hellwig		((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
120a67d00a5SChristoph Hellwig		 ((xfs_bmbt_rec_base_t)s->br_blockcount &
121135dcc10SChristoph Hellwig		  (xfs_bmbt_rec_base_t)xfs_mask64lo(21)), &r->l1);
1221da177e4SLinus Torvalds}
1238cba4344SChristoph Hellwig
1241da177e4SLinus Torvalds/*
1251da177e4SLinus Torvalds * Convert in-memory form of btree root to on-disk form.
1261da177e4SLinus Torvalds */
1271da177e4SLinus Torvaldsvoid
1281da177e4SLinus Torvaldsxfs_bmbt_to_bmdr(
12960197e8dSChristoph Hellwig	struct xfs_mount	*mp,
1307cc95a82SChristoph Hellwig	struct xfs_btree_block	*rblock,
1311da177e4SLinus Torvalds	int			rblocklen,
1321da177e4SLinus Torvalds	xfs_bmdr_block_t	*dblock,
1331da177e4SLinus Torvalds	int			dblocklen)
1341da177e4SLinus Torvalds{
1351da177e4SLinus Torvalds	int			dmxr;
1361da177e4SLinus Torvalds	xfs_bmbt_key_t		*fkp;
137576039cfSChristoph Hellwig	__be64			*fpp;
1381da177e4SLinus Torvalds	xfs_bmbt_key_t		*tkp;
139576039cfSChristoph Hellwig	__be64			*tpp;
1401da177e4SLinus Torvalds
14138c26bfdSDave Chinner	if (xfs_has_crc(mp)) {
142ee1a47abSChristoph Hellwig		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC));
143ce748eaaSEric Sandeen		ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid,
144ce748eaaSEric Sandeen		       &mp->m_sb.sb_meta_uuid));
145ee1a47abSChristoph Hellwig		ASSERT(rblock->bb_u.l.bb_blkno ==
146ee1a47abSChristoph Hellwig		       cpu_to_be64(XFS_BUF_DADDR_NULL));
147ee1a47abSChristoph Hellwig	} else
148ee1a47abSChristoph Hellwig		ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC));
149d5cf09baSChristoph Hellwig	ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK));
150d5cf09baSChristoph Hellwig	ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK));
15169ef921bSChristoph Hellwig	ASSERT(rblock->bb_level != 0);
15216259e7dSChristoph Hellwig	dblock->bb_level = rblock->bb_level;
15316259e7dSChristoph Hellwig	dblock->bb_numrecs = rblock->bb_numrecs;
154152d93b7SEric Sandeen	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
155136341b4SChristoph Hellwig	fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
156136341b4SChristoph Hellwig	tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
15760197e8dSChristoph Hellwig	fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
158136341b4SChristoph Hellwig	tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
15916259e7dSChristoph Hellwig	dmxr = be16_to_cpu(dblock->bb_numrecs);
1601da177e4SLinus Torvalds	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
161576039cfSChristoph Hellwig	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
1621da177e4SLinus Torvalds}
1631da177e4SLinus Torvalds
164561f7d17SChristoph HellwigSTATIC struct xfs_btree_cur *
165561f7d17SChristoph Hellwigxfs_bmbt_dup_cursor(
166561f7d17SChristoph Hellwig	struct xfs_btree_cur	*cur)
167561f7d17SChristoph Hellwig{
168561f7d17SChristoph Hellwig	struct xfs_btree_cur	*new;
169561f7d17SChristoph Hellwig
170561f7d17SChristoph Hellwig	new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp,
17192219c29SDave Chinner			cur->bc_ino.ip, cur->bc_ino.whichfork);
172561f7d17SChristoph Hellwig
173561f7d17SChristoph Hellwig	/*
1742c3234d1SDarrick J. Wong	 * Copy the firstblock, dfops, and flags values,
175561f7d17SChristoph Hellwig	 * since init cursor doesn't get them.
176561f7d17SChristoph Hellwig	 */
17792219c29SDave Chinner	new->bc_ino.flags = cur->bc_ino.flags;
178561f7d17SChristoph Hellwig
179561f7d17SChristoph Hellwig	return new;
180561f7d17SChristoph Hellwig}
181561f7d17SChristoph Hellwig
1824b22a571SChristoph HellwigSTATIC void
1834b22a571SChristoph Hellwigxfs_bmbt_update_cursor(
1844b22a571SChristoph Hellwig	struct xfs_btree_cur	*src,
1854b22a571SChristoph Hellwig	struct xfs_btree_cur	*dst)
1864b22a571SChristoph Hellwig{
187cf612de7SBrian Foster	ASSERT((dst->bc_tp->t_firstblock != NULLFSBLOCK) ||
188db07349dSChristoph Hellwig	       (dst->bc_ino.ip->i_diflags & XFS_DIFLAG_REALTIME));
1894b22a571SChristoph Hellwig
19092219c29SDave Chinner	dst->bc_ino.allocated += src->bc_ino.allocated;
191cf612de7SBrian Foster	dst->bc_tp->t_firstblock = src->bc_tp->t_firstblock;
1924b22a571SChristoph Hellwig
19392219c29SDave Chinner	src->bc_ino.allocated = 0;
1944b22a571SChristoph Hellwig}
1954b22a571SChristoph Hellwig
196f5eb8e7cSChristoph HellwigSTATIC int
197f5eb8e7cSChristoph Hellwigxfs_bmbt_alloc_block(
198deb06b9aSDarrick J. Wong	struct xfs_btree_cur		*cur,
199deb06b9aSDarrick J. Wong	const union xfs_btree_ptr	*start,
200deb06b9aSDarrick J. Wong	union xfs_btree_ptr		*new,
201deb06b9aSDarrick J. Wong	int				*stat)
202f5eb8e7cSChristoph Hellwig{
203f5eb8e7cSChristoph Hellwig	xfs_alloc_arg_t		args;		/* block allocation args */
204f5eb8e7cSChristoph Hellwig	int			error;		/* error return value */
205f5eb8e7cSChristoph Hellwig
206f5eb8e7cSChristoph Hellwig	memset(&args, 0, sizeof(args));
207f5eb8e7cSChristoph Hellwig	args.tp = cur->bc_tp;
208f5eb8e7cSChristoph Hellwig	args.mp = cur->bc_mp;
209cf612de7SBrian Foster	args.fsbno = cur->bc_tp->t_firstblock;
21092219c29SDave Chinner	xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_ino.ip->i_ino,
21192219c29SDave Chinner			cur->bc_ino.whichfork);
212f5eb8e7cSChristoph Hellwig
213f5eb8e7cSChristoph Hellwig	if (args.fsbno == NULLFSBLOCK) {
214f5eb8e7cSChristoph Hellwig		args.fsbno = be64_to_cpu(start->l);
215f5eb8e7cSChristoph Hellwig		args.type = XFS_ALLOCTYPE_START_BNO;
216f5eb8e7cSChristoph Hellwig		/*
217f5eb8e7cSChristoph Hellwig		 * Make sure there is sufficient room left in the AG to
218f5eb8e7cSChristoph Hellwig		 * complete a full tree split for an extent insert.  If
219f5eb8e7cSChristoph Hellwig		 * we are converting the middle part of an extent then
220f5eb8e7cSChristoph Hellwig		 * we may need space for two tree splits.
221f5eb8e7cSChristoph Hellwig		 *
222f5eb8e7cSChristoph Hellwig		 * We are relying on the caller to make the correct block
223f5eb8e7cSChristoph Hellwig		 * reservation for this operation to succeed.  If the
224f5eb8e7cSChristoph Hellwig		 * reservation amount is insufficient then we may fail a
225f5eb8e7cSChristoph Hellwig		 * block allocation here and corrupt the filesystem.
226f5eb8e7cSChristoph Hellwig		 */
227a7e5d03bSChristoph Hellwig		args.minleft = args.tp->t_blk_res;
2281214f1cfSBrian Foster	} else if (cur->bc_tp->t_flags & XFS_TRANS_LOWMODE) {
229f5eb8e7cSChristoph Hellwig		args.type = XFS_ALLOCTYPE_START_BNO;
230f5eb8e7cSChristoph Hellwig	} else {
231f5eb8e7cSChristoph Hellwig		args.type = XFS_ALLOCTYPE_NEAR_BNO;
232f5eb8e7cSChristoph Hellwig	}
233f5eb8e7cSChristoph Hellwig
234f5eb8e7cSChristoph Hellwig	args.minlen = args.maxlen = args.prod = 1;
2358ef54797SDave Chinner	args.wasdel = cur->bc_ino.flags & XFS_BTCUR_BMBT_WASDEL;
236a7e5d03bSChristoph Hellwig	if (!args.wasdel && args.tp->t_blk_res == 0) {
2372451337dSDave Chinner		error = -ENOSPC;
238f5eb8e7cSChristoph Hellwig		goto error0;
239f5eb8e7cSChristoph Hellwig	}
240f5eb8e7cSChristoph Hellwig	error = xfs_alloc_vextent(&args);
241f5eb8e7cSChristoph Hellwig	if (error)
242f5eb8e7cSChristoph Hellwig		goto error0;
243f5eb8e7cSChristoph Hellwig
244f5eb8e7cSChristoph Hellwig	if (args.fsbno == NULLFSBLOCK && args.minleft) {
245f5eb8e7cSChristoph Hellwig		/*
246f5eb8e7cSChristoph Hellwig		 * Could not find an AG with enough free space to satisfy
247255c5162SChristoph Hellwig		 * a full btree split.  Try again and if
248f5eb8e7cSChristoph Hellwig		 * successful activate the lowspace algorithm.
249f5eb8e7cSChristoph Hellwig		 */
250f5eb8e7cSChristoph Hellwig		args.fsbno = 0;
251f5eb8e7cSChristoph Hellwig		args.type = XFS_ALLOCTYPE_FIRST_AG;
252f5eb8e7cSChristoph Hellwig		error = xfs_alloc_vextent(&args);
253f5eb8e7cSChristoph Hellwig		if (error)
254f5eb8e7cSChristoph Hellwig			goto error0;
2551214f1cfSBrian Foster		cur->bc_tp->t_flags |= XFS_TRANS_LOWMODE;
256f5eb8e7cSChristoph Hellwig	}
2572fcc319dSChristoph Hellwig	if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
258f5eb8e7cSChristoph Hellwig		*stat = 0;
259f5eb8e7cSChristoph Hellwig		return 0;
260f5eb8e7cSChristoph Hellwig	}
261e157ebdcSCarlos Maiolino
262f5eb8e7cSChristoph Hellwig	ASSERT(args.len == 1);
263cf612de7SBrian Foster	cur->bc_tp->t_firstblock = args.fsbno;
26492219c29SDave Chinner	cur->bc_ino.allocated++;
2656e73a545SChristoph Hellwig	cur->bc_ino.ip->i_nblocks++;
26692219c29SDave Chinner	xfs_trans_log_inode(args.tp, cur->bc_ino.ip, XFS_ILOG_CORE);
26792219c29SDave Chinner	xfs_trans_mod_dquot_byino(args.tp, cur->bc_ino.ip,
268f5eb8e7cSChristoph Hellwig			XFS_TRANS_DQ_BCOUNT, 1L);
269f5eb8e7cSChristoph Hellwig
270f5eb8e7cSChristoph Hellwig	new->l = cpu_to_be64(args.fsbno);
271f5eb8e7cSChristoph Hellwig
272f5eb8e7cSChristoph Hellwig	*stat = 1;
273f5eb8e7cSChristoph Hellwig	return 0;
274f5eb8e7cSChristoph Hellwig
275f5eb8e7cSChristoph Hellwig error0:
276f5eb8e7cSChristoph Hellwig	return error;
277f5eb8e7cSChristoph Hellwig}
278f5eb8e7cSChristoph Hellwig
279d4b3a4b7SChristoph HellwigSTATIC int
280d4b3a4b7SChristoph Hellwigxfs_bmbt_free_block(
281d4b3a4b7SChristoph Hellwig	struct xfs_btree_cur	*cur,
282d4b3a4b7SChristoph Hellwig	struct xfs_buf		*bp)
283d4b3a4b7SChristoph Hellwig{
284d4b3a4b7SChristoph Hellwig	struct xfs_mount	*mp = cur->bc_mp;
28592219c29SDave Chinner	struct xfs_inode	*ip = cur->bc_ino.ip;
286d4b3a4b7SChristoph Hellwig	struct xfs_trans	*tp = cur->bc_tp;
28704fcad80SDave Chinner	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
288340785ccSDarrick J. Wong	struct xfs_owner_info	oinfo;
289d4b3a4b7SChristoph Hellwig
29092219c29SDave Chinner	xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
291c201d9caSDarrick J. Wong	xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo);
2926e73a545SChristoph Hellwig	ip->i_nblocks--;
293d4b3a4b7SChristoph Hellwig
294d4b3a4b7SChristoph Hellwig	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
2957d095257SChristoph Hellwig	xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
296d4b3a4b7SChristoph Hellwig	return 0;
297d4b3a4b7SChristoph Hellwig}
298d4b3a4b7SChristoph Hellwig
29991cca5dfSChristoph HellwigSTATIC int
30091cca5dfSChristoph Hellwigxfs_bmbt_get_minrecs(
30191cca5dfSChristoph Hellwig	struct xfs_btree_cur	*cur,
30291cca5dfSChristoph Hellwig	int			level)
30391cca5dfSChristoph Hellwig{
30460197e8dSChristoph Hellwig	if (level == cur->bc_nlevels - 1) {
30560197e8dSChristoph Hellwig		struct xfs_ifork	*ifp;
30660197e8dSChristoph Hellwig
30792219c29SDave Chinner		ifp = XFS_IFORK_PTR(cur->bc_ino.ip,
30892219c29SDave Chinner				    cur->bc_ino.whichfork);
30960197e8dSChristoph Hellwig
31060197e8dSChristoph Hellwig		return xfs_bmbt_maxrecs(cur->bc_mp,
31160197e8dSChristoph Hellwig					ifp->if_broot_bytes, level == 0) / 2;
31260197e8dSChristoph Hellwig	}
31360197e8dSChristoph Hellwig
31460197e8dSChristoph Hellwig	return cur->bc_mp->m_bmap_dmnr[level != 0];
31591cca5dfSChristoph Hellwig}
31691cca5dfSChristoph Hellwig
31760197e8dSChristoph Hellwigint
318ce5e42dbSChristoph Hellwigxfs_bmbt_get_maxrecs(
319ce5e42dbSChristoph Hellwig	struct xfs_btree_cur	*cur,
320ce5e42dbSChristoph Hellwig	int			level)
321ce5e42dbSChristoph Hellwig{
32260197e8dSChristoph Hellwig	if (level == cur->bc_nlevels - 1) {
32360197e8dSChristoph Hellwig		struct xfs_ifork	*ifp;
32460197e8dSChristoph Hellwig
32592219c29SDave Chinner		ifp = XFS_IFORK_PTR(cur->bc_ino.ip,
32692219c29SDave Chinner				    cur->bc_ino.whichfork);
32760197e8dSChristoph Hellwig
32860197e8dSChristoph Hellwig		return xfs_bmbt_maxrecs(cur->bc_mp,
32960197e8dSChristoph Hellwig					ifp->if_broot_bytes, level == 0);
33060197e8dSChristoph Hellwig	}
33160197e8dSChristoph Hellwig
33260197e8dSChristoph Hellwig	return cur->bc_mp->m_bmap_dmxr[level != 0];
33360197e8dSChristoph Hellwig
334ce5e42dbSChristoph Hellwig}
335ce5e42dbSChristoph Hellwig
3364b22a571SChristoph Hellwig/*
3374b22a571SChristoph Hellwig * Get the maximum records we could store in the on-disk format.
3384b22a571SChristoph Hellwig *
3394b22a571SChristoph Hellwig * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but
3404b22a571SChristoph Hellwig * for the root node this checks the available space in the dinode fork
3414b22a571SChristoph Hellwig * so that we can resize the in-memory buffer to match it.  After a
3424b22a571SChristoph Hellwig * resize to the maximum size this function returns the same value
3434b22a571SChristoph Hellwig * as xfs_bmbt_get_maxrecs for the root node, too.
3444b22a571SChristoph Hellwig */
3454b22a571SChristoph HellwigSTATIC int
3464b22a571SChristoph Hellwigxfs_bmbt_get_dmaxrecs(
3474b22a571SChristoph Hellwig	struct xfs_btree_cur	*cur,
3484b22a571SChristoph Hellwig	int			level)
3494b22a571SChristoph Hellwig{
35060197e8dSChristoph Hellwig	if (level != cur->bc_nlevels - 1)
35160197e8dSChristoph Hellwig		return cur->bc_mp->m_bmap_dmxr[level != 0];
35292219c29SDave Chinner	return xfs_bmdr_maxrecs(cur->bc_ino.forksize, level == 0);
3534b22a571SChristoph Hellwig}
3544b22a571SChristoph Hellwig
355fe033cc8SChristoph HellwigSTATIC void
356fe033cc8SChristoph Hellwigxfs_bmbt_init_key_from_rec(
35723825cd1SDarrick J. Wong	union xfs_btree_key		*key,
35823825cd1SDarrick J. Wong	const union xfs_btree_rec	*rec)
359fe033cc8SChristoph Hellwig{
360fe033cc8SChristoph Hellwig	key->bmbt.br_startoff =
361fe033cc8SChristoph Hellwig		cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt));
362fe033cc8SChristoph Hellwig}
363fe033cc8SChristoph Hellwig
364118bb47eSDarrick J. WongSTATIC void
365118bb47eSDarrick J. Wongxfs_bmbt_init_high_key_from_rec(
36623825cd1SDarrick J. Wong	union xfs_btree_key		*key,
36723825cd1SDarrick J. Wong	const union xfs_btree_rec	*rec)
368118bb47eSDarrick J. Wong{
369118bb47eSDarrick J. Wong	key->bmbt.br_startoff = cpu_to_be64(
370118bb47eSDarrick J. Wong			xfs_bmbt_disk_get_startoff(&rec->bmbt) +
371118bb47eSDarrick J. Wong			xfs_bmbt_disk_get_blockcount(&rec->bmbt) - 1);
372118bb47eSDarrick J. Wong}
373118bb47eSDarrick J. Wong
3744b22a571SChristoph HellwigSTATIC void
3754b22a571SChristoph Hellwigxfs_bmbt_init_rec_from_cur(
3764b22a571SChristoph Hellwig	struct xfs_btree_cur	*cur,
3774b22a571SChristoph Hellwig	union xfs_btree_rec	*rec)
3784b22a571SChristoph Hellwig{
3794b22a571SChristoph Hellwig	xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b);
3804b22a571SChristoph Hellwig}
3814b22a571SChristoph Hellwig
382fe033cc8SChristoph HellwigSTATIC void
383fe033cc8SChristoph Hellwigxfs_bmbt_init_ptr_from_cur(
384fe033cc8SChristoph Hellwig	struct xfs_btree_cur	*cur,
385fe033cc8SChristoph Hellwig	union xfs_btree_ptr	*ptr)
386fe033cc8SChristoph Hellwig{
387fe033cc8SChristoph Hellwig	ptr->l = 0;
388fe033cc8SChristoph Hellwig}
389fe033cc8SChristoph Hellwig
390c8ce540dSDarrick J. WongSTATIC int64_t
391fe033cc8SChristoph Hellwigxfs_bmbt_key_diff(
392d29d5577SDarrick J. Wong	struct xfs_btree_cur		*cur,
393d29d5577SDarrick J. Wong	const union xfs_btree_key	*key)
394fe033cc8SChristoph Hellwig{
395c8ce540dSDarrick J. Wong	return (int64_t)be64_to_cpu(key->bmbt.br_startoff) -
396fe033cc8SChristoph Hellwig				      cur->bc_rec.b.br_startoff;
397fe033cc8SChristoph Hellwig}
398fe033cc8SChristoph Hellwig
399118bb47eSDarrick J. WongSTATIC int64_t
400118bb47eSDarrick J. Wongxfs_bmbt_diff_two_keys(
401d29d5577SDarrick J. Wong	struct xfs_btree_cur		*cur,
402d29d5577SDarrick J. Wong	const union xfs_btree_key	*k1,
403d29d5577SDarrick J. Wong	const union xfs_btree_key	*k2)
404118bb47eSDarrick J. Wong{
405d29d5577SDarrick J. Wong	uint64_t			a = be64_to_cpu(k1->bmbt.br_startoff);
406d29d5577SDarrick J. Wong	uint64_t			b = be64_to_cpu(k2->bmbt.br_startoff);
407b521c890SDarrick J. Wong
408b521c890SDarrick J. Wong	/*
409b521c890SDarrick J. Wong	 * Note: This routine previously casted a and b to int64 and subtracted
410b521c890SDarrick J. Wong	 * them to generate a result.  This lead to problems if b was the
411b521c890SDarrick J. Wong	 * "maximum" key value (all ones) being signed incorrectly, hence this
412b521c890SDarrick J. Wong	 * somewhat less efficient version.
413b521c890SDarrick J. Wong	 */
414b521c890SDarrick J. Wong	if (a > b)
415b521c890SDarrick J. Wong		return 1;
416b521c890SDarrick J. Wong	if (b > a)
417b521c890SDarrick J. Wong		return -1;
418b521c890SDarrick J. Wong	return 0;
419118bb47eSDarrick J. Wong}
420118bb47eSDarrick J. Wong
421a6a781a5SDarrick J. Wongstatic xfs_failaddr_t
422612cfbfeSDave Chinnerxfs_bmbt_verify(
4233d3e6f64SDave Chinner	struct xfs_buf		*bp)
4243d3e6f64SDave Chinner{
425dbd329f1SChristoph Hellwig	struct xfs_mount	*mp = bp->b_mount;
4263d3e6f64SDave Chinner	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
427a6a781a5SDarrick J. Wong	xfs_failaddr_t		fa;
4283d3e6f64SDave Chinner	unsigned int		level;
4293d3e6f64SDave Chinner
43039708c20SBrian Foster	if (!xfs_verify_magic(bp, block->bb_magic))
43139708c20SBrian Foster		return __this_address;
43239708c20SBrian Foster
433ebd9027dSDave Chinner	if (xfs_has_crc(mp)) {
434ee1a47abSChristoph Hellwig		/*
435ee1a47abSChristoph Hellwig		 * XXX: need a better way of verifying the owner here. Right now
436ee1a47abSChristoph Hellwig		 * just make sure there has been one set.
437ee1a47abSChristoph Hellwig		 */
438a6a781a5SDarrick J. Wong		fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
439a6a781a5SDarrick J. Wong		if (fa)
440a6a781a5SDarrick J. Wong			return fa;
441ee1a47abSChristoph Hellwig	}
442ee1a47abSChristoph Hellwig
443ee1a47abSChristoph Hellwig	/*
444ee1a47abSChristoph Hellwig	 * numrecs and level verification.
4453d3e6f64SDave Chinner	 *
446ee1a47abSChristoph Hellwig	 * We don't know what fork we belong to, so just verify that the level
4473d3e6f64SDave Chinner	 * is less than the maximum of the two. Later checks will be more
4483d3e6f64SDave Chinner	 * precise.
4493d3e6f64SDave Chinner	 */
4503d3e6f64SDave Chinner	level = be16_to_cpu(block->bb_level);
451ee1a47abSChristoph Hellwig	if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]))
452a6a781a5SDarrick J. Wong		return __this_address;
453ee1a47abSChristoph Hellwig
4548368a601SDarrick J. Wong	return xfs_btree_lblock_verify(bp, mp->m_bmap_dmxr[level != 0]);
455612cfbfeSDave Chinner}
4563d3e6f64SDave Chinner
4571813dd64SDave Chinnerstatic void
4581813dd64SDave Chinnerxfs_bmbt_read_verify(
459612cfbfeSDave Chinner	struct xfs_buf	*bp)
460612cfbfeSDave Chinner{
461bc1a09b8SDarrick J. Wong	xfs_failaddr_t	fa;
462bc1a09b8SDarrick J. Wong
463ce5028cfSEric Sandeen	if (!xfs_btree_lblock_verify_crc(bp))
464bc1a09b8SDarrick J. Wong		xfs_verifier_error(bp, -EFSBADCRC, __this_address);
465bc1a09b8SDarrick J. Wong	else {
466bc1a09b8SDarrick J. Wong		fa = xfs_bmbt_verify(bp);
467bc1a09b8SDarrick J. Wong		if (fa)
468bc1a09b8SDarrick J. Wong			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
469bc1a09b8SDarrick J. Wong	}
470ce5028cfSEric Sandeen
47131ca03c9SDarrick J. Wong	if (bp->b_error)
472ce5028cfSEric Sandeen		trace_xfs_btree_corrupt(bp, _RET_IP_);
473612cfbfeSDave Chinner}
474612cfbfeSDave Chinner
4751813dd64SDave Chinnerstatic void
4761813dd64SDave Chinnerxfs_bmbt_write_verify(
477612cfbfeSDave Chinner	struct xfs_buf	*bp)
478612cfbfeSDave Chinner{
479bc1a09b8SDarrick J. Wong	xfs_failaddr_t	fa;
480bc1a09b8SDarrick J. Wong
481bc1a09b8SDarrick J. Wong	fa = xfs_bmbt_verify(bp);
482bc1a09b8SDarrick J. Wong	if (fa) {
483ee1a47abSChristoph Hellwig		trace_xfs_btree_corrupt(bp, _RET_IP_);
484bc1a09b8SDarrick J. Wong		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
485ee1a47abSChristoph Hellwig		return;
486ee1a47abSChristoph Hellwig	}
487ee1a47abSChristoph Hellwig	xfs_btree_lblock_calc_crc(bp);
4883d3e6f64SDave Chinner}
4893d3e6f64SDave Chinner
4901813dd64SDave Chinnerconst struct xfs_buf_ops xfs_bmbt_buf_ops = {
491233135b7SEric Sandeen	.name = "xfs_bmbt",
49239708c20SBrian Foster	.magic = { cpu_to_be32(XFS_BMAP_MAGIC),
49339708c20SBrian Foster		   cpu_to_be32(XFS_BMAP_CRC_MAGIC) },
4941813dd64SDave Chinner	.verify_read = xfs_bmbt_read_verify,
4951813dd64SDave Chinner	.verify_write = xfs_bmbt_write_verify,
496b5572597SDarrick J. Wong	.verify_struct = xfs_bmbt_verify,
4971813dd64SDave Chinner};
4981813dd64SDave Chinner
4991813dd64SDave Chinner
5004a26e66eSChristoph HellwigSTATIC int
5014a26e66eSChristoph Hellwigxfs_bmbt_keys_inorder(
5028e38dc88SDarrick J. Wong	struct xfs_btree_cur		*cur,
5038e38dc88SDarrick J. Wong	const union xfs_btree_key	*k1,
5048e38dc88SDarrick J. Wong	const union xfs_btree_key	*k2)
5054a26e66eSChristoph Hellwig{
5064a26e66eSChristoph Hellwig	return be64_to_cpu(k1->bmbt.br_startoff) <
5074a26e66eSChristoph Hellwig		be64_to_cpu(k2->bmbt.br_startoff);
5084a26e66eSChristoph Hellwig}
5094a26e66eSChristoph Hellwig
5104a26e66eSChristoph HellwigSTATIC int
5114a26e66eSChristoph Hellwigxfs_bmbt_recs_inorder(
5128e38dc88SDarrick J. Wong	struct xfs_btree_cur		*cur,
5138e38dc88SDarrick J. Wong	const union xfs_btree_rec	*r1,
5148e38dc88SDarrick J. Wong	const union xfs_btree_rec	*r2)
5154a26e66eSChristoph Hellwig{
5164a26e66eSChristoph Hellwig	return xfs_bmbt_disk_get_startoff(&r1->bmbt) +
5174a26e66eSChristoph Hellwig		xfs_bmbt_disk_get_blockcount(&r1->bmbt) <=
5184a26e66eSChristoph Hellwig		xfs_bmbt_disk_get_startoff(&r2->bmbt);
5194a26e66eSChristoph Hellwig}
5204a26e66eSChristoph Hellwig
521561f7d17SChristoph Hellwigstatic const struct xfs_btree_ops xfs_bmbt_ops = {
52265f1eaeaSChristoph Hellwig	.rec_len		= sizeof(xfs_bmbt_rec_t),
52365f1eaeaSChristoph Hellwig	.key_len		= sizeof(xfs_bmbt_key_t),
52465f1eaeaSChristoph Hellwig
525561f7d17SChristoph Hellwig	.dup_cursor		= xfs_bmbt_dup_cursor,
5264b22a571SChristoph Hellwig	.update_cursor		= xfs_bmbt_update_cursor,
527f5eb8e7cSChristoph Hellwig	.alloc_block		= xfs_bmbt_alloc_block,
528d4b3a4b7SChristoph Hellwig	.free_block		= xfs_bmbt_free_block,
529ce5e42dbSChristoph Hellwig	.get_maxrecs		= xfs_bmbt_get_maxrecs,
53091cca5dfSChristoph Hellwig	.get_minrecs		= xfs_bmbt_get_minrecs,
5314b22a571SChristoph Hellwig	.get_dmaxrecs		= xfs_bmbt_get_dmaxrecs,
532fe033cc8SChristoph Hellwig	.init_key_from_rec	= xfs_bmbt_init_key_from_rec,
533118bb47eSDarrick J. Wong	.init_high_key_from_rec	= xfs_bmbt_init_high_key_from_rec,
5344b22a571SChristoph Hellwig	.init_rec_from_cur	= xfs_bmbt_init_rec_from_cur,
535fe033cc8SChristoph Hellwig	.init_ptr_from_cur	= xfs_bmbt_init_ptr_from_cur,
536fe033cc8SChristoph Hellwig	.key_diff		= xfs_bmbt_key_diff,
537118bb47eSDarrick J. Wong	.diff_two_keys		= xfs_bmbt_diff_two_keys,
5381813dd64SDave Chinner	.buf_ops		= &xfs_bmbt_buf_ops,
5394a26e66eSChristoph Hellwig	.keys_inorder		= xfs_bmbt_keys_inorder,
5404a26e66eSChristoph Hellwig	.recs_inorder		= xfs_bmbt_recs_inorder,
541561f7d17SChristoph Hellwig};
542561f7d17SChristoph Hellwig
543561f7d17SChristoph Hellwig/*
544561f7d17SChristoph Hellwig * Allocate a new bmap btree cursor.
545561f7d17SChristoph Hellwig */
546561f7d17SChristoph Hellwigstruct xfs_btree_cur *				/* new bmap btree cursor */
547561f7d17SChristoph Hellwigxfs_bmbt_init_cursor(
548561f7d17SChristoph Hellwig	struct xfs_mount	*mp,		/* file system mount point */
549561f7d17SChristoph Hellwig	struct xfs_trans	*tp,		/* transaction pointer */
550561f7d17SChristoph Hellwig	struct xfs_inode	*ip,		/* inode owning the btree */
551561f7d17SChristoph Hellwig	int			whichfork)	/* data or attr fork */
552561f7d17SChristoph Hellwig{
553561f7d17SChristoph Hellwig	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
554561f7d17SChristoph Hellwig	struct xfs_btree_cur	*cur;
5553993baebSDarrick J. Wong	ASSERT(whichfork != XFS_COW_FORK);
556561f7d17SChristoph Hellwig
557c940a0c5SDarrick J. Wong	cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_BMAP,
5589fa47bdcSDarrick J. Wong			mp->m_bm_maxlevels[whichfork], xfs_bmbt_cur_cache);
559561f7d17SChristoph Hellwig	cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
56011ef38afSDave Chinner	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_bmbt_2);
561561f7d17SChristoph Hellwig
562561f7d17SChristoph Hellwig	cur->bc_ops = &xfs_bmbt_ops;
563e99ab90dSChristoph Hellwig	cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
56438c26bfdSDave Chinner	if (xfs_has_crc(mp))
565ee1a47abSChristoph Hellwig		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
566561f7d17SChristoph Hellwig
56792219c29SDave Chinner	cur->bc_ino.forksize = XFS_IFORK_SIZE(ip, whichfork);
56892219c29SDave Chinner	cur->bc_ino.ip = ip;
56992219c29SDave Chinner	cur->bc_ino.allocated = 0;
57092219c29SDave Chinner	cur->bc_ino.flags = 0;
57192219c29SDave Chinner	cur->bc_ino.whichfork = whichfork;
572561f7d17SChristoph Hellwig
573561f7d17SChristoph Hellwig	return cur;
574561f7d17SChristoph Hellwig}
57560197e8dSChristoph Hellwig
5760ed5f735SDarrick J. Wong/* Calculate number of records in a block mapping btree block. */
5770ed5f735SDarrick J. Wongstatic inline unsigned int
5780ed5f735SDarrick J. Wongxfs_bmbt_block_maxrecs(
5790ed5f735SDarrick J. Wong	unsigned int		blocklen,
5800ed5f735SDarrick J. Wong	bool			leaf)
5810ed5f735SDarrick J. Wong{
5820ed5f735SDarrick J. Wong	if (leaf)
5830ed5f735SDarrick J. Wong		return blocklen / sizeof(xfs_bmbt_rec_t);
5840ed5f735SDarrick J. Wong	return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t));
5850ed5f735SDarrick J. Wong}
5860ed5f735SDarrick J. Wong
58760197e8dSChristoph Hellwig/*
58860197e8dSChristoph Hellwig * Calculate number of records in a bmap btree block.
58960197e8dSChristoph Hellwig */
59060197e8dSChristoph Hellwigint
59160197e8dSChristoph Hellwigxfs_bmbt_maxrecs(
59260197e8dSChristoph Hellwig	struct xfs_mount	*mp,
59360197e8dSChristoph Hellwig	int			blocklen,
59460197e8dSChristoph Hellwig	int			leaf)
59560197e8dSChristoph Hellwig{
5967cc95a82SChristoph Hellwig	blocklen -= XFS_BMBT_BLOCK_LEN(mp);
5970ed5f735SDarrick J. Wong	return xfs_bmbt_block_maxrecs(blocklen, leaf);
5980ed5f735SDarrick J. Wong}
59960197e8dSChristoph Hellwig
6000ed5f735SDarrick J. Wong/* Compute the max possible height for block mapping btrees. */
6010ed5f735SDarrick J. Wongunsigned int
6020ed5f735SDarrick J. Wongxfs_bmbt_maxlevels_ondisk(void)
6030ed5f735SDarrick J. Wong{
6040ed5f735SDarrick J. Wong	unsigned int		minrecs[2];
6050ed5f735SDarrick J. Wong	unsigned int		blocklen;
6060ed5f735SDarrick J. Wong
6070ed5f735SDarrick J. Wong	blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN,
6080ed5f735SDarrick J. Wong		       XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN);
6090ed5f735SDarrick J. Wong
6100ed5f735SDarrick J. Wong	minrecs[0] = xfs_bmbt_block_maxrecs(blocklen, true) / 2;
6110ed5f735SDarrick J. Wong	minrecs[1] = xfs_bmbt_block_maxrecs(blocklen, false) / 2;
6120ed5f735SDarrick J. Wong
6130ed5f735SDarrick J. Wong	/* One extra level for the inode root. */
6140ed5f735SDarrick J. Wong	return xfs_btree_compute_maxlevels(minrecs, MAXEXTNUM) + 1;
61560197e8dSChristoph Hellwig}
61660197e8dSChristoph Hellwig
61760197e8dSChristoph Hellwig/*
61860197e8dSChristoph Hellwig * Calculate number of records in a bmap btree inode root.
61960197e8dSChristoph Hellwig */
62060197e8dSChristoph Hellwigint
62160197e8dSChristoph Hellwigxfs_bmdr_maxrecs(
62260197e8dSChristoph Hellwig	int			blocklen,
62360197e8dSChristoph Hellwig	int			leaf)
62460197e8dSChristoph Hellwig{
62560197e8dSChristoph Hellwig	blocklen -= sizeof(xfs_bmdr_block_t);
62660197e8dSChristoph Hellwig
62760197e8dSChristoph Hellwig	if (leaf)
62860197e8dSChristoph Hellwig		return blocklen / sizeof(xfs_bmdr_rec_t);
62960197e8dSChristoph Hellwig	return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
63060197e8dSChristoph Hellwig}
63121b5c978SDave Chinner
63221b5c978SDave Chinner/*
63321b5c978SDave Chinner * Change the owner of a btree format fork fo the inode passed in. Change it to
63421b5c978SDave Chinner * the owner of that is passed in so that we can change owners before or after
63521b5c978SDave Chinner * we switch forks between inodes. The operation that the caller is doing will
63621b5c978SDave Chinner * determine whether is needs to change owner before or after the switch.
63721b5c978SDave Chinner *
638638f4416SDave Chinner * For demand paged transactional modification, the fork switch should be done
639638f4416SDave Chinner * after reading in all the blocks, modifying them and pinning them in the
640638f4416SDave Chinner * transaction. For modification when the buffers are already pinned in memory,
641638f4416SDave Chinner * the fork switch can be done before changing the owner as we won't need to
642638f4416SDave Chinner * validate the owner until the btree buffers are unpinned and writes can occur
643638f4416SDave Chinner * again.
644638f4416SDave Chinner *
645638f4416SDave Chinner * For recovery based ownership change, there is no transactional context and
646638f4416SDave Chinner * so a buffer list must be supplied so that we can record the buffers that we
647638f4416SDave Chinner * modified for the caller to issue IO on.
64821b5c978SDave Chinner */
64921b5c978SDave Chinnerint
65021b5c978SDave Chinnerxfs_bmbt_change_owner(
65121b5c978SDave Chinner	struct xfs_trans	*tp,
65221b5c978SDave Chinner	struct xfs_inode	*ip,
65321b5c978SDave Chinner	int			whichfork,
654638f4416SDave Chinner	xfs_ino_t		new_owner,
655638f4416SDave Chinner	struct list_head	*buffer_list)
65621b5c978SDave Chinner{
65721b5c978SDave Chinner	struct xfs_btree_cur	*cur;
65821b5c978SDave Chinner	int			error;
65921b5c978SDave Chinner
660638f4416SDave Chinner	ASSERT(tp || buffer_list);
661638f4416SDave Chinner	ASSERT(!(tp && buffer_list));
662f7e67b20SChristoph Hellwig	ASSERT(XFS_IFORK_PTR(ip, whichfork)->if_format == XFS_DINODE_FMT_BTREE);
66321b5c978SDave Chinner
66421b5c978SDave Chinner	cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
6658ef54797SDave Chinner	cur->bc_ino.flags |= XFS_BTCUR_BMBT_INVALID_OWNER;
666638f4416SDave Chinner
667638f4416SDave Chinner	error = xfs_btree_change_owner(cur, new_owner, buffer_list);
6680b04b6b8SDarrick J. Wong	xfs_btree_del_cursor(cur, error);
66921b5c978SDave Chinner	return error;
67021b5c978SDave Chinner}
67114861c47SDarrick J. Wong
67214861c47SDarrick J. Wong/* Calculate the bmap btree size for some records. */
67314861c47SDarrick J. Wongunsigned long long
67414861c47SDarrick J. Wongxfs_bmbt_calc_size(
67514861c47SDarrick J. Wong	struct xfs_mount	*mp,
67614861c47SDarrick J. Wong	unsigned long long	len)
67714861c47SDarrick J. Wong{
67814861c47SDarrick J. Wong	return xfs_btree_calc_size(mp->m_bmap_dmnr, len);
67914861c47SDarrick J. Wong}
6809fa47bdcSDarrick J. Wong
6819fa47bdcSDarrick J. Wongint __init
6829fa47bdcSDarrick J. Wongxfs_bmbt_init_cur_cache(void)
6839fa47bdcSDarrick J. Wong{
6849fa47bdcSDarrick J. Wong	xfs_bmbt_cur_cache = kmem_cache_create("xfs_bmbt_cur",
6859fa47bdcSDarrick J. Wong			xfs_btree_cur_sizeof(xfs_bmbt_maxlevels_ondisk()),
6869fa47bdcSDarrick J. Wong			0, 0, NULL);
6879fa47bdcSDarrick J. Wong
6889fa47bdcSDarrick J. Wong	if (!xfs_bmbt_cur_cache)
6899fa47bdcSDarrick J. Wong		return -ENOMEM;
6909fa47bdcSDarrick J. Wong	return 0;
6919fa47bdcSDarrick J. Wong}
6929fa47bdcSDarrick J. Wong
6939fa47bdcSDarrick J. Wongvoid
6949fa47bdcSDarrick J. Wongxfs_bmbt_destroy_cur_cache(void)
6959fa47bdcSDarrick J. Wong{
6969fa47bdcSDarrick J. Wong	kmem_cache_destroy(xfs_bmbt_cur_cache);
6979fa47bdcSDarrick J. Wong	xfs_bmbt_cur_cache = NULL;
6989fa47bdcSDarrick J. Wong}
699