Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vsock: enable setting SO_ZEROCOPY

For AF_VSOCK, zerocopy tx mode depends on transport, so this option must
be set in AF_VSOCK implementation where transport is accessible (if
transport is not set during setting SO_ZEROCOPY: for example socket is
not connected, then SO_ZEROCOPY will be enabled, but once transport will
be assigned, support of this type of transmission will be checked).

To handle SO_ZEROCOPY, AF_VSOCK implementation uses SOCK_CUSTOM_SOCKOPT
bit, thus handling SOL_SOCKET option operations, but all of them except
SO_ZEROCOPY will be forwarded to the generic handler by calling
'sock_setsockopt()'.

Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arseniy Krasnov and committed by
David S. Miller
e0718bd8 cfdca390

+43 -2
+43 -2
net/vmw_vsock/af_vsock.c
··· 1406 1406 goto out; 1407 1407 } 1408 1408 1409 - if (vsock_msgzerocopy_allow(transport)) 1409 + if (vsock_msgzerocopy_allow(transport)) { 1410 1410 set_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags); 1411 + } else if (sock_flag(sk, SOCK_ZEROCOPY)) { 1412 + /* If this option was set before 'connect()', 1413 + * when transport was unknown, check that this 1414 + * feature is supported here. 1415 + */ 1416 + err = -EOPNOTSUPP; 1417 + goto out; 1418 + } 1411 1419 1412 1420 err = vsock_auto_bind(vsk); 1413 1421 if (err) ··· 1651 1643 const struct vsock_transport *transport; 1652 1644 u64 val; 1653 1645 1654 - if (level != AF_VSOCK) 1646 + if (level != AF_VSOCK && level != SOL_SOCKET) 1655 1647 return -ENOPROTOOPT; 1656 1648 1657 1649 #define COPY_IN(_v) \ ··· 1673 1665 lock_sock(sk); 1674 1666 1675 1667 transport = vsk->transport; 1668 + 1669 + if (level == SOL_SOCKET) { 1670 + int zerocopy; 1671 + 1672 + if (optname != SO_ZEROCOPY) { 1673 + release_sock(sk); 1674 + return sock_setsockopt(sock, level, optname, optval, optlen); 1675 + } 1676 + 1677 + /* Use 'int' type here, because variable to 1678 + * set this option usually has this type. 1679 + */ 1680 + COPY_IN(zerocopy); 1681 + 1682 + if (zerocopy < 0 || zerocopy > 1) { 1683 + err = -EINVAL; 1684 + goto exit; 1685 + } 1686 + 1687 + if (transport && !vsock_msgzerocopy_allow(transport)) { 1688 + err = -EOPNOTSUPP; 1689 + goto exit; 1690 + } 1691 + 1692 + sock_valbool_flag(sk, SOCK_ZEROCOPY, zerocopy); 1693 + goto exit; 1694 + } 1676 1695 1677 1696 switch (optname) { 1678 1697 case SO_VM_SOCKETS_BUFFER_SIZE: ··· 2356 2321 return ret; 2357 2322 } 2358 2323 } 2324 + 2325 + /* SOCK_DGRAM doesn't have 'setsockopt' callback set in its 2326 + * proto_ops, so there is no handler for custom logic. 2327 + */ 2328 + if (sock_type_connectible(sock->type)) 2329 + set_bit(SOCK_CUSTOM_SOCKOPT, &sk->sk_socket->flags); 2359 2330 2360 2331 vsock_insert_unbound(vsk); 2361 2332