On Fri, Nov 06, 2026 at 01:57 PM Jerome Mohm via B4 Relay
<[email protected]> wrote:
> example by a credit update. So the wait also loops until data arrives
> or one of the native exits applies: a socket error, a local or peer
> shutdown, a socket that is no longer connected, the timeout or a
> pending signal. The loop alone, with the lock still held, keeps the
> deadlock, so the fix needs both halves and stays one patch.
No need for a 2nd copy of the return values.
The old code returns true on RCV_SHUTDOWN. The psock queue is empty, so
the caller goes to __vsock_recvmsg(), which picks the return value.
tcp_bpf, udp_bpf and unix_bpf do the same.
Do it for sk_err, peer_shutdown and sk_state too.
__vsock_recvmsg() doesn't wait in any of these states.
It handles len == 0, MSG_OOB and MSG_ERRQUEUE as well.
The copy differs from a socket that is not in a sockmap in four cases.
The diff differs in one, the last row:
recv() no sockmap this series the diff
------------------------------ ------------ ------------ -----------
after a virtio reset -ENOTCONN -ECONNRESET -ENOTCONN
after a reset, len == 0 -ENOTCONN 0 -ENOTCONN
after a reset, MSG_OOB -ENOTCONN -EOPNOTSUPP -ENOTCONN
after peer shutdown, SO_INQ on 0 + SCM_INQ 0 0 + SCM_INQ
asleep when the reset comes -ECONNRESET -ECONNRESET -ENOTCONN
Instead of patches 1 and 2 (compile tested only):
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
index 9049d26..3cf017d 100644
--- a/net/vmw_vsock/vsock_bpf.c
+++ b/net/vmw_vsock/vsock_bpf.c
@@ -34,24 +34,34 @@ static bool vsock_has_data(struct sock *sk, struct sk_psock
*psock)
return vsock_sk_has_data(sk, psock);
}
-static bool vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long
timeo)
+/* __vsock_recvmsg() doesn't wait in these states and knows what to return. */
+static bool vsock_rx_done(struct sock *sk)
{
- bool ret;
-
- DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ return sk->sk_err || sk->sk_state != TCP_ESTABLISHED ||
+ (sk->sk_shutdown & RCV_SHUTDOWN) ||
+ (vsock_sk(sk)->peer_shutdown & SEND_SHUTDOWN);
+}
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- return true;
+static int vsock_msg_wait_data(struct sock *sk, struct sk_psock *psock, long
timeo)
+{
+ int ret = 0;
- if (!timeo)
- return false;
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
add_wait_queue(sk_sleep(sk), &wait);
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
- ret = vsock_has_data(sk, psock);
- if (!ret) {
- wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
- ret = vsock_has_data(sk, psock);
+ while (!vsock_has_data(sk, psock) && !vsock_rx_done(sk)) {
+ if (!timeo) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = sock_intr_errno(timeo);
+ break;
+ }
+ release_sock(sk);
+ timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
+ lock_sock(sk);
}
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
remove_wait_queue(sk_sleep(sk), &wait);
@@ -80,6 +90,9 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr
*msg,
struct vsock_sock *vsk;
int copied;
+ if (unlikely(!len || (flags & (MSG_OOB | MSG_ERRQUEUE))))
+ return __vsock_recvmsg(sk, msg, len, flags);
+
psock = sk_psock_get(sk);
if (unlikely(!psock))
return __vsock_recvmsg(sk, msg, len, flags);
@@ -102,10 +115,9 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct
msghdr *msg,
while (copied == 0) {
long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
- if (!vsock_msg_wait_data(sk, psock, timeo)) {
- copied = -EAGAIN;
+ copied = vsock_msg_wait_data(sk, psock, timeo);
+ if (copied)
break;
- }
if (sk_psock_queue_empty(psock)) {
release_sock(sk);
[...]
> guest's virtio-vsock device. With the series applied they behave as on
> a native socket, except for the reset case above, and the vsock
> vmtest.sh single-VM tests and the BPF sockmap test_progs pass.
None of these tests sleeps in vsock_msg_wait_data().
The sockmap tests call select() before recv() or pass MSG_DONTWAIT.
vmtest.sh doesn't use sockmap.
pw-bot: cr