12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2017 Christoph Hellwig.
- */
- #include <linux/cache.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include "xfs.h"
- #include "xfs_format.h"
- #include "xfs_bit.h"
- #include "xfs_log_format.h"
- #include "xfs_inode.h"
- #include "xfs_inode_fork.h"
- #include "xfs_trans_resv.h"
- #include "xfs_mount.h"
- #include "xfs_bmap.h"
- #include "xfs_trace.h"
- /*
- * In-core extent record layout:
- *
- * +-------+----------------------------+
- * | 00:53 | all 54 bits of startoff |
- * | 54:63 | low 10 bits of startblock |
- * +-------+----------------------------+
- * | 00:20 | all 21 bits of length |
- * | 21 | unwritten extent bit |
- * | 22:63 | high 42 bits of startblock |
- * +-------+----------------------------+
- */
- #define XFS_IEXT_STARTOFF_MASK xfs_mask64lo(BMBT_STARTOFF_BITLEN)
- #define XFS_IEXT_LENGTH_MASK xfs_mask64lo(BMBT_BLOCKCOUNT_BITLEN)
- #define XFS_IEXT_STARTBLOCK_MASK xfs_mask64lo(BMBT_STARTBLOCK_BITLEN)
- struct xfs_iext_rec {
- uint64_t lo;
- uint64_t hi;
- };
- /*
- * Given that the length can't be a zero, only an empty hi value indicates an
- * unused record.
- */
- static bool xfs_iext_rec_is_empty(struct xfs_iext_rec *rec)
- {
- return rec->hi == 0;
- }
- static inline void xfs_iext_rec_clear(struct xfs_iext_rec *rec)
- {
- rec->lo = 0;
- rec->hi = 0;
- }
- static void
- xfs_iext_set(
- struct xfs_iext_rec *rec,
- struct xfs_bmbt_irec *irec)
- {
- ASSERT((irec->br_startoff & ~XFS_IEXT_STARTOFF_MASK) == 0);
- ASSERT((irec->br_blockcount & ~XFS_IEXT_LENGTH_MASK) == 0);
- ASSERT((irec->br_startblock & ~XFS_IEXT_STARTBLOCK_MASK) == 0);
- rec->lo = irec->br_startoff & XFS_IEXT_STARTOFF_MASK;
- rec->hi = irec->br_blockcount & XFS_IEXT_LENGTH_MASK;
- rec->lo |= (irec->br_startblock << 54);
- rec->hi |= ((irec->br_startblock & ~xfs_mask64lo(10)) << (22 - 10));
- if (irec->br_state == XFS_EXT_UNWRITTEN)
- rec->hi |= (1 << 21);
- }
- static void
- xfs_iext_get(
- struct xfs_bmbt_irec *irec,
- struct xfs_iext_rec *rec)
- {
- irec->br_startoff = rec->lo & XFS_IEXT_STARTOFF_MASK;
- irec->br_blockcount = rec->hi & XFS_IEXT_LENGTH_MASK;
- irec->br_startblock = rec->lo >> 54;
- irec->br_startblock |= (rec->hi & xfs_mask64hi(42)) >> (22 - 10);
- if (rec->hi & (1 << 21))
- irec->br_state = XFS_EXT_UNWRITTEN;
- else
- irec->br_state = XFS_EXT_NORM;
- }
- enum {
- NODE_SIZE = 256,
- KEYS_PER_NODE = NODE_SIZE / (sizeof(uint64_t) + sizeof(void *)),
- RECS_PER_LEAF = (NODE_SIZE - (2 * sizeof(struct xfs_iext_leaf *))) /
- sizeof(struct xfs_iext_rec),
- };
- /*
- * In-core extent btree block layout:
- *
- * There are two types of blocks in the btree: leaf and inner (non-leaf) blocks.
- *
- * The leaf blocks are made up by %KEYS_PER_NODE extent records, which each
- * contain the startoffset, blockcount, startblock and unwritten extent flag.
- * See above for the exact format, followed by pointers to the previous and next
- * leaf blocks (if there are any).
- *
- * The inner (non-leaf) blocks first contain KEYS_PER_NODE lookup keys, followed
- * by an equal number of pointers to the btree blocks at the next lower level.
- *
- * +-------+-------+-------+-------+-------+----------+----------+
- * Leaf: | rec 1 | rec 2 | rec 3 | rec 4 | rec N | prev-ptr | next-ptr |
- * +-------+-------+-------+-------+-------+----------+----------+
- *
- * +-------+-------+-------+-------+-------+-------+------+-------+
- * Inner: | key 1 | key 2 | key 3 | key N | ptr 1 | ptr 2 | ptr3 | ptr N |
- * +-------+-------+-------+-------+-------+-------+------+-------+
- */
- struct xfs_iext_node {
- uint64_t keys[KEYS_PER_NODE];
- #define XFS_IEXT_KEY_INVALID (1ULL << 63)
- void *ptrs[KEYS_PER_NODE];
- };
- struct xfs_iext_leaf {
- struct xfs_iext_rec recs[RECS_PER_LEAF];
- struct xfs_iext_leaf *prev;
- struct xfs_iext_leaf *next;
- };
- inline xfs_extnum_t xfs_iext_count(struct xfs_ifork *ifp)
- {
- return ifp->if_bytes / sizeof(struct xfs_iext_rec);
- }
- static inline int xfs_iext_max_recs(struct xfs_ifork *ifp)
- {
- if (ifp->if_height == 1)
- return xfs_iext_count(ifp);
- return RECS_PER_LEAF;
- }
- static inline struct xfs_iext_rec *cur_rec(struct xfs_iext_cursor *cur)
- {
- return &cur->leaf->recs[cur->pos];
- }
- static inline bool xfs_iext_valid(struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- if (!cur->leaf)
- return false;
- if (cur->pos < 0 || cur->pos >= xfs_iext_max_recs(ifp))
- return false;
- if (xfs_iext_rec_is_empty(cur_rec(cur)))
- return false;
- return true;
- }
- static void *
- xfs_iext_find_first_leaf(
- struct xfs_ifork *ifp)
- {
- struct xfs_iext_node *node = ifp->if_u1.if_root;
- int height;
- if (!ifp->if_height)
- return NULL;
- for (height = ifp->if_height; height > 1; height--) {
- node = node->ptrs[0];
- ASSERT(node);
- }
- return node;
- }
- static void *
- xfs_iext_find_last_leaf(
- struct xfs_ifork *ifp)
- {
- struct xfs_iext_node *node = ifp->if_u1.if_root;
- int height, i;
- if (!ifp->if_height)
- return NULL;
- for (height = ifp->if_height; height > 1; height--) {
- for (i = 1; i < KEYS_PER_NODE; i++)
- if (!node->ptrs[i])
- break;
- node = node->ptrs[i - 1];
- ASSERT(node);
- }
- return node;
- }
- void
- xfs_iext_first(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- cur->pos = 0;
- cur->leaf = xfs_iext_find_first_leaf(ifp);
- }
- void
- xfs_iext_last(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- int i;
- cur->leaf = xfs_iext_find_last_leaf(ifp);
- if (!cur->leaf) {
- cur->pos = 0;
- return;
- }
- for (i = 1; i < xfs_iext_max_recs(ifp); i++) {
- if (xfs_iext_rec_is_empty(&cur->leaf->recs[i]))
- break;
- }
- cur->pos = i - 1;
- }
- void
- xfs_iext_next(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- if (!cur->leaf) {
- ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF);
- xfs_iext_first(ifp, cur);
- return;
- }
- ASSERT(cur->pos >= 0);
- ASSERT(cur->pos < xfs_iext_max_recs(ifp));
- cur->pos++;
- if (ifp->if_height > 1 && !xfs_iext_valid(ifp, cur) &&
- cur->leaf->next) {
- cur->leaf = cur->leaf->next;
- cur->pos = 0;
- }
- }
- void
- xfs_iext_prev(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- if (!cur->leaf) {
- ASSERT(cur->pos <= 0 || cur->pos >= RECS_PER_LEAF);
- xfs_iext_last(ifp, cur);
- return;
- }
- ASSERT(cur->pos >= 0);
- ASSERT(cur->pos <= RECS_PER_LEAF);
- recurse:
- do {
- cur->pos--;
- if (xfs_iext_valid(ifp, cur))
- return;
- } while (cur->pos > 0);
- if (ifp->if_height > 1 && cur->leaf->prev) {
- cur->leaf = cur->leaf->prev;
- cur->pos = RECS_PER_LEAF;
- goto recurse;
- }
- }
- static inline int
- xfs_iext_key_cmp(
- struct xfs_iext_node *node,
- int n,
- xfs_fileoff_t offset)
- {
- if (node->keys[n] > offset)
- return 1;
- if (node->keys[n] < offset)
- return -1;
- return 0;
- }
- static inline int
- xfs_iext_rec_cmp(
- struct xfs_iext_rec *rec,
- xfs_fileoff_t offset)
- {
- uint64_t rec_offset = rec->lo & XFS_IEXT_STARTOFF_MASK;
- uint32_t rec_len = rec->hi & XFS_IEXT_LENGTH_MASK;
- if (rec_offset > offset)
- return 1;
- if (rec_offset + rec_len <= offset)
- return -1;
- return 0;
- }
- static void *
- xfs_iext_find_level(
- struct xfs_ifork *ifp,
- xfs_fileoff_t offset,
- int level)
- {
- struct xfs_iext_node *node = ifp->if_u1.if_root;
- int height, i;
- if (!ifp->if_height)
- return NULL;
- for (height = ifp->if_height; height > level; height--) {
- for (i = 1; i < KEYS_PER_NODE; i++)
- if (xfs_iext_key_cmp(node, i, offset) > 0)
- break;
- node = node->ptrs[i - 1];
- if (!node)
- break;
- }
- return node;
- }
- static int
- xfs_iext_node_pos(
- struct xfs_iext_node *node,
- xfs_fileoff_t offset)
- {
- int i;
- for (i = 1; i < KEYS_PER_NODE; i++) {
- if (xfs_iext_key_cmp(node, i, offset) > 0)
- break;
- }
- return i - 1;
- }
- static int
- xfs_iext_node_insert_pos(
- struct xfs_iext_node *node,
- xfs_fileoff_t offset)
- {
- int i;
- for (i = 0; i < KEYS_PER_NODE; i++) {
- if (xfs_iext_key_cmp(node, i, offset) > 0)
- return i;
- }
- return KEYS_PER_NODE;
- }
- static int
- xfs_iext_node_nr_entries(
- struct xfs_iext_node *node,
- int start)
- {
- int i;
- for (i = start; i < KEYS_PER_NODE; i++) {
- if (node->keys[i] == XFS_IEXT_KEY_INVALID)
- break;
- }
- return i;
- }
- static int
- xfs_iext_leaf_nr_entries(
- struct xfs_ifork *ifp,
- struct xfs_iext_leaf *leaf,
- int start)
- {
- int i;
- for (i = start; i < xfs_iext_max_recs(ifp); i++) {
- if (xfs_iext_rec_is_empty(&leaf->recs[i]))
- break;
- }
- return i;
- }
- static inline uint64_t
- xfs_iext_leaf_key(
- struct xfs_iext_leaf *leaf,
- int n)
- {
- return leaf->recs[n].lo & XFS_IEXT_STARTOFF_MASK;
- }
- static void
- xfs_iext_grow(
- struct xfs_ifork *ifp)
- {
- struct xfs_iext_node *node = kmem_zalloc(NODE_SIZE, KM_NOFS);
- int i;
- if (ifp->if_height == 1) {
- struct xfs_iext_leaf *prev = ifp->if_u1.if_root;
- node->keys[0] = xfs_iext_leaf_key(prev, 0);
- node->ptrs[0] = prev;
- } else {
- struct xfs_iext_node *prev = ifp->if_u1.if_root;
- ASSERT(ifp->if_height > 1);
- node->keys[0] = prev->keys[0];
- node->ptrs[0] = prev;
- }
- for (i = 1; i < KEYS_PER_NODE; i++)
- node->keys[i] = XFS_IEXT_KEY_INVALID;
- ifp->if_u1.if_root = node;
- ifp->if_height++;
- }
- static void
- xfs_iext_update_node(
- struct xfs_ifork *ifp,
- xfs_fileoff_t old_offset,
- xfs_fileoff_t new_offset,
- int level,
- void *ptr)
- {
- struct xfs_iext_node *node = ifp->if_u1.if_root;
- int height, i;
- for (height = ifp->if_height; height > level; height--) {
- for (i = 0; i < KEYS_PER_NODE; i++) {
- if (i > 0 && xfs_iext_key_cmp(node, i, old_offset) > 0)
- break;
- if (node->keys[i] == old_offset)
- node->keys[i] = new_offset;
- }
- node = node->ptrs[i - 1];
- ASSERT(node);
- }
- ASSERT(node == ptr);
- }
- static struct xfs_iext_node *
- xfs_iext_split_node(
- struct xfs_iext_node **nodep,
- int *pos,
- int *nr_entries)
- {
- struct xfs_iext_node *node = *nodep;
- struct xfs_iext_node *new = kmem_zalloc(NODE_SIZE, KM_NOFS);
- const int nr_move = KEYS_PER_NODE / 2;
- int nr_keep = nr_move + (KEYS_PER_NODE & 1);
- int i = 0;
- /* for sequential append operations just spill over into the new node */
- if (*pos == KEYS_PER_NODE) {
- *nodep = new;
- *pos = 0;
- *nr_entries = 0;
- goto done;
- }
- for (i = 0; i < nr_move; i++) {
- new->keys[i] = node->keys[nr_keep + i];
- new->ptrs[i] = node->ptrs[nr_keep + i];
- node->keys[nr_keep + i] = XFS_IEXT_KEY_INVALID;
- node->ptrs[nr_keep + i] = NULL;
- }
- if (*pos >= nr_keep) {
- *nodep = new;
- *pos -= nr_keep;
- *nr_entries = nr_move;
- } else {
- *nr_entries = nr_keep;
- }
- done:
- for (; i < KEYS_PER_NODE; i++)
- new->keys[i] = XFS_IEXT_KEY_INVALID;
- return new;
- }
- static void
- xfs_iext_insert_node(
- struct xfs_ifork *ifp,
- uint64_t offset,
- void *ptr,
- int level)
- {
- struct xfs_iext_node *node, *new;
- int i, pos, nr_entries;
- again:
- if (ifp->if_height < level)
- xfs_iext_grow(ifp);
- new = NULL;
- node = xfs_iext_find_level(ifp, offset, level);
- pos = xfs_iext_node_insert_pos(node, offset);
- nr_entries = xfs_iext_node_nr_entries(node, pos);
- ASSERT(pos >= nr_entries || xfs_iext_key_cmp(node, pos, offset) != 0);
- ASSERT(nr_entries <= KEYS_PER_NODE);
- if (nr_entries == KEYS_PER_NODE)
- new = xfs_iext_split_node(&node, &pos, &nr_entries);
- /*
- * Update the pointers in higher levels if the first entry changes
- * in an existing node.
- */
- if (node != new && pos == 0 && nr_entries > 0)
- xfs_iext_update_node(ifp, node->keys[0], offset, level, node);
- for (i = nr_entries; i > pos; i--) {
- node->keys[i] = node->keys[i - 1];
- node->ptrs[i] = node->ptrs[i - 1];
- }
- node->keys[pos] = offset;
- node->ptrs[pos] = ptr;
- if (new) {
- offset = new->keys[0];
- ptr = new;
- level++;
- goto again;
- }
- }
- static struct xfs_iext_leaf *
- xfs_iext_split_leaf(
- struct xfs_iext_cursor *cur,
- int *nr_entries)
- {
- struct xfs_iext_leaf *leaf = cur->leaf;
- struct xfs_iext_leaf *new = kmem_zalloc(NODE_SIZE, KM_NOFS);
- const int nr_move = RECS_PER_LEAF / 2;
- int nr_keep = nr_move + (RECS_PER_LEAF & 1);
- int i;
- /* for sequential append operations just spill over into the new node */
- if (cur->pos == RECS_PER_LEAF) {
- cur->leaf = new;
- cur->pos = 0;
- *nr_entries = 0;
- goto done;
- }
- for (i = 0; i < nr_move; i++) {
- new->recs[i] = leaf->recs[nr_keep + i];
- xfs_iext_rec_clear(&leaf->recs[nr_keep + i]);
- }
- if (cur->pos >= nr_keep) {
- cur->leaf = new;
- cur->pos -= nr_keep;
- *nr_entries = nr_move;
- } else {
- *nr_entries = nr_keep;
- }
- done:
- if (leaf->next)
- leaf->next->prev = new;
- new->next = leaf->next;
- new->prev = leaf;
- leaf->next = new;
- return new;
- }
- static void
- xfs_iext_alloc_root(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- ASSERT(ifp->if_bytes == 0);
- ifp->if_u1.if_root = kmem_zalloc(sizeof(struct xfs_iext_rec), KM_NOFS);
- ifp->if_height = 1;
- /* now that we have a node step into it */
- cur->leaf = ifp->if_u1.if_root;
- cur->pos = 0;
- }
- static void
- xfs_iext_realloc_root(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur)
- {
- size_t new_size = ifp->if_bytes + sizeof(struct xfs_iext_rec);
- void *new;
- /* account for the prev/next pointers */
- if (new_size / sizeof(struct xfs_iext_rec) == RECS_PER_LEAF)
- new_size = NODE_SIZE;
- new = kmem_realloc(ifp->if_u1.if_root, new_size, KM_NOFS);
- memset(new + ifp->if_bytes, 0, new_size - ifp->if_bytes);
- ifp->if_u1.if_root = new;
- cur->leaf = new;
- }
- /*
- * Increment the sequence counter if we are on a COW fork. This allows
- * the writeback code to skip looking for a COW extent if the COW fork
- * hasn't changed. We use WRITE_ONCE here to ensure the update to the
- * sequence counter is seen before the modifications to the extent
- * tree itself take effect.
- */
- static inline void xfs_iext_inc_seq(struct xfs_ifork *ifp, int state)
- {
- if (state & BMAP_COWFORK)
- WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1);
- }
- void
- xfs_iext_insert(
- struct xfs_inode *ip,
- struct xfs_iext_cursor *cur,
- struct xfs_bmbt_irec *irec,
- int state)
- {
- struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state);
- xfs_fileoff_t offset = irec->br_startoff;
- struct xfs_iext_leaf *new = NULL;
- int nr_entries, i;
- xfs_iext_inc_seq(ifp, state);
- if (ifp->if_height == 0)
- xfs_iext_alloc_root(ifp, cur);
- else if (ifp->if_height == 1)
- xfs_iext_realloc_root(ifp, cur);
- nr_entries = xfs_iext_leaf_nr_entries(ifp, cur->leaf, cur->pos);
- ASSERT(nr_entries <= RECS_PER_LEAF);
- ASSERT(cur->pos >= nr_entries ||
- xfs_iext_rec_cmp(cur_rec(cur), irec->br_startoff) != 0);
- if (nr_entries == RECS_PER_LEAF)
- new = xfs_iext_split_leaf(cur, &nr_entries);
- /*
- * Update the pointers in higher levels if the first entry changes
- * in an existing node.
- */
- if (cur->leaf != new && cur->pos == 0 && nr_entries > 0) {
- xfs_iext_update_node(ifp, xfs_iext_leaf_key(cur->leaf, 0),
- offset, 1, cur->leaf);
- }
- for (i = nr_entries; i > cur->pos; i--)
- cur->leaf->recs[i] = cur->leaf->recs[i - 1];
- xfs_iext_set(cur_rec(cur), irec);
- ifp->if_bytes += sizeof(struct xfs_iext_rec);
- trace_xfs_iext_insert(ip, cur, state, _RET_IP_);
- if (new)
- xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2);
- }
- static struct xfs_iext_node *
- xfs_iext_rebalance_node(
- struct xfs_iext_node *parent,
- int *pos,
- struct xfs_iext_node *node,
- int nr_entries)
- {
- /*
- * If the neighbouring nodes are completely full, or have different
- * parents, we might never be able to merge our node, and will only
- * delete it once the number of entries hits zero.
- */
- if (nr_entries == 0)
- return node;
- if (*pos > 0) {
- struct xfs_iext_node *prev = parent->ptrs[*pos - 1];
- int nr_prev = xfs_iext_node_nr_entries(prev, 0), i;
- if (nr_prev + nr_entries <= KEYS_PER_NODE) {
- for (i = 0; i < nr_entries; i++) {
- prev->keys[nr_prev + i] = node->keys[i];
- prev->ptrs[nr_prev + i] = node->ptrs[i];
- }
- return node;
- }
- }
- if (*pos + 1 < xfs_iext_node_nr_entries(parent, *pos)) {
- struct xfs_iext_node *next = parent->ptrs[*pos + 1];
- int nr_next = xfs_iext_node_nr_entries(next, 0), i;
- if (nr_entries + nr_next <= KEYS_PER_NODE) {
- /*
- * Merge the next node into this node so that we don't
- * have to do an additional update of the keys in the
- * higher levels.
- */
- for (i = 0; i < nr_next; i++) {
- node->keys[nr_entries + i] = next->keys[i];
- node->ptrs[nr_entries + i] = next->ptrs[i];
- }
- ++*pos;
- return next;
- }
- }
- return NULL;
- }
- static void
- xfs_iext_remove_node(
- struct xfs_ifork *ifp,
- xfs_fileoff_t offset,
- void *victim)
- {
- struct xfs_iext_node *node, *parent;
- int level = 2, pos, nr_entries, i;
- ASSERT(level <= ifp->if_height);
- node = xfs_iext_find_level(ifp, offset, level);
- pos = xfs_iext_node_pos(node, offset);
- again:
- ASSERT(node->ptrs[pos]);
- ASSERT(node->ptrs[pos] == victim);
- kmem_free(victim);
- nr_entries = xfs_iext_node_nr_entries(node, pos) - 1;
- offset = node->keys[0];
- for (i = pos; i < nr_entries; i++) {
- node->keys[i] = node->keys[i + 1];
- node->ptrs[i] = node->ptrs[i + 1];
- }
- node->keys[nr_entries] = XFS_IEXT_KEY_INVALID;
- node->ptrs[nr_entries] = NULL;
- if (pos == 0 && nr_entries > 0) {
- xfs_iext_update_node(ifp, offset, node->keys[0], level, node);
- offset = node->keys[0];
- }
- if (nr_entries >= KEYS_PER_NODE / 2)
- return;
- if (level < ifp->if_height) {
- /*
- * If we aren't at the root yet try to find a neighbour node to
- * merge with (or delete the node if it is empty), and then
- * recurse up to the next level.
- */
- level++;
- parent = xfs_iext_find_level(ifp, offset, level);
- pos = xfs_iext_node_pos(parent, offset);
- ASSERT(pos != KEYS_PER_NODE);
- ASSERT(parent->ptrs[pos] == node);
- node = xfs_iext_rebalance_node(parent, &pos, node, nr_entries);
- if (node) {
- victim = node;
- node = parent;
- goto again;
- }
- } else if (nr_entries == 1) {
- /*
- * If we are at the root and only one entry is left we can just
- * free this node and update the root pointer.
- */
- ASSERT(node == ifp->if_u1.if_root);
- ifp->if_u1.if_root = node->ptrs[0];
- ifp->if_height--;
- kmem_free(node);
- }
- }
- static void
- xfs_iext_rebalance_leaf(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur,
- struct xfs_iext_leaf *leaf,
- xfs_fileoff_t offset,
- int nr_entries)
- {
- /*
- * If the neighbouring nodes are completely full we might never be able
- * to merge our node, and will only delete it once the number of
- * entries hits zero.
- */
- if (nr_entries == 0)
- goto remove_node;
- if (leaf->prev) {
- int nr_prev = xfs_iext_leaf_nr_entries(ifp, leaf->prev, 0), i;
- if (nr_prev + nr_entries <= RECS_PER_LEAF) {
- for (i = 0; i < nr_entries; i++)
- leaf->prev->recs[nr_prev + i] = leaf->recs[i];
- if (cur->leaf == leaf) {
- cur->leaf = leaf->prev;
- cur->pos += nr_prev;
- }
- goto remove_node;
- }
- }
- if (leaf->next) {
- int nr_next = xfs_iext_leaf_nr_entries(ifp, leaf->next, 0), i;
- if (nr_entries + nr_next <= RECS_PER_LEAF) {
- /*
- * Merge the next node into this node so that we don't
- * have to do an additional update of the keys in the
- * higher levels.
- */
- for (i = 0; i < nr_next; i++) {
- leaf->recs[nr_entries + i] =
- leaf->next->recs[i];
- }
- if (cur->leaf == leaf->next) {
- cur->leaf = leaf;
- cur->pos += nr_entries;
- }
- offset = xfs_iext_leaf_key(leaf->next, 0);
- leaf = leaf->next;
- goto remove_node;
- }
- }
- return;
- remove_node:
- if (leaf->prev)
- leaf->prev->next = leaf->next;
- if (leaf->next)
- leaf->next->prev = leaf->prev;
- xfs_iext_remove_node(ifp, offset, leaf);
- }
- static void
- xfs_iext_free_last_leaf(
- struct xfs_ifork *ifp)
- {
- ifp->if_height--;
- kmem_free(ifp->if_u1.if_root);
- ifp->if_u1.if_root = NULL;
- }
- void
- xfs_iext_remove(
- struct xfs_inode *ip,
- struct xfs_iext_cursor *cur,
- int state)
- {
- struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state);
- struct xfs_iext_leaf *leaf = cur->leaf;
- xfs_fileoff_t offset = xfs_iext_leaf_key(leaf, 0);
- int i, nr_entries;
- trace_xfs_iext_remove(ip, cur, state, _RET_IP_);
- ASSERT(ifp->if_height > 0);
- ASSERT(ifp->if_u1.if_root != NULL);
- ASSERT(xfs_iext_valid(ifp, cur));
- xfs_iext_inc_seq(ifp, state);
- nr_entries = xfs_iext_leaf_nr_entries(ifp, leaf, cur->pos) - 1;
- for (i = cur->pos; i < nr_entries; i++)
- leaf->recs[i] = leaf->recs[i + 1];
- xfs_iext_rec_clear(&leaf->recs[nr_entries]);
- ifp->if_bytes -= sizeof(struct xfs_iext_rec);
- if (cur->pos == 0 && nr_entries > 0) {
- xfs_iext_update_node(ifp, offset, xfs_iext_leaf_key(leaf, 0), 1,
- leaf);
- offset = xfs_iext_leaf_key(leaf, 0);
- } else if (cur->pos == nr_entries) {
- if (ifp->if_height > 1 && leaf->next)
- cur->leaf = leaf->next;
- else
- cur->leaf = NULL;
- cur->pos = 0;
- }
- if (nr_entries >= RECS_PER_LEAF / 2)
- return;
- if (ifp->if_height > 1)
- xfs_iext_rebalance_leaf(ifp, cur, leaf, offset, nr_entries);
- else if (nr_entries == 0)
- xfs_iext_free_last_leaf(ifp);
- }
- /*
- * Lookup the extent covering bno.
- *
- * If there is an extent covering bno return the extent index, and store the
- * expanded extent structure in *gotp, and the extent cursor in *cur.
- * If there is no extent covering bno, but there is an extent after it (e.g.
- * it lies in a hole) return that extent in *gotp and its cursor in *cur
- * instead.
- * If bno is beyond the last extent return false, and return an invalid
- * cursor value.
- */
- bool
- xfs_iext_lookup_extent(
- struct xfs_inode *ip,
- struct xfs_ifork *ifp,
- xfs_fileoff_t offset,
- struct xfs_iext_cursor *cur,
- struct xfs_bmbt_irec *gotp)
- {
- XFS_STATS_INC(ip->i_mount, xs_look_exlist);
- cur->leaf = xfs_iext_find_level(ifp, offset, 1);
- if (!cur->leaf) {
- cur->pos = 0;
- return false;
- }
- for (cur->pos = 0; cur->pos < xfs_iext_max_recs(ifp); cur->pos++) {
- struct xfs_iext_rec *rec = cur_rec(cur);
- if (xfs_iext_rec_is_empty(rec))
- break;
- if (xfs_iext_rec_cmp(rec, offset) >= 0)
- goto found;
- }
- /* Try looking in the next node for an entry > offset */
- if (ifp->if_height == 1 || !cur->leaf->next)
- return false;
- cur->leaf = cur->leaf->next;
- cur->pos = 0;
- if (!xfs_iext_valid(ifp, cur))
- return false;
- found:
- xfs_iext_get(gotp, cur_rec(cur));
- return true;
- }
- /*
- * Returns the last extent before end, and if this extent doesn't cover
- * end, update end to the end of the extent.
- */
- bool
- xfs_iext_lookup_extent_before(
- struct xfs_inode *ip,
- struct xfs_ifork *ifp,
- xfs_fileoff_t *end,
- struct xfs_iext_cursor *cur,
- struct xfs_bmbt_irec *gotp)
- {
- /* could be optimized to not even look up the next on a match.. */
- if (xfs_iext_lookup_extent(ip, ifp, *end - 1, cur, gotp) &&
- gotp->br_startoff <= *end - 1)
- return true;
- if (!xfs_iext_prev_extent(ifp, cur, gotp))
- return false;
- *end = gotp->br_startoff + gotp->br_blockcount;
- return true;
- }
- void
- xfs_iext_update_extent(
- struct xfs_inode *ip,
- int state,
- struct xfs_iext_cursor *cur,
- struct xfs_bmbt_irec *new)
- {
- struct xfs_ifork *ifp = xfs_iext_state_to_fork(ip, state);
- xfs_iext_inc_seq(ifp, state);
- if (cur->pos == 0) {
- struct xfs_bmbt_irec old;
- xfs_iext_get(&old, cur_rec(cur));
- if (new->br_startoff != old.br_startoff) {
- xfs_iext_update_node(ifp, old.br_startoff,
- new->br_startoff, 1, cur->leaf);
- }
- }
- trace_xfs_bmap_pre_update(ip, cur, state, _RET_IP_);
- xfs_iext_set(cur_rec(cur), new);
- trace_xfs_bmap_post_update(ip, cur, state, _RET_IP_);
- }
- /*
- * Return true if the cursor points at an extent and return the extent structure
- * in gotp. Else return false.
- */
- bool
- xfs_iext_get_extent(
- struct xfs_ifork *ifp,
- struct xfs_iext_cursor *cur,
- struct xfs_bmbt_irec *gotp)
- {
- if (!xfs_iext_valid(ifp, cur))
- return false;
- xfs_iext_get(gotp, cur_rec(cur));
- return true;
- }
- /*
- * This is a recursive function, because of that we need to be extremely
- * careful with stack usage.
- */
- static void
- xfs_iext_destroy_node(
- struct xfs_iext_node *node,
- int level)
- {
- int i;
- if (level > 1) {
- for (i = 0; i < KEYS_PER_NODE; i++) {
- if (node->keys[i] == XFS_IEXT_KEY_INVALID)
- break;
- xfs_iext_destroy_node(node->ptrs[i], level - 1);
- }
- }
- kmem_free(node);
- }
- void
- xfs_iext_destroy(
- struct xfs_ifork *ifp)
- {
- xfs_iext_destroy_node(ifp->if_u1.if_root, ifp->if_height);
- ifp->if_bytes = 0;
- ifp->if_height = 0;
- ifp->if_u1.if_root = NULL;
- }
|