diff options
-rw-r--r-- | include/linux/idr.h | 1 | ||||
-rw-r--r-- | lib/idr.c | 43 |
2 files changed, 44 insertions, 0 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h index d37c8d808b0f..f559a719dbe8 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h | |||
@@ -78,6 +78,7 @@ void *idr_find(struct idr *idp, int id); | |||
78 | int idr_pre_get(struct idr *idp, gfp_t gfp_mask); | 78 | int idr_pre_get(struct idr *idp, gfp_t gfp_mask); |
79 | int idr_get_new(struct idr *idp, void *ptr, int *id); | 79 | int idr_get_new(struct idr *idp, void *ptr, int *id); |
80 | int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); | 80 | int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); |
81 | void *idr_replace(struct idr *idp, void *ptr, int id); | ||
81 | void idr_remove(struct idr *idp, int id); | 82 | void idr_remove(struct idr *idp, int id); |
82 | void idr_destroy(struct idr *idp); | 83 | void idr_destroy(struct idr *idp); |
83 | void idr_init(struct idr *idp); | 84 | void idr_init(struct idr *idp); |
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #endif | 31 | #endif |
32 | #include <linux/err.h> | ||
32 | #include <linux/string.h> | 33 | #include <linux/string.h> |
33 | #include <linux/idr.h> | 34 | #include <linux/idr.h> |
34 | 35 | ||
@@ -398,6 +399,48 @@ void *idr_find(struct idr *idp, int id) | |||
398 | } | 399 | } |
399 | EXPORT_SYMBOL(idr_find); | 400 | EXPORT_SYMBOL(idr_find); |
400 | 401 | ||
402 | /** | ||
403 | * idr_replace - replace pointer for given id | ||
404 | * @idp: idr handle | ||
405 | * @ptr: pointer you want associated with the id | ||
406 | * @id: lookup key | ||
407 | * | ||
408 | * Replace the pointer registered with an id and return the old value. | ||
409 | * A -ENOENT return indicates that @id was not found. | ||
410 | * A -EINVAL return indicates that @id was not within valid constraints. | ||
411 | * | ||
412 | * The caller must serialize vs idr_find(), idr_get_new(), and idr_remove(). | ||
413 | */ | ||
414 | void *idr_replace(struct idr *idp, void *ptr, int id) | ||
415 | { | ||
416 | int n; | ||
417 | struct idr_layer *p, *old_p; | ||
418 | |||
419 | n = idp->layers * IDR_BITS; | ||
420 | p = idp->top; | ||
421 | |||
422 | id &= MAX_ID_MASK; | ||
423 | |||
424 | if (id >= (1 << n)) | ||
425 | return ERR_PTR(-EINVAL); | ||
426 | |||
427 | n -= IDR_BITS; | ||
428 | while ((n > 0) && p) { | ||
429 | p = p->ary[(id >> n) & IDR_MASK]; | ||
430 | n -= IDR_BITS; | ||
431 | } | ||
432 | |||
433 | n = id & IDR_MASK; | ||
434 | if (unlikely(p == NULL || !test_bit(n, &p->bitmap))) | ||
435 | return ERR_PTR(-ENOENT); | ||
436 | |||
437 | old_p = p->ary[n]; | ||
438 | p->ary[n] = ptr; | ||
439 | |||
440 | return old_p; | ||
441 | } | ||
442 | EXPORT_SYMBOL(idr_replace); | ||
443 | |||
401 | static void idr_cache_ctor(void * idr_layer, kmem_cache_t *idr_layer_cache, | 444 | static void idr_cache_ctor(void * idr_layer, kmem_cache_t *idr_layer_cache, |
402 | unsigned long flags) | 445 | unsigned long flags) |
403 | { | 446 | { |