aboutsummaryrefslogtreecommitdiffstats
path: root/lib
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 /lib
parent9a0a81f9e4a1719e212a7fc5892f9af030beaf97 (diff)
downloadhistory-1d2921ea5ac7c1bf010367b0b4ce74463db46ce6.tar.gz
[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>
Diffstat (limited to 'lib')
-rw-r--r--lib/idr.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/lib/idr.c b/lib/idr.c
index 7d92cfc23ac266..81fc430602ee8f 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);
}
}