};
static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
-static inline void *ptr_to_indirect(void *ptr)
+static inline void *node_to_entry(void *ptr)
{
- return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
+ return (void *)((unsigned long)ptr | RADIX_TREE_INTERNAL_NODE);
}
-#define RADIX_TREE_RETRY ptr_to_indirect(NULL)
+#define RADIX_TREE_RETRY node_to_entry(NULL)
#ifdef CONFIG_RADIX_TREE_MULTIORDER
/* Sibling slots point directly to another slot in the same node */
return slot - parent->slots;
}
-static unsigned radix_tree_descend(struct radix_tree_node *parent,
- struct radix_tree_node **nodep, unsigned offset)
+static unsigned int radix_tree_descend(struct radix_tree_node *parent,
+ struct radix_tree_node **nodep, unsigned long index)
{
+ unsigned int offset = (index >> parent->shift) & RADIX_TREE_MAP_MASK;
void **entry = rcu_dereference_raw(parent->slots[offset]);
#ifdef CONFIG_RADIX_TREE_MULTIORDER
- if (radix_tree_is_indirect_ptr(entry)) {
+ if (radix_tree_is_internal_node(entry)) {
unsigned long siboff = get_slot_offset(parent, entry);
if (siboff < RADIX_TREE_MAP_SIZE) {
offset = siboff;
if (is_sibling_entry(node, entry)) {
pr_debug("radix sblng %p offset %ld val %p indices %ld-%ld\n",
entry, i,
- *(void **)indirect_to_ptr(entry),
+ *(void **)entry_to_node(entry),
first, last);
- } else if (!radix_tree_is_indirect_ptr(entry)) {
+ } else if (!radix_tree_is_internal_node(entry)) {
pr_debug("radix entry %p offset %ld indices %ld-%ld\n",
entry, i, first, last);
} else {
- dump_node(indirect_to_ptr(entry), first);
+ dump_node(entry_to_node(entry), first);
}
}
}
pr_debug("radix root: %p rnode %p tags %x\n",
root, root->rnode,
root->gfp_mask >> __GFP_BITS_SHIFT);
- if (!radix_tree_is_indirect_ptr(root->rnode))
+ if (!radix_tree_is_internal_node(root->rnode))
return;
- dump_node(indirect_to_ptr(root->rnode), 0);
+ dump_node(entry_to_node(root->rnode), 0);
}
#endif
ret = kmem_cache_alloc(radix_tree_node_cachep,
gfp_mask | __GFP_ACCOUNT);
out:
- BUG_ON(radix_tree_is_indirect_ptr(ret));
+ BUG_ON(radix_tree_is_internal_node(ret));
return ret;
}
*nodep = node;
- if (likely(radix_tree_is_indirect_ptr(node))) {
- node = indirect_to_ptr(node);
+ if (likely(radix_tree_is_internal_node(node))) {
+ node = entry_to_node(node);
*maxindex = node_maxindex(node);
return node->shift + RADIX_TREE_MAP_SHIFT;
}
node->offset = 0;
node->count = 1;
node->parent = NULL;
- if (radix_tree_is_indirect_ptr(slot)) {
- slot = indirect_to_ptr(slot);
- slot->parent = node;
- slot = ptr_to_indirect(slot);
- }
+ if (radix_tree_is_internal_node(slot))
+ entry_to_node(slot)->parent = node;
node->slots[0] = slot;
- node = ptr_to_indirect(node);
- rcu_assign_pointer(root->rnode, node);
+ slot = node_to_entry(node);
+ rcu_assign_pointer(root->rnode, slot);
shift += RADIX_TREE_MAP_SHIFT;
- slot = node;
} while (shift <= maxshift);
out:
return maxshift + RADIX_TREE_MAP_SHIFT;
unsigned order, struct radix_tree_node **nodep,
void ***slotp)
{
- struct radix_tree_node *node = NULL, *slot;
+ struct radix_tree_node *node = NULL, *child;
+ void **slot = (void **)&root->rnode;
unsigned long maxindex;
- unsigned int shift, offset;
+ unsigned int shift, offset = 0;
unsigned long max = index | ((1UL << order) - 1);
- shift = radix_tree_load_root(root, &slot, &maxindex);
+ shift = radix_tree_load_root(root, &child, &maxindex);
/* Make sure the tree is high enough. */
if (max > maxindex) {
if (error < 0)
return error;
shift = error;
- slot = root->rnode;
+ child = root->rnode;
if (order == shift)
shift += RADIX_TREE_MAP_SHIFT;
}
- offset = 0; /* uninitialised var warning */
while (shift > order) {
shift -= RADIX_TREE_MAP_SHIFT;
- if (slot == NULL) {
+ if (child == NULL) {
/* Have to add a child node. */
- slot = radix_tree_node_alloc(root);
- if (!slot)
+ child = radix_tree_node_alloc(root);
+ if (!child)
return -ENOMEM;
- slot->shift = shift;
- slot->offset = offset;
- slot->parent = node;
- if (node) {
- rcu_assign_pointer(node->slots[offset],
- ptr_to_indirect(slot));
+ child->shift = shift;
+ child->offset = offset;
+ child->parent = node;
+ rcu_assign_pointer(*slot, node_to_entry(child));
+ if (node)
node->count++;
- } else
- rcu_assign_pointer(root->rnode,
- ptr_to_indirect(slot));
- } else if (!radix_tree_is_indirect_ptr(slot))
+ } else if (!radix_tree_is_internal_node(child))
break;
/* Go a level down */
- node = indirect_to_ptr(slot);
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- offset = radix_tree_descend(node, &slot, offset);
+ node = entry_to_node(child);
+ offset = radix_tree_descend(node, &child, index);
+ slot = &node->slots[offset];
}
#ifdef CONFIG_RADIX_TREE_MULTIORDER
/* Insert pointers to the canonical entry */
if (order > shift) {
- int i, n = 1 << (order - shift);
+ unsigned i, n = 1 << (order - shift);
offset = offset & ~(n - 1);
- slot = ptr_to_indirect(&node->slots[offset]);
+ slot = &node->slots[offset];
+ child = node_to_entry(slot);
for (i = 0; i < n; i++) {
- if (node->slots[offset + i])
+ if (slot[i])
return -EEXIST;
}
for (i = 1; i < n; i++) {
- rcu_assign_pointer(node->slots[offset + i], slot);
+ rcu_assign_pointer(slot[i], child);
node->count++;
}
}
if (nodep)
*nodep = node;
if (slotp)
- *slotp = node ? node->slots + offset : (void **)&root->rnode;
+ *slotp = slot;
return 0;
}
void **slot;
int error;
- BUG_ON(radix_tree_is_indirect_ptr(item));
+ BUG_ON(radix_tree_is_internal_node(item));
error = __radix_tree_create(root, index, order, &node, &slot);
if (error)
{
struct radix_tree_node *node, *parent;
unsigned long maxindex;
- unsigned int shift;
void **slot;
restart:
parent = NULL;
slot = (void **)&root->rnode;
- shift = radix_tree_load_root(root, &node, &maxindex);
+ radix_tree_load_root(root, &node, &maxindex);
if (index > maxindex)
return NULL;
- while (radix_tree_is_indirect_ptr(node)) {
+ while (radix_tree_is_internal_node(node)) {
unsigned offset;
if (node == RADIX_TREE_RETRY)
goto restart;
- parent = indirect_to_ptr(node);
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- offset = radix_tree_descend(parent, &node, offset);
+ parent = entry_to_node(node);
+ offset = radix_tree_descend(parent, &node, index);
slot = parent->slots + offset;
}
{
struct radix_tree_node *node, *parent;
unsigned long maxindex;
- unsigned int shift;
- shift = radix_tree_load_root(root, &node, &maxindex);
+ radix_tree_load_root(root, &node, &maxindex);
BUG_ON(index > maxindex);
- while (radix_tree_is_indirect_ptr(node)) {
+ while (radix_tree_is_internal_node(node)) {
unsigned offset;
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-
- parent = indirect_to_ptr(node);
- offset = radix_tree_descend(parent, &node, offset);
+ parent = entry_to_node(node);
+ offset = radix_tree_descend(parent, &node, index);
BUG_ON(!node);
if (!tag_get(parent, tag, offset))
}
EXPORT_SYMBOL(radix_tree_tag_set);
+static void node_tag_clear(struct radix_tree_root *root,
+ struct radix_tree_node *node,
+ unsigned int tag, unsigned int offset)
+{
+ while (node) {
+ if (!tag_get(node, tag, offset))
+ return;
+ tag_clear(node, tag, offset);
+ if (any_tag_set(node, tag))
+ return;
+
+ offset = node->offset;
+ node = node->parent;
+ }
+
+ /* clear the root's tag bit */
+ if (root_tag_get(root, tag))
+ root_tag_clear(root, tag);
+}
+
/**
* radix_tree_tag_clear - clear a tag on a radix tree node
* @root: radix tree root
{
struct radix_tree_node *node, *parent;
unsigned long maxindex;
- unsigned int shift;
int uninitialized_var(offset);
- shift = radix_tree_load_root(root, &node, &maxindex);
+ radix_tree_load_root(root, &node, &maxindex);
if (index > maxindex)
return NULL;
parent = NULL;
- while (radix_tree_is_indirect_ptr(node)) {
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-
- parent = indirect_to_ptr(node);
- offset = radix_tree_descend(parent, &node, offset);
+ while (radix_tree_is_internal_node(node)) {
+ parent = entry_to_node(node);
+ offset = radix_tree_descend(parent, &node, index);
}
- if (node == NULL)
- goto out;
-
- index >>= shift;
+ if (node)
+ node_tag_clear(root, parent, tag, offset);
- while (parent) {
- if (!tag_get(parent, tag, offset))
- goto out;
- tag_clear(parent, tag, offset);
- if (any_tag_set(parent, tag))
- goto out;
-
- index >>= RADIX_TREE_MAP_SHIFT;
- offset = index & RADIX_TREE_MAP_MASK;
- parent = parent->parent;
- }
-
- /* clear the root's tag bit */
- if (root_tag_get(root, tag))
- root_tag_clear(root, tag);
-
-out:
return node;
}
EXPORT_SYMBOL(radix_tree_tag_clear);
{
struct radix_tree_node *node, *parent;
unsigned long maxindex;
- unsigned int shift;
if (!root_tag_get(root, tag))
return 0;
- shift = radix_tree_load_root(root, &node, &maxindex);
+ radix_tree_load_root(root, &node, &maxindex);
if (index > maxindex)
return 0;
if (node == NULL)
return 0;
- while (radix_tree_is_indirect_ptr(node)) {
- int offset;
-
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+ while (radix_tree_is_internal_node(node)) {
+ unsigned offset;
- parent = indirect_to_ptr(node);
- offset = radix_tree_descend(parent, &node, offset);
+ parent = entry_to_node(node);
+ offset = radix_tree_descend(parent, &node, index);
if (!node)
return 0;
void **radix_tree_next_chunk(struct radix_tree_root *root,
struct radix_tree_iter *iter, unsigned flags)
{
- unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK;
- struct radix_tree_node *rnode, *node;
+ unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK;
+ struct radix_tree_node *node, *child;
unsigned long index, offset, maxindex;
if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag))
return NULL;
restart:
- shift = radix_tree_load_root(root, &rnode, &maxindex);
+ radix_tree_load_root(root, &child, &maxindex);
if (index > maxindex)
return NULL;
+ if (!child)
+ return NULL;
- if (radix_tree_is_indirect_ptr(rnode)) {
- rnode = indirect_to_ptr(rnode);
- } else if (rnode) {
+ if (!radix_tree_is_internal_node(child)) {
/* Single-slot tree */
iter->index = index;
iter->next_index = maxindex + 1;
iter->tags = 1;
- __set_iter_shift(iter, shift);
+ __set_iter_shift(iter, 0);
return (void **)&root->rnode;
- } else
- return NULL;
-
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = index >> shift;
-
- node = rnode;
- while (1) {
- struct radix_tree_node *slot;
- unsigned new_off = radix_tree_descend(node, &slot, offset);
+ }
- if (new_off < offset) {
- offset = new_off;
- index &= ~((RADIX_TREE_MAP_SIZE << shift) - 1);
- index |= offset << shift;
- }
+ do {
+ node = entry_to_node(child);
+ offset = radix_tree_descend(node, &child, index);
if ((flags & RADIX_TREE_ITER_TAGGED) ?
- !tag_get(node, tag, offset) : !slot) {
+ !tag_get(node, tag, offset) : !child) {
/* Hole detected */
if (flags & RADIX_TREE_ITER_CONTIG)
return NULL;
if (slot)
break;
}
- index &= ~((RADIX_TREE_MAP_SIZE << shift) - 1);
- index += offset << shift;
+ index &= ~node_maxindex(node);
+ index += offset << node->shift;
/* Overflow after ~0UL */
if (!index)
return NULL;
if (offset == RADIX_TREE_MAP_SIZE)
goto restart;
- slot = rcu_dereference_raw(node->slots[offset]);
+ child = rcu_dereference_raw(node->slots[offset]);
}
- if ((slot == NULL) || (slot == RADIX_TREE_RETRY))
+ if ((child == NULL) || (child == RADIX_TREE_RETRY))
goto restart;
- if (!radix_tree_is_indirect_ptr(slot))
- break;
-
- node = indirect_to_ptr(slot);
- shift -= RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- }
+ } while (radix_tree_is_internal_node(child));
/* Update the iterator state */
- iter->index = index & ~((1 << shift) - 1);
- iter->next_index = (index | ((RADIX_TREE_MAP_SIZE << shift) - 1)) + 1;
- __set_iter_shift(iter, shift);
+ iter->index = (index &~ node_maxindex(node)) | (offset << node->shift);
+ iter->next_index = (index | node_maxindex(node)) + 1;
+ __set_iter_shift(iter, node->shift);
/* Construct iter->tags bit-mask from node->tags[tag] array */
if (flags & RADIX_TREE_ITER_TAGGED) {
unsigned long nr_to_tag,
unsigned int iftag, unsigned int settag)
{
- struct radix_tree_node *slot, *node = NULL;
+ struct radix_tree_node *parent, *node, *child;
unsigned long maxindex;
- unsigned int shift = radix_tree_load_root(root, &slot, &maxindex);
unsigned long tagged = 0;
unsigned long index = *first_indexp;
+ radix_tree_load_root(root, &child, &maxindex);
last_index = min(last_index, maxindex);
if (index > last_index)
return 0;
*first_indexp = last_index + 1;
return 0;
}
- if (!radix_tree_is_indirect_ptr(slot)) {
+ if (!radix_tree_is_internal_node(child)) {
*first_indexp = last_index + 1;
root_tag_set(root, settag);
return 1;
}
- node = indirect_to_ptr(slot);
- shift -= RADIX_TREE_MAP_SHIFT;
+ node = entry_to_node(child);
for (;;) {
- unsigned long upindex;
- unsigned offset;
-
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
- offset = radix_tree_descend(node, &slot, offset);
- if (!slot)
+ unsigned offset = radix_tree_descend(node, &child, index);
+ if (!child)
goto next;
if (!tag_get(node, iftag, offset))
goto next;
/* Sibling slots never have tags set on them */
- if (radix_tree_is_indirect_ptr(slot)) {
- node = indirect_to_ptr(slot);
- shift -= RADIX_TREE_MAP_SHIFT;
+ if (radix_tree_is_internal_node(child)) {
+ node = entry_to_node(child);
continue;
}
tagged++;
tag_set(node, settag, offset);
- slot = node->parent;
/* walk back up the path tagging interior nodes */
- upindex = index >> shift;
- while (slot) {
- upindex >>= RADIX_TREE_MAP_SHIFT;
- offset = upindex & RADIX_TREE_MAP_MASK;
-
+ parent = node;
+ for (;;) {
+ offset = parent->offset;
+ parent = parent->parent;
+ if (!parent)
+ break;
/* stop if we find a node with the tag already set */
- if (tag_get(slot, settag, offset))
+ if (tag_get(parent, settag, offset))
break;
- tag_set(slot, settag, offset);
- slot = slot->parent;
+ tag_set(parent, settag, offset);
}
-
next:
- /* Go to next item at level determined by 'shift' */
- index = ((index >> shift) + 1) << shift;
+ /* Go to next entry in node */
+ index = ((index >> node->shift) + 1) << node->shift;
/* Overflow can happen when last_index is ~0UL... */
if (index > last_index || !index)
break;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+ offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
while (offset == 0) {
/*
* We've fully scanned this node. Go up. Because
* we do below cannot wander astray.
*/
node = node->parent;
- shift += RADIX_TREE_MAP_SHIFT;
- offset = (index >> shift) & RADIX_TREE_MAP_MASK;
+ offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
}
if (is_sibling_entry(node, node->slots[offset]))
goto next;
results[ret] = rcu_dereference_raw(*slot);
if (!results[ret])
continue;
- if (radix_tree_is_indirect_ptr(results[ret])) {
+ if (radix_tree_is_internal_node(results[ret])) {
slot = radix_tree_iter_retry(&iter);
continue;
}
results[ret] = rcu_dereference_raw(*slot);
if (!results[ret])
continue;
- if (radix_tree_is_indirect_ptr(results[ret])) {
+ if (radix_tree_is_internal_node(results[ret])) {
slot = radix_tree_iter_retry(&iter);
continue;
}
static unsigned long __locate(struct radix_tree_node *slot, void *item,
unsigned long index, struct locate_info *info)
{
- unsigned int shift;
unsigned long i;
- shift = slot->shift + RADIX_TREE_MAP_SHIFT;
-
do {
- shift -= RADIX_TREE_MAP_SHIFT;
+ unsigned int shift = slot->shift;
for (i = (index >> shift) & RADIX_TREE_MAP_MASK;
i < RADIX_TREE_MAP_SIZE;
rcu_dereference_raw(slot->slots[i]);
if (node == RADIX_TREE_RETRY)
goto out;
- if (!radix_tree_is_indirect_ptr(node)) {
+ if (!radix_tree_is_internal_node(node)) {
if (node == item) {
info->found_index = index;
info->stop = true;
}
continue;
}
- node = indirect_to_ptr(node);
+ node = entry_to_node(node);
if (is_sibling_entry(slot, node))
continue;
slot = node;
break;
}
- if (i == RADIX_TREE_MAP_SIZE)
- break;
- } while (shift);
+ } while (i < RADIX_TREE_MAP_SIZE);
out:
if ((index == 0) && (i == RADIX_TREE_MAP_SIZE))
do {
rcu_read_lock();
node = rcu_dereference_raw(root->rnode);
- if (!radix_tree_is_indirect_ptr(node)) {
+ if (!radix_tree_is_internal_node(node)) {
rcu_read_unlock();
if (node == item)
info.found_index = 0;
break;
}
- node = indirect_to_ptr(node);
+ node = entry_to_node(node);
max_index = node_maxindex(node);
if (cur_index > max_index) {
bool shrunk = false;
for (;;) {
- struct radix_tree_node *to_free = root->rnode;
- struct radix_tree_node *slot;
+ struct radix_tree_node *node = root->rnode;
+ struct radix_tree_node *child;
- if (!radix_tree_is_indirect_ptr(to_free))
+ if (!radix_tree_is_internal_node(node))
break;
- to_free = indirect_to_ptr(to_free);
+ node = entry_to_node(node);
/*
* The candidate node has more than one child, or its child
* is not at the leftmost slot, or the child is a multiorder
* entry, we cannot shrink.
*/
- if (to_free->count != 1)
+ if (node->count != 1)
break;
- slot = to_free->slots[0];
- if (!slot)
+ child = node->slots[0];
+ if (!child)
break;
- if (!radix_tree_is_indirect_ptr(slot) && to_free->shift)
+ if (!radix_tree_is_internal_node(child) && node->shift)
break;
- if (radix_tree_is_indirect_ptr(slot)) {
- slot = indirect_to_ptr(slot);
- slot->parent = NULL;
- slot = ptr_to_indirect(slot);
- }
+ if (radix_tree_is_internal_node(child))
+ entry_to_node(child)->parent = NULL;
/*
* We don't need rcu_assign_pointer(), since we are simply
* moving the node from one part of the tree to another: if it
* was safe to dereference the old pointer to it
- * (to_free->slots[0]), it will be safe to dereference the new
+ * (node->slots[0]), it will be safe to dereference the new
* one (root->rnode) as far as dependent read barriers go.
*/
- root->rnode = slot;
+ root->rnode = child;
/*
* We have a dilemma here. The node's slot[0] must not be
* also results in a stale slot). So tag the slot as indirect
* to force callers to retry.
*/
- if (!radix_tree_is_indirect_ptr(slot))
- to_free->slots[0] = RADIX_TREE_RETRY;
+ if (!radix_tree_is_internal_node(child))
+ node->slots[0] = RADIX_TREE_RETRY;
- radix_tree_node_free(to_free);
+ radix_tree_node_free(node);
shrunk = true;
}
struct radix_tree_node *parent;
if (node->count) {
- if (node == indirect_to_ptr(root->rnode))
+ if (node == entry_to_node(root->rnode))
deleted |= radix_tree_shrink(root);
return deleted;
}
offset = get_slot_offset(node, slot);
- /*
- * Clear all tags associated with the item to be deleted.
- * This way of doing it would be inefficient, but seldom is any set.
- */
- for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
- if (tag_get(node, tag, offset))
- radix_tree_tag_clear(root, index, tag);
- }
+ /* Clear all tags associated with the item to be deleted. */
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ node_tag_clear(root, node, tag, offset);
- delete_sibling_entries(node, ptr_to_indirect(slot), offset);
+ delete_sibling_entries(node, node_to_entry(slot), offset);
node->slots[offset] = NULL;
node->count--;
}
EXPORT_SYMBOL(radix_tree_delete);
+struct radix_tree_node *radix_tree_replace_clear_tags(
+ struct radix_tree_root *root,
+ unsigned long index, void *entry)
+{
+ struct radix_tree_node *node;
+ void **slot;
+
+ __radix_tree_lookup(root, index, &node, &slot);
+
+ if (node) {
+ unsigned int tag, offset = get_slot_offset(node, slot);
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ node_tag_clear(root, node, tag, offset);
+ } else {
+ /* Clear root node tags */
+ root->gfp_mask &= __GFP_BITS_MASK;
+ }
+
+ radix_tree_replace_slot(slot, entry);
+ return node;
+}
+
/**
* radix_tree_tagged - test whether any items in the tree are tagged
* @root: radix tree root