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 <[email protected]> --- net/vmw_vsock/af_vsock.c | 90 +++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 1c2d1cea67f4..ac2faac97462 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -2014,6 +2014,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, @@ -2045,36 +2105,16 @@ static int vsock_connectible_setsockopt(struct socket *sock, sk = sock->sk; vsk = vsock_sk(sk); - lock_sock(sk); - - transport = vsk->transport; - if (level == SOL_SOCKET) { - int zerocopy; - - if (optname != SO_ZEROCOPY) { - release_sock(sk); + if (!vsock_sol_socket_custom(optname)) 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; - } + return vsock_sol_socket_setsockopt(sk, optname, optval, optlen); + } - if (transport && !vsock_msgzerocopy_allow(transport)) { - err = -EOPNOTSUPP; - goto exit; - } + lock_sock(sk); - sock_valbool_flag(sk, SOCK_ZEROCOPY, zerocopy); - goto exit; - } + transport = vsk->transport; switch (optname) { case SO_VM_SOCKETS_BUFFER_SIZE: -- 2.55.0

