aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/idr.h2
-rw-r--r--lib/idr.c55
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);
78int idr_pre_get(struct idr *idp, gfp_t gfp_mask); 78int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
79int idr_get_new(struct idr *idp, void *ptr, int *id); 79int idr_get_new(struct idr *idp, void *ptr, int *id);
80int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); 80int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
81int idr_for_each(struct idr *idp,
82 int (*fn)(int id, void *p, void *data), void *data);
81void *idr_replace(struct idr *idp, void *ptr, int id); 83void *idr_replace(struct idr *idp, void *ptr, int id);
82void idr_remove(struct idr *idp, int id); 84void idr_remove(struct idr *idp, int id);
83void idr_destroy(struct idr *idp); 85void idr_destroy(struct idr *idp);
diff --git a/lib/idr.c b/lib/idr.c
index b98f01a2eb94..d29da6159dae 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -437,6 +437,61 @@ void *idr_find(struct idr *idp, int id)
437EXPORT_SYMBOL(idr_find); 437EXPORT_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 */
457int 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}
492EXPORT_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