aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/notify/fanotify/fanotify.c9
-rw-r--r--fs/notify/fanotify/fanotify_user.c12
-rw-r--r--fs/notify/notification.c18
-rw-r--r--include/linux/fsnotify_backend.h2
4 files changed, 39 insertions, 2 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index fdeb36b70c65..30d3addfad75 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -70,8 +70,15 @@ static int fanotify_get_response(struct fsnotify_group *group,
70 wait_event(group->fanotify_data.access_waitq, event->response || 70 wait_event(group->fanotify_data.access_waitq, event->response ||
71 atomic_read(&group->fanotify_data.bypass_perm)); 71 atomic_read(&group->fanotify_data.bypass_perm));
72 72
73 if (!event->response) /* bypass_perm set */ 73 if (!event->response) { /* bypass_perm set */
74 /*
75 * Event was canceled because group is being destroyed. Remove
76 * it from group's event list because we are responsible for
77 * freeing the permission event.
78 */
79 fsnotify_remove_event(group, &event->fae.fse);
74 return 0; 80 return 0;
81 }
75 82
76 /* userspace responded, convert to something usable */ 83 /* userspace responded, convert to something usable */
77 switch (event->response) { 84 switch (event->response) {
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index fbf2210823ab..b13992a41bd9 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -359,6 +359,11 @@ static int fanotify_release(struct inode *ignored, struct file *file)
359#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 359#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
360 struct fanotify_perm_event_info *event, *next; 360 struct fanotify_perm_event_info *event, *next;
361 361
362 /*
363 * There may be still new events arriving in the notification queue
364 * but since userspace cannot use fanotify fd anymore, no event can
365 * enter or leave access_list by now.
366 */
362 spin_lock(&group->fanotify_data.access_lock); 367 spin_lock(&group->fanotify_data.access_lock);
363 368
364 atomic_inc(&group->fanotify_data.bypass_perm); 369 atomic_inc(&group->fanotify_data.bypass_perm);
@@ -373,6 +378,13 @@ static int fanotify_release(struct inode *ignored, struct file *file)
373 } 378 }
374 spin_unlock(&group->fanotify_data.access_lock); 379 spin_unlock(&group->fanotify_data.access_lock);
375 380
381 /*
382 * Since bypass_perm is set, newly queued events will not wait for
383 * access response. Wake up the already sleeping ones now.
384 * synchronize_srcu() in fsnotify_destroy_group() will wait for all
385 * processes sleeping in fanotify_handle_event() waiting for access
386 * response and thus also for all permission events to be freed.
387 */
376 wake_up(&group->fanotify_data.access_waitq); 388 wake_up(&group->fanotify_data.access_waitq);
377#endif 389#endif
378 390
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 1d394220acbe..a95d8e037aeb 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -73,7 +73,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
73 /* Overflow events are per-group and we don't want to free them */ 73 /* Overflow events are per-group and we don't want to free them */
74 if (!event || event->mask == FS_Q_OVERFLOW) 74 if (!event || event->mask == FS_Q_OVERFLOW)
75 return; 75 return;
76 76 /* If the event is still queued, we have a problem... */
77 WARN_ON(!list_empty(&event->list));
77 group->ops->free_event(event); 78 group->ops->free_event(event);
78} 79}
79 80
@@ -125,6 +126,21 @@ queue:
125} 126}
126 127
127/* 128/*
129 * Remove @event from group's notification queue. It is the responsibility of
130 * the caller to destroy the event.
131 */
132void fsnotify_remove_event(struct fsnotify_group *group,
133 struct fsnotify_event *event)
134{
135 mutex_lock(&group->notification_mutex);
136 if (!list_empty(&event->list)) {
137 list_del_init(&event->list);
138 group->q_len--;
139 }
140 mutex_unlock(&group->notification_mutex);
141}
142
143/*
128 * Remove and return the first event from the notification list. It is the 144 * Remove and return the first event from the notification list. It is the
129 * responsibility of the caller to destroy the obtained event 145 * responsibility of the caller to destroy the obtained event
130 */ 146 */
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index a6e899943363..ca060d7c4fa6 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -326,6 +326,8 @@ extern int fsnotify_add_event(struct fsnotify_group *group,
326 struct fsnotify_event *event, 326 struct fsnotify_event *event,
327 int (*merge)(struct list_head *, 327 int (*merge)(struct list_head *,
328 struct fsnotify_event *)); 328 struct fsnotify_event *));
329/* Remove passed event from groups notification queue */
330extern void fsnotify_remove_event(struct fsnotify_group *group, struct fsnotify_event *event);
329/* true if the group notification queue is empty */ 331/* true if the group notification queue is empty */
330extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); 332extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
331/* return, but do not dequeue the first event on the notification queue */ 333/* return, but do not dequeue the first event on the notification queue */