/* * Given that the length can't be a zero, only an empty hi value indicates an * unused record.
*/ staticbool xfs_iext_rec_is_empty(struct xfs_iext_rec *rec)
{ return rec->hi == 0;
}
/* * 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];
};
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);
}
staticstruct 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 = xfs_iext_alloc_node(NODE_SIZE); constint 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];
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;
/* 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]);
}
/* * Increment the sequence counter on extent tree changes. 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.
*/ staticinlinevoid xfs_iext_inc_seq(struct xfs_ifork *ifp)
{
WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1);
}
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);
if (new)
xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2);
}
staticstruct 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 (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];
}
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);
node = xfs_iext_rebalance_node(parent, &pos, node, nr_entries); if (node) {
victim = node;
node = parent; goto again;
}
} elseif (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_data);
ifp->if_data = node->ptrs[0];
ifp->if_height--;
kfree(node);
}
}
staticvoid
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 (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];
}
/* * 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);
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) returnfalse;
cur->leaf = cur->leaf->next;
cur->pos = 0; if (!xfs_iext_valid(ifp, cur)) returnfalse;
found:
xfs_iext_get(gotp, cur_rec(cur)); returntrue;
}
/* * 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) returntrue; if (!xfs_iext_prev_extent(ifp, cur, gotp)) returnfalse;
*end = gotp->br_startoff + gotp->br_blockcount; returntrue;
}
/* * 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)) returnfalse;
xfs_iext_get(gotp, cur_rec(cur)); returntrue;
}
/* * This is a recursive function, because of that we need to be extremely * careful with stack usage.
*/ staticvoid
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);
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.119Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.