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:
parent
b3fd644f1b
commit
2d0baa779d
@ -412,6 +412,8 @@ static inline int tcp_close_disconnect(FAR struct socket *psock)
|
|||||||
static inline int udp_close(FAR struct socket *psock)
|
static inline int udp_close(FAR struct socket *psock)
|
||||||
{
|
{
|
||||||
FAR struct udp_conn_s *conn;
|
FAR struct udp_conn_s *conn;
|
||||||
|
unsigned int timeout = UINT_MAX;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Interrupts are disabled here to avoid race conditions */
|
/* 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))
|
if (_SO_GETOPT(psock->s_options, SO_LINGER))
|
||||||
{
|
{
|
||||||
int ret;
|
timeout = _SO_TIMEOUT(psock->s_linger);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
/* Free any semi-permanent write buffer callback in place. */
|
/* Free any semi-permanent write buffer callback in place. */
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
#include "neighbor/neighbor.h"
|
#include "neighbor/neighbor.h"
|
||||||
#include "udp/udp.h"
|
#include "udp/udp.h"
|
||||||
#include "devif/devif.h"
|
#include "devif/devif.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
@ -713,8 +714,21 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||||||
}
|
}
|
||||||
else
|
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,
|
ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false,
|
||||||
IOBUSER_NET_SOCK_UDP);
|
IOBUSER_NET_SOCK_UDP);
|
||||||
|
if (blresult >= 0)
|
||||||
|
{
|
||||||
|
net_restorelock(count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user