summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Houston <jim.houston@ccur.com>2004-10-25 04:23:23 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-10-25 04:23:23 -0700
commit1d2921ea5ac7c1bf010367b0b4ce74463db46ce6 (patch)
tree33126e3c6f1e7dbe1db23e3f74e70b89654a3de8
parent9a0a81f9e4a1719e212a7fc5892f9af030beaf97 (diff)
[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: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--lib/idr.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/lib/idr.c b/lib/idr.c
index 7d92cfc23ac2..81fc430602ee 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -275,24 +275,31 @@ int idr_get_new(struct idr *idp, void *ptr, int *id)
}
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)
{
struct idr_layer *p = idp->top;
struct idr_layer **pa[MAX_LEVEL];
struct idr_layer ***paa = &pa[0];
+ int n;
*paa = NULL;
*++paa = &idp->top;
while ((shift > 0) && p) {
- int n = (id >> shift) & IDR_MASK;
+ n = (id >> shift) & IDR_MASK;
__clear_bit(n, &p->bitmap);
*++paa = &p->ary[n];
p = p->ary[n];
shift -= IDR_BITS;
}
- if (likely(p != NULL)){
- int n = id & IDR_MASK;
+ n = id & IDR_MASK;
+ if (likely(p != NULL && test_bit(n, &p->bitmap))){
__clear_bit(n, &p->bitmap);
p->ary[n] = NULL;
while(*paa && ! --((**paa)->count)){
@@ -301,6 +308,8 @@ static void sub_remove(struct idr *idp, int shift, int id)
}
if ( ! *paa )
idp->layers = 0;
+ } else {
+ idr_remove_warning(id);
}
}