Skip to content

Commit db59acb

Browse files
ccli8dkalowsk
authored andcommitted
drivers: wifi: esp_at: fix deadlock in socket close path
This fixes deadlock in socket close path. In the scenario: 1. on_cmd_ipd/esp_socket_rx invokes esp_socket_ref_from_link_id and increments refcount. 2. zvfs_close/esp_put locks cond.lock. 3. zvfs_close/esp_put waits on sem_free. 4. on_cmd_ipd/esp_socket_rx waits on cond.lock before esp_socket_unref. 5. sem_free waits on esp_socket_unref for refcount reaching zero. As we detect socket is closing, we can ignore last rx data and escape from the trap. Signed-off-by: Chun-Chieh Li <ccli8@nuvoton.com>
1 parent 622fddb commit db59acb

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

drivers/wifi/esp_at/esp_socket.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,29 @@ void esp_socket_rx(struct esp_socket *sock, struct net_buf *buf,
194194
* net_context and socket mutex claims matches the TX code path. Failure
195195
* to do so can lead to deadlocks.
196196
*/
197+
/* In the close path, we will meet deadlock in the scenario:
198+
* 1. on_cmd_ipd/esp_socket_rx invokes esp_socket_ref_from_link_id
199+
* and increments refcount.
200+
* 2. zvfs_close/esp_put locks cond.lock.
201+
* 3. zvfs_close/esp_put waits on sem_free.
202+
* 4. on_cmd_ipd/esp_socket_rx waits on cond.lock before esp_socket_unref.
203+
* 5. sem_free waits on esp_socket_unref for refcount reaching zero.
204+
*/
197205
if (sock->context->cond.lock) {
198-
k_mutex_lock(sock->context->cond.lock, K_FOREVER);
206+
int ret = -EAGAIN;
207+
208+
/*
209+
* If the socket is closing, we can ignore the packet and won't
210+
* trap in deadlock.
211+
*/
212+
while (atomic_get(&sock->refcount) > 1 && ret == -EAGAIN) {
213+
ret = k_mutex_lock(sock->context->cond.lock, K_SECONDS(1));
214+
}
215+
if (ret != 0) {
216+
/* Discard */
217+
net_pkt_unref(pkt);
218+
return;
219+
}
199220
}
200221
#endif /* CONFIG_NET_SOCKETS */
201222
k_mutex_lock(&sock->lock, K_FOREVER);

0 commit comments

Comments
 (0)