diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 5549298c1ec6..e8481f12312e 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -68,6 +68,7 @@ struct vsock_sock { u64 buffer_size; u64 buffer_min_size; u64 buffer_max_size; + bool recvmsg_inq; /* Private to transport. */ void *trans; diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 847afbebef01..d0508887a2fb 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -984,6 +984,7 @@ static struct sock *__vsock_create(struct net *net, vsk->buffer_size = psk->buffer_size; vsk->buffer_min_size = psk->buffer_min_size; vsk->buffer_max_size = psk->buffer_max_size; + vsk->recvmsg_inq = psk->recvmsg_inq; security_sk_clone(parent, sk); } else { vsk->trusted = ns_capable_noaudit(&init_user_ns, CAP_NET_ADMIN); @@ -2017,6 +2018,7 @@ static bool vsock_sol_socket_custom(int optname) { switch (optname) { case SO_ZEROCOPY: + case SO_INQ: return true; default: return false; @@ -2064,6 +2066,19 @@ static int vsock_sol_socket_setsockopt(struct sock *sk, int optname, sock_valbool_flag(sk, SOCK_ZEROCOPY, val); break; + case SO_INQ: + if (sk->sk_type != SOCK_STREAM) { + err = -ENOPROTOOPT; + break; + } + + err = vsock_sol_socket_get_bool(optval, optlen, &val); + if (err) + break; + + vsk->recvmsg_inq = val; + break; + default: err = -ENOPROTOOPT; break; @@ -2620,6 +2635,7 @@ __vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, struct sock *sk; struct vsock_sock *vsk; const struct vsock_transport *transport; + bool do_cmsg = false; int err; sk = sock->sk; @@ -2676,13 +2692,26 @@ __vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, err = __vsock_seqpacket_recvmsg(sk, msg, len, flags); out: - /* Seqpacket has_data counts messages, while io_uring treats msg_inq as - * a byte length when sizing retries, so only streams report a hint. + /* Seqpacket has_data counts messages, while SCM_INQ reports bytes and + * io_uring treats msg_inq as a byte length when sizing retries, so + * only streams report it. */ - if (msg->msg_get_inq && err >= 0 && sk->sk_type == SOCK_STREAM) + if ((vsk->recvmsg_inq || msg->msg_get_inq) && err >= 0 && + sk->sk_type == SOCK_STREAM) { msg->msg_inq = vsock_stream_inq_hint(sk); + /* A negative hint means the transport could not tell. SCM_INQ + * has no encoding for that, so report nothing. + */ + do_cmsg = vsk->recvmsg_inq && msg->msg_inq >= 0; + } + release_sock(sk); + + if (do_cmsg) + put_cmsg(msg, SOL_SOCKET, SCM_INQ, sizeof(msg->msg_inq), + &msg->msg_inq); + return err; }