Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / notify / group.c
index fbe3cbe..3235753 100644 (file)
@@ -66,14 +66,23 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
         */
        fsnotify_group_stop_queueing(group);
 
-       /* clear all inode marks for this group, attach them to destroy_list */
-       fsnotify_detach_group_marks(group);
+       /* Clear all marks for this group and queue them for destruction */
+       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES);
 
        /*
-        * Wait for fsnotify_mark_srcu period to end and free all marks in
-        * destroy_list
+        * Some marks can still be pinned when waiting for response from
+        * userspace. Wait for those now. fsnotify_prepare_user_wait() will
+        * not succeed now so this wait is race-free.
         */
-       fsnotify_mark_destroy_list();
+       wait_event(group->notification_waitq, !atomic_read(&group->user_waits));
+
+       /*
+        * Wait until all marks get really destroyed. We could actually destroy
+        * them ourselves instead of waiting for worker to do it, however that
+        * would be racy as worker can already be processing some marks before
+        * we even entered fsnotify_destroy_group().
+        */
+       fsnotify_wait_marks_destroyed();
 
        /*
         * Since we have waited for fsnotify_mark_srcu in
@@ -124,6 +133,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
        /* set to 0 when there a no external references to this group */
        atomic_set(&group->refcnt, 1);
        atomic_set(&group->num_marks, 0);
+       atomic_set(&group->user_waits, 0);
 
        spin_lock_init(&group->notification_lock);
        INIT_LIST_HEAD(&group->notification_list);