aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2005-10-23 15:57:18 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-23 19:38:39 -0400
commit8d3b35914aa54232b27e6a2b57d84092aadc5e86 (patch)
tree809be8fad6743a751964677e68c5c01af3198e4b
parentc0fef676bbd75e711711ed3ff5bebb7bfd1bdb00 (diff)
[PATCH] inotify/idr leak fix
Fix a bug which was reported and diagnosed by Stefan Jones <stefan.jones@churchillrandoms.co.uk> 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 <ericvh@ericvh.myip.org> Cc: Roland Dreier <rolandd@cisco.com> Cc: Robert Love <rml@novell.com> Cc: John McCutchan <ttb@tentacle.dhs.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/inotify.c1
-rw-r--r--include/linux/idr.h1
-rw-r--r--lib/idr.c13
3 files changed, 15 insertions, 0 deletions
diff --git a/fs/inotify.c b/fs/inotify.c
index a37e9fb1da58..9fbaebfdf40b 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -176,6 +176,7 @@ static inline void put_inotify_dev(struct inotify_device *dev)
176 if (atomic_dec_and_test(&dev->count)) { 176 if (atomic_dec_and_test(&dev->count)) {
177 atomic_dec(&dev->user->inotify_devs); 177 atomic_dec(&dev->user->inotify_devs);
178 free_uid(dev->user); 178 free_uid(dev->user);
179 idr_destroy(&dev->idr);
179 kfree(dev); 180 kfree(dev);
180 } 181 }
181} 182}
diff --git a/include/linux/idr.h b/include/linux/idr.h
index ca3b7e462576..3d5de45f961b 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);
75int idr_get_new(struct idr *idp, void *ptr, int *id); 75int idr_get_new(struct idr *idp, void *ptr, int *id);
76int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); 76int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
77void idr_remove(struct idr *idp, int id); 77void idr_remove(struct idr *idp, int id);
78void idr_destroy(struct idr *idp);
78void idr_init(struct idr *idp); 79void idr_init(struct idr *idp);
diff --git a/lib/idr.c b/lib/idr.c
index 6415d053e2bf..d4df21debc4d 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -346,6 +346,19 @@ void idr_remove(struct idr *idp, int id)
346EXPORT_SYMBOL(idr_remove); 346EXPORT_SYMBOL(idr_remove);
347 347
348/** 348/**
349 * idr_destroy - release all cached layers within an idr tree
350 * idp: idr handle
351 */
352void idr_destroy(struct idr *idp)
353{
354 while (idp->id_free_cnt) {
355 struct idr_layer *p = alloc_layer(idp);
356 kmem_cache_free(idr_layer_cache, p);
357 }
358}
359EXPORT_SYMBOL(idr_destroy);
360
361/**
349 * idr_find - return pointer for given id 362 * idr_find - return pointer for given id
350 * @idp: idr handle 363 * @idp: idr handle
351 * @id: lookup key 364 * @id: lookup key