From: Eric Paris Date: Tue, 7 Jul 2009 14:28:23 +0000 (-0400) Subject: inotify: do not leak inode marks in inotify_add_watch X-Git-Tag: v2.6.31-rc5~81^2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=75fe2b26394c59c8e16bd7b76f4be5d048103ad1;p=platform%2Fkernel%2Flinux-stable.git inotify: do not leak inode marks in inotify_add_watch inotify_add_watch had a couple of problems. The biggest being that if inotify_add_watch was called on the same inode twice (to update or change the event mask) a refence was taken on the original inode mark by fsnotify_find_mark_entry but was not being dropped at the end of the inotify_add_watch call. Thus if inotify_rm_watch was called although the mark was removed from the inode, the refcnt wouldn't hit zero and we would leak memory. Reported-by: Catalin Marinas Signed-off-by: Eric Paris --- diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 1a870f9..aff4214 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -463,9 +463,6 @@ retry: goto out_err; spin_lock(&group->inotify_data.idr_lock); - /* if entry is added to the idr we keep the reference obtained - * through fsnotify_mark_add. remember to drop this reference - * when entry is removed from idr */ ret = idr_get_new_above(&group->inotify_data.idr, entry, ++group->inotify_data.last_wd, &ientry->wd); @@ -476,8 +473,13 @@ retry: goto out_err; } atomic_inc(&group->inotify_data.user->inotify_watches); + + /* we put the mark on the idr, take a reference */ + fsnotify_get_mark(entry); } + ret = ientry->wd; + spin_lock(&entry->lock); old_mask = entry->mask; @@ -508,7 +510,11 @@ retry: fsnotify_recalc_group_mask(group); } - return ientry->wd; + /* this either matches fsnotify_find_mark_entry, or init_mark_entry + * depending on which path we took... */ + fsnotify_put_mark(entry); + + return ret; out_err: /* see this isn't supposed to happen, just kill the watch */