Message ID | 20200828151747.21445-1-mdoucha@suse.cz |
---|---|
State | Accepted |
Headers | show |
Series | Add test for send(MSG_MORE) | expand |
Hi Martin, > The setsockopt05 test will not work properly if kernel handles the MSG_MORE > flag incorrectly. Add a new test to detect broken test environment. Thanks for your patch, merged. Kind regards, Petr
Hi Martin, Peter > Hi Martin, > >> The setsockopt05 test will not work properly if kernel handles the MSG_MORE >> flag incorrectly. Add a new test to detect broken test environment. > > Thanks for your patch, merged. I test this case on centos8.2, it failed, but it passed on centos7.8 and fedora31. On upstream kernel (5.9-rc7+,commit 6f2f486d57c4,using kvm,4G memory,2 cpus), it also failed. I don't know whether it has some kernel parameters or kconfig to affect this. It seems not a kernel bug and like a environment bug(I guess). tst_test.c:1250: TINFO: Timeout per run is 0h 05m 00s send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) Best Regards Yang Xu > > Kind regards, > Petr >
On 12. 10. 20 9:22, Yang Xu wrote: > I test this case on centos8.2, it failed, but it passed on centos7.8 and > fedora31. On upstream kernel (5.9-rc7+,commit 6f2f486d57c4,using kvm,4G > memory,2 cpus), it also failed. I don't know whether it has some kernel > parameters or kconfig to affect this. It seems not a kernel bug and like > a environment bug(I guess). > > tst_test.c:1250: TINFO: Timeout per run is 0h 05m 00s > send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) > send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) > send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) > send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) We have some similar failures on old s390 kernels (v4.4). I can't reproduce any failures at all on our 4.12 and 5.3 kernels. Can you add some debug prints and check whether it fails on the first iteration or after a few successful loops? Also, do you have any test runs where the TCP test case succeeded?
Hi Martin > On 12. 10. 20 9:22, Yang Xu wrote: >> I test this case on centos8.2, it failed, but it passed on centos7.8 and >> fedora31. On upstream kernel (5.9-rc7+,commit 6f2f486d57c4,using kvm,4G >> memory,2 cpus), it also failed. I don't know whether it has some kernel >> parameters or kconfig to affect this. It seems not a kernel bug and like >> a environment bug(I guess). >> >> tst_test.c:1250: TINFO: Timeout per run is 0h 05m 00s >> send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) >> send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) >> send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) >> send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) > We have some similar failures on old s390 kernels (v4.4). I can't > reproduce any failures at all on our 4.12 and 5.3 kernels. I try 5.7,5.8 and lastest upstream, it all failed. I didn't figure out the reason. > Can you add some debug prints and check whether it fails on the first > iteration or after a few successful loops? It fails after a few successful loops in internal(not using -i parameters), and when I lower the loops into 100, tcp and udp (using send) may succeed --- a/testcases/kernel/syscalls/send/send02.c +++ b/testcases/kernel/syscalls/send/send02.c @@ -129,7 +129,7 @@ static void run(unsigned int n) if (tc->needs_accept) SAFE_LISTEN(listen_sock, 1); - for (i = 0; i < 1000; i++) { + for (i = 0; i < 100; i++) { ./send02 tst_test.c:1250: TINFO: Timeout per run is 0h 05m 00s send02.c:166: TPASS: TCP send(MSG_MORE) works correctly send02.c:166: TPASS: UDP send(MSG_MORE) works correctly send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) send02.c:86: TFAIL: recv() error: EAGAIN/EWOULDBLOCK (11) > Also, do you have any test > runs where the TCP test case succeeded? > Yes, tcp test sometimes succeeded. ps: I think we can send a patch to print more output in this case, so we know which case fails(tcp,udp, send,or sendto, sendmsg ). Best Regards Yang Xu
diff --git a/runtest/syscalls b/runtest/syscalls index a6ab75ba7..fd43977fa 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1174,6 +1174,7 @@ semop02 semop02 semop03 semop03 send01 send01 +send02 send02 sendfile02 sendfile02 sendfile02_64 sendfile02_64 diff --git a/testcases/kernel/syscalls/send/.gitignore b/testcases/kernel/syscalls/send/.gitignore index 9394e972f..ec3cc677c 100644 --- a/testcases/kernel/syscalls/send/.gitignore +++ b/testcases/kernel/syscalls/send/.gitignore @@ -1 +1,2 @@ /send01 +/send02 diff --git a/testcases/kernel/syscalls/send/send02.c b/testcases/kernel/syscalls/send/send02.c new file mode 100644 index 000000000..5630230fa --- /dev/null +++ b/testcases/kernel/syscalls/send/send02.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz> + */ + +/* + * Check that the kernel correctly handles send()/sendto()/sendmsg() calls + * with MSG_MORE flag + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <sched.h> + +#include "tst_test.h" +#include "tst_net.h" + +#define SENDSIZE 16 +#define RECVSIZE 32 + +static int sock = -1, dst_sock = -1, listen_sock = -1; +static struct sockaddr_in addr; +static char sendbuf[SENDSIZE]; + +static void do_send(int sock, void *buf, size_t size, int flags) +{ + SAFE_SEND(1, sock, buf, size, flags); +} + +static void do_sendto(int sock, void *buf, size_t size, int flags) +{ + SAFE_SENDTO(1, sock, buf, size, flags, (struct sockaddr *)&addr, + sizeof(addr)); +} + +static void do_sendmsg(int sock, void *buf, size_t size, int flags) +{ + struct msghdr msg; + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = &addr; + msg.msg_namelen = sizeof(addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + SAFE_SENDMSG(size, sock, &msg, flags); +} + +static struct test_case { + int domain, type, protocol; + void (*send)(int sock, void *buf, size_t size, int flags); + int needs_connect, needs_accept; + const char *name; +} testcase_list[] = { + {AF_INET, SOCK_STREAM, 0, do_send, 1, 1, "TCP send"}, + {AF_INET, SOCK_DGRAM, 0, do_send, 1, 0, "UDP send"}, + {AF_INET, SOCK_DGRAM, 0, do_sendto, 0, 0, "UDP sendto"}, + {AF_INET, SOCK_DGRAM, 0, do_sendmsg, 0, 0, "UDP sendmsg"} +}; + +static void setup(void) +{ + memset(sendbuf, 0x42, SENDSIZE); +} + +static int check_recv(int sock, long expsize) +{ + char recvbuf[RECVSIZE] = {0}; + + TEST(recv(sock, recvbuf, RECVSIZE, MSG_DONTWAIT)); + + if (TST_RET == -1) { + /* expected error immediately after send(MSG_MORE) */ + if (!expsize && (TST_ERR == EAGAIN || TST_ERR == EWOULDBLOCK)) + return 1; + + /* unexpected error */ + tst_res(TFAIL | TTERRNO, "recv() error"); + return 0; + } + + if (TST_RET < 0) { + tst_res(TFAIL | TTERRNO, "Invalid recv() return value %ld", + TST_RET); + return 0; + } + + if (TST_RET != expsize) { + tst_res(TFAIL, "recv() read %ld bytes, expected %ld", TST_RET, + expsize); + return 0; + } + + return 1; +} + +static void cleanup(void) +{ + if (sock >= 0) + SAFE_CLOSE(sock); + + if (dst_sock >= 0 && dst_sock != listen_sock) + SAFE_CLOSE(dst_sock); + + if (listen_sock >= 0) + SAFE_CLOSE(listen_sock); +} + +static void run(unsigned int n) +{ + int i, ret; + struct test_case *tc = testcase_list + n; + socklen_t len = sizeof(addr); + + tst_init_sockaddr_inet_bin(&addr, INADDR_LOOPBACK, 0); + listen_sock = SAFE_SOCKET(tc->domain, tc->type, tc->protocol); + dst_sock = listen_sock; + SAFE_BIND(listen_sock, (struct sockaddr *)&addr, sizeof(addr)); + SAFE_GETSOCKNAME(listen_sock, (struct sockaddr *)&addr, &len); + + if (tc->needs_accept) + SAFE_LISTEN(listen_sock, 1); + + for (i = 0; i < 1000; i++) { + sock = SAFE_SOCKET(tc->domain, tc->type, tc->protocol); + + if (tc->needs_connect) + SAFE_CONNECT(sock, (struct sockaddr *)&addr, len); + + if (tc->needs_accept) + dst_sock = SAFE_ACCEPT(listen_sock, NULL, NULL); + + tc->send(sock, sendbuf, SENDSIZE, 0); + ret = check_recv(dst_sock, SENDSIZE); + + if (!ret) + break; + + tc->send(sock, sendbuf, SENDSIZE, MSG_MORE); + ret = check_recv(dst_sock, 0); + + if (!ret) + break; + + tc->send(sock, sendbuf, 1, 0); + ret = check_recv(dst_sock, SENDSIZE + 1); + + if (!ret) + break; + + SAFE_CLOSE(sock); + + if (dst_sock != listen_sock) + SAFE_CLOSE(dst_sock); + } + + if (ret) + tst_res(TPASS, "%s(MSG_MORE) works correctly", tc->name); + + cleanup(); + dst_sock = -1; +} + +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(testcase_list), + .setup = setup, + .cleanup = cleanup +};
The setsockopt05 test will not work properly if kernel handles the MSG_MORE flag incorrectly. Add a new test to detect broken test environment. Signed-off-by: Martin Doucha <mdoucha@suse.cz> --- runtest/syscalls | 1 + testcases/kernel/syscalls/send/.gitignore | 1 + testcases/kernel/syscalls/send/send02.c | 177 ++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 testcases/kernel/syscalls/send/send02.c