Commit 7aae6dd8 authored by Tejun Heo's avatar Tejun Heo Committed by Greg Kroah-Hartman

idr: fix obscure bug in allocation path

In sub_alloc(), when bitmap search fails, it goes up one level to
continue search.  This is done by updating the id cursor and searching
the upper level again.  If the cursor was at the end of the upper
level, we need to go further than that.

This wasn't implemented and when that happens the part of the cursor
which indexes into the upper level wraps and sub_alloc() ends up
searching the wrong bitmap.  It allocates id which doesn't match the
actual slot.

This patch fixes this by restarting from the top if the search needs
to go higher than one level.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dc0afa83
...@@ -100,10 +100,11 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) ...@@ -100,10 +100,11 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
int n, m, sh; int n, m, sh;
struct idr_layer *p, *new; struct idr_layer *p, *new;
struct idr_layer *pa[MAX_LEVEL]; struct idr_layer *pa[MAX_LEVEL];
int l, id; int l, id, oid;
long bm; long bm;
id = *starting_id; id = *starting_id;
restart:
p = idp->top; p = idp->top;
l = idp->layers; l = idp->layers;
pa[l--] = NULL; pa[l--] = NULL;
...@@ -117,12 +118,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) ...@@ -117,12 +118,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
if (m == IDR_SIZE) { if (m == IDR_SIZE) {
/* no space available go back to previous layer. */ /* no space available go back to previous layer. */
l++; l++;
oid = id;
id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
/* if already at the top layer, we need to grow */
if (!(p = pa[l])) { if (!(p = pa[l])) {
*starting_id = id; *starting_id = id;
return -2; return -2;
} }
continue;
/* If we need to go up one layer, continue the
* loop; otherwise, restart from the top.
*/
sh = IDR_BITS * (l + 1);
if (oid >> sh == id >> sh)
continue;
else
goto restart;
} }
if (m != n) { if (m != n) {
sh = IDR_BITS*l; sh = IDR_BITS*l;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment