|
@@ -1,6 +1,7 @@
|
|
/*
|
|
/*
|
|
* Copyright (C) 2001 Momchil Velikov
|
|
* Copyright (C) 2001 Momchil Velikov
|
|
* Portions Copyright (C) 2001 Christoph Hellwig
|
|
* Portions Copyright (C) 2001 Christoph Hellwig
|
|
|
|
+ * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* modify it under the terms of the GNU General Public License as
|
|
@@ -51,7 +52,7 @@ struct radix_tree_node {
|
|
};
|
|
};
|
|
|
|
|
|
struct radix_tree_path {
|
|
struct radix_tree_path {
|
|
- struct radix_tree_node *node, **slot;
|
|
|
|
|
|
+ struct radix_tree_node *node;
|
|
int offset;
|
|
int offset;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -227,7 +228,7 @@ out:
|
|
int radix_tree_insert(struct radix_tree_root *root,
|
|
int radix_tree_insert(struct radix_tree_root *root,
|
|
unsigned long index, void *item)
|
|
unsigned long index, void *item)
|
|
{
|
|
{
|
|
- struct radix_tree_node *node = NULL, *tmp, **slot;
|
|
|
|
|
|
+ struct radix_tree_node *node = NULL, *slot;
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
int offset;
|
|
int offset;
|
|
int error;
|
|
int error;
|
|
@@ -240,38 +241,42 @@ int radix_tree_insert(struct radix_tree_root *root,
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
- slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
height = root->height;
|
|
height = root->height;
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
|
|
|
|
offset = 0; /* uninitialised var warning */
|
|
offset = 0; /* uninitialised var warning */
|
|
while (height > 0) {
|
|
while (height > 0) {
|
|
- if (*slot == NULL) {
|
|
|
|
|
|
+ if (slot == NULL) {
|
|
/* Have to add a child node. */
|
|
/* Have to add a child node. */
|
|
- if (!(tmp = radix_tree_node_alloc(root)))
|
|
|
|
|
|
+ if (!(slot = radix_tree_node_alloc(root)))
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
- *slot = tmp;
|
|
|
|
- if (node)
|
|
|
|
|
|
+ if (node) {
|
|
|
|
+ node->slots[offset] = slot;
|
|
node->count++;
|
|
node->count++;
|
|
|
|
+ } else
|
|
|
|
+ root->rnode = slot;
|
|
}
|
|
}
|
|
|
|
|
|
/* Go a level down */
|
|
/* Go a level down */
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
- node = *slot;
|
|
|
|
- slot = (struct radix_tree_node **)(node->slots + offset);
|
|
|
|
|
|
+ node = slot;
|
|
|
|
+ slot = node->slots[offset];
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
height--;
|
|
height--;
|
|
}
|
|
}
|
|
|
|
|
|
- if (*slot != NULL)
|
|
|
|
|
|
+ if (slot != NULL)
|
|
return -EEXIST;
|
|
return -EEXIST;
|
|
|
|
+
|
|
if (node) {
|
|
if (node) {
|
|
node->count++;
|
|
node->count++;
|
|
|
|
+ node->slots[offset] = item;
|
|
BUG_ON(tag_get(node, 0, offset));
|
|
BUG_ON(tag_get(node, 0, offset));
|
|
BUG_ON(tag_get(node, 1, offset));
|
|
BUG_ON(tag_get(node, 1, offset));
|
|
- }
|
|
|
|
|
|
+ } else
|
|
|
|
+ root->rnode = item;
|
|
|
|
|
|
- *slot = item;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(radix_tree_insert);
|
|
EXPORT_SYMBOL(radix_tree_insert);
|
|
@@ -286,27 +291,25 @@ EXPORT_SYMBOL(radix_tree_insert);
|
|
void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
|
|
void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
|
|
{
|
|
{
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
- struct radix_tree_node **slot;
|
|
|
|
|
|
+ struct radix_tree_node *slot;
|
|
|
|
|
|
height = root->height;
|
|
height = root->height;
|
|
if (index > radix_tree_maxindex(height))
|
|
if (index > radix_tree_maxindex(height))
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
- slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
|
|
|
|
while (height > 0) {
|
|
while (height > 0) {
|
|
- if (*slot == NULL)
|
|
|
|
|
|
+ if (slot == NULL)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- slot = (struct radix_tree_node **)
|
|
|
|
- ((*slot)->slots +
|
|
|
|
- ((index >> shift) & RADIX_TREE_MAP_MASK));
|
|
|
|
|
|
+ slot = slot->slots[(index >> shift) & RADIX_TREE_MAP_MASK];
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
height--;
|
|
height--;
|
|
}
|
|
}
|
|
|
|
|
|
- return *slot;
|
|
|
|
|
|
+ return slot;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(radix_tree_lookup);
|
|
EXPORT_SYMBOL(radix_tree_lookup);
|
|
|
|
|
|
@@ -326,27 +329,27 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
|
|
unsigned long index, int tag)
|
|
unsigned long index, int tag)
|
|
{
|
|
{
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
- struct radix_tree_node **slot;
|
|
|
|
|
|
+ struct radix_tree_node *slot;
|
|
|
|
|
|
height = root->height;
|
|
height = root->height;
|
|
if (index > radix_tree_maxindex(height))
|
|
if (index > radix_tree_maxindex(height))
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
- slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
|
|
|
|
while (height > 0) {
|
|
while (height > 0) {
|
|
int offset;
|
|
int offset;
|
|
|
|
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
- tag_set(*slot, tag, offset);
|
|
|
|
- slot = (struct radix_tree_node **)((*slot)->slots + offset);
|
|
|
|
- BUG_ON(*slot == NULL);
|
|
|
|
|
|
+ tag_set(slot, tag, offset);
|
|
|
|
+ slot = slot->slots[offset];
|
|
|
|
+ BUG_ON(slot == NULL);
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
height--;
|
|
height--;
|
|
}
|
|
}
|
|
|
|
|
|
- return *slot;
|
|
|
|
|
|
+ return slot;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(radix_tree_tag_set);
|
|
EXPORT_SYMBOL(radix_tree_tag_set);
|
|
|
|
|
|
@@ -367,6 +370,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
|
|
unsigned long index, int tag)
|
|
unsigned long index, int tag)
|
|
{
|
|
{
|
|
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
|
|
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
|
|
|
|
+ struct radix_tree_node *slot;
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
void *ret = NULL;
|
|
void *ret = NULL;
|
|
|
|
|
|
@@ -376,38 +380,37 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
|
|
|
|
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
pathp->node = NULL;
|
|
pathp->node = NULL;
|
|
- pathp->slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
|
|
|
|
while (height > 0) {
|
|
while (height > 0) {
|
|
int offset;
|
|
int offset;
|
|
|
|
|
|
- if (*pathp->slot == NULL)
|
|
|
|
|
|
+ if (slot == NULL)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
pathp[1].offset = offset;
|
|
pathp[1].offset = offset;
|
|
- pathp[1].node = *pathp[0].slot;
|
|
|
|
- pathp[1].slot = (struct radix_tree_node **)
|
|
|
|
- (pathp[1].node->slots + offset);
|
|
|
|
|
|
+ pathp[1].node = slot;
|
|
|
|
+ slot = slot->slots[offset];
|
|
pathp++;
|
|
pathp++;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
height--;
|
|
height--;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = *pathp[0].slot;
|
|
|
|
|
|
+ ret = slot;
|
|
if (ret == NULL)
|
|
if (ret == NULL)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
do {
|
|
do {
|
|
int idx;
|
|
int idx;
|
|
|
|
|
|
- tag_clear(pathp[0].node, tag, pathp[0].offset);
|
|
|
|
|
|
+ tag_clear(pathp->node, tag, pathp->offset);
|
|
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
- if (pathp[0].node->tags[tag][idx])
|
|
|
|
|
|
+ if (pathp->node->tags[tag][idx])
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
pathp--;
|
|
pathp--;
|
|
- } while (pathp[0].node);
|
|
|
|
|
|
+ } while (pathp->node);
|
|
out:
|
|
out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -429,7 +432,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
|
|
unsigned long index, int tag)
|
|
unsigned long index, int tag)
|
|
{
|
|
{
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
- struct radix_tree_node **slot;
|
|
|
|
|
|
+ struct radix_tree_node *slot;
|
|
int saw_unset_tag = 0;
|
|
int saw_unset_tag = 0;
|
|
|
|
|
|
height = root->height;
|
|
height = root->height;
|
|
@@ -437,12 +440,12 @@ int radix_tree_tag_get(struct radix_tree_root *root,
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
- slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
|
|
|
|
for ( ; ; ) {
|
|
for ( ; ; ) {
|
|
int offset;
|
|
int offset;
|
|
|
|
|
|
- if (*slot == NULL)
|
|
|
|
|
|
+ if (slot == NULL)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
@@ -451,15 +454,15 @@ int radix_tree_tag_get(struct radix_tree_root *root,
|
|
* This is just a debug check. Later, we can bale as soon as
|
|
* This is just a debug check. Later, we can bale as soon as
|
|
* we see an unset tag.
|
|
* we see an unset tag.
|
|
*/
|
|
*/
|
|
- if (!tag_get(*slot, tag, offset))
|
|
|
|
|
|
+ if (!tag_get(slot, tag, offset))
|
|
saw_unset_tag = 1;
|
|
saw_unset_tag = 1;
|
|
if (height == 1) {
|
|
if (height == 1) {
|
|
- int ret = tag_get(*slot, tag, offset);
|
|
|
|
|
|
+ int ret = tag_get(slot, tag, offset);
|
|
|
|
|
|
BUG_ON(ret && saw_unset_tag);
|
|
BUG_ON(ret && saw_unset_tag);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
- slot = (struct radix_tree_node **)((*slot)->slots + offset);
|
|
|
|
|
|
+ slot = slot->slots[offset];
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
height--;
|
|
height--;
|
|
}
|
|
}
|
|
@@ -472,17 +475,21 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
|
|
unsigned int max_items, unsigned long *next_index)
|
|
unsigned int max_items, unsigned long *next_index)
|
|
{
|
|
{
|
|
unsigned int nr_found = 0;
|
|
unsigned int nr_found = 0;
|
|
- unsigned int shift;
|
|
|
|
- unsigned int height = root->height;
|
|
|
|
|
|
+ unsigned int shift, height;
|
|
struct radix_tree_node *slot;
|
|
struct radix_tree_node *slot;
|
|
|
|
+ unsigned long i;
|
|
|
|
+
|
|
|
|
+ height = root->height;
|
|
|
|
+ if (height == 0)
|
|
|
|
+ goto out;
|
|
|
|
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
|
|
slot = root->rnode;
|
|
slot = root->rnode;
|
|
|
|
|
|
- while (height > 0) {
|
|
|
|
- unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
|
|
|
|
+ for ( ; height > 1; height--) {
|
|
|
|
|
|
- for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
|
|
|
|
|
|
+ for (i = (index >> shift) & RADIX_TREE_MAP_MASK ;
|
|
|
|
+ i < RADIX_TREE_MAP_SIZE; i++) {
|
|
if (slot->slots[i] != NULL)
|
|
if (slot->slots[i] != NULL)
|
|
break;
|
|
break;
|
|
index &= ~((1UL << shift) - 1);
|
|
index &= ~((1UL << shift) - 1);
|
|
@@ -492,22 +499,20 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
|
|
}
|
|
}
|
|
if (i == RADIX_TREE_MAP_SIZE)
|
|
if (i == RADIX_TREE_MAP_SIZE)
|
|
goto out;
|
|
goto out;
|
|
- height--;
|
|
|
|
- if (height == 0) { /* Bottom level: grab some items */
|
|
|
|
- unsigned long j = index & RADIX_TREE_MAP_MASK;
|
|
|
|
|
|
|
|
- for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
|
|
|
|
- index++;
|
|
|
|
- if (slot->slots[j]) {
|
|
|
|
- results[nr_found++] = slot->slots[j];
|
|
|
|
- if (nr_found == max_items)
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
slot = slot->slots[i];
|
|
slot = slot->slots[i];
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Bottom level: grab some items */
|
|
|
|
+ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
|
|
|
|
+ index++;
|
|
|
|
+ if (slot->slots[i]) {
|
|
|
|
+ results[nr_found++] = slot->slots[i];
|
|
|
|
+ if (nr_found == max_items)
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
out:
|
|
out:
|
|
*next_index = index;
|
|
*next_index = index;
|
|
return nr_found;
|
|
return nr_found;
|
|
@@ -655,6 +660,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
|
{
|
|
{
|
|
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
|
|
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
|
|
struct radix_tree_path *orig_pathp;
|
|
struct radix_tree_path *orig_pathp;
|
|
|
|
+ struct radix_tree_node *slot;
|
|
unsigned int height, shift;
|
|
unsigned int height, shift;
|
|
void *ret = NULL;
|
|
void *ret = NULL;
|
|
char tags[RADIX_TREE_TAGS];
|
|
char tags[RADIX_TREE_TAGS];
|
|
@@ -666,25 +672,23 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
|
|
|
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
|
|
pathp->node = NULL;
|
|
pathp->node = NULL;
|
|
- pathp->slot = &root->rnode;
|
|
|
|
|
|
+ slot = root->rnode;
|
|
|
|
|
|
- while (height > 0) {
|
|
|
|
|
|
+ for ( ; height > 0; height--) {
|
|
int offset;
|
|
int offset;
|
|
|
|
|
|
- if (*pathp->slot == NULL)
|
|
|
|
|
|
+ if (slot == NULL)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
|
|
pathp[1].offset = offset;
|
|
pathp[1].offset = offset;
|
|
- pathp[1].node = *pathp[0].slot;
|
|
|
|
- pathp[1].slot = (struct radix_tree_node **)
|
|
|
|
- (pathp[1].node->slots + offset);
|
|
|
|
|
|
+ pathp[1].node = slot;
|
|
|
|
+ slot = slot->slots[offset];
|
|
pathp++;
|
|
pathp++;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
shift -= RADIX_TREE_MAP_SHIFT;
|
|
- height--;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- ret = *pathp[0].slot;
|
|
|
|
|
|
+ ret = slot;
|
|
if (ret == NULL)
|
|
if (ret == NULL)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -704,10 +708,10 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
|
if (tags[tag])
|
|
if (tags[tag])
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- tag_clear(pathp[0].node, tag, pathp[0].offset);
|
|
|
|
|
|
+ tag_clear(pathp->node, tag, pathp->offset);
|
|
|
|
|
|
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
|
|
- if (pathp[0].node->tags[tag][idx]) {
|
|
|
|
|
|
+ if (pathp->node->tags[tag][idx]) {
|
|
tags[tag] = 1;
|
|
tags[tag] = 1;
|
|
nr_cleared_tags--;
|
|
nr_cleared_tags--;
|
|
break;
|
|
break;
|
|
@@ -715,18 +719,19 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pathp--;
|
|
pathp--;
|
|
- } while (pathp[0].node && nr_cleared_tags);
|
|
|
|
|
|
+ } while (pathp->node && nr_cleared_tags);
|
|
|
|
|
|
- pathp = orig_pathp;
|
|
|
|
- *pathp[0].slot = NULL;
|
|
|
|
- while (pathp[0].node && --pathp[0].node->count == 0) {
|
|
|
|
- pathp--;
|
|
|
|
- BUG_ON(*pathp[0].slot == NULL);
|
|
|
|
- *pathp[0].slot = NULL;
|
|
|
|
- radix_tree_node_free(pathp[1].node);
|
|
|
|
|
|
+ /* Now free the nodes we do not need anymore */
|
|
|
|
+ for (pathp = orig_pathp; pathp->node; pathp--) {
|
|
|
|
+ pathp->node->slots[pathp->offset] = NULL;
|
|
|
|
+ if (--pathp->node->count)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ /* Node with zero slots in use so free it */
|
|
|
|
+ radix_tree_node_free(pathp->node);
|
|
}
|
|
}
|
|
- if (root->rnode == NULL)
|
|
|
|
- root->height = 0;
|
|
|
|
|
|
+ root->rnode = NULL;
|
|
|
|
+ root->height = 0;
|
|
out:
|
|
out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|