x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / fs / notify / notification.c
index e455e83..66f85c6 100644 (file)
@@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
 /* return true if the notify queue is empty, false otherwise */
 bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
 {
-       BUG_ON(!mutex_is_locked(&group->notification_mutex));
+       assert_spin_locked(&group->notification_lock);
        return list_empty(&group->notification_list) ? true : false;
 }
 
@@ -73,8 +73,17 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
        /* Overflow events are per-group and we don't want to free them */
        if (!event || event->mask == FS_Q_OVERFLOW)
                return;
-       /* If the event is still queued, we have a problem... */
-       WARN_ON(!list_empty(&event->list));
+       /*
+        * If the event is still queued, we have a problem... Do an unreliable
+        * lockless check first to avoid locking in the common case. The
+        * locking may be necessary for permission events which got removed
+        * from the list by a different CPU than the one freeing the event.
+        */
+       if (!list_empty(&event->list)) {
+               spin_lock(&group->notification_lock);
+               WARN_ON(!list_empty(&event->list));
+               spin_unlock(&group->notification_lock);
+       }
        group->ops->free_event(event);
 }
 
@@ -95,10 +104,10 @@ int fsnotify_add_event(struct fsnotify_group *group,
 
        pr_debug("%s: group=%p event=%p\n", __func__, group, event);
 
-       mutex_lock(&group->notification_mutex);
+       spin_lock(&group->notification_lock);
 
        if (group->shutdown) {
-               mutex_unlock(&group->notification_mutex);
+               spin_unlock(&group->notification_lock);
                return 2;
        }
 
@@ -106,7 +115,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
                ret = 2;
                /* Queue overflow event only if it isn't already queued */
                if (!list_empty(&group->overflow_event->list)) {
-                       mutex_unlock(&group->notification_mutex);
+                       spin_unlock(&group->notification_lock);
                        return ret;
                }
                event = group->overflow_event;
@@ -116,7 +125,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
        if (!list_empty(list) && merge) {
                ret = merge(list, event);
                if (ret) {
-                       mutex_unlock(&group->notification_mutex);
+                       spin_unlock(&group->notification_lock);
                        return ret;
                }
        }
@@ -124,7 +133,7 @@ int fsnotify_add_event(struct fsnotify_group *group,
 queue:
        group->q_len++;
        list_add_tail(&event->list, list);
-       mutex_unlock(&group->notification_mutex);
+       spin_unlock(&group->notification_lock);
 
        wake_up(&group->notification_waitq);
        kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
@@ -139,7 +148,7 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
 {
        struct fsnotify_event *event;
 
-       BUG_ON(!mutex_is_locked(&group->notification_mutex));
+       assert_spin_locked(&group->notification_lock);
 
        pr_debug("%s: group=%p\n", __func__, group);
 
@@ -161,7 +170,7 @@ struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group)
  */
 struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group)
 {
-       BUG_ON(!mutex_is_locked(&group->notification_mutex));
+       assert_spin_locked(&group->notification_lock);
 
        return list_first_entry(&group->notification_list,
                                struct fsnotify_event, list);
@@ -175,12 +184,14 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
 {
        struct fsnotify_event *event;
 
-       mutex_lock(&group->notification_mutex);
+       spin_lock(&group->notification_lock);
        while (!fsnotify_notify_queue_is_empty(group)) {
                event = fsnotify_remove_first_event(group);
+               spin_unlock(&group->notification_lock);
                fsnotify_destroy_event(group, event);
+               spin_lock(&group->notification_lock);
        }
-       mutex_unlock(&group->notification_mutex);
+       spin_unlock(&group->notification_lock);
 }
 
 /*