net/udp: break the network lock to avoid deadlock

Author: chao.an <anchao@xiaomi.com>

    net/udp: break the network lock to avoid deadlock

      network deadlock when udp sendto() storm is coming

    net/close: force wait tx drain to complete

      atomic send() and close() will causes data to be discarded directly

Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2020-01-16 14:20:09 -03:00 committed by Alan Carvalho de Assis
parent b3fd644f1b
commit 2d0baa779d
2 changed files with 29 additions and 13 deletions

View File

@ -412,6 +412,8 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
static inline int udp_close(FAR struct socket *psock)
{
FAR struct udp_conn_s *conn;
unsigned int timeout = UINT_MAX;
int ret;
/* Interrupts are disabled here to avoid race conditions */
@ -435,22 +437,22 @@ static inline int udp_close(FAR struct socket *psock)
if (_SO_GETOPT(psock->s_options, SO_LINGER))
{
int ret;
/* Wait until for the buffered TX data to be sent. */
ret = udp_txdrain(psock, _SO_TIMEOUT(psock->s_linger));
if (ret < 0)
{
/* udp_txdrain may fail, but that won't stop us from closing
* the socket.
*/
nerr("ERROR: udp_txdrain() failed: %d\n", ret);
}
timeout = _SO_TIMEOUT(psock->s_linger);
}
#endif
/* Wait until for the buffered TX data to be sent. */
ret = udp_txdrain(psock, timeout);
if (ret < 0)
{
/* udp_txdrain may fail, but that won't stop us from closing
* the socket.
*/
nerr("ERROR: udp_txdrain() failed: %d\n", ret);
}
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
/* Free any semi-permanent write buffer callback in place. */

View File

@ -75,6 +75,7 @@
#include "neighbor/neighbor.h"
#include "udp/udp.h"
#include "devif/devif.h"
#include "utils/utils.h"
/****************************************************************************
* Pre-processor Definitions
@ -713,8 +714,21 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
}
else
{
unsigned int count;
int blresult;
/* iob_copyin might wait for buffers to be freed, but if
* network is locked this might never happen, since network
* driver is also locked, therefore we need to break the lock
*/
blresult = net_breaklock(&count);
ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false,
IOBUSER_NET_SOCK_UDP);
if (blresult >= 0)
{
net_restorelock(count);
}
}
if (ret < 0)