Skip to content

Commit 35a7a2f

Browse files
author
Paolo Abeni
committed
Merge branch 'vsock-sock_linger-rework'
Michal Luczaj says: ==================== vsock: SOCK_LINGER rework Change vsock's lingerning to wait on close() until all data is sent, i.e. until workers picked all the packets for processing. v5: https://lore.kernel.org/r/[email protected] v4: https://lore.kernel.org/r/[email protected] v3: https://lore.kernel.org/r/[email protected] v2: https://lore.kernel.org/r/[email protected] v1: https://lore.kernel.org/r/[email protected] Signed-off-by: Michal Luczaj <[email protected]> ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents b2908a9 + 393d070 commit 35a7a2f

File tree

6 files changed

+134
-44
lines changed

6 files changed

+134
-44
lines changed

include/net/af_vsock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ void vsock_for_each_connected_socket(struct vsock_transport *transport,
221221
void (*fn)(struct sock *sk));
222222
int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk);
223223
bool vsock_find_cid(unsigned int cid);
224+
void vsock_linger(struct sock *sk);
224225

225226
/**** TAP ****/
226227

net/vmw_vsock/af_vsock.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,39 @@ static int vsock_getname(struct socket *sock,
10131013
return err;
10141014
}
10151015

1016+
void vsock_linger(struct sock *sk)
1017+
{
1018+
DEFINE_WAIT_FUNC(wait, woken_wake_function);
1019+
ssize_t (*unsent)(struct vsock_sock *vsk);
1020+
struct vsock_sock *vsk = vsock_sk(sk);
1021+
long timeout;
1022+
1023+
if (!sock_flag(sk, SOCK_LINGER))
1024+
return;
1025+
1026+
timeout = sk->sk_lingertime;
1027+
if (!timeout)
1028+
return;
1029+
1030+
/* Transports must implement `unsent_bytes` if they want to support
1031+
* SOCK_LINGER through `vsock_linger()` since we use it to check when
1032+
* the socket can be closed.
1033+
*/
1034+
unsent = vsk->transport->unsent_bytes;
1035+
if (!unsent)
1036+
return;
1037+
1038+
add_wait_queue(sk_sleep(sk), &wait);
1039+
1040+
do {
1041+
if (sk_wait_event(sk, &timeout, unsent(vsk) == 0, &wait))
1042+
break;
1043+
} while (!signal_pending(current) && timeout);
1044+
1045+
remove_wait_queue(sk_sleep(sk), &wait);
1046+
}
1047+
EXPORT_SYMBOL_GPL(vsock_linger);
1048+
10161049
static int vsock_shutdown(struct socket *sock, int mode)
10171050
{
10181051
int err;

net/vmw_vsock/virtio_transport_common.c

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,23 +1191,6 @@ static void virtio_transport_remove_sock(struct vsock_sock *vsk)
11911191
vsock_remove_sock(vsk);
11921192
}
11931193

1194-
static void virtio_transport_wait_close(struct sock *sk, long timeout)
1195-
{
1196-
if (timeout) {
1197-
DEFINE_WAIT_FUNC(wait, woken_wake_function);
1198-
1199-
add_wait_queue(sk_sleep(sk), &wait);
1200-
1201-
do {
1202-
if (sk_wait_event(sk, &timeout,
1203-
sock_flag(sk, SOCK_DONE), &wait))
1204-
break;
1205-
} while (!signal_pending(current) && timeout);
1206-
1207-
remove_wait_queue(sk_sleep(sk), &wait);
1208-
}
1209-
}
1210-
12111194
static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
12121195
bool cancel_timeout)
12131196
{
@@ -1277,8 +1260,8 @@ static bool virtio_transport_close(struct vsock_sock *vsk)
12771260
if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
12781261
(void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK);
12791262

1280-
if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING))
1281-
virtio_transport_wait_close(sk, sk->sk_lingertime);
1263+
if (!(current->flags & PF_EXITING))
1264+
vsock_linger(sk);
12821265

12831266
if (sock_flag(sk, SOCK_DONE)) {
12841267
return true;

tools/testing/vsock/util.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <assert.h>
1818
#include <sys/epoll.h>
1919
#include <sys/mman.h>
20+
#include <linux/sockios.h>
2021

2122
#include "timeout.h"
2223
#include "control.h"
@@ -96,6 +97,30 @@ void vsock_wait_remote_close(int fd)
9697
close(epollfd);
9798
}
9899

100+
/* Wait until transport reports no data left to be sent.
101+
* Return false if transport does not implement the unsent_bytes() callback.
102+
*/
103+
bool vsock_wait_sent(int fd)
104+
{
105+
int ret, sock_bytes_unsent;
106+
107+
timeout_begin(TIMEOUT);
108+
do {
109+
ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent);
110+
if (ret < 0) {
111+
if (errno == EOPNOTSUPP)
112+
break;
113+
114+
perror("ioctl(SIOCOUTQ)");
115+
exit(EXIT_FAILURE);
116+
}
117+
timeout_check("SIOCOUTQ");
118+
} while (sock_bytes_unsent != 0);
119+
timeout_end();
120+
121+
return !ret;
122+
}
123+
99124
/* Create socket <type>, bind to <cid, port> and return the file descriptor. */
100125
int vsock_bind(unsigned int cid, unsigned int port, int type)
101126
{
@@ -798,3 +823,16 @@ void enable_so_zerocopy_check(int fd)
798823
setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1,
799824
"setsockopt SO_ZEROCOPY");
800825
}
826+
827+
void enable_so_linger(int fd, int timeout)
828+
{
829+
struct linger optval = {
830+
.l_onoff = 1,
831+
.l_linger = timeout
832+
};
833+
834+
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) {
835+
perror("setsockopt(SO_LINGER)");
836+
exit(EXIT_FAILURE);
837+
}
838+
}

tools/testing/vsock/util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ int vsock_stream_listen(unsigned int cid, unsigned int port);
5454
int vsock_seqpacket_accept(unsigned int cid, unsigned int port,
5555
struct sockaddr_vm *clientaddrp);
5656
void vsock_wait_remote_close(int fd);
57+
bool vsock_wait_sent(int fd);
5758
void send_buf(int fd, const void *buf, size_t len, int flags,
5859
ssize_t expected_ret);
5960
void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret);
@@ -79,4 +80,5 @@ void setsockopt_int_check(int fd, int level, int optname, int val,
7980
void setsockopt_timeval_check(int fd, int level, int optname,
8081
struct timeval val, char const *errmsg);
8182
void enable_so_zerocopy_check(int fd);
83+
void enable_so_linger(int fd, int timeout);
8284
#endif /* UTIL_H */

tools/testing/vsock/vsock_test.c

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include <poll.h>
2222
#include <signal.h>
2323
#include <sys/ioctl.h>
24-
#include <linux/sockios.h>
2524
#include <linux/time64.h>
2625

2726
#include "vsock_test_zerocopy.h"
@@ -1280,7 +1279,7 @@ static void test_unsent_bytes_server(const struct test_opts *opts, int type)
12801279
static void test_unsent_bytes_client(const struct test_opts *opts, int type)
12811280
{
12821281
unsigned char buf[MSG_BUF_IOCTL_LEN];
1283-
int ret, fd, sock_bytes_unsent;
1282+
int fd;
12841283

12851284
fd = vsock_connect(opts->peer_cid, opts->peer_port, type);
12861285
if (fd < 0) {
@@ -1297,22 +1296,12 @@ static void test_unsent_bytes_client(const struct test_opts *opts, int type)
12971296
/* SIOCOUTQ isn't guaranteed to instantly track sent data. Even though
12981297
* the "RECEIVED" message means that the other side has received the
12991298
* data, there can be a delay in our kernel before updating the "unsent
1300-
* bytes" counter. Repeat SIOCOUTQ until it returns 0.
1299+
* bytes" counter. vsock_wait_sent() will repeat SIOCOUTQ until it
1300+
* returns 0.
13011301
*/
1302-
timeout_begin(TIMEOUT);
1303-
do {
1304-
ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent);
1305-
if (ret < 0) {
1306-
if (errno == EOPNOTSUPP) {
1307-
fprintf(stderr, "Test skipped, SIOCOUTQ not supported.\n");
1308-
break;
1309-
}
1310-
perror("ioctl");
1311-
exit(EXIT_FAILURE);
1312-
}
1313-
timeout_check("SIOCOUTQ");
1314-
} while (sock_bytes_unsent != 0);
1315-
timeout_end();
1302+
if (!vsock_wait_sent(fd))
1303+
fprintf(stderr, "Test skipped, SIOCOUTQ not supported.\n");
1304+
13161305
close(fd);
13171306
}
13181307

@@ -1824,10 +1813,6 @@ static void test_stream_connect_retry_server(const struct test_opts *opts)
18241813

18251814
static void test_stream_linger_client(const struct test_opts *opts)
18261815
{
1827-
struct linger optval = {
1828-
.l_onoff = 1,
1829-
.l_linger = 1
1830-
};
18311816
int fd;
18321817

18331818
fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
@@ -1836,15 +1821,58 @@ static void test_stream_linger_client(const struct test_opts *opts)
18361821
exit(EXIT_FAILURE);
18371822
}
18381823

1839-
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) {
1840-
perror("setsockopt(SO_LINGER)");
1824+
enable_so_linger(fd, 1);
1825+
close(fd);
1826+
}
1827+
1828+
static void test_stream_linger_server(const struct test_opts *opts)
1829+
{
1830+
int fd;
1831+
1832+
fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
1833+
if (fd < 0) {
1834+
perror("accept");
18411835
exit(EXIT_FAILURE);
18421836
}
18431837

1838+
vsock_wait_remote_close(fd);
18441839
close(fd);
18451840
}
18461841

1847-
static void test_stream_linger_server(const struct test_opts *opts)
1842+
/* Half of the default to not risk timing out the control channel */
1843+
#define LINGER_TIMEOUT (TIMEOUT / 2)
1844+
1845+
static void test_stream_nolinger_client(const struct test_opts *opts)
1846+
{
1847+
bool waited;
1848+
time_t ns;
1849+
int fd;
1850+
1851+
fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
1852+
if (fd < 0) {
1853+
perror("connect");
1854+
exit(EXIT_FAILURE);
1855+
}
1856+
1857+
enable_so_linger(fd, LINGER_TIMEOUT);
1858+
send_byte(fd, 1, 0); /* Left unread to expose incorrect behaviour. */
1859+
waited = vsock_wait_sent(fd);
1860+
1861+
ns = current_nsec();
1862+
close(fd);
1863+
ns = current_nsec() - ns;
1864+
1865+
if (!waited) {
1866+
fprintf(stderr, "Test skipped, SIOCOUTQ not supported.\n");
1867+
} else if (DIV_ROUND_UP(ns, NSEC_PER_SEC) >= LINGER_TIMEOUT) {
1868+
fprintf(stderr, "Unexpected lingering\n");
1869+
exit(EXIT_FAILURE);
1870+
}
1871+
1872+
control_writeln("DONE");
1873+
}
1874+
1875+
static void test_stream_nolinger_server(const struct test_opts *opts)
18481876
{
18491877
int fd;
18501878

@@ -1854,7 +1882,7 @@ static void test_stream_linger_server(const struct test_opts *opts)
18541882
exit(EXIT_FAILURE);
18551883
}
18561884

1857-
vsock_wait_remote_close(fd);
1885+
control_expectln("DONE");
18581886
close(fd);
18591887
}
18601888

@@ -2018,6 +2046,11 @@ static struct test_case test_cases[] = {
20182046
.run_client = test_stream_linger_client,
20192047
.run_server = test_stream_linger_server,
20202048
},
2049+
{
2050+
.name = "SOCK_STREAM SO_LINGER close() on unread",
2051+
.run_client = test_stream_nolinger_client,
2052+
.run_server = test_stream_nolinger_server,
2053+
},
20212054
{},
20222055
};
20232056

0 commit comments

Comments
 (0)