diff options
-rw-r--r-- | include/linux/idr.h | 2 | ||||
-rw-r--r-- | lib/idr.c | 55 |
2 files changed, 57 insertions, 0 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h index 915572fa030b..8442c0bffc06 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h | |||
@@ -78,6 +78,8 @@ 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 | int idr_for_each(struct idr *idp, | ||
82 | int (*fn)(int id, void *p, void *data), void *data); | ||
81 | void *idr_replace(struct idr *idp, void *ptr, int id); | 83 | void *idr_replace(struct idr *idp, void *ptr, int id); |
82 | void idr_remove(struct idr *idp, int id); | 84 | void idr_remove(struct idr *idp, int id); |
83 | void idr_destroy(struct idr *idp); | 85 | void idr_destroy(struct idr *idp); |
@@ -437,6 +437,61 @@ void *idr_find(struct idr *idp, int id) | |||
437 | EXPORT_SYMBOL(idr_find); | 437 | EXPORT_SYMBOL(idr_find); |
438 | 438 | ||
439 | /** | 439 | /** |
440 | * idr_for_each - iterate through all stored pointers | ||
441 | * @idp: idr handle | ||
442 | * @fn: function to be called for each pointer | ||
443 | * @data: data passed back to callback function | ||
444 | * | ||
445 | * Iterate over the pointers registered with the given idr. The | ||
446 | * callback function will be called for each pointer currently | ||
447 | * registered, passing the id, the pointer and the data pointer passed | ||
448 | * to this function. It is not safe to modify the idr tree while in | ||
449 | * the callback, so functions such as idr_get_new and idr_remove are | ||
450 | * not allowed. | ||
451 | * | ||
452 | * We check the return of @fn each time. If it returns anything other | ||
453 | * than 0, we break out and return that value. | ||
454 | * | ||
455 | * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove(). | ||
456 | */ | ||
457 | int idr_for_each(struct idr *idp, | ||
458 | int (*fn)(int id, void *p, void *data), void *data) | ||
459 | { | ||
460 | int n, id, max, error = 0; | ||
461 | struct idr_layer *p; | ||
462 | struct idr_layer *pa[MAX_LEVEL]; | ||
463 | struct idr_layer **paa = &pa[0]; | ||
464 | |||
465 | n = idp->layers * IDR_BITS; | ||
466 | p = idp->top; | ||
467 | max = 1 << n; | ||
468 | |||
469 | id = 0; | ||
470 | while (id < max) { | ||
471 | while (n > 0 && p) { | ||
472 | n -= IDR_BITS; | ||
473 | *paa++ = p; | ||
474 | p = p->ary[(id >> n) & IDR_MASK]; | ||
475 | } | ||
476 | |||
477 | if (p) { | ||
478 | error = fn(id, (void *)p, data); | ||
479 | if (error) | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | id += 1 << n; | ||
484 | while (n < fls(id)) { | ||
485 | n += IDR_BITS; | ||
486 | p = *--paa; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | return error; | ||
491 | } | ||
492 | EXPORT_SYMBOL(idr_for_each); | ||
493 | |||
494 | /** | ||
440 | * idr_replace - replace pointer for given id | 495 | * idr_replace - replace pointer for given id |
441 | * @idp: idr handle | 496 | * @idp: idr handle |
442 | * @ptr: pointer you want associated with the id | 497 | * @ptr: pointer you want associated with the id |