#include "fsnotify.h"
 
 struct srcu_struct fsnotify_mark_srcu;
-static DEFINE_SPINLOCK(destroy_lock);
-static LIST_HEAD(destroy_list);
-static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq);
 
 void fsnotify_get_mark(struct fsnotify_mark *mark)
 {
        atomic_dec(&group->num_marks);
 }
 
+static void
+fsnotify_mark_free_rcu(struct rcu_head *rcu)
+{
+       struct fsnotify_mark    *mark;
+
+       mark = container_of(rcu, struct fsnotify_mark, g_rcu);
+       fsnotify_put_mark(mark);
+}
+
 /*
- * Free fsnotify mark. The freeing is actually happening from a kthread which
- * first waits for srcu period end. Caller must have a reference to the mark
- * or be protected by fsnotify_mark_srcu.
+ * Free fsnotify mark. The freeing is actually happening from a call_srcu
+ * callback. Caller must have a reference to the mark or be protected by
+ * fsnotify_mark_srcu.
  */
 void fsnotify_free_mark(struct fsnotify_mark *mark)
 {
        mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
        spin_unlock(&mark->lock);
 
-       spin_lock(&destroy_lock);
-       list_add(&mark->g_list, &destroy_list);
-       spin_unlock(&destroy_lock);
-       wake_up(&destroy_waitq);
+       call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
 
        /*
         * Some groups like to know that marks are being freed.  This is a
 
        spin_unlock(&mark->lock);
 
-       spin_lock(&destroy_lock);
-       list_add(&mark->g_list, &destroy_list);
-       spin_unlock(&destroy_lock);
-       wake_up(&destroy_waitq);
-
+       call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
        return ret;
 }
 
        atomic_set(&mark->refcnt, 1);
        mark->free_mark = free_mark;
 }
-
-static int fsnotify_mark_destroy(void *ignored)
-{
-       struct fsnotify_mark *mark, *next;
-       struct list_head private_destroy_list;
-
-       for (;;) {
-               spin_lock(&destroy_lock);
-               /* exchange the list head */
-               list_replace_init(&destroy_list, &private_destroy_list);
-               spin_unlock(&destroy_lock);
-
-               synchronize_srcu(&fsnotify_mark_srcu);
-
-               list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
-                       list_del_init(&mark->g_list);
-                       fsnotify_put_mark(mark);
-               }
-
-               wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list));
-       }
-
-       return 0;
-}
-
-static int __init fsnotify_mark_init(void)
-{
-       struct task_struct *thread;
-
-       thread = kthread_run(fsnotify_mark_destroy, NULL,
-                            "fsnotify_mark");
-       if (IS_ERR(thread))
-               panic("unable to start fsnotify mark destruction thread.");
-
-       return 0;
-}
-device_initcall(fsnotify_mark_init);