Commit 8d3b35914aa54232b27e6a2b57d84092aadc5e86

Authored by Andrew Morton
Committed by Linus Torvalds
1 parent c0fef676bb

[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>

Showing 3 changed files with 15 additions and 0 deletions Side-by-side Diff

... ... @@ -176,6 +176,7 @@
176 176 if (atomic_dec_and_test(&dev->count)) {
177 177 atomic_dec(&dev->user->inotify_devs);
178 178 free_uid(dev->user);
  179 + idr_destroy(&dev->idr);
179 180 kfree(dev);
180 181 }
181 182 }
... ... @@ -75,5 +75,6 @@
75 75 int idr_get_new(struct idr *idp, void *ptr, int *id);
76 76 int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
77 77 void idr_remove(struct idr *idp, int id);
  78 +void idr_destroy(struct idr *idp);
78 79 void idr_init(struct idr *idp);
... ... @@ -346,6 +346,19 @@
346 346 EXPORT_SYMBOL(idr_remove);
347 347  
348 348 /**
  349 + * idr_destroy - release all cached layers within an idr tree
  350 + * idp: idr handle
  351 + */
  352 +void 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 +}
  359 +EXPORT_SYMBOL(idr_destroy);
  360 +
  361 +/**
349 362 * idr_find - return pointer for given id
350 363 * @idp: idr handle
351 364 * @id: lookup key