From 8d3b35914aa54232b27e6a2b57d84092aadc5e86 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 23 Oct 2005 12:57:18 -0700 Subject: [PATCH] inotify/idr leak fix Fix a bug which was reported and diagnosed by Stefan Jones IDR trees include a cache of idr_layer objects. There's no way to destroy this cache, so when we discard an overall idr tree we end up leaking some memory. Add and use idr_destroy() for this. v9fs and infiniband also need to use idr_destroy() to avoid leaks. Or, we make the cache global, like radix_tree_preload(). Which is probably better. Later. Cc: Eric Van Hensbergen Cc: Roland Dreier Cc: Robert Love Cc: John McCutchan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inotify.c | 1 + include/linux/idr.h | 1 + lib/idr.c | 13 +++++++++++++ 3 files changed, 15 insertions(+) diff --git a/fs/inotify.c b/fs/inotify.c index a37e9fb1da5..9fbaebfdf40 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -176,6 +176,7 @@ static inline void put_inotify_dev(struct inotify_device *dev) if (atomic_dec_and_test(&dev->count)) { atomic_dec(&dev->user->inotify_devs); free_uid(dev->user); + idr_destroy(&dev->idr); kfree(dev); } } diff --git a/include/linux/idr.h b/include/linux/idr.h index ca3b7e46257..3d5de45f961 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -75,4 +75,5 @@ 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_above(struct idr *idp, void *ptr, int starting_id, int *id); void idr_remove(struct idr *idp, int id); +void idr_destroy(struct idr *idp); void idr_init(struct idr *idp); diff --git a/lib/idr.c b/lib/idr.c index 6415d053e2b..d4df21debc4 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -345,6 +345,19 @@ void idr_remove(struct idr *idp, int id) } EXPORT_SYMBOL(idr_remove); +/** + * idr_destroy - release all cached layers within an idr tree + * idp: idr handle + */ +void idr_destroy(struct idr *idp) +{ + while (idp->id_free_cnt) { + struct idr_layer *p = alloc_layer(idp); + kmem_cache_free(idr_layer_cache, p); + } +} +EXPORT_SYMBOL(idr_destroy); + /** * idr_find - return pointer for given id * @idp: idr handle -- cgit v1.2.3