Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[linux-2.6-microblaze.git] / fs / notify / group.c
index b47f7cf..3235753 100644 (file)
@@ -45,9 +45,9 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
  */
 void fsnotify_group_stop_queueing(struct fsnotify_group *group)
 {
-       mutex_lock(&group->notification_mutex);
+       spin_lock(&group->notification_lock);
        group->shutdown = true;
-       mutex_unlock(&group->notification_mutex);
+       spin_unlock(&group->notification_lock);
 }
 
 /*
@@ -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,8 +133,9 @@ 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);
 
-       mutex_init(&group->notification_mutex);
+       spin_lock_init(&group->notification_lock);
        INIT_LIST_HEAD(&group->notification_list);
        init_waitqueue_head(&group->notification_waitq);
        group->max_events = UINT_MAX;