[PATCH net v2 3/3] net/iucv: send the window update outside message_q.lock
Bryam Vargas via B4 Relay <[email protected]>
| Newsgroups | org.kernel.vger.netdev,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.linux-s390 |
|---|---|
| Message-ID | <[email protected]> |
From: Bryam Vargas <[email protected]> iucv_sock_recvmsg() calls iucv_send_ctrl() with message_q.lock held, and iucv_send_ctrl() allocates through sock_alloc_send_skb() with sk->sk_allocation -- GFP_KERNEL here -- so the allocation may sleep inside the spin_lock_bh() section; noblock suppresses only the wait for send buffer space, not the allocation flags. CONFIG_DEBUG_ATOMIC_SLEEP reports it. Note that the update is due and send it once the lock is dropped. That leaves two recvmsg() able to reach afiucv_hs_send() concurrently, which message_q.lock used to prevent; the preceding patch is what makes that safe, so do not apply this one without it. Fixes: 3881ac441f64 ("af_iucv: add HiperSockets transport") Cc: [email protected] Signed-off-by: Bryam Vargas <[email protected]> --- net/iucv/af_iucv.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 492a45bb2bba..a7c0f60bb5bf 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1244,6 +1244,7 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg, struct iucv_sock *iucv = iucv_sk(sk); unsigned int copied, rlen; struct sk_buff *skb, *rskb, *cskb; + bool send_win = false; int err = 0; u32 offset; @@ -1336,15 +1337,18 @@ static int iucv_sock_recvmsg(struct socket *sock, struct msghdr *msg, iucv_process_message_q(sk); if (iucv->transport == AF_IUCV_TRANS_HIPER && atomic_read(&iucv->msg_recv) >= - iucv->msglimit / 2) { - err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); - if (err) { - sk->sk_state = IUCV_DISCONN; - sk->sk_state_change(sk); - } - } + iucv->msglimit / 2) + send_win = true; } spin_unlock_bh(&iucv->message_q.lock); + + if (send_win) { + err = iucv_send_ctrl(sk, AF_IUCV_FLAG_WIN); + if (err) { + sk->sk_state = IUCV_DISCONN; + sk->sk_state_change(sk); + } + } } done: -- 2.55.0