Merge tag 'memblock-v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt...
[linux-2.6-microblaze.git] / fs / eventpoll.c
index e2daa94..8b56b94 100644 (file)
@@ -1747,6 +1747,21 @@ static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms)
        return to;
 }
 
+/*
+ * autoremove_wake_function, but remove even on failure to wake up, because we
+ * know that default_wake_function/ttwu will only fail if the thread is already
+ * woken, and in that case the ep_poll loop will remove the entry anyways, not
+ * try to reuse it.
+ */
+static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
+                                      unsigned int mode, int sync, void *key)
+{
+       int ret = default_wake_function(wq_entry, mode, sync, key);
+
+       list_del_init(&wq_entry->entry);
+       return ret;
+}
+
 /**
  * ep_poll - Retrieves ready events, and delivers them to the caller-supplied
  *           event buffer.
@@ -1828,8 +1843,15 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                 * normal wakeup path no need to call __remove_wait_queue()
                 * explicitly, thus ep->lock is not taken, which halts the
                 * event delivery.
+                *
+                * In fact, we now use an even more aggressive function that
+                * unconditionally removes, because we don't reuse the wait
+                * entry between loop iterations. This lets us also avoid the
+                * performance issue if a process is killed, causing all of its
+                * threads to wake up without being removed normally.
                 */
                init_wait(&wait);
+               wait.func = ep_autoremove_wake_function;
 
                write_lock_irq(&ep->lock);
                /*