From a006b921ad32940676993bfae460b9f57547b79b Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 16 Oct 2026 14:27:14 +0100 Subject: [PATCH] vsock: move SOL_SOCKET options to vsock_sol_socket_setsockopt() SO_ZEROCOPY is handled inline in vsock_connectible_setsockopt(). Move it to a helper with a switch on optname, so other SOL_SOCKET options can be added as new cases. The value parsing goes to its own helper too, so each option can do its own checks before it. No functional change. Signed-off-by: David Carlier Reviewed-by: Stefano Garzarella Link: https://patch.msgid.link/20261016132716.272018-2-devnexen@gmail.com Signed-off-by: Paolo Abeni --- net/vmw_vsock/af_vsock.c | 94 ++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 483af15a5109..847afbebef01 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -2013,6 +2013,66 @@ static void vsock_update_buffer_size(struct vsock_sock *vsk, vsk->buffer_size = val; } +static bool vsock_sol_socket_custom(int optname) +{ + switch (optname) { + case SO_ZEROCOPY: + return true; + default: + return false; + } +} + +static int vsock_sol_socket_get_bool(sockptr_t optval, unsigned int optlen, + int *val) +{ + /* Use 'int' type here, because variable to set these options usually + * has this type. + */ + if (optlen < sizeof(*val)) + return -EINVAL; + + if (copy_from_sockptr(val, optval, sizeof(*val))) + return -EFAULT; + + if (*val < 0 || *val > 1) + return -EINVAL; + + return 0; +} + +static int vsock_sol_socket_setsockopt(struct sock *sk, int optname, + sockptr_t optval, unsigned int optlen) +{ + struct vsock_sock *vsk = vsock_sk(sk); + int err; + int val; + + lock_sock(sk); + + switch (optname) { + case SO_ZEROCOPY: + err = vsock_sol_socket_get_bool(optval, optlen, &val); + if (err) + break; + + if (vsk->transport && !vsock_msgzerocopy_allow(vsk->transport)) { + err = -EOPNOTSUPP; + break; + } + + sock_valbool_flag(sk, SOCK_ZEROCOPY, val); + break; + + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + return err; +} + static int vsock_connectible_setsockopt(struct socket *sock, int level, int optname, @@ -2044,37 +2104,17 @@ static int vsock_connectible_setsockopt(struct socket *sock, sk = sock->sk; vsk = vsock_sk(sk); + if (level == SOL_SOCKET) { + if (!vsock_sol_socket_custom(optname)) + return sock_setsockopt(sock, level, optname, optval, optlen); + + return vsock_sol_socket_setsockopt(sk, optname, optval, optlen); + } + lock_sock(sk); transport = vsk->transport; - if (level == SOL_SOCKET) { - int zerocopy; - - if (optname != SO_ZEROCOPY) { - release_sock(sk); - return sock_setsockopt(sock, level, optname, optval, optlen); - } - - /* Use 'int' type here, because variable to - * set this option usually has this type. - */ - COPY_IN(zerocopy); - - if (zerocopy < 0 || zerocopy > 1) { - err = -EINVAL; - goto exit; - } - - if (transport && !vsock_msgzerocopy_allow(transport)) { - err = -EOPNOTSUPP; - goto exit; - } - - sock_valbool_flag(sk, SOCK_ZEROCOPY, zerocopy); - goto exit; - } - switch (optname) { case SO_VM_SOCKETS_BUFFER_SIZE: COPY_IN(val);