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 <catalin.marinas@arm.com> Signed-off-by: Eric Paris <eparis@redhat.com>
This commit is contained in:
@@ -463,9 +463,6 @@ retry:
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
spin_lock(&group->inotify_data.idr_lock);
|
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,
|
ret = idr_get_new_above(&group->inotify_data.idr, entry,
|
||||||
++group->inotify_data.last_wd,
|
++group->inotify_data.last_wd,
|
||||||
&ientry->wd);
|
&ientry->wd);
|
||||||
@@ -476,8 +473,13 @@ retry:
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
atomic_inc(&group->inotify_data.user->inotify_watches);
|
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);
|
spin_lock(&entry->lock);
|
||||||
|
|
||||||
old_mask = entry->mask;
|
old_mask = entry->mask;
|
||||||
@@ -508,7 +510,11 @@ retry:
|
|||||||
fsnotify_recalc_group_mask(group);
|
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:
|
out_err:
|
||||||
/* see this isn't supposed to happen, just kill the watch */
|
/* see this isn't supposed to happen, just kill the watch */
|
||||||
|
Reference in New Issue
Block a user