aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2017-10-30 16:14:56 -0400
committerJan Kara <jack@suse.cz>2017-10-31 12:54:56 -0400
commit9a31d7ad997f55768c687974ce36b759065b49e5 (patch)
tree370270d9166e6c4080e0afebb893b7feb02f222f
parent0d6ec079d6aaa098b978d6395973bb027c752a03 (diff)
fsnotify: fix pinning group in fsnotify_prepare_user_wait()
Blind increment of group's user_waits is not enough, we could be far enough in the group's destruction that it isn't taken into account (i.e. grabbing the mark ref afterwards doesn't guarantee that it was the ref coming from the _group_ that was grabbed). Instead we need to check (under lock) that the mark is still attached to the group after having obtained a ref to the mark. If not, skip it. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: 9385a84d7e1f ("fsnotify: Pass fsnotify_iter_info into handle_event handler") Cc: <stable@vger.kernel.org> # v4.12 Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/notify/mark.c25
1 files changed, 11 insertions, 14 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
index 7ecd15add6a7..f3a32ea15b49 100644
--- a/fs/notify/mark.c
+++ b/fs/notify/mark.c
@@ -255,23 +255,20 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
255 */ 255 */
256static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark) 256static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
257{ 257{
258 struct fsnotify_group *group;
259
260 if (!mark) 258 if (!mark)
261 return true; 259 return true;
262 260
263 group = mark->group; 261 if (atomic_inc_not_zero(&mark->refcnt)) {
264 /* 262 spin_lock(&mark->lock);
265 * Since acquisition of mark reference is an atomic op as well, we can 263 if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
266 * be sure this inc is seen before any effect of refcount increment. 264 /* mark is attached, group is still alive then */
267 */ 265 atomic_inc(&mark->group->user_waits);
268 atomic_inc(&group->user_waits); 266 spin_unlock(&mark->lock);
269 if (atomic_inc_not_zero(&mark->refcnt)) 267 return true;
270 return true; 268 }
271 269 spin_unlock(&mark->lock);
272 if (atomic_dec_and_test(&group->user_waits) && group->shutdown) 270 fsnotify_put_mark(mark);
273 wake_up(&group->notification_waitq); 271 }
274
275 return false; 272 return false;
276} 273}
277 274