lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 051/389] epoll: autoremove wakers even more aggressively
    Date
    From: Benjamin Segall <bsegall@google.com>

    commit a16ceb13961068f7209e34d7984f8e42d2c06159 upstream.

    If a process is killed or otherwise exits while having active network
    connections and many threads waiting on epoll_wait, the threads will all
    be woken immediately, but not removed from ep->wq. Then when network
    traffic scans ep->wq in wake_up, every wakeup attempt will fail, and will
    not remove the entries from the list.

    This means that the cost of the wakeup attempt is far higher than usual,
    does not decrease, and this also competes with the dying threads trying to
    actually make progress and remove themselves from the wq.

    Handle this by removing visited epoll wq entries unconditionally, rather
    than only when the wakeup succeeds - the structure of ep_poll means that
    the only potential loss is the timed_out->eavail heuristic, which now can
    race and result in a redundant ep_send_events attempt. (But only when
    incoming data and a timeout actually race, not on every timeout)

    Shakeel added:

    : We are seeing this issue in production with real workloads and it has
    : caused hard lockups. Particularly network heavy workloads with a lot
    : of threads in epoll_wait() can easily trigger this issue if they get
    : killed (oom-killed in our case).

    Link: https://lkml.kernel.org/r/xm26fsjotqda.fsf@google.com
    Signed-off-by: Ben Segall <bsegall@google.com>
    Tested-by: Shakeel Butt <shakeelb@google.com>
    Cc: Alexander Viro <viro@zeniv.linux.org.uk>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Shakeel Butt <shakeelb@google.com>
    Cc: Eric Dumazet <edumazet@google.com>
    Cc: Roman Penyaev <rpenyaev@suse.de>
    Cc: Jason Baron <jbaron@akamai.com>
    Cc: Khazhismel Kumykov <khazhy@google.com>
    Cc: Heiher <r@hev.cc>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/eventpoll.c | 22 ++++++++++++++++++++++
    1 file changed, 22 insertions(+)

    --- a/fs/eventpoll.c
    +++ b/fs/eventpoll.c
    @@ -1803,6 +1803,21 @@ static inline struct timespec64 ep_set_m
    return timespec64_add_safe(now, ts);
    }

    +/*
    + * 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.
    @@ -1880,8 +1895,15 @@ fetch_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);
    __add_wait_queue_exclusive(&ep->wq, &wait);
    write_unlock_irq(&ep->lock);

    \
     
     \ /
      Last update: 2022-08-23 13:14    [W:4.051 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site