• J
    af_unix: ensure POLLOUT on remote close() for connected dgram socket · 51f7e951
    Jason Baron 提交于
    Applications use -ECONNREFUSED as returned from write() in order to
    determine that a socket should be closed. However, when using connected
    dgram unix sockets in a poll/write loop, a final POLLOUT event can be
    missed when the remote end closes. Thus, the poll is stuck forever:
    
              thread 1 (client)                   thread 2 (server)
    
    connect() to server
    write() returns -EAGAIN
    unix_dgram_poll()
     -> unix_recvq_full() is true
                                           close()
                                            ->unix_release_sock()
                                             ->wake_up_interruptible_all()
    unix_dgram_poll() (due to the
         wake_up_interruptible_all)
     -> unix_recvq_full() still is true
                                             ->free all skbs
    
    Now thread 1 is stuck and will not receive anymore wakeups. In this
    case, when thread 1 gets the -EAGAIN, it has not queued any skbs
    otherwise the 'free all skbs' step would in fact cause a wakeup and
    a POLLOUT return. So the race here is probably fairly rare because
    it means there are no skbs that thread 1 queued and that thread 1
    schedules before the 'free all skbs' step.
    
    This issue was reported as a hang when /dev/log is closed.
    
    The fix is to signal POLLOUT if the socket is marked as SOCK_DEAD, which
    means a subsequent write() will get -ECONNREFUSED.
    Reported-by: NIan Lance Taylor <iant@golang.org>
    Cc: David Rientjes <rientjes@google.com>
    Cc: Rainer Weikusat <rweikusat@mobileactivedefense.com>
    Cc: Eric Dumazet <edumazet@google.com>
    Signed-off-by: NJason Baron <jbaron@akamai.com>
    Signed-off-by: NDavid S. Miller <davem@davemloft.net>
    51f7e951
af_unix.c 67.4 KB