Commit 1d2921ea authored by Jim Houston's avatar Jim Houston Committed by Linus Torvalds

[PATCH] idr_remove safety checking

idr_remove() should fail gracefully and warn if the id being removed is not
valid.

The attached patch should do the job without additional overhead.

With the existing code, removing an id which was not allocated could remove
a valid id which shares the same lowest layer of the radix tree.

I ran a kernel with this patch but have not done any tests to force
a failure.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9a0a81f9
...@@ -275,24 +275,31 @@ int idr_get_new(struct idr *idp, void *ptr, int *id) ...@@ -275,24 +275,31 @@ int idr_get_new(struct idr *idp, void *ptr, int *id)
} }
EXPORT_SYMBOL(idr_get_new); EXPORT_SYMBOL(idr_get_new);
static void idr_remove_warning(int id)
{
printk("idr_remove called for id=%d which is not allocated.\n", id);
dump_stack();
}
static void sub_remove(struct idr *idp, int shift, int id) static void sub_remove(struct idr *idp, int shift, int id)
{ {
struct idr_layer *p = idp->top; struct idr_layer *p = idp->top;
struct idr_layer **pa[MAX_LEVEL]; struct idr_layer **pa[MAX_LEVEL];
struct idr_layer ***paa = &pa[0]; struct idr_layer ***paa = &pa[0];
int n;
*paa = NULL; *paa = NULL;
*++paa = &idp->top; *++paa = &idp->top;
while ((shift > 0) && p) { while ((shift > 0) && p) {
int n = (id >> shift) & IDR_MASK; n = (id >> shift) & IDR_MASK;
__clear_bit(n, &p->bitmap); __clear_bit(n, &p->bitmap);
*++paa = &p->ary[n]; *++paa = &p->ary[n];
p = p->ary[n]; p = p->ary[n];
shift -= IDR_BITS; shift -= IDR_BITS;
} }
if (likely(p != NULL)){ n = id & IDR_MASK;
int n = id & IDR_MASK; if (likely(p != NULL && test_bit(n, &p->bitmap))){
__clear_bit(n, &p->bitmap); __clear_bit(n, &p->bitmap);
p->ary[n] = NULL; p->ary[n] = NULL;
while(*paa && ! --((**paa)->count)){ while(*paa && ! --((**paa)->count)){
...@@ -301,6 +308,8 @@ static void sub_remove(struct idr *idp, int shift, int id) ...@@ -301,6 +308,8 @@ static void sub_remove(struct idr *idp, int shift, int id)
} }
if ( ! *paa ) if ( ! *paa )
idp->layers = 0; idp->layers = 0;
} else {
idr_remove_warning(id);
} }
} }
......
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