18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2017 Christoph Hellwig.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_shared.h"
88c2ecf20Sopenharmony_ci#include "xfs_format.h"
98c2ecf20Sopenharmony_ci#include "xfs_bit.h"
108c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
118c2ecf20Sopenharmony_ci#include "xfs_inode.h"
128c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
138c2ecf20Sopenharmony_ci#include "xfs_mount.h"
148c2ecf20Sopenharmony_ci#include "xfs_trace.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/*
178c2ecf20Sopenharmony_ci * In-core extent record layout:
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * +-------+----------------------------+
208c2ecf20Sopenharmony_ci * | 00:53 | all 54 bits of startoff    |
218c2ecf20Sopenharmony_ci * | 54:63 | low 10 bits of startblock  |
228c2ecf20Sopenharmony_ci * +-------+----------------------------+
238c2ecf20Sopenharmony_ci * | 00:20 | all 21 bits of length      |
248c2ecf20Sopenharmony_ci * |    21 | unwritten extent bit       |
258c2ecf20Sopenharmony_ci * | 22:63 | high 42 bits of startblock |
268c2ecf20Sopenharmony_ci * +-------+----------------------------+
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#define XFS_IEXT_STARTOFF_MASK		xfs_mask64lo(BMBT_STARTOFF_BITLEN)
298c2ecf20Sopenharmony_ci#define XFS_IEXT_LENGTH_MASK		xfs_mask64lo(BMBT_BLOCKCOUNT_BITLEN)
308c2ecf20Sopenharmony_ci#define XFS_IEXT_STARTBLOCK_MASK	xfs_mask64lo(BMBT_STARTBLOCK_BITLEN)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct xfs_iext_rec {
338c2ecf20Sopenharmony_ci	uint64_t			lo;
348c2ecf20Sopenharmony_ci	uint64_t			hi;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/*
388c2ecf20Sopenharmony_ci * Given that the length can't be a zero, only an empty hi value indicates an
398c2ecf20Sopenharmony_ci * unused record.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_cistatic bool xfs_iext_rec_is_empty(struct xfs_iext_rec *rec)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return rec->hi == 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic inline void xfs_iext_rec_clear(struct xfs_iext_rec *rec)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	rec->lo = 0;
498c2ecf20Sopenharmony_ci	rec->hi = 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void
538c2ecf20Sopenharmony_cixfs_iext_set(
548c2ecf20Sopenharmony_ci	struct xfs_iext_rec	*rec,
558c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*irec)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	ASSERT((irec->br_startoff & ~XFS_IEXT_STARTOFF_MASK) == 0);
588c2ecf20Sopenharmony_ci	ASSERT((irec->br_blockcount & ~XFS_IEXT_LENGTH_MASK) == 0);
598c2ecf20Sopenharmony_ci	ASSERT((irec->br_startblock & ~XFS_IEXT_STARTBLOCK_MASK) == 0);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	rec->lo = irec->br_startoff & XFS_IEXT_STARTOFF_MASK;
628c2ecf20Sopenharmony_ci	rec->hi = irec->br_blockcount & XFS_IEXT_LENGTH_MASK;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	rec->lo |= (irec->br_startblock << 54);
658c2ecf20Sopenharmony_ci	rec->hi |= ((irec->br_startblock & ~xfs_mask64lo(10)) << (22 - 10));
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (irec->br_state == XFS_EXT_UNWRITTEN)
688c2ecf20Sopenharmony_ci		rec->hi |= (1 << 21);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void
728c2ecf20Sopenharmony_cixfs_iext_get(
738c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*irec,
748c2ecf20Sopenharmony_ci	struct xfs_iext_rec	*rec)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	irec->br_startoff = rec->lo & XFS_IEXT_STARTOFF_MASK;
778c2ecf20Sopenharmony_ci	irec->br_blockcount = rec->hi & XFS_IEXT_LENGTH_MASK;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	irec->br_startblock = rec->lo >> 54;
808c2ecf20Sopenharmony_ci	irec->br_startblock |= (rec->hi & xfs_mask64hi(42)) >> (22 - 10);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (rec->hi & (1 << 21))
838c2ecf20Sopenharmony_ci		irec->br_state = XFS_EXT_UNWRITTEN;
848c2ecf20Sopenharmony_ci	else
858c2ecf20Sopenharmony_ci		irec->br_state = XFS_EXT_NORM;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum {
898c2ecf20Sopenharmony_ci	NODE_SIZE	= 256,
908c2ecf20Sopenharmony_ci	KEYS_PER_NODE	= NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)),
918c2ecf20Sopenharmony_ci	RECS_PER_LEAF	= (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) /
928c2ecf20Sopenharmony_ci				sizeof(struct xfs_iext_rec),
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/*
968c2ecf20Sopenharmony_ci * In-core extent btree block layout:
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * There are two types of blocks in the btree: leaf and inner (non-leaf) blocks.
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * The leaf blocks are made up by %KEYS_PER_NODE extent records, which each
1018c2ecf20Sopenharmony_ci * contain the startoffset, blockcount, startblock and unwritten extent flag.
1028c2ecf20Sopenharmony_ci * See above for the exact format, followed by pointers to the previous and next
1038c2ecf20Sopenharmony_ci * leaf blocks (if there are any).
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci * The inner (non-leaf) blocks first contain KEYS_PER_NODE lookup keys, followed
1068c2ecf20Sopenharmony_ci * by an equal number of pointers to the btree blocks at the next lower level.
1078c2ecf20Sopenharmony_ci *
1088c2ecf20Sopenharmony_ci *		+-------+-------+-------+-------+-------+----------+----------+
1098c2ecf20Sopenharmony_ci * Leaf:	| rec 1 | rec 2 | rec 3 | rec 4 | rec N | prev-ptr | next-ptr |
1108c2ecf20Sopenharmony_ci *		+-------+-------+-------+-------+-------+----------+----------+
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci *		+-------+-------+-------+-------+-------+-------+------+-------+
1138c2ecf20Sopenharmony_ci * Inner:	| key 1 | key 2 | key 3 | key N | ptr 1 | ptr 2 | ptr3 | ptr N |
1148c2ecf20Sopenharmony_ci *		+-------+-------+-------+-------+-------+-------+------+-------+
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistruct xfs_iext_node {
1178c2ecf20Sopenharmony_ci	uint64_t		keys[KEYS_PER_NODE];
1188c2ecf20Sopenharmony_ci#define XFS_IEXT_KEY_INVALID	(1ULL << 63)
1198c2ecf20Sopenharmony_ci	void			*ptrs[KEYS_PER_NODE];
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistruct xfs_iext_leaf {
1238c2ecf20Sopenharmony_ci	struct xfs_iext_rec	recs[RECS_PER_LEAF];
1248c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*prev;
1258c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*next;
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ciinline xfs_extnum_t xfs_iext_count(struct xfs_ifork *ifp)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	return ifp->if_bytes / sizeof(struct xfs_iext_rec);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic inline int xfs_iext_max_recs(struct xfs_ifork *ifp)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	if (ifp->if_height == 1)
1368c2ecf20Sopenharmony_ci		return xfs_iext_count(ifp);
1378c2ecf20Sopenharmony_ci	return RECS_PER_LEAF;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline struct xfs_iext_rec *cur_rec(struct xfs_iext_cursor *cur)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	return &cur->leaf->recs[cur->pos];
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic inline bool xfs_iext_valid(struct xfs_ifork *ifp,
1468c2ecf20Sopenharmony_ci		struct xfs_iext_cursor *cur)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	if (!cur->leaf)
1498c2ecf20Sopenharmony_ci		return false;
1508c2ecf20Sopenharmony_ci	if (cur->pos < 0 || cur->pos >= xfs_iext_max_recs(ifp))
1518c2ecf20Sopenharmony_ci		return false;
1528c2ecf20Sopenharmony_ci	if (xfs_iext_rec_is_empty(cur_rec(cur)))
1538c2ecf20Sopenharmony_ci		return false;
1548c2ecf20Sopenharmony_ci	return true;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic void *
1588c2ecf20Sopenharmony_cixfs_iext_find_first_leaf(
1598c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = ifp->if_u1.if_root;
1628c2ecf20Sopenharmony_ci	int			height;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (!ifp->if_height)
1658c2ecf20Sopenharmony_ci		return NULL;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (height = ifp->if_height; height > 1; height--) {
1688c2ecf20Sopenharmony_ci		node = node->ptrs[0];
1698c2ecf20Sopenharmony_ci		ASSERT(node);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return node;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void *
1768c2ecf20Sopenharmony_cixfs_iext_find_last_leaf(
1778c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = ifp->if_u1.if_root;
1808c2ecf20Sopenharmony_ci	int			height, i;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (!ifp->if_height)
1838c2ecf20Sopenharmony_ci		return NULL;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	for (height = ifp->if_height; height > 1; height--) {
1868c2ecf20Sopenharmony_ci		for (i = 1; i < KEYS_PER_NODE; i++)
1878c2ecf20Sopenharmony_ci			if (!node->ptrs[i])
1888c2ecf20Sopenharmony_ci				break;
1898c2ecf20Sopenharmony_ci		node = node->ptrs[i - 1];
1908c2ecf20Sopenharmony_ci		ASSERT(node);
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return node;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_civoid
1978c2ecf20Sopenharmony_cixfs_iext_first(
1988c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
1998c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	cur->pos = 0;
2028c2ecf20Sopenharmony_ci	cur->leaf = xfs_iext_find_first_leaf(ifp);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_civoid
2068c2ecf20Sopenharmony_cixfs_iext_last(
2078c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
2088c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	int			i;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	cur->leaf = xfs_iext_find_last_leaf(ifp);
2138c2ecf20Sopenharmony_ci	if (!cur->leaf) {
2148c2ecf20Sopenharmony_ci		cur->pos = 0;
2158c2ecf20Sopenharmony_ci		return;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	for (i = 1; i < xfs_iext_max_recs(ifp); i++) {
2198c2ecf20Sopenharmony_ci		if (xfs_iext_rec_is_empty(&cur->leaf->recs[i]))
2208c2ecf20Sopenharmony_ci			break;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	cur->pos = i - 1;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_civoid
2268c2ecf20Sopenharmony_cixfs_iext_next(
2278c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
2288c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	if (!cur->leaf) {
2318c2ecf20Sopenharmony_ci		ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF);
2328c2ecf20Sopenharmony_ci		xfs_iext_first(ifp, cur);
2338c2ecf20Sopenharmony_ci		return;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	ASSERT(cur->pos >= 0);
2378c2ecf20Sopenharmony_ci	ASSERT(cur->pos < xfs_iext_max_recs(ifp));
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	cur->pos++;
2408c2ecf20Sopenharmony_ci	if (ifp->if_height > 1 && !xfs_iext_valid(ifp, cur) &&
2418c2ecf20Sopenharmony_ci	    cur->leaf->next) {
2428c2ecf20Sopenharmony_ci		cur->leaf = cur->leaf->next;
2438c2ecf20Sopenharmony_ci		cur->pos = 0;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_civoid
2488c2ecf20Sopenharmony_cixfs_iext_prev(
2498c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
2508c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	if (!cur->leaf) {
2538c2ecf20Sopenharmony_ci		ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF);
2548c2ecf20Sopenharmony_ci		xfs_iext_last(ifp, cur);
2558c2ecf20Sopenharmony_ci		return;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ASSERT(cur->pos >= 0);
2598c2ecf20Sopenharmony_ci	ASSERT(cur->pos <= RECS_PER_LEAF);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cirecurse:
2628c2ecf20Sopenharmony_ci	do {
2638c2ecf20Sopenharmony_ci		cur->pos--;
2648c2ecf20Sopenharmony_ci		if (xfs_iext_valid(ifp, cur))
2658c2ecf20Sopenharmony_ci			return;
2668c2ecf20Sopenharmony_ci	} while (cur->pos > 0);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (ifp->if_height > 1 && cur->leaf->prev) {
2698c2ecf20Sopenharmony_ci		cur->leaf = cur->leaf->prev;
2708c2ecf20Sopenharmony_ci		cur->pos = RECS_PER_LEAF;
2718c2ecf20Sopenharmony_ci		goto recurse;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic inline int
2768c2ecf20Sopenharmony_cixfs_iext_key_cmp(
2778c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
2788c2ecf20Sopenharmony_ci	int			n,
2798c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	if (node->keys[n] > offset)
2828c2ecf20Sopenharmony_ci		return 1;
2838c2ecf20Sopenharmony_ci	if (node->keys[n] < offset)
2848c2ecf20Sopenharmony_ci		return -1;
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic inline int
2898c2ecf20Sopenharmony_cixfs_iext_rec_cmp(
2908c2ecf20Sopenharmony_ci	struct xfs_iext_rec	*rec,
2918c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	uint64_t		rec_offset = rec->lo & XFS_IEXT_STARTOFF_MASK;
2948c2ecf20Sopenharmony_ci	uint32_t		rec_len = rec->hi & XFS_IEXT_LENGTH_MASK;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (rec_offset > offset)
2978c2ecf20Sopenharmony_ci		return 1;
2988c2ecf20Sopenharmony_ci	if (rec_offset + rec_len <= offset)
2998c2ecf20Sopenharmony_ci		return -1;
3008c2ecf20Sopenharmony_ci	return 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic void *
3048c2ecf20Sopenharmony_cixfs_iext_find_level(
3058c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
3068c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset,
3078c2ecf20Sopenharmony_ci	int			level)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = ifp->if_u1.if_root;
3108c2ecf20Sopenharmony_ci	int			height, i;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (!ifp->if_height)
3138c2ecf20Sopenharmony_ci		return NULL;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	for (height = ifp->if_height; height > level; height--) {
3168c2ecf20Sopenharmony_ci		for (i = 1; i < KEYS_PER_NODE; i++)
3178c2ecf20Sopenharmony_ci			if (xfs_iext_key_cmp(node, i, offset) > 0)
3188c2ecf20Sopenharmony_ci				break;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		node = node->ptrs[i - 1];
3218c2ecf20Sopenharmony_ci		if (!node)
3228c2ecf20Sopenharmony_ci			break;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return node;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int
3298c2ecf20Sopenharmony_cixfs_iext_node_pos(
3308c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
3318c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	int			i;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	for (i = 1; i < KEYS_PER_NODE; i++) {
3368c2ecf20Sopenharmony_ci		if (xfs_iext_key_cmp(node, i, offset) > 0)
3378c2ecf20Sopenharmony_ci			break;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return i - 1;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int
3448c2ecf20Sopenharmony_cixfs_iext_node_insert_pos(
3458c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
3468c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	int			i;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	for (i = 0; i < KEYS_PER_NODE; i++) {
3518c2ecf20Sopenharmony_ci		if (xfs_iext_key_cmp(node, i, offset) > 0)
3528c2ecf20Sopenharmony_ci			return i;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return KEYS_PER_NODE;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int
3598c2ecf20Sopenharmony_cixfs_iext_node_nr_entries(
3608c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
3618c2ecf20Sopenharmony_ci	int			start)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	int			i;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	for (i = start; i < KEYS_PER_NODE; i++) {
3668c2ecf20Sopenharmony_ci		if (node->keys[i] == XFS_IEXT_KEY_INVALID)
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return i;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int
3748c2ecf20Sopenharmony_cixfs_iext_leaf_nr_entries(
3758c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
3768c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*leaf,
3778c2ecf20Sopenharmony_ci	int			start)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	int			i;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	for (i = start; i < xfs_iext_max_recs(ifp); i++) {
3828c2ecf20Sopenharmony_ci		if (xfs_iext_rec_is_empty(&leaf->recs[i]))
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return i;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic inline uint64_t
3908c2ecf20Sopenharmony_cixfs_iext_leaf_key(
3918c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*leaf,
3928c2ecf20Sopenharmony_ci	int			n)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	return leaf->recs[n].lo & XFS_IEXT_STARTOFF_MASK;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void
3988c2ecf20Sopenharmony_cixfs_iext_grow(
3998c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = kmem_zalloc(NODE_SIZE, KM_NOFS);
4028c2ecf20Sopenharmony_ci	int			i;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (ifp->if_height == 1) {
4058c2ecf20Sopenharmony_ci		struct xfs_iext_leaf *prev = ifp->if_u1.if_root;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		node->keys[0] = xfs_iext_leaf_key(prev, 0);
4088c2ecf20Sopenharmony_ci		node->ptrs[0] = prev;
4098c2ecf20Sopenharmony_ci	} else  {
4108c2ecf20Sopenharmony_ci		struct xfs_iext_node *prev = ifp->if_u1.if_root;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		ASSERT(ifp->if_height > 1);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		node->keys[0] = prev->keys[0];
4158c2ecf20Sopenharmony_ci		node->ptrs[0] = prev;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	for (i = 1; i < KEYS_PER_NODE; i++)
4198c2ecf20Sopenharmony_ci		node->keys[i] = XFS_IEXT_KEY_INVALID;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	ifp->if_u1.if_root = node;
4228c2ecf20Sopenharmony_ci	ifp->if_height++;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void
4268c2ecf20Sopenharmony_cixfs_iext_update_node(
4278c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
4288c2ecf20Sopenharmony_ci	xfs_fileoff_t		old_offset,
4298c2ecf20Sopenharmony_ci	xfs_fileoff_t		new_offset,
4308c2ecf20Sopenharmony_ci	int			level,
4318c2ecf20Sopenharmony_ci	void			*ptr)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = ifp->if_u1.if_root;
4348c2ecf20Sopenharmony_ci	int			height, i;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	for (height = ifp->if_height; height > level; height--) {
4378c2ecf20Sopenharmony_ci		for (i = 0; i < KEYS_PER_NODE; i++) {
4388c2ecf20Sopenharmony_ci			if (i > 0 && xfs_iext_key_cmp(node, i, old_offset) > 0)
4398c2ecf20Sopenharmony_ci				break;
4408c2ecf20Sopenharmony_ci			if (node->keys[i] == old_offset)
4418c2ecf20Sopenharmony_ci				node->keys[i] = new_offset;
4428c2ecf20Sopenharmony_ci		}
4438c2ecf20Sopenharmony_ci		node = node->ptrs[i - 1];
4448c2ecf20Sopenharmony_ci		ASSERT(node);
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	ASSERT(node == ptr);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic struct xfs_iext_node *
4518c2ecf20Sopenharmony_cixfs_iext_split_node(
4528c2ecf20Sopenharmony_ci	struct xfs_iext_node	**nodep,
4538c2ecf20Sopenharmony_ci	int			*pos,
4548c2ecf20Sopenharmony_ci	int			*nr_entries)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node = *nodep;
4578c2ecf20Sopenharmony_ci	struct xfs_iext_node	*new = kmem_zalloc(NODE_SIZE, KM_NOFS);
4588c2ecf20Sopenharmony_ci	const int		nr_move = KEYS_PER_NODE / 2;
4598c2ecf20Sopenharmony_ci	int			nr_keep = nr_move + (KEYS_PER_NODE & 1);
4608c2ecf20Sopenharmony_ci	int			i = 0;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* for sequential append operations just spill over into the new node */
4638c2ecf20Sopenharmony_ci	if (*pos == KEYS_PER_NODE) {
4648c2ecf20Sopenharmony_ci		*nodep = new;
4658c2ecf20Sopenharmony_ci		*pos = 0;
4668c2ecf20Sopenharmony_ci		*nr_entries = 0;
4678c2ecf20Sopenharmony_ci		goto done;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	for (i = 0; i < nr_move; i++) {
4728c2ecf20Sopenharmony_ci		new->keys[i] = node->keys[nr_keep + i];
4738c2ecf20Sopenharmony_ci		new->ptrs[i] = node->ptrs[nr_keep + i];
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		node->keys[nr_keep + i] = XFS_IEXT_KEY_INVALID;
4768c2ecf20Sopenharmony_ci		node->ptrs[nr_keep + i] = NULL;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (*pos >= nr_keep) {
4808c2ecf20Sopenharmony_ci		*nodep = new;
4818c2ecf20Sopenharmony_ci		*pos -= nr_keep;
4828c2ecf20Sopenharmony_ci		*nr_entries = nr_move;
4838c2ecf20Sopenharmony_ci	} else {
4848c2ecf20Sopenharmony_ci		*nr_entries = nr_keep;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_cidone:
4878c2ecf20Sopenharmony_ci	for (; i < KEYS_PER_NODE; i++)
4888c2ecf20Sopenharmony_ci		new->keys[i] = XFS_IEXT_KEY_INVALID;
4898c2ecf20Sopenharmony_ci	return new;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic void
4938c2ecf20Sopenharmony_cixfs_iext_insert_node(
4948c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
4958c2ecf20Sopenharmony_ci	uint64_t		offset,
4968c2ecf20Sopenharmony_ci	void			*ptr,
4978c2ecf20Sopenharmony_ci	int			level)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node, *new;
5008c2ecf20Sopenharmony_ci	int			i, pos, nr_entries;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ciagain:
5038c2ecf20Sopenharmony_ci	if (ifp->if_height < level)
5048c2ecf20Sopenharmony_ci		xfs_iext_grow(ifp);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	new = NULL;
5078c2ecf20Sopenharmony_ci	node = xfs_iext_find_level(ifp, offset, level);
5088c2ecf20Sopenharmony_ci	pos = xfs_iext_node_insert_pos(node, offset);
5098c2ecf20Sopenharmony_ci	nr_entries = xfs_iext_node_nr_entries(node, pos);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	ASSERT(pos >= nr_entries || xfs_iext_key_cmp(node, pos, offset) != 0);
5128c2ecf20Sopenharmony_ci	ASSERT(nr_entries <= KEYS_PER_NODE);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	if (nr_entries == KEYS_PER_NODE)
5158c2ecf20Sopenharmony_ci		new = xfs_iext_split_node(&node, &pos, &nr_entries);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/*
5188c2ecf20Sopenharmony_ci	 * Update the pointers in higher levels if the first entry changes
5198c2ecf20Sopenharmony_ci	 * in an existing node.
5208c2ecf20Sopenharmony_ci	 */
5218c2ecf20Sopenharmony_ci	if (node != new && pos == 0 && nr_entries > 0)
5228c2ecf20Sopenharmony_ci		xfs_iext_update_node(ifp, node->keys[0], offset, level, node);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	for (i = nr_entries; i > pos; i--) {
5258c2ecf20Sopenharmony_ci		node->keys[i] = node->keys[i - 1];
5268c2ecf20Sopenharmony_ci		node->ptrs[i] = node->ptrs[i - 1];
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci	node->keys[pos] = offset;
5298c2ecf20Sopenharmony_ci	node->ptrs[pos] = ptr;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (new) {
5328c2ecf20Sopenharmony_ci		offset = new->keys[0];
5338c2ecf20Sopenharmony_ci		ptr = new;
5348c2ecf20Sopenharmony_ci		level++;
5358c2ecf20Sopenharmony_ci		goto again;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic struct xfs_iext_leaf *
5408c2ecf20Sopenharmony_cixfs_iext_split_leaf(
5418c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
5428c2ecf20Sopenharmony_ci	int			*nr_entries)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*leaf = cur->leaf;
5458c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*new = kmem_zalloc(NODE_SIZE, KM_NOFS);
5468c2ecf20Sopenharmony_ci	const int		nr_move = RECS_PER_LEAF / 2;
5478c2ecf20Sopenharmony_ci	int			nr_keep = nr_move + (RECS_PER_LEAF & 1);
5488c2ecf20Sopenharmony_ci	int			i;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* for sequential append operations just spill over into the new node */
5518c2ecf20Sopenharmony_ci	if (cur->pos == RECS_PER_LEAF) {
5528c2ecf20Sopenharmony_ci		cur->leaf = new;
5538c2ecf20Sopenharmony_ci		cur->pos = 0;
5548c2ecf20Sopenharmony_ci		*nr_entries = 0;
5558c2ecf20Sopenharmony_ci		goto done;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	for (i = 0; i < nr_move; i++) {
5598c2ecf20Sopenharmony_ci		new->recs[i] = leaf->recs[nr_keep + i];
5608c2ecf20Sopenharmony_ci		xfs_iext_rec_clear(&leaf->recs[nr_keep + i]);
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (cur->pos >= nr_keep) {
5648c2ecf20Sopenharmony_ci		cur->leaf = new;
5658c2ecf20Sopenharmony_ci		cur->pos -= nr_keep;
5668c2ecf20Sopenharmony_ci		*nr_entries = nr_move;
5678c2ecf20Sopenharmony_ci	} else {
5688c2ecf20Sopenharmony_ci		*nr_entries = nr_keep;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_cidone:
5718c2ecf20Sopenharmony_ci	if (leaf->next)
5728c2ecf20Sopenharmony_ci		leaf->next->prev = new;
5738c2ecf20Sopenharmony_ci	new->next = leaf->next;
5748c2ecf20Sopenharmony_ci	new->prev = leaf;
5758c2ecf20Sopenharmony_ci	leaf->next = new;
5768c2ecf20Sopenharmony_ci	return new;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic void
5808c2ecf20Sopenharmony_cixfs_iext_alloc_root(
5818c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
5828c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	ASSERT(ifp->if_bytes == 0);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	ifp->if_u1.if_root = kmem_zalloc(sizeof(struct xfs_iext_rec), KM_NOFS);
5878c2ecf20Sopenharmony_ci	ifp->if_height = 1;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/* now that we have a node step into it */
5908c2ecf20Sopenharmony_ci	cur->leaf = ifp->if_u1.if_root;
5918c2ecf20Sopenharmony_ci	cur->pos = 0;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistatic void
5958c2ecf20Sopenharmony_cixfs_iext_realloc_root(
5968c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
5978c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	int64_t new_size = ifp->if_bytes + sizeof(struct xfs_iext_rec);
6008c2ecf20Sopenharmony_ci	void *new;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	/* account for the prev/next pointers */
6038c2ecf20Sopenharmony_ci	if (new_size / sizeof(struct xfs_iext_rec) == RECS_PER_LEAF)
6048c2ecf20Sopenharmony_ci		new_size = NODE_SIZE;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	new = krealloc(ifp->if_u1.if_root, new_size, GFP_NOFS | __GFP_NOFAIL);
6078c2ecf20Sopenharmony_ci	memset(new + ifp->if_bytes, 0, new_size - ifp->if_bytes);
6088c2ecf20Sopenharmony_ci	ifp->if_u1.if_root = new;
6098c2ecf20Sopenharmony_ci	cur->leaf = new;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/*
6138c2ecf20Sopenharmony_ci * Increment the sequence counter on extent tree changes. If we are on a COW
6148c2ecf20Sopenharmony_ci * fork, this allows the writeback code to skip looking for a COW extent if the
6158c2ecf20Sopenharmony_ci * COW fork hasn't changed. We use WRITE_ONCE here to ensure the update to the
6168c2ecf20Sopenharmony_ci * sequence counter is seen before the modifications to the extent tree itself
6178c2ecf20Sopenharmony_ci * take effect.
6188c2ecf20Sopenharmony_ci */
6198c2ecf20Sopenharmony_cistatic inline void xfs_iext_inc_seq(struct xfs_ifork *ifp)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1);
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_civoid
6258c2ecf20Sopenharmony_cixfs_iext_insert(
6268c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
6278c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
6288c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*irec,
6298c2ecf20Sopenharmony_ci	int			state)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp = xfs_iext_state_to_fork(ip, state);
6328c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset = irec->br_startoff;
6338c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*new = NULL;
6348c2ecf20Sopenharmony_ci	int			nr_entries, i;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	xfs_iext_inc_seq(ifp);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (ifp->if_height == 0)
6398c2ecf20Sopenharmony_ci		xfs_iext_alloc_root(ifp, cur);
6408c2ecf20Sopenharmony_ci	else if (ifp->if_height == 1)
6418c2ecf20Sopenharmony_ci		xfs_iext_realloc_root(ifp, cur);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	nr_entries = xfs_iext_leaf_nr_entries(ifp, cur->leaf, cur->pos);
6448c2ecf20Sopenharmony_ci	ASSERT(nr_entries <= RECS_PER_LEAF);
6458c2ecf20Sopenharmony_ci	ASSERT(cur->pos >= nr_entries ||
6468c2ecf20Sopenharmony_ci	       xfs_iext_rec_cmp(cur_rec(cur), irec->br_startoff) != 0);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (nr_entries == RECS_PER_LEAF)
6498c2ecf20Sopenharmony_ci		new = xfs_iext_split_leaf(cur, &nr_entries);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/*
6528c2ecf20Sopenharmony_ci	 * Update the pointers in higher levels if the first entry changes
6538c2ecf20Sopenharmony_ci	 * in an existing node.
6548c2ecf20Sopenharmony_ci	 */
6558c2ecf20Sopenharmony_ci	if (cur->leaf != new && cur->pos == 0 && nr_entries > 0) {
6568c2ecf20Sopenharmony_ci		xfs_iext_update_node(ifp, xfs_iext_leaf_key(cur->leaf, 0),
6578c2ecf20Sopenharmony_ci				offset, 1, cur->leaf);
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	for (i = nr_entries; i > cur->pos; i--)
6618c2ecf20Sopenharmony_ci		cur->leaf->recs[i] = cur->leaf->recs[i - 1];
6628c2ecf20Sopenharmony_ci	xfs_iext_set(cur_rec(cur), irec);
6638c2ecf20Sopenharmony_ci	ifp->if_bytes += sizeof(struct xfs_iext_rec);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	trace_xfs_iext_insert(ip, cur, state, _RET_IP_);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (new)
6688c2ecf20Sopenharmony_ci		xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic struct xfs_iext_node *
6728c2ecf20Sopenharmony_cixfs_iext_rebalance_node(
6738c2ecf20Sopenharmony_ci	struct xfs_iext_node	*parent,
6748c2ecf20Sopenharmony_ci	int			*pos,
6758c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
6768c2ecf20Sopenharmony_ci	int			nr_entries)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	/*
6798c2ecf20Sopenharmony_ci	 * If the neighbouring nodes are completely full, or have different
6808c2ecf20Sopenharmony_ci	 * parents, we might never be able to merge our node, and will only
6818c2ecf20Sopenharmony_ci	 * delete it once the number of entries hits zero.
6828c2ecf20Sopenharmony_ci	 */
6838c2ecf20Sopenharmony_ci	if (nr_entries == 0)
6848c2ecf20Sopenharmony_ci		return node;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (*pos > 0) {
6878c2ecf20Sopenharmony_ci		struct xfs_iext_node *prev = parent->ptrs[*pos - 1];
6888c2ecf20Sopenharmony_ci		int nr_prev = xfs_iext_node_nr_entries(prev, 0), i;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci		if (nr_prev + nr_entries <= KEYS_PER_NODE) {
6918c2ecf20Sopenharmony_ci			for (i = 0; i < nr_entries; i++) {
6928c2ecf20Sopenharmony_ci				prev->keys[nr_prev + i] = node->keys[i];
6938c2ecf20Sopenharmony_ci				prev->ptrs[nr_prev + i] = node->ptrs[i];
6948c2ecf20Sopenharmony_ci			}
6958c2ecf20Sopenharmony_ci			return node;
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (*pos + 1 < xfs_iext_node_nr_entries(parent, *pos)) {
7008c2ecf20Sopenharmony_ci		struct xfs_iext_node *next = parent->ptrs[*pos + 1];
7018c2ecf20Sopenharmony_ci		int nr_next = xfs_iext_node_nr_entries(next, 0), i;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		if (nr_entries + nr_next <= KEYS_PER_NODE) {
7048c2ecf20Sopenharmony_ci			/*
7058c2ecf20Sopenharmony_ci			 * Merge the next node into this node so that we don't
7068c2ecf20Sopenharmony_ci			 * have to do an additional update of the keys in the
7078c2ecf20Sopenharmony_ci			 * higher levels.
7088c2ecf20Sopenharmony_ci			 */
7098c2ecf20Sopenharmony_ci			for (i = 0; i < nr_next; i++) {
7108c2ecf20Sopenharmony_ci				node->keys[nr_entries + i] = next->keys[i];
7118c2ecf20Sopenharmony_ci				node->ptrs[nr_entries + i] = next->ptrs[i];
7128c2ecf20Sopenharmony_ci			}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci			++*pos;
7158c2ecf20Sopenharmony_ci			return next;
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return NULL;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic void
7238c2ecf20Sopenharmony_cixfs_iext_remove_node(
7248c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
7258c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset,
7268c2ecf20Sopenharmony_ci	void			*victim)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node, *parent;
7298c2ecf20Sopenharmony_ci	int			level = 2, pos, nr_entries, i;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	ASSERT(level <= ifp->if_height);
7328c2ecf20Sopenharmony_ci	node = xfs_iext_find_level(ifp, offset, level);
7338c2ecf20Sopenharmony_ci	pos = xfs_iext_node_pos(node, offset);
7348c2ecf20Sopenharmony_ciagain:
7358c2ecf20Sopenharmony_ci	ASSERT(node->ptrs[pos]);
7368c2ecf20Sopenharmony_ci	ASSERT(node->ptrs[pos] == victim);
7378c2ecf20Sopenharmony_ci	kmem_free(victim);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	nr_entries = xfs_iext_node_nr_entries(node, pos) - 1;
7408c2ecf20Sopenharmony_ci	offset = node->keys[0];
7418c2ecf20Sopenharmony_ci	for (i = pos; i < nr_entries; i++) {
7428c2ecf20Sopenharmony_ci		node->keys[i] = node->keys[i + 1];
7438c2ecf20Sopenharmony_ci		node->ptrs[i] = node->ptrs[i + 1];
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci	node->keys[nr_entries] = XFS_IEXT_KEY_INVALID;
7468c2ecf20Sopenharmony_ci	node->ptrs[nr_entries] = NULL;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (pos == 0 && nr_entries > 0) {
7498c2ecf20Sopenharmony_ci		xfs_iext_update_node(ifp, offset, node->keys[0], level, node);
7508c2ecf20Sopenharmony_ci		offset = node->keys[0];
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (nr_entries >= KEYS_PER_NODE / 2)
7548c2ecf20Sopenharmony_ci		return;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (level < ifp->if_height) {
7578c2ecf20Sopenharmony_ci		/*
7588c2ecf20Sopenharmony_ci		 * If we aren't at the root yet try to find a neighbour node to
7598c2ecf20Sopenharmony_ci		 * merge with (or delete the node if it is empty), and then
7608c2ecf20Sopenharmony_ci		 * recurse up to the next level.
7618c2ecf20Sopenharmony_ci		 */
7628c2ecf20Sopenharmony_ci		level++;
7638c2ecf20Sopenharmony_ci		parent = xfs_iext_find_level(ifp, offset, level);
7648c2ecf20Sopenharmony_ci		pos = xfs_iext_node_pos(parent, offset);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		ASSERT(pos != KEYS_PER_NODE);
7678c2ecf20Sopenharmony_ci		ASSERT(parent->ptrs[pos] == node);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		node = xfs_iext_rebalance_node(parent, &pos, node, nr_entries);
7708c2ecf20Sopenharmony_ci		if (node) {
7718c2ecf20Sopenharmony_ci			victim = node;
7728c2ecf20Sopenharmony_ci			node = parent;
7738c2ecf20Sopenharmony_ci			goto again;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci	} else if (nr_entries == 1) {
7768c2ecf20Sopenharmony_ci		/*
7778c2ecf20Sopenharmony_ci		 * If we are at the root and only one entry is left we can just
7788c2ecf20Sopenharmony_ci		 * free this node and update the root pointer.
7798c2ecf20Sopenharmony_ci		 */
7808c2ecf20Sopenharmony_ci		ASSERT(node == ifp->if_u1.if_root);
7818c2ecf20Sopenharmony_ci		ifp->if_u1.if_root = node->ptrs[0];
7828c2ecf20Sopenharmony_ci		ifp->if_height--;
7838c2ecf20Sopenharmony_ci		kmem_free(node);
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void
7888c2ecf20Sopenharmony_cixfs_iext_rebalance_leaf(
7898c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
7908c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
7918c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*leaf,
7928c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset,
7938c2ecf20Sopenharmony_ci	int			nr_entries)
7948c2ecf20Sopenharmony_ci{
7958c2ecf20Sopenharmony_ci	/*
7968c2ecf20Sopenharmony_ci	 * If the neighbouring nodes are completely full we might never be able
7978c2ecf20Sopenharmony_ci	 * to merge our node, and will only delete it once the number of
7988c2ecf20Sopenharmony_ci	 * entries hits zero.
7998c2ecf20Sopenharmony_ci	 */
8008c2ecf20Sopenharmony_ci	if (nr_entries == 0)
8018c2ecf20Sopenharmony_ci		goto remove_node;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (leaf->prev) {
8048c2ecf20Sopenharmony_ci		int nr_prev = xfs_iext_leaf_nr_entries(ifp, leaf->prev, 0), i;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci		if (nr_prev + nr_entries <= RECS_PER_LEAF) {
8078c2ecf20Sopenharmony_ci			for (i = 0; i < nr_entries; i++)
8088c2ecf20Sopenharmony_ci				leaf->prev->recs[nr_prev + i] = leaf->recs[i];
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci			if (cur->leaf == leaf) {
8118c2ecf20Sopenharmony_ci				cur->leaf = leaf->prev;
8128c2ecf20Sopenharmony_ci				cur->pos += nr_prev;
8138c2ecf20Sopenharmony_ci			}
8148c2ecf20Sopenharmony_ci			goto remove_node;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (leaf->next) {
8198c2ecf20Sopenharmony_ci		int nr_next = xfs_iext_leaf_nr_entries(ifp, leaf->next, 0), i;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		if (nr_entries + nr_next <= RECS_PER_LEAF) {
8228c2ecf20Sopenharmony_ci			/*
8238c2ecf20Sopenharmony_ci			 * Merge the next node into this node so that we don't
8248c2ecf20Sopenharmony_ci			 * have to do an additional update of the keys in the
8258c2ecf20Sopenharmony_ci			 * higher levels.
8268c2ecf20Sopenharmony_ci			 */
8278c2ecf20Sopenharmony_ci			for (i = 0; i < nr_next; i++) {
8288c2ecf20Sopenharmony_ci				leaf->recs[nr_entries + i] =
8298c2ecf20Sopenharmony_ci					leaf->next->recs[i];
8308c2ecf20Sopenharmony_ci			}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci			if (cur->leaf == leaf->next) {
8338c2ecf20Sopenharmony_ci				cur->leaf = leaf;
8348c2ecf20Sopenharmony_ci				cur->pos += nr_entries;
8358c2ecf20Sopenharmony_ci			}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci			offset = xfs_iext_leaf_key(leaf->next, 0);
8388c2ecf20Sopenharmony_ci			leaf = leaf->next;
8398c2ecf20Sopenharmony_ci			goto remove_node;
8408c2ecf20Sopenharmony_ci		}
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return;
8448c2ecf20Sopenharmony_ciremove_node:
8458c2ecf20Sopenharmony_ci	if (leaf->prev)
8468c2ecf20Sopenharmony_ci		leaf->prev->next = leaf->next;
8478c2ecf20Sopenharmony_ci	if (leaf->next)
8488c2ecf20Sopenharmony_ci		leaf->next->prev = leaf->prev;
8498c2ecf20Sopenharmony_ci	xfs_iext_remove_node(ifp, offset, leaf);
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic void
8538c2ecf20Sopenharmony_cixfs_iext_free_last_leaf(
8548c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	ifp->if_height--;
8578c2ecf20Sopenharmony_ci	kmem_free(ifp->if_u1.if_root);
8588c2ecf20Sopenharmony_ci	ifp->if_u1.if_root = NULL;
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_civoid
8628c2ecf20Sopenharmony_cixfs_iext_remove(
8638c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
8648c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
8658c2ecf20Sopenharmony_ci	int			state)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp = xfs_iext_state_to_fork(ip, state);
8688c2ecf20Sopenharmony_ci	struct xfs_iext_leaf	*leaf = cur->leaf;
8698c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset = xfs_iext_leaf_key(leaf, 0);
8708c2ecf20Sopenharmony_ci	int			i, nr_entries;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	trace_xfs_iext_remove(ip, cur, state, _RET_IP_);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	ASSERT(ifp->if_height > 0);
8758c2ecf20Sopenharmony_ci	ASSERT(ifp->if_u1.if_root != NULL);
8768c2ecf20Sopenharmony_ci	ASSERT(xfs_iext_valid(ifp, cur));
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	xfs_iext_inc_seq(ifp);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	nr_entries = xfs_iext_leaf_nr_entries(ifp, leaf, cur->pos) - 1;
8818c2ecf20Sopenharmony_ci	for (i = cur->pos; i < nr_entries; i++)
8828c2ecf20Sopenharmony_ci		leaf->recs[i] = leaf->recs[i + 1];
8838c2ecf20Sopenharmony_ci	xfs_iext_rec_clear(&leaf->recs[nr_entries]);
8848c2ecf20Sopenharmony_ci	ifp->if_bytes -= sizeof(struct xfs_iext_rec);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (cur->pos == 0 && nr_entries > 0) {
8878c2ecf20Sopenharmony_ci		xfs_iext_update_node(ifp, offset, xfs_iext_leaf_key(leaf, 0), 1,
8888c2ecf20Sopenharmony_ci				leaf);
8898c2ecf20Sopenharmony_ci		offset = xfs_iext_leaf_key(leaf, 0);
8908c2ecf20Sopenharmony_ci	} else if (cur->pos == nr_entries) {
8918c2ecf20Sopenharmony_ci		if (ifp->if_height > 1 && leaf->next)
8928c2ecf20Sopenharmony_ci			cur->leaf = leaf->next;
8938c2ecf20Sopenharmony_ci		else
8948c2ecf20Sopenharmony_ci			cur->leaf = NULL;
8958c2ecf20Sopenharmony_ci		cur->pos = 0;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (nr_entries >= RECS_PER_LEAF / 2)
8998c2ecf20Sopenharmony_ci		return;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (ifp->if_height > 1)
9028c2ecf20Sopenharmony_ci		xfs_iext_rebalance_leaf(ifp, cur, leaf, offset, nr_entries);
9038c2ecf20Sopenharmony_ci	else if (nr_entries == 0)
9048c2ecf20Sopenharmony_ci		xfs_iext_free_last_leaf(ifp);
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci/*
9088c2ecf20Sopenharmony_ci * Lookup the extent covering bno.
9098c2ecf20Sopenharmony_ci *
9108c2ecf20Sopenharmony_ci * If there is an extent covering bno return the extent index, and store the
9118c2ecf20Sopenharmony_ci * expanded extent structure in *gotp, and the extent cursor in *cur.
9128c2ecf20Sopenharmony_ci * If there is no extent covering bno, but there is an extent after it (e.g.
9138c2ecf20Sopenharmony_ci * it lies in a hole) return that extent in *gotp and its cursor in *cur
9148c2ecf20Sopenharmony_ci * instead.
9158c2ecf20Sopenharmony_ci * If bno is beyond the last extent return false, and return an invalid
9168c2ecf20Sopenharmony_ci * cursor value.
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_cibool
9198c2ecf20Sopenharmony_cixfs_iext_lookup_extent(
9208c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
9218c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
9228c2ecf20Sopenharmony_ci	xfs_fileoff_t		offset,
9238c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
9248c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*gotp)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	XFS_STATS_INC(ip->i_mount, xs_look_exlist);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	cur->leaf = xfs_iext_find_level(ifp, offset, 1);
9298c2ecf20Sopenharmony_ci	if (!cur->leaf) {
9308c2ecf20Sopenharmony_ci		cur->pos = 0;
9318c2ecf20Sopenharmony_ci		return false;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	for (cur->pos = 0; cur->pos < xfs_iext_max_recs(ifp); cur->pos++) {
9358c2ecf20Sopenharmony_ci		struct xfs_iext_rec *rec = cur_rec(cur);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci		if (xfs_iext_rec_is_empty(rec))
9388c2ecf20Sopenharmony_ci			break;
9398c2ecf20Sopenharmony_ci		if (xfs_iext_rec_cmp(rec, offset) >= 0)
9408c2ecf20Sopenharmony_ci			goto found;
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/* Try looking in the next node for an entry > offset */
9448c2ecf20Sopenharmony_ci	if (ifp->if_height == 1 || !cur->leaf->next)
9458c2ecf20Sopenharmony_ci		return false;
9468c2ecf20Sopenharmony_ci	cur->leaf = cur->leaf->next;
9478c2ecf20Sopenharmony_ci	cur->pos = 0;
9488c2ecf20Sopenharmony_ci	if (!xfs_iext_valid(ifp, cur))
9498c2ecf20Sopenharmony_ci		return false;
9508c2ecf20Sopenharmony_cifound:
9518c2ecf20Sopenharmony_ci	xfs_iext_get(gotp, cur_rec(cur));
9528c2ecf20Sopenharmony_ci	return true;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci/*
9568c2ecf20Sopenharmony_ci * Returns the last extent before end, and if this extent doesn't cover
9578c2ecf20Sopenharmony_ci * end, update end to the end of the extent.
9588c2ecf20Sopenharmony_ci */
9598c2ecf20Sopenharmony_cibool
9608c2ecf20Sopenharmony_cixfs_iext_lookup_extent_before(
9618c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
9628c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
9638c2ecf20Sopenharmony_ci	xfs_fileoff_t		*end,
9648c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
9658c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*gotp)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	/* could be optimized to not even look up the next on a match.. */
9688c2ecf20Sopenharmony_ci	if (xfs_iext_lookup_extent(ip, ifp, *end - 1, cur, gotp) &&
9698c2ecf20Sopenharmony_ci	    gotp->br_startoff <= *end - 1)
9708c2ecf20Sopenharmony_ci		return true;
9718c2ecf20Sopenharmony_ci	if (!xfs_iext_prev_extent(ifp, cur, gotp))
9728c2ecf20Sopenharmony_ci		return false;
9738c2ecf20Sopenharmony_ci	*end = gotp->br_startoff + gotp->br_blockcount;
9748c2ecf20Sopenharmony_ci	return true;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_civoid
9788c2ecf20Sopenharmony_cixfs_iext_update_extent(
9798c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
9808c2ecf20Sopenharmony_ci	int			state,
9818c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
9828c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*new)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp = xfs_iext_state_to_fork(ip, state);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	xfs_iext_inc_seq(ifp);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (cur->pos == 0) {
9898c2ecf20Sopenharmony_ci		struct xfs_bmbt_irec	old;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci		xfs_iext_get(&old, cur_rec(cur));
9928c2ecf20Sopenharmony_ci		if (new->br_startoff != old.br_startoff) {
9938c2ecf20Sopenharmony_ci			xfs_iext_update_node(ifp, old.br_startoff,
9948c2ecf20Sopenharmony_ci					new->br_startoff, 1, cur->leaf);
9958c2ecf20Sopenharmony_ci		}
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	trace_xfs_bmap_pre_update(ip, cur, state, _RET_IP_);
9998c2ecf20Sopenharmony_ci	xfs_iext_set(cur_rec(cur), new);
10008c2ecf20Sopenharmony_ci	trace_xfs_bmap_post_update(ip, cur, state, _RET_IP_);
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci/*
10048c2ecf20Sopenharmony_ci * Return true if the cursor points at an extent and return the extent structure
10058c2ecf20Sopenharmony_ci * in gotp.  Else return false.
10068c2ecf20Sopenharmony_ci */
10078c2ecf20Sopenharmony_cibool
10088c2ecf20Sopenharmony_cixfs_iext_get_extent(
10098c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp,
10108c2ecf20Sopenharmony_ci	struct xfs_iext_cursor	*cur,
10118c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*gotp)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	if (!xfs_iext_valid(ifp, cur))
10148c2ecf20Sopenharmony_ci		return false;
10158c2ecf20Sopenharmony_ci	xfs_iext_get(gotp, cur_rec(cur));
10168c2ecf20Sopenharmony_ci	return true;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci/*
10208c2ecf20Sopenharmony_ci * This is a recursive function, because of that we need to be extremely
10218c2ecf20Sopenharmony_ci * careful with stack usage.
10228c2ecf20Sopenharmony_ci */
10238c2ecf20Sopenharmony_cistatic void
10248c2ecf20Sopenharmony_cixfs_iext_destroy_node(
10258c2ecf20Sopenharmony_ci	struct xfs_iext_node	*node,
10268c2ecf20Sopenharmony_ci	int			level)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	int			i;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (level > 1) {
10318c2ecf20Sopenharmony_ci		for (i = 0; i < KEYS_PER_NODE; i++) {
10328c2ecf20Sopenharmony_ci			if (node->keys[i] == XFS_IEXT_KEY_INVALID)
10338c2ecf20Sopenharmony_ci				break;
10348c2ecf20Sopenharmony_ci			xfs_iext_destroy_node(node->ptrs[i], level - 1);
10358c2ecf20Sopenharmony_ci		}
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	kmem_free(node);
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_civoid
10428c2ecf20Sopenharmony_cixfs_iext_destroy(
10438c2ecf20Sopenharmony_ci	struct xfs_ifork	*ifp)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	xfs_iext_destroy_node(ifp->if_u1.if_root, ifp->if_height);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	ifp->if_bytes = 0;
10488c2ecf20Sopenharmony_ci	ifp->if_height = 0;
10498c2ecf20Sopenharmony_ci	ifp->if_u1.if_root = NULL;
10508c2ecf20Sopenharmony_ci}
1051