diff options
Diffstat (limited to 'lib/idr.c')
| -rw-r--r-- | lib/idr.c | 102 |
1 files changed, 102 insertions, 0 deletions
| @@ -391,6 +391,53 @@ void idr_remove(struct idr *idp, int id) | |||
| 391 | EXPORT_SYMBOL(idr_remove); | 391 | EXPORT_SYMBOL(idr_remove); |
| 392 | 392 | ||
| 393 | /** | 393 | /** |
| 394 | * idr_remove_all - remove all ids from the given idr tree | ||
| 395 | * @idp: idr handle | ||
| 396 | * | ||
| 397 | * idr_destroy() only frees up unused, cached idp_layers, but this | ||
| 398 | * function will remove all id mappings and leave all idp_layers | ||
| 399 | * unused. | ||
| 400 | * | ||
| 401 | * A typical clean-up sequence for objects stored in an idr tree, will | ||
| 402 | * use idr_for_each() to free all objects, if necessay, then | ||
| 403 | * idr_remove_all() to remove all ids, and idr_destroy() to free | ||
| 404 | * up the cached idr_layers. | ||
| 405 | */ | ||
| 406 | void idr_remove_all(struct idr *idp) | ||
| 407 | { | ||
| 408 | int n, id, max, error = 0; | ||
| 409 | struct idr_layer *p; | ||
| 410 | struct idr_layer *pa[MAX_LEVEL]; | ||
| 411 | struct idr_layer **paa = &pa[0]; | ||
| 412 | |||
| 413 | n = idp->layers * IDR_BITS; | ||
| 414 | p = idp->top; | ||
| 415 | max = 1 << n; | ||
| 416 | |||
| 417 | id = 0; | ||
| 418 | while (id < max && !error) { | ||
| 419 | while (n > IDR_BITS && p) { | ||
| 420 | n -= IDR_BITS; | ||
| 421 | *paa++ = p; | ||
| 422 | p = p->ary[(id >> n) & IDR_MASK]; | ||
| 423 | } | ||
| 424 | |||
| 425 | id += 1 << n; | ||
| 426 | while (n < fls(id)) { | ||
| 427 | if (p) { | ||
| 428 | memset(p, 0, sizeof *p); | ||
| 429 | free_layer(idp, p); | ||
| 430 | } | ||
| 431 | n += IDR_BITS; | ||
| 432 | p = *--paa; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | idp->top = NULL; | ||
| 436 | idp->layers = 0; | ||
| 437 | } | ||
| 438 | EXPORT_SYMBOL(idr_remove_all); | ||
| 439 | |||
| 440 | /** | ||
| 394 | * idr_destroy - release all cached layers within an idr tree | 441 | * idr_destroy - release all cached layers within an idr tree |
| 395 | * idp: idr handle | 442 | * idp: idr handle |
| 396 | */ | 443 | */ |
| @@ -437,6 +484,61 @@ void *idr_find(struct idr *idp, int id) | |||
| 437 | EXPORT_SYMBOL(idr_find); | 484 | EXPORT_SYMBOL(idr_find); |
| 438 | 485 | ||
| 439 | /** | 486 | /** |
| 487 | * idr_for_each - iterate through all stored pointers | ||
| 488 | * @idp: idr handle | ||
| 489 | * @fn: function to be called for each pointer | ||
| 490 | * @data: data passed back to callback function | ||
| 491 | * | ||
| 492 | * Iterate over the pointers registered with the given idr. The | ||
| 493 | * callback function will be called for each pointer currently | ||
| 494 | * registered, passing the id, the pointer and the data pointer passed | ||
| 495 | * to this function. It is not safe to modify the idr tree while in | ||
| 496 | * the callback, so functions such as idr_get_new and idr_remove are | ||
| 497 | * not allowed. | ||
| 498 | * | ||
| 499 | * We check the return of @fn each time. If it returns anything other | ||
| 500 | * than 0, we break out and return that value. | ||
| 501 | * | ||
| 502 | * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove(). | ||
| 503 | */ | ||
| 504 | int idr_for_each(struct idr *idp, | ||
| 505 | int (*fn)(int id, void *p, void *data), void *data) | ||
| 506 | { | ||
| 507 | int n, id, max, error = 0; | ||
| 508 | struct idr_layer *p; | ||
| 509 | struct idr_layer *pa[MAX_LEVEL]; | ||
| 510 | struct idr_layer **paa = &pa[0]; | ||
| 511 | |||
| 512 | n = idp->layers * IDR_BITS; | ||
| 513 | p = idp->top; | ||
| 514 | max = 1 << n; | ||
| 515 | |||
| 516 | id = 0; | ||
| 517 | while (id < max) { | ||
| 518 | while (n > 0 && p) { | ||
| 519 | n -= IDR_BITS; | ||
| 520 | *paa++ = p; | ||
| 521 | p = p->ary[(id >> n) & IDR_MASK]; | ||
| 522 | } | ||
| 523 | |||
| 524 | if (p) { | ||
| 525 | error = fn(id, (void *)p, data); | ||
| 526 | if (error) | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | |||
| 530 | id += 1 << n; | ||
| 531 | while (n < fls(id)) { | ||
| 532 | n += IDR_BITS; | ||
| 533 | p = *--paa; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | return error; | ||
| 538 | } | ||
| 539 | EXPORT_SYMBOL(idr_for_each); | ||
| 540 | |||
| 541 | /** | ||
| 440 | * idr_replace - replace pointer for given id | 542 | * idr_replace - replace pointer for given id |
| 441 | * @idp: idr handle | 543 | * @idp: idr handle |
| 442 | * @ptr: pointer you want associated with the id | 544 | * @ptr: pointer you want associated with the id |
