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