mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
vsock: support SO_INQ on stream sockets
SO_INQ makes recvmsg() return the bytes left in the receive queue in an SCM_INQ cmsg, saving a SIOCINQ call per receive. AF_UNIX stream sockets support it, AF_VSOCK fails with ENOPROTOOPT. Add it for SOCK_STREAM, reusing the hint already computed for io_uring. As with TCP_INQ, 1 is reported once the stream is finished so the caller reads again and sees EOF, and accepted sockets inherit the setting from the listener. No cmsg is sent when the transport cannot report the queue length. SOCK_SEQPACKET is refused, as on AF_UNIX: its transport callback counts messages, not bytes. Signed-off-by: David Carlier <devnexen@gmail.com> Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> Link: https://patch.msgid.link/20261016132716.272018-3-devnexen@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
1 parent
a006b921ad
commit
d7bb20b911
2 files changed
+33
-3
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user