linux-bk/lib/radix-tree.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001 Momchil Velikov
   3 * Portions Copyright (C) 2001 Christoph Hellwig
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation; either version 2, or (at
   8 * your option) any later version.
   9 * 
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 * 
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 */
  19
  20#include <linux/errno.h>
  21#include <linux/init.h>
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/radix-tree.h>
  25#include <linux/percpu.h>
  26#include <linux/slab.h>
  27#include <linux/gfp.h>
  28#include <linux/string.h>
  29
  30/*
  31 * Radix tree node definition.
  32 */
  33#define RADIX_TREE_MAP_SHIFT  6
  34#define RADIX_TREE_MAP_SIZE  (1UL << RADIX_TREE_MAP_SHIFT)
  35#define RADIX_TREE_MAP_MASK  (RADIX_TREE_MAP_SIZE-1)
  36
  37struct radix_tree_node {
  38        unsigned int    count;
  39        void            *slots[RADIX_TREE_MAP_SIZE];
  40};
  41
  42struct radix_tree_path {
  43        struct radix_tree_node *node, **slot;
  44};
  45
  46#define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
  47#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
  48
  49static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
  50
  51/*
  52 * Radix tree node cache.
  53 */
  54static kmem_cache_t *radix_tree_node_cachep;
  55
  56/*
  57 * Per-cpu pool of preloaded nodes
  58 */
  59struct radix_tree_preload {
  60        int nr;
  61        struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH];
  62};
  63DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
  64
  65/*
  66 * This assumes that the caller has performed appropriate preallocation, and
  67 * that the caller has pinned this thread of control to the current CPU.
  68 */
  69static struct radix_tree_node *
  70radix_tree_node_alloc(struct radix_tree_root *root)
  71{
  72        struct radix_tree_node *ret;
  73
  74        ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask);
  75        if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) {
  76                struct radix_tree_preload *rtp;
  77
  78                rtp = &__get_cpu_var(radix_tree_preloads);
  79                if (rtp->nr) {
  80                        ret = rtp->nodes[rtp->nr - 1];
  81                        rtp->nodes[rtp->nr - 1] = NULL;
  82                        rtp->nr--;
  83                }
  84        }
  85        return ret;
  86}
  87
  88static inline void
  89radix_tree_node_free(struct radix_tree_node *node)
  90{
  91        kmem_cache_free(radix_tree_node_cachep, node);
  92}
  93
  94/*
  95 * Load up this CPU's radix_tree_node buffer with sufficient objects to
  96 * ensure that the addition of a single element in the tree cannot fail.  On
  97 * success, return zero, with preemption disabled.  On error, return -ENOMEM
  98 * with preemption not disabled.
  99 */
 100int radix_tree_preload(int gfp_mask)
 101{
 102        struct radix_tree_preload *rtp;
 103        struct radix_tree_node *node;
 104        int ret = -ENOMEM;
 105
 106        preempt_disable();
 107        rtp = &__get_cpu_var(radix_tree_preloads);
 108        while (rtp->nr < ARRAY_SIZE(rtp->nodes)) {
 109                preempt_enable();
 110                node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
 111                if (node == NULL)
 112                        goto out;
 113                preempt_disable();
 114                rtp = &__get_cpu_var(radix_tree_preloads);
 115                if (rtp->nr < ARRAY_SIZE(rtp->nodes))
 116                        rtp->nodes[rtp->nr++] = node;
 117                else
 118                        kmem_cache_free(radix_tree_node_cachep, node);
 119        }
 120        ret = 0;
 121out:
 122        return ret;
 123}
 124
 125/*
 126 *      Return the maximum key which can be store into a
 127 *      radix tree with height HEIGHT.
 128 */
 129static inline unsigned long radix_tree_maxindex(unsigned int height)
 130{
 131        return height_to_maxindex[height];
 132}
 133
 134/*
 135 *      Extend a radix tree so it can store key @index.
 136 */
 137static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
 138{
 139        struct radix_tree_node *node;
 140        unsigned int height;
 141
 142        /* Figure out what the height should be.  */
 143        height = root->height + 1;
 144        while (index > radix_tree_maxindex(height))
 145                height++;
 146
 147        if (root->rnode) {
 148                do {
 149                        if (!(node = radix_tree_node_alloc(root)))
 150                                return -ENOMEM;
 151
 152                        /* Increase the height.  */
 153                        node->slots[0] = root->rnode;
 154                        node->count = 1;
 155                        root->rnode = node;
 156                        root->height++;
 157                } while (height > root->height);
 158        } else 
 159                root->height = height;
 160
 161        return 0;
 162}
 163
 164/**
 165 *      radix_tree_insert    -    insert into a radix tree
 166 *      @root:          radix tree root
 167 *      @index:         index key
 168 *      @item:          item to insert
 169 *
 170 *      Insert an item into the radix tree at position @index.
 171 */
 172int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
 173{
 174        struct radix_tree_node *node = NULL, *tmp, **slot;
 175        unsigned int height, shift;
 176        int error;
 177
 178        /* Make sure the tree is high enough.  */
 179        if (index > radix_tree_maxindex(root->height)) {
 180                error = radix_tree_extend(root, index);
 181                if (error)
 182                        return error;
 183        }
 184    
 185        slot = &root->rnode;
 186        height = root->height;
 187        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 188
 189        while (height > 0) {
 190                if (*slot == NULL) {
 191                        /* Have to add a child node.  */
 192                        if (!(tmp = radix_tree_node_alloc(root)))
 193                                return -ENOMEM;
 194                        *slot = tmp;
 195                        if (node)
 196                                node->count++;
 197                }
 198
 199                /* Go a level down.  */
 200                node = *slot;
 201                slot = (struct radix_tree_node **)
 202                        (node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
 203                shift -= RADIX_TREE_MAP_SHIFT;
 204                height--;
 205        }
 206
 207        if (*slot != NULL)
 208                return -EEXIST;
 209        if (node)
 210                node->count++;
 211
 212        *slot = item;
 213        return 0;
 214}
 215EXPORT_SYMBOL(radix_tree_insert);
 216
 217/**
 218 *      radix_tree_lookup    -    perform lookup operation on a radix tree
 219 *      @root:          radix tree root
 220 *      @index:         index key
 221 *
 222 *      Lookup them item at the position @index in the radix tree @root.
 223 */
 224void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 225{
 226        unsigned int height, shift;
 227        struct radix_tree_node **slot;
 228
 229        height = root->height;
 230        if (index > radix_tree_maxindex(height))
 231                return NULL;
 232
 233        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 234        slot = &root->rnode;
 235
 236        while (height > 0) {
 237                if (*slot == NULL)
 238                        return NULL;
 239
 240                slot = (struct radix_tree_node **)
 241                        ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
 242                shift -= RADIX_TREE_MAP_SHIFT;
 243                height--;
 244        }
 245
 246        return (void *) *slot;
 247}
 248EXPORT_SYMBOL(radix_tree_lookup);
 249
 250static /* inline */ unsigned int
 251__lookup(struct radix_tree_root *root, void **results, unsigned long index,
 252        unsigned int max_items, unsigned long *next_index)
 253{
 254        unsigned int nr_found = 0;
 255        unsigned int shift;
 256        unsigned int height = root->height;
 257        struct radix_tree_node *slot;
 258
 259        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 260        slot = root->rnode;
 261
 262        while (height > 0) {
 263                unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
 264
 265                for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
 266                        if (slot->slots[i] != NULL)
 267                                break;
 268                        index &= ~((1 << shift) - 1);
 269                        index += 1 << shift;
 270                        if (index == 0)
 271                                goto out;       /* 32-bit wraparound */
 272                }
 273                if (i == RADIX_TREE_MAP_SIZE)
 274                        goto out;
 275                height--;
 276                if (height == 0) {      /* Bottom level: grab some items */
 277                        unsigned long j = index & RADIX_TREE_MAP_MASK;
 278
 279                        for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
 280                                index++;
 281                                if (slot->slots[j]) {
 282                                        results[nr_found++] = slot->slots[j];
 283                                        if (nr_found == max_items)
 284                                                goto out;
 285                                }
 286                        }
 287                }
 288                shift -= RADIX_TREE_MAP_SHIFT;
 289                slot = slot->slots[i];
 290        }
 291out:
 292        *next_index = index;
 293        return nr_found;
 294}
 295
 296/**
 297 *      radix_tree_gang_lookup - perform multiple lookup on a radix tree
 298 *      @root:          radix tree root
 299 *      @results:       where the results of the lookup are placed
 300 *      @first_index:   start the lookup from this key
 301 *      @max_items:     place up to this many items at *results
 302 *
 303 *      Performs an index-ascending scan of the tree for present items.  Places
 304 *      them at *@results and returns the number of items which were placed at
 305 *      *@results.
 306 *
 307 *      The implementation is naive.
 308 */
 309unsigned int
 310radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
 311                        unsigned long first_index, unsigned int max_items)
 312{
 313        const unsigned long max_index = radix_tree_maxindex(root->height);
 314        unsigned long cur_index = first_index;
 315        unsigned int ret = 0;
 316
 317        if (root->rnode == NULL)
 318                goto out;
 319        if (max_index == 0) {                   /* Bah.  Special case */
 320                if (first_index == 0) {
 321                        if (max_items > 0) {
 322                                *results = root->rnode;
 323                                ret = 1;
 324                        }
 325                }
 326                goto out;
 327        }
 328        while (ret < max_items) {
 329                unsigned int nr_found;
 330                unsigned long next_index;       /* Index of next search */
 331
 332                if (cur_index > max_index)
 333                        break;
 334                nr_found = __lookup(root, results + ret, cur_index,
 335                                        max_items - ret, &next_index);
 336                ret += nr_found;
 337                if (next_index == 0)
 338                        break;
 339                cur_index = next_index;
 340        }
 341out:
 342        return ret;
 343}
 344EXPORT_SYMBOL(radix_tree_gang_lookup);
 345
 346/**
 347 *      radix_tree_delete    -    delete an item from a radix tree
 348 *      @root:          radix tree root
 349 *      @index:         index key
 350 *
 351 *      Remove the item at @index from the radix tree rooted at @root.
 352 *
 353 *      Returns the address of the deleted item, or NULL if it was not present.
 354 */
 355void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 356{
 357        struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
 358        unsigned int height, shift;
 359        void *ret = NULL;
 360
 361        height = root->height;
 362        if (index > radix_tree_maxindex(height))
 363                goto out;
 364
 365        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
 366        pathp->node = NULL;
 367        pathp->slot = &root->rnode;
 368
 369        while (height > 0) {
 370                if (*pathp->slot == NULL)
 371                        goto out;
 372
 373                pathp[1].node = *pathp[0].slot;
 374                pathp[1].slot = (struct radix_tree_node **)
 375                    (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
 376                pathp++;
 377                shift -= RADIX_TREE_MAP_SHIFT;
 378                height--;
 379        }
 380
 381        ret = *pathp[0].slot;
 382        if (ret == NULL)
 383                goto out;
 384
 385        *pathp[0].slot = NULL;
 386        while (pathp[0].node && --pathp[0].node->count == 0) {
 387                pathp--;
 388                *pathp[0].slot = NULL;
 389                radix_tree_node_free(pathp[1].node);
 390        }
 391
 392        if (root->rnode == NULL)
 393                root->height = 0;  /* Empty tree, we can reset the height */
 394out:
 395        return ret;
 396}
 397EXPORT_SYMBOL(radix_tree_delete);
 398
 399static void
 400radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
 401{
 402        memset(node, 0, sizeof(struct radix_tree_node));
 403}
 404
 405static __init unsigned long __maxindex(unsigned int height)
 406{
 407        unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
 408        unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
 409
 410        if (tmp >= RADIX_TREE_INDEX_BITS)
 411                index = ~0UL;
 412        return index;
 413}
 414
 415static __init void radix_tree_init_maxindex(void)
 416{
 417        unsigned int i;
 418
 419        for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++)
 420                height_to_maxindex[i] = __maxindex(i);
 421}
 422
 423void __init radix_tree_init(void)
 424{
 425        radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
 426                        sizeof(struct radix_tree_node), 0,
 427                        0, radix_tree_node_ctor, NULL);
 428        if (!radix_tree_node_cachep)
 429                panic ("Failed to create radix_tree_node cache\n");
 430        radix_tree_init_maxindex();
 431}
 432
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.