diff options
author | Jim Houston <jim.houston@ccur.com> | 2004-10-25 04:23:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-10-25 04:23:23 -0700 |
commit | 1d2921ea5ac7c1bf010367b0b4ce74463db46ce6 (patch) | |
tree | 33126e3c6f1e7dbe1db23e3f74e70b89654a3de8 /lib | |
parent | 9a0a81f9e4a1719e212a7fc5892f9af030beaf97 (diff) | |
download | history-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.c | 15 |
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); } } |