aboutsummaryrefslogtreecommitdiffstats
path: root/lib/idr.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/idr.c')
-rw-r--r--lib/idr.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/lib/idr.c b/lib/idr.c
index 1cac726c44b..7f1a4f0acf5 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -156,10 +156,12 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
156 id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; 156 id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
157 157
158 /* if already at the top layer, we need to grow */ 158 /* if already at the top layer, we need to grow */
159 if (!(p = pa[l])) { 159 if (id >= 1 << (idp->layers * IDR_BITS)) {
160 *starting_id = id; 160 *starting_id = id;
161 return IDR_NEED_TO_GROW; 161 return IDR_NEED_TO_GROW;
162 } 162 }
163 p = pa[l];
164 BUG_ON(!p);
163 165
164 /* If we need to go up one layer, continue the 166 /* If we need to go up one layer, continue the
165 * loop; otherwise, restart from the top. 167 * loop; otherwise, restart from the top.
@@ -443,6 +445,7 @@ EXPORT_SYMBOL(idr_remove);
443void idr_remove_all(struct idr *idp) 445void idr_remove_all(struct idr *idp)
444{ 446{
445 int n, id, max; 447 int n, id, max;
448 int bt_mask;
446 struct idr_layer *p; 449 struct idr_layer *p;
447 struct idr_layer *pa[MAX_LEVEL]; 450 struct idr_layer *pa[MAX_LEVEL];
448 struct idr_layer **paa = &pa[0]; 451 struct idr_layer **paa = &pa[0];
@@ -460,8 +463,10 @@ void idr_remove_all(struct idr *idp)
460 p = p->ary[(id >> n) & IDR_MASK]; 463 p = p->ary[(id >> n) & IDR_MASK];
461 } 464 }
462 465
466 bt_mask = id;
463 id += 1 << n; 467 id += 1 << n;
464 while (n < fls(id)) { 468 /* Get the highest bit that the above add changed from 0->1. */
469 while (n < fls(id ^ bt_mask)) {
465 if (p) 470 if (p)
466 free_layer(p); 471 free_layer(p);
467 n += IDR_BITS; 472 n += IDR_BITS;
@@ -502,7 +507,7 @@ void *idr_find(struct idr *idp, int id)
502 int n; 507 int n;
503 struct idr_layer *p; 508 struct idr_layer *p;
504 509
505 p = rcu_dereference(idp->top); 510 p = rcu_dereference_raw(idp->top);
506 if (!p) 511 if (!p)
507 return NULL; 512 return NULL;
508 n = (p->layer+1) * IDR_BITS; 513 n = (p->layer+1) * IDR_BITS;
@@ -517,7 +522,7 @@ void *idr_find(struct idr *idp, int id)
517 while (n > 0 && p) { 522 while (n > 0 && p) {
518 n -= IDR_BITS; 523 n -= IDR_BITS;
519 BUG_ON(n != p->layer*IDR_BITS); 524 BUG_ON(n != p->layer*IDR_BITS);
520 p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); 525 p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
521 } 526 }
522 return((void *)p); 527 return((void *)p);
523} 528}
@@ -550,7 +555,7 @@ int idr_for_each(struct idr *idp,
550 struct idr_layer **paa = &pa[0]; 555 struct idr_layer **paa = &pa[0];
551 556
552 n = idp->layers * IDR_BITS; 557 n = idp->layers * IDR_BITS;
553 p = rcu_dereference(idp->top); 558 p = rcu_dereference_raw(idp->top);
554 max = 1 << n; 559 max = 1 << n;
555 560
556 id = 0; 561 id = 0;
@@ -558,7 +563,7 @@ int idr_for_each(struct idr *idp,
558 while (n > 0 && p) { 563 while (n > 0 && p) {
559 n -= IDR_BITS; 564 n -= IDR_BITS;
560 *paa++ = p; 565 *paa++ = p;
561 p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); 566 p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
562 } 567 }
563 568
564 if (p) { 569 if (p) {
@@ -597,7 +602,7 @@ void *idr_get_next(struct idr *idp, int *nextidp)
597 /* find first ent */ 602 /* find first ent */
598 n = idp->layers * IDR_BITS; 603 n = idp->layers * IDR_BITS;
599 max = 1 << n; 604 max = 1 << n;
600 p = rcu_dereference(idp->top); 605 p = rcu_dereference_raw(idp->top);
601 if (!p) 606 if (!p)
602 return NULL; 607 return NULL;
603 608
@@ -605,7 +610,7 @@ void *idr_get_next(struct idr *idp, int *nextidp)
605 while (n > 0 && p) { 610 while (n > 0 && p) {
606 n -= IDR_BITS; 611 n -= IDR_BITS;
607 *paa++ = p; 612 *paa++ = p;
608 p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); 613 p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
609 } 614 }
610 615
611 if (p) { 616 if (p) {
@@ -621,7 +626,7 @@ void *idr_get_next(struct idr *idp, int *nextidp)
621 } 626 }
622 return NULL; 627 return NULL;
623} 628}
624 629EXPORT_SYMBOL(idr_get_next);
625 630
626 631
627/** 632/**