Commit 935b33bc authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

[PATCH] IDR fixups

There were definately some problems in there.  I've made some changes and
tested with a lot of bounds.  I don't have a machine with enough memory to
fill it up (it would take ~16GB on a 64-bit machine), but I use the "above"
code to simulate a lot of situations.

The problems were:

    * IDR_FULL was not the right value
    * idr_get_new_above() was not defined in the headers or documented.
    * idr_alloc() bug-ed if there was a race and not enough memory was
      allocated.  It should have returned NULL.
    * id will overflow when you go past the end.
    * There was a "(id >= (1 << (layers*IDR_BITS)))" comparison, but at
      the top layer it would overflow the id and be zero.
    * The allocation should return ENOSPC for an "above" value with
      nothing above it, but it returned EAGAIN.

I have not tested on 64-bits (as I don't have a 64-bit machine).

I've included the files, a diff from the previous version, and my test
programs.

For the test programs, idr_test <size> will just attempt to allocate 
<size> elements, check them, free them, and check them again.

idr_test2 <size> <incr> will allocate <size> element with <incr> between
them.

idr_test3 just tests some bounds and tries all values with just a few in
the idr.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5470e17c
...@@ -14,15 +14,17 @@ ...@@ -14,15 +14,17 @@
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
# define IDR_BITS 5 # define IDR_BITS 5
# define IDR_FULL 0xfffffffful # define IDR_FULL 0xfffffffful
/* We can only use half the bits in the top level because there are /* We can only use two of the bits in the top level because there is
only four possible bits in the top level (5 bits * 4 levels = 25 only one possible bit in the top level (5 bits * 7 levels = 35
bits, but you only use 24 bits in the id). */ bits, but you only use 31 bits in the id). */
# define TOP_LEVEL_FULL (IDR_FULL >> 16) # define TOP_LEVEL_FULL (IDR_FULL >> 30)
#elif BITS_PER_LONG == 64 #elif BITS_PER_LONG == 64
# define IDR_BITS 6 # define IDR_BITS 6
# define IDR_FULL 0xfffffffffffffffful # define IDR_FULL 0xfffffffffffffffful
/* We can use all the bits in a 64-bit long at the top level. */ /* We can only use two of the bits in the top level because there is
# define TOP_LEVEL_FULL IDR_FULL only one possible bit in the top level (6 bits * 6 levels = 36
bits, but you only use 31 bits in the id). */
# define TOP_LEVEL_FULL (IDR_FULL >> 62)
#else #else
# error "BITS_PER_LONG is not 32 or 64" # error "BITS_PER_LONG is not 32 or 64"
#endif #endif
...@@ -71,6 +73,7 @@ struct idr { ...@@ -71,6 +73,7 @@ struct idr {
void *idr_find(struct idr *idp, int id); void *idr_find(struct idr *idp, int id);
int idr_pre_get(struct idr *idp, unsigned gfp_mask); int idr_pre_get(struct idr *idp, unsigned gfp_mask);
int idr_get_new(struct idr *idp, void *ptr, int *id); int idr_get_new(struct idr *idp, void *ptr, int *id);
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
void idr_remove(struct idr *idp, int id); void idr_remove(struct idr *idp, int id);
void idr_init(struct idr *idp); void idr_init(struct idr *idp);
......
...@@ -72,6 +72,11 @@ ...@@ -72,6 +72,11 @@
* with the id. The value is returned in the "id" field. idr_get_new() * with the id. The value is returned in the "id" field. idr_get_new()
* returns a value in the range 0 ... 0x7fffffff * returns a value in the range 0 ... 0x7fffffff
* int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);
* Like idr_get_new(), but the returned id is guaranteed to be at or
* above start_id.
* void *idr_find(struct idr *idp, int id); * void *idr_find(struct idr *idp, int id);
* returns the "ptr", given the id. A NULL return indicates that the * returns the "ptr", given the id. A NULL return indicates that the
...@@ -112,7 +117,7 @@ static struct idr_layer *alloc_layer(struct idr *idp) ...@@ -112,7 +117,7 @@ static struct idr_layer *alloc_layer(struct idr *idp)
spin_lock(&idp->lock); spin_lock(&idp->lock);
if (!(p = idp->id_free)) if (!(p = idp->id_free))
BUG(); return NULL;
idp->id_free = p->ary[0]; idp->id_free = p->ary[0];
idp->id_free_cnt--; idp->id_free_cnt--;
p->ary[0] = 0; p->ary[0] = 0;
...@@ -178,8 +183,8 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) ...@@ -178,8 +183,8 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
sh = IDR_BITS*l; sh = IDR_BITS*l;
id = ((id >> sh) ^ n ^ m) << sh; id = ((id >> sh) ^ n ^ m) << sh;
} }
if (id >= MAX_ID_BIT) if ((id >= MAX_ID_BIT) || (id < 0))
return -1; return -3;
if (l == 0) if (l == 0)
break; break;
/* /*
...@@ -217,7 +222,7 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) ...@@ -217,7 +222,7 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
return(id); return(id);
} }
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id) static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
{ {
struct idr_layer *p, *new; struct idr_layer *p, *new;
int layers, v, id; int layers, v, id;
...@@ -235,7 +240,7 @@ int idr_get_new_above(struct idr *idp, void *ptr, int starting_id) ...@@ -235,7 +240,7 @@ int idr_get_new_above(struct idr *idp, void *ptr, int starting_id)
* Add a new layer to the top of the tree if the requested * Add a new layer to the top of the tree if the requested
* id is larger than the currently allocated space. * id is larger than the currently allocated space.
*/ */
while (id >= (1 << (layers*IDR_BITS))) { while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
layers++; layers++;
if (!p->count) if (!p->count)
continue; continue;
...@@ -265,27 +270,39 @@ int idr_get_new_above(struct idr *idp, void *ptr, int starting_id) ...@@ -265,27 +270,39 @@ int idr_get_new_above(struct idr *idp, void *ptr, int starting_id)
goto build_up; goto build_up;
return(v); return(v);
} }
EXPORT_SYMBOL(idr_get_new_above);
static int idr_full(struct idr *idp) int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
{ {
return ((idp->layers >= MAX_LEVEL) int rv;
&& (idp->top->bitmap == TOP_LEVEL_FULL)); rv = idr_get_new_above_int(idp, ptr, starting_id);
/*
* This is a cheap hack until the IDR code can be fixed to
* return proper error values.
*/
if (rv < 0) {
if (rv == -1)
return -EAGAIN;
else /* Will be -3 */
return -ENOSPC;
}
*id = rv;
return 0;
} }
EXPORT_SYMBOL(idr_get_new_above);
int idr_get_new(struct idr *idp, void *ptr, int *id) int idr_get_new(struct idr *idp, void *ptr, int *id)
{ {
int rv; int rv;
rv = idr_get_new_above(idp, ptr, 0); rv = idr_get_new_above_int(idp, ptr, 0);
/* /*
* This is a cheap hack until the IDR code can be fixed to * This is a cheap hack until the IDR code can be fixed to
* return proper error values. * return proper error values.
*/ */
if (rv == -1) { if (rv < 0) {
if (idr_full(idp)) if (rv == -1)
return -ENOSPC;
else
return -EAGAIN; return -EAGAIN;
else /* Will be -3 */
return -ENOSPC;
} }
*id = rv; *id = rv;
return 0; return 0;
......
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