Message ID | 20201213224729.17974-2-Filip.Bozuta@syrmia.com |
---|---|
State | Accepted |
Headers | show |
Series | Adding new testcases for existing tests | expand |
Hi! I've been looking at the code and, in the end, decided to fix it since that would be easier than explaining what should be changed. Detailed comments below. Generally speaking it would be easier to review if you send the unrelated changes in a separate patches. For this changes I would have send each new test in a separate patch to make the review easier. Thanks for your contributions! > Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com> > --- > runtest/syscalls | 3 + > testcases/kernel/syscalls/recvmmsg/Makefile | 7 + > .../kernel/syscalls/recvmmsg/recvmmsg01.c | 146 ++++++++++++++++++ Added missing .gitignore here. > testcases/kernel/syscalls/sendmmsg/.gitignore | 1 + > testcases/kernel/syscalls/sendmmsg/sendmmsg.h | 45 ++++++ > .../kernel/syscalls/sendmmsg/sendmmsg01.c | 111 ++++++------- > .../kernel/syscalls/sendmmsg/sendmmsg02.c | 87 +++++++++++ > 7 files changed, 347 insertions(+), 53 deletions(-) > create mode 100644 testcases/kernel/syscalls/recvmmsg/Makefile > create mode 100644 testcases/kernel/syscalls/recvmmsg/recvmmsg01.c > create mode 100644 testcases/kernel/syscalls/sendmmsg/sendmmsg.h > create mode 100644 testcases/kernel/syscalls/sendmmsg/sendmmsg02.c ... > diff --git a/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c > new file mode 100644 > index 000000000..b3204cc9a > --- /dev/null > +++ b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c > @@ -0,0 +1,146 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +/* test status of errors: > + * > + * EBADF v ('Bad socket file descriptor') > + * EFAULT v ('Bad message vector address') > + * EINVAL v ('Bad seconds value for the timeout argument') > + * EINVAL v ('Bad nanoseconds value for the timeout argument') > + * EFAULT v ('Bad timeout address') > + */ I've reformatted these comments to asciidoc and changed the comment so that it's picked by the documentation parser. > +#define _GNU_SOURCE > +#include "../sendmmsg/sendmmsg.h" > + > +static struct tst_ts ts; > + > +enum test_type { > + BAD_FD, > + BAD_MSGVEC, > + BAD_TS_VALUE_1, > + BAD_TS_VALUE_2, > + BAD_TS_ADDR, > +}; > + > +#define TYPE_NAME(x) .ttype = x, .desc = #x > +struct test_case { > + int ttype; > + const char *desc; > + int fd; > + long tv_sec; > + long tv_nsec; > + int exp_errno; > +}; I think that this whole test type makes the code harder to read, and we more usually use indirection over something like this, so I've changed the test structures in the testcases like that. > +static struct test_case tcase[] = { > + { > + TYPE_NAME(BAD_FD), > + .fd = -1, > + .exp_errno = EBADF, > + }, > + { > + TYPE_NAME(BAD_MSGVEC), > + .exp_errno = EFAULT, > + }, > + { > + TYPE_NAME(BAD_TS_VALUE_1), > + .tv_sec = -1, > + .tv_nsec = 0, > + .exp_errno = EINVAL, > + }, > + { > + TYPE_NAME(BAD_TS_VALUE_2), > + .tv_sec = 1, > + .tv_nsec = 1000000001, > + .exp_errno = EINVAL, > + }, > + { > + TYPE_NAME(BAD_TS_ADDR), > + .exp_errno = EFAULT, > + } > +}; > + > +static void do_test(unsigned int i) > +{ > + struct time64_variants *tv = &variants[tst_variant]; > + struct test_case *tc = &tcase[i]; > + void *rcv_msgvec, *timeout; > + > + tst_res(TINFO, "case %s", tc->desc); > + > + if (tc->ttype != BAD_FD) > + tc->fd = receive_sockfd; > + > + TEST(tv->sendmmsg(send_sockfd, snd_msg, 1, 0)); > + > + if (TST_RET != 1) { > + tst_res(TFAIL | TERRNO, "sendmmsg() failed"); > + return; > + } This is actually no-op sice the snd_msg is not initialized with the iov vectors in setup. If you want to send any data you have to do that first. Also it does not make sense to call this on each iteration, even when you want to have some data on the socket ready it could be done once in the test setup. So I've moved this to the test setup and changed the code to initialize the message header correctly. > + memset(rcv1->iov_base, 0, rcv1->iov_len); > + memset(rcv2->iov_base, 0, rcv2->iov_len); This is pointless we never check the content anways. > + ts.type = tv->ts_type; > + tst_ts_set_sec(&ts, tc->tv_sec); > + tst_ts_set_nsec(&ts, tc->tv_nsec); > + > + if (tc->ttype == BAD_MSGVEC) > + rcv_msgvec = bad_addr; > + else > + rcv_msgvec = rcv_msg; > + > + if (tc->ttype == BAD_TS_ADDR) > + timeout = bad_addr; > + else > + timeout = tst_ts_get(&ts); > + > + TEST(tv->recvmmsg(tc->fd, rcv_msgvec, VLEN, 0, timeout)); > + > + if (TST_RET < 0) { > + if (tc->exp_errno == errno) > + tst_res(TPASS | TERRNO, "recvemmsg() failed successfully"); > + else > + tst_res(TFAIL | TERRNO, "recvemmsg() failed unexpectedly"); > + } else { > + tst_res(TFAIL | TERRNO, "recvemmsg() succeded unexpectedly"); > + } I've replaced this whole chunk with the newly introduced TST_EXP_FAIL() macro. > +} > + > +static void setup(void) > +{ > + struct sockaddr_in addr; > + unsigned int port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM); > + > + send_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); > + receive_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); > + > + addr.sin_family = AF_INET; > + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); > + addr.sin_port = port; > + > + SAFE_BIND(receive_sockfd, (struct sockaddr *)&addr, sizeof(addr)); > + SAFE_CONNECT(send_sockfd, (struct sockaddr *)&addr, sizeof(addr)); > + > + bad_addr = tst_get_bad_addr(NULL); > + > + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); > +} > + > +static struct tst_test test = { > + .test = do_test, > + .tcnt = ARRAY_SIZE(tcase), > + .setup = setup, > + .cleanup = cleanup, > + .test_variants = ARRAY_SIZE(variants), > + .bufs = (struct tst_buffers []) { > + {&snd1, .iov_sizes = (int[]){3, 3, -1}}, > + {&snd2, .iov_sizes = (int[]){6, -1}}, > + {&rcv1, .iov_sizes = (int[]){6, -1}}, > + {&rcv2, .iov_sizes = (int[]){5, -1}}, > + {&snd_msg, .size = VLEN * sizeof(*snd_msg)}, > + {&rcv_msg, .size = VLEN * sizeof(*rcv_msg)}, > + {}, > + } > +}; And I've did a similar changed to the sendmmsg02.c test. > diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h > new file mode 100644 > index 000000000..68a9a4020 > --- /dev/null > +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h > @@ -0,0 +1,45 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > + > +#include <netinet/ip.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/types.h> > + > +#include "time64_variants.h" > +#include "tst_test.h" > +#include "lapi/socket.h" > +#include "tst_safe_macros.h" > +#include "sendmmsg_var.h" > + > +#define BUFSIZE 16 > +#define VLEN 2 > + > +static int send_sockfd; > +static int receive_sockfd; > +static struct mmsghdr *snd_msg, *rcv_msg; > +static struct iovec *snd1, *snd2, *rcv1, *rcv2; > + > +static void *bad_addr; Hiding variables like this in headers makes the code harder to understand also most of the tests does not need more than one header and one iov, so I've moved these to testcases where we declare only what we actually need. > +#define TYPE_NAME(x) .ttype = x, .desc = #x > + > +static struct time64_variants variants[] = { > + { .recvmmsg = libc_recvmmsg, .sendmmsg = libc_sendmmsg, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, > + > +#if (__NR_recvmmsg != __LTP__NR_INVALID_SYSCALL) > + { .recvmmsg = sys_recvmmsg, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, > +#endif > + > +#if (__NR_recvmmsg_time64 != __LTP__NR_INVALID_SYSCALL) > + { .recvmmsg = sys_recvmmsg64, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, > +#endif > +}; > + > +static void cleanup(void) > +{ > + if (send_sockfd > 0) > + SAFE_CLOSE(send_sockfd); > + if (receive_sockfd > 0) > + SAFE_CLOSE(receive_sockfd); > +} Same here, moved the cleanup to tests and changed it to close only what was opened. > diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c > index d6a717687..ad26a7b4d 100644 > --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c > +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c As for this changes I've reverted the added test. Techincally this is testing recvmmsg() timeout, as far as I can tell it would be better if we added a recvmmsg test based on these changes. Also having the timeout tests in a separate test would make the code a bit easier to read. The full diff: diff --git a/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c index b3204cc9a..8f066de9b 100644 --- a/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c +++ b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c @@ -1,63 +1,76 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* test status of errors: +/*\ + * Test recvmmsg() errors: * - * EBADF v ('Bad socket file descriptor') - * EFAULT v ('Bad message vector address') - * EINVAL v ('Bad seconds value for the timeout argument') - * EINVAL v ('Bad nanoseconds value for the timeout argument') - * EFAULT v ('Bad timeout address') - */ + * - EBADF Bad socket file descriptor + * - EFAULT Bad message vector address + * - EINVAL Bad seconds value for the timeout argument + * - EINVAL Bad nanoseconds value for the timeout argument + * - EFAULT Bad timeout address +\*/ #define _GNU_SOURCE #include "../sendmmsg/sendmmsg.h" -static struct tst_ts ts; +static int send_sockfd; +static int receive_sockfd; -enum test_type { - BAD_FD, - BAD_MSGVEC, - BAD_TS_VALUE_1, - BAD_TS_VALUE_2, - BAD_TS_ADDR, -}; +#define VLEN 1 + +static struct mmsghdr *msg; +static struct iovec *iov; + +static void *bad_addr; +static int bad_fd = -1; -#define TYPE_NAME(x) .ttype = x, .desc = #x +static struct tst_ts ts; struct test_case { - int ttype; const char *desc; - int fd; + int *fd; long tv_sec; long tv_nsec; int exp_errno; + struct mmsghdr **msg_vec; + int bad_ts_addr; }; static struct test_case tcase[] = { { - TYPE_NAME(BAD_FD), - .fd = -1, + .desc = "bad socket file descriptor", + .fd = &bad_fd, .exp_errno = EBADF, + .msg_vec = &msg, }, { - TYPE_NAME(BAD_MSGVEC), + .desc = "bad message vector address", + .fd = &receive_sockfd, .exp_errno = EFAULT, + .msg_vec = (void*)&bad_addr, }, { - TYPE_NAME(BAD_TS_VALUE_1), + .desc = "negative seconds in timeout", + .fd = &receive_sockfd, .tv_sec = -1, .tv_nsec = 0, .exp_errno = EINVAL, + .msg_vec = &msg, }, { - TYPE_NAME(BAD_TS_VALUE_2), + .desc = "overflow in nanoseconds in timeout", + .fd = &receive_sockfd, .tv_sec = 1, .tv_nsec = 1000000001, .exp_errno = EINVAL, + .msg_vec = &msg, }, { - TYPE_NAME(BAD_TS_ADDR), + .desc = "bad timeout address", + .fd = &receive_sockfd, .exp_errno = EFAULT, + .msg_vec = &msg, + .bad_ts_addr = 1, } }; @@ -65,53 +78,28 @@ static void do_test(unsigned int i) { struct time64_variants *tv = &variants[tst_variant]; struct test_case *tc = &tcase[i]; - void *rcv_msgvec, *timeout; - - tst_res(TINFO, "case %s", tc->desc); - - if (tc->ttype != BAD_FD) - tc->fd = receive_sockfd; - - TEST(tv->sendmmsg(send_sockfd, snd_msg, 1, 0)); - - if (TST_RET != 1) { - tst_res(TFAIL | TERRNO, "sendmmsg() failed"); - return; - } - - memset(rcv1->iov_base, 0, rcv1->iov_len); - memset(rcv2->iov_base, 0, rcv2->iov_len); + void *timeout; ts.type = tv->ts_type; tst_ts_set_sec(&ts, tc->tv_sec); tst_ts_set_nsec(&ts, tc->tv_nsec); - if (tc->ttype == BAD_MSGVEC) - rcv_msgvec = bad_addr; - else - rcv_msgvec = rcv_msg; - - if (tc->ttype == BAD_TS_ADDR) + if (tc->bad_ts_addr) timeout = bad_addr; else timeout = tst_ts_get(&ts); - TEST(tv->recvmmsg(tc->fd, rcv_msgvec, VLEN, 0, timeout)); - - if (TST_RET < 0) { - if (tc->exp_errno == errno) - tst_res(TPASS | TERRNO, "recvemmsg() failed successfully"); - else - tst_res(TFAIL | TERRNO, "recvemmsg() failed unexpectedly"); - } else { - tst_res(TFAIL | TERRNO, "recvemmsg() succeded unexpectedly"); - } + TST_EXP_FAIL(tv->recvmmsg(*tc->fd, *tc->msg_vec, VLEN, 0, timeout), + tc->exp_errno, "recvmmsg() %s", tc->desc); } static void setup(void) { struct sockaddr_in addr; unsigned int port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM); + struct time64_variants *tv = &variants[tst_variant]; + + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); send_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); receive_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); @@ -123,9 +111,26 @@ static void setup(void) SAFE_BIND(receive_sockfd, (struct sockaddr *)&addr, sizeof(addr)); SAFE_CONNECT(send_sockfd, (struct sockaddr *)&addr, sizeof(addr)); + msg[0].msg_hdr.msg_iov = iov; + msg[0].msg_hdr.msg_iovlen = 1; + + TEST(tv->sendmmsg(send_sockfd, msg, 1, 0)); + + if (TST_RET != 1) { + tst_res(TFAIL | TERRNO, "sendmmsg() failed"); + return; + } + bad_addr = tst_get_bad_addr(NULL); +} - tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); +static void cleanup(void) +{ + if (send_sockfd > 0) + SAFE_CLOSE(send_sockfd); + + if (receive_sockfd > 0) + SAFE_CLOSE(receive_sockfd); } static struct tst_test test = { @@ -135,12 +140,8 @@ static struct tst_test test = { .cleanup = cleanup, .test_variants = ARRAY_SIZE(variants), .bufs = (struct tst_buffers []) { - {&snd1, .iov_sizes = (int[]){3, 3, -1}}, - {&snd2, .iov_sizes = (int[]){6, -1}}, - {&rcv1, .iov_sizes = (int[]){6, -1}}, - {&rcv2, .iov_sizes = (int[]){5, -1}}, - {&snd_msg, .size = VLEN * sizeof(*snd_msg)}, - {&rcv_msg, .size = VLEN * sizeof(*rcv_msg)}, + {&iov, .iov_sizes = (int[]){1, -1}}, + {&msg, .size = VLEN * sizeof(*msg)}, {}, } }; diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h index 68a9a4020..65d5b680f 100644 --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h @@ -13,16 +13,6 @@ #include "sendmmsg_var.h" #define BUFSIZE 16 -#define VLEN 2 - -static int send_sockfd; -static int receive_sockfd; -static struct mmsghdr *snd_msg, *rcv_msg; -static struct iovec *snd1, *snd2, *rcv1, *rcv2; - -static void *bad_addr; - -#define TYPE_NAME(x) .ttype = x, .desc = #x static struct time64_variants variants[] = { { .recvmmsg = libc_recvmmsg, .sendmmsg = libc_sendmmsg, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, @@ -35,11 +25,3 @@ static struct time64_variants variants[] = { { .recvmmsg = sys_recvmmsg64, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, #endif }; - -static void cleanup(void) -{ - if (send_sockfd > 0) - SAFE_CLOSE(send_sockfd); - if (receive_sockfd > 0) - SAFE_CLOSE(receive_sockfd); -} diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c index ad26a7b4d..e3884f1fd 100644 --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c @@ -1,52 +1,30 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* +/*\ + * Basic sendmmsg() test that sends and receives messages. + * * This test is based on source contained in the man pages for sendmmsg and * recvmmsg in release 4.15 of the Linux man-pages project. - */ +\*/ #define _GNU_SOURCE - #include "sendmmsg.h" -enum test_type { - NORMAL, - TIMEOUT, -}; +#define BUFSIZE 16 +#define VLEN 2 -struct test_case { - int ttype; - const char *desc; - long tv_sec; - long tv_nsec; - int exp_ret; -}; +static int send_sockfd; +static int receive_sockfd; +static struct mmsghdr *snd_msg, *rcv_msg; +static struct iovec *snd1, *snd2, *rcv1, *rcv2; -static struct test_case tcase[] = { - { - TYPE_NAME(NORMAL), - .tv_sec = 1, - .tv_nsec = 0, - .exp_ret = 2, - }, - { - TYPE_NAME(TIMEOUT), - .tv_sec = 0, - .tv_nsec = 0, - .exp_ret = 1, - }, -}; - -static void do_test(unsigned int i) +static void run(void) { struct time64_variants *tv = &variants[tst_variant]; - struct test_case *tc = &tcase[i]; struct tst_ts timeout; + int retval; - tst_res(TINFO, "case %s", tc->desc); - - TEST(tv->sendmmsg(send_sockfd, snd_msg, VLEN, 0)); - - if (TST_RET < 0 || snd_msg[0].msg_len != 6 || snd_msg[1].msg_len != 6) { + retval = tv->sendmmsg(send_sockfd, snd_msg, VLEN, 0); + if (retval < 0 || snd_msg[0].msg_len != 6 || snd_msg[1].msg_len != 6) { tst_res(TFAIL | TERRNO, "sendmmsg() failed"); return; } @@ -55,18 +33,18 @@ static void do_test(unsigned int i) memset(rcv2->iov_base, 0, rcv2->iov_len); timeout.type = tv->ts_type; - tst_ts_set_sec(&timeout, tc->tv_sec); - tst_ts_set_nsec(&timeout, tc->tv_nsec); + tst_ts_set_sec(&timeout, 1); + tst_ts_set_nsec(&timeout, 0); - TEST(tv->recvmmsg(receive_sockfd, rcv_msg, VLEN, 0, tst_ts_get(&timeout))); + retval = tv->recvmmsg(receive_sockfd, rcv_msg, VLEN, 0, tst_ts_get(&timeout)); - if (TST_RET == -1) { + if (retval == -1) { tst_res(TFAIL | TERRNO, "recvmmsg() failed"); return; } - if (tc->exp_ret != TST_RET) { + if (retval != 2) { tst_res(TFAIL, "Received unexpected number of messages (%d)", - TST_RET); + retval); return; } @@ -75,18 +53,10 @@ static void do_test(unsigned int i) else tst_res(TPASS, "First message received successfully"); - if (tc->ttype == NORMAL) { - if (memcmp(rcv2->iov_base, "three", 5)) - tst_res(TFAIL, "Error in second received message"); - else - tst_res(TPASS, "Second message received successfully"); - } else { - TEST(tv->recvmmsg(receive_sockfd, rcv_msg, 1, 0, NULL)); - if (TST_RET != 1 || memcmp(rcv1->iov_base, "three", 5)) - tst_res(TFAIL, "Error in second message after the timeout"); - else - tst_res(TPASS, "Timeout successfully reached before second message"); - } + if (memcmp(rcv2->iov_base, "three", 5)) + tst_res(TFAIL, "Error in second received message"); + else + tst_res(TPASS, "Second message received successfully"); } static void setup(void) @@ -120,14 +90,19 @@ static void setup(void) rcv_msg[1].msg_hdr.msg_iov = rcv2; rcv_msg[1].msg_hdr.msg_iovlen = 1; - bad_addr = tst_get_bad_addr(NULL); - tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); } +static void cleanup(void) +{ + if (send_sockfd > 0) + SAFE_CLOSE(send_sockfd); + if (receive_sockfd > 0) + SAFE_CLOSE(receive_sockfd); +} + static struct tst_test test = { - .test = do_test, - .tcnt = ARRAY_SIZE(tcase), + .test_all = run, .setup = setup, .cleanup = cleanup, .test_variants = ARRAY_SIZE(variants), diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c index 8ed345b09..7c3f2164c 100644 --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c @@ -1,36 +1,41 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* test status of errors: +/*\ + * Tests sendmmsg() failures: * - * EBADF v ('Bad socket file descriptor') - * EFAULT v ('Bad message vector address') - */ + * - EBADF Bad socket file descriptor + * - EFAULT Bad message vector address +\*/ #define _GNU_SOURCE #include "sendmmsg.h" -enum test_type { - BAD_FD, - BAD_MSGVEC, -}; +#define VLEN 1 + +static int send_sockfd; +static struct mmsghdr *snd_msg; -#define TYPE_NAME(x) .ttype = x, .desc = #x +static void *bad_addr; +static int bad_fd = -1; struct test_case { - int ttype; const char *desc; - int fd; + int *fd; int exp_errno; + struct mmsghdr **msg_vec; }; static struct test_case tcase[] = { { - TYPE_NAME(BAD_FD), - .fd = -1, + .desc = "bad file descriptor", + .fd = &bad_fd, + .msg_vec = &snd_msg, .exp_errno = EBADF, }, { - TYPE_NAME(BAD_MSGVEC), + .desc = "invalid msgvec address", + .fd = &send_sockfd, + .msg_vec = (void*)&bad_addr, .exp_errno = EFAULT, }, }; @@ -39,27 +44,9 @@ static void do_test(unsigned int i) { struct time64_variants *tv = &variants[tst_variant]; struct test_case *tc = &tcase[i]; - void *snd_msgvec; - - tst_res(TINFO, "case %s", tc->desc); - - if (tc->ttype != BAD_FD) - tc->fd = send_sockfd; - - if (tc->ttype == BAD_MSGVEC) - snd_msgvec = bad_addr; - else - snd_msgvec = snd_msg; - TEST(tv->sendmmsg(tc->fd, snd_msgvec, VLEN, 0)); - - if (TST_RET < 0) - if (tc->exp_errno != TST_ERR) - tst_res(TFAIL | TERRNO, "sendmmsg() failed unexpectedly"); - else - tst_res(TPASS | TERRNO, "sendmmg() failed successfully"); - else - tst_res(TFAIL, "sendmmsg() succeded unexpectedly"); + TST_EXP_FAIL(tv->sendmmsg(*tc->fd, *tc->msg_vec, VLEN, 0), + tc->exp_errno, "%s", tc->desc); } static void setup(void) @@ -69,6 +56,12 @@ static void setup(void) tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); } +static void cleanup(void) +{ + if (send_sockfd > 0) + SAFE_CLOSE(send_sockfd); +} + static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(tcase), @@ -76,12 +69,7 @@ static struct tst_test test = { .cleanup = cleanup, .test_variants = ARRAY_SIZE(variants), .bufs = (struct tst_buffers []) { - {&snd1, .iov_sizes = (int[]){3, 3, -1}}, - {&snd2, .iov_sizes = (int[]){6, -1}}, - {&rcv1, .iov_sizes = (int[]){6, -1}}, - {&rcv2, .iov_sizes = (int[]){5, -1}}, {&snd_msg, .size = VLEN * sizeof(*snd_msg)}, - {&rcv_msg, .size = VLEN * sizeof(*rcv_msg)}, {}, } };
diff --git a/runtest/syscalls b/runtest/syscalls index 409800dbb..9c328697b 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -1072,6 +1072,8 @@ recvmsg01 recvmsg01 recvmsg02 recvmsg02 recvmsg03 recvmsg03 +recvmmsg01 recvmmsg01 + remap_file_pages01 remap_file_pages01 remap_file_pages02 remap_file_pages02 @@ -1211,6 +1213,7 @@ sendmsg02 sendmsg02 sendmsg03 sendmsg03 sendmmsg01 sendmmsg01 +sendmmsg02 sendmmsg02 sendto01 sendto01 sendto02 sendto02 diff --git a/testcases/kernel/syscalls/recvmmsg/Makefile b/testcases/kernel/syscalls/recvmmsg/Makefile new file mode 100644 index 000000000..18896b6f2 --- /dev/null +++ b/testcases/kernel/syscalls/recvmmsg/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c new file mode 100644 index 000000000..b3204cc9a --- /dev/null +++ b/testcases/kernel/syscalls/recvmmsg/recvmmsg01.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* test status of errors: + * + * EBADF v ('Bad socket file descriptor') + * EFAULT v ('Bad message vector address') + * EINVAL v ('Bad seconds value for the timeout argument') + * EINVAL v ('Bad nanoseconds value for the timeout argument') + * EFAULT v ('Bad timeout address') + */ + +#define _GNU_SOURCE +#include "../sendmmsg/sendmmsg.h" + +static struct tst_ts ts; + +enum test_type { + BAD_FD, + BAD_MSGVEC, + BAD_TS_VALUE_1, + BAD_TS_VALUE_2, + BAD_TS_ADDR, +}; + +#define TYPE_NAME(x) .ttype = x, .desc = #x + +struct test_case { + int ttype; + const char *desc; + int fd; + long tv_sec; + long tv_nsec; + int exp_errno; +}; + +static struct test_case tcase[] = { + { + TYPE_NAME(BAD_FD), + .fd = -1, + .exp_errno = EBADF, + }, + { + TYPE_NAME(BAD_MSGVEC), + .exp_errno = EFAULT, + }, + { + TYPE_NAME(BAD_TS_VALUE_1), + .tv_sec = -1, + .tv_nsec = 0, + .exp_errno = EINVAL, + }, + { + TYPE_NAME(BAD_TS_VALUE_2), + .tv_sec = 1, + .tv_nsec = 1000000001, + .exp_errno = EINVAL, + }, + { + TYPE_NAME(BAD_TS_ADDR), + .exp_errno = EFAULT, + } +}; + +static void do_test(unsigned int i) +{ + struct time64_variants *tv = &variants[tst_variant]; + struct test_case *tc = &tcase[i]; + void *rcv_msgvec, *timeout; + + tst_res(TINFO, "case %s", tc->desc); + + if (tc->ttype != BAD_FD) + tc->fd = receive_sockfd; + + TEST(tv->sendmmsg(send_sockfd, snd_msg, 1, 0)); + + if (TST_RET != 1) { + tst_res(TFAIL | TERRNO, "sendmmsg() failed"); + return; + } + + memset(rcv1->iov_base, 0, rcv1->iov_len); + memset(rcv2->iov_base, 0, rcv2->iov_len); + + ts.type = tv->ts_type; + tst_ts_set_sec(&ts, tc->tv_sec); + tst_ts_set_nsec(&ts, tc->tv_nsec); + + if (tc->ttype == BAD_MSGVEC) + rcv_msgvec = bad_addr; + else + rcv_msgvec = rcv_msg; + + if (tc->ttype == BAD_TS_ADDR) + timeout = bad_addr; + else + timeout = tst_ts_get(&ts); + + TEST(tv->recvmmsg(tc->fd, rcv_msgvec, VLEN, 0, timeout)); + + if (TST_RET < 0) { + if (tc->exp_errno == errno) + tst_res(TPASS | TERRNO, "recvemmsg() failed successfully"); + else + tst_res(TFAIL | TERRNO, "recvemmsg() failed unexpectedly"); + } else { + tst_res(TFAIL | TERRNO, "recvemmsg() succeded unexpectedly"); + } +} + +static void setup(void) +{ + struct sockaddr_in addr; + unsigned int port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM); + + send_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); + receive_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = port; + + SAFE_BIND(receive_sockfd, (struct sockaddr *)&addr, sizeof(addr)); + SAFE_CONNECT(send_sockfd, (struct sockaddr *)&addr, sizeof(addr)); + + bad_addr = tst_get_bad_addr(NULL); + + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); +} + +static struct tst_test test = { + .test = do_test, + .tcnt = ARRAY_SIZE(tcase), + .setup = setup, + .cleanup = cleanup, + .test_variants = ARRAY_SIZE(variants), + .bufs = (struct tst_buffers []) { + {&snd1, .iov_sizes = (int[]){3, 3, -1}}, + {&snd2, .iov_sizes = (int[]){6, -1}}, + {&rcv1, .iov_sizes = (int[]){6, -1}}, + {&rcv2, .iov_sizes = (int[]){5, -1}}, + {&snd_msg, .size = VLEN * sizeof(*snd_msg)}, + {&rcv_msg, .size = VLEN * sizeof(*rcv_msg)}, + {}, + } +}; diff --git a/testcases/kernel/syscalls/sendmmsg/.gitignore b/testcases/kernel/syscalls/sendmmsg/.gitignore index b703ececd..42693c44d 100644 --- a/testcases/kernel/syscalls/sendmmsg/.gitignore +++ b/testcases/kernel/syscalls/sendmmsg/.gitignore @@ -1 +1,2 @@ sendmmsg01 +sendmmsg02 diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h new file mode 100644 index 000000000..68a9a4020 --- /dev/null +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <netinet/ip.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "time64_variants.h" +#include "tst_test.h" +#include "lapi/socket.h" +#include "tst_safe_macros.h" +#include "sendmmsg_var.h" + +#define BUFSIZE 16 +#define VLEN 2 + +static int send_sockfd; +static int receive_sockfd; +static struct mmsghdr *snd_msg, *rcv_msg; +static struct iovec *snd1, *snd2, *rcv1, *rcv2; + +static void *bad_addr; + +#define TYPE_NAME(x) .ttype = x, .desc = #x + +static struct time64_variants variants[] = { + { .recvmmsg = libc_recvmmsg, .sendmmsg = libc_sendmmsg, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, + +#if (__NR_recvmmsg != __LTP__NR_INVALID_SYSCALL) + { .recvmmsg = sys_recvmmsg, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, +#endif + +#if (__NR_recvmmsg_time64 != __LTP__NR_INVALID_SYSCALL) + { .recvmmsg = sys_recvmmsg64, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, +#endif +}; + +static void cleanup(void) +{ + if (send_sockfd > 0) + SAFE_CLOSE(send_sockfd); + if (receive_sockfd > 0) + SAFE_CLOSE(receive_sockfd); +} diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c index d6a717687..ad26a7b4d 100644 --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c @@ -5,46 +5,48 @@ */ #define _GNU_SOURCE -#include <netinet/ip.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> - -#include "time64_variants.h" -#include "tst_test.h" -#include "lapi/socket.h" -#include "tst_safe_macros.h" -#include "sendmmsg_var.h" - -#define BUFSIZE 16 -#define VLEN 2 - -static int send_sockfd; -static int receive_sockfd; -static struct mmsghdr *snd_msg, *rcv_msg; -static struct iovec *snd1, *snd2, *rcv1, *rcv2; - -static struct time64_variants variants[] = { - { .recvmmsg = libc_recvmmsg, .sendmmsg = libc_sendmmsg, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, - -#if (__NR_recvmmsg != __LTP__NR_INVALID_SYSCALL) - { .recvmmsg = sys_recvmmsg, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, -#endif - -#if (__NR_recvmmsg_time64 != __LTP__NR_INVALID_SYSCALL) - { .recvmmsg = sys_recvmmsg64, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, -#endif + +#include "sendmmsg.h" + +enum test_type { + NORMAL, + TIMEOUT, +}; + +struct test_case { + int ttype; + const char *desc; + long tv_sec; + long tv_nsec; + int exp_ret; }; -static void run(void) +static struct test_case tcase[] = { + { + TYPE_NAME(NORMAL), + .tv_sec = 1, + .tv_nsec = 0, + .exp_ret = 2, + }, + { + TYPE_NAME(TIMEOUT), + .tv_sec = 0, + .tv_nsec = 0, + .exp_ret = 1, + }, +}; + +static void do_test(unsigned int i) { struct time64_variants *tv = &variants[tst_variant]; + struct test_case *tc = &tcase[i]; struct tst_ts timeout; - int retval; - retval = tv->sendmmsg(send_sockfd, snd_msg, VLEN, 0); - if (retval < 0 || snd_msg[0].msg_len != 6 || snd_msg[1].msg_len != 6) { + tst_res(TINFO, "case %s", tc->desc); + + TEST(tv->sendmmsg(send_sockfd, snd_msg, VLEN, 0)); + + if (TST_RET < 0 || snd_msg[0].msg_len != 6 || snd_msg[1].msg_len != 6) { tst_res(TFAIL | TERRNO, "sendmmsg() failed"); return; } @@ -53,18 +55,18 @@ static void run(void) memset(rcv2->iov_base, 0, rcv2->iov_len); timeout.type = tv->ts_type; - tst_ts_set_sec(&timeout, 1); - tst_ts_set_nsec(&timeout, 0); + tst_ts_set_sec(&timeout, tc->tv_sec); + tst_ts_set_nsec(&timeout, tc->tv_nsec); - retval = tv->recvmmsg(receive_sockfd, rcv_msg, VLEN, 0, tst_ts_get(&timeout)); + TEST(tv->recvmmsg(receive_sockfd, rcv_msg, VLEN, 0, tst_ts_get(&timeout))); - if (retval == -1) { + if (TST_RET == -1) { tst_res(TFAIL | TERRNO, "recvmmsg() failed"); return; } - if (retval != 2) { + if (tc->exp_ret != TST_RET) { tst_res(TFAIL, "Received unexpected number of messages (%d)", - retval); + TST_RET); return; } @@ -73,10 +75,18 @@ static void run(void) else tst_res(TPASS, "First message received successfully"); - if (memcmp(rcv2->iov_base, "three", 5)) - tst_res(TFAIL, "Error in second received message"); - else - tst_res(TPASS, "Second message received successfully"); + if (tc->ttype == NORMAL) { + if (memcmp(rcv2->iov_base, "three", 5)) + tst_res(TFAIL, "Error in second received message"); + else + tst_res(TPASS, "Second message received successfully"); + } else { + TEST(tv->recvmmsg(receive_sockfd, rcv_msg, 1, 0, NULL)); + if (TST_RET != 1 || memcmp(rcv1->iov_base, "three", 5)) + tst_res(TFAIL, "Error in second message after the timeout"); + else + tst_res(TPASS, "Timeout successfully reached before second message"); + } } static void setup(void) @@ -110,19 +120,14 @@ static void setup(void) rcv_msg[1].msg_hdr.msg_iov = rcv2; rcv_msg[1].msg_hdr.msg_iovlen = 1; - tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); -} + bad_addr = tst_get_bad_addr(NULL); -static void cleanup(void) -{ - if (send_sockfd > 0) - SAFE_CLOSE(send_sockfd); - if (receive_sockfd > 0) - SAFE_CLOSE(receive_sockfd); + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); } static struct tst_test test = { - .test_all = run, + .test = do_test, + .tcnt = ARRAY_SIZE(tcase), .setup = setup, .cleanup = cleanup, .test_variants = ARRAY_SIZE(variants), diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c new file mode 100644 index 000000000..8ed345b09 --- /dev/null +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg02.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* test status of errors: + * + * EBADF v ('Bad socket file descriptor') + * EFAULT v ('Bad message vector address') + */ + +#define _GNU_SOURCE +#include "sendmmsg.h" + +enum test_type { + BAD_FD, + BAD_MSGVEC, +}; + +#define TYPE_NAME(x) .ttype = x, .desc = #x + +struct test_case { + int ttype; + const char *desc; + int fd; + int exp_errno; +}; + +static struct test_case tcase[] = { + { + TYPE_NAME(BAD_FD), + .fd = -1, + .exp_errno = EBADF, + }, + { + TYPE_NAME(BAD_MSGVEC), + .exp_errno = EFAULT, + }, +}; + +static void do_test(unsigned int i) +{ + struct time64_variants *tv = &variants[tst_variant]; + struct test_case *tc = &tcase[i]; + void *snd_msgvec; + + tst_res(TINFO, "case %s", tc->desc); + + if (tc->ttype != BAD_FD) + tc->fd = send_sockfd; + + if (tc->ttype == BAD_MSGVEC) + snd_msgvec = bad_addr; + else + snd_msgvec = snd_msg; + + TEST(tv->sendmmsg(tc->fd, snd_msgvec, VLEN, 0)); + + if (TST_RET < 0) + if (tc->exp_errno != TST_ERR) + tst_res(TFAIL | TERRNO, "sendmmsg() failed unexpectedly"); + else + tst_res(TPASS | TERRNO, "sendmmg() failed successfully"); + else + tst_res(TFAIL, "sendmmsg() succeded unexpectedly"); +} + +static void setup(void) +{ + send_sockfd = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); + + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); +} + +static struct tst_test test = { + .test = do_test, + .tcnt = ARRAY_SIZE(tcase), + .setup = setup, + .cleanup = cleanup, + .test_variants = ARRAY_SIZE(variants), + .bufs = (struct tst_buffers []) { + {&snd1, .iov_sizes = (int[]){3, 3, -1}}, + {&snd2, .iov_sizes = (int[]){6, -1}}, + {&rcv1, .iov_sizes = (int[]){6, -1}}, + {&rcv2, .iov_sizes = (int[]){5, -1}}, + {&snd_msg, .size = VLEN * sizeof(*snd_msg)}, + {&rcv_msg, .size = VLEN * sizeof(*rcv_msg)}, + {}, + } +};
This patch introduces a test case for the already existing test for syscalls 'sendmmsg()' and 'recvmmsg()' (sendmmsg01). This test case is meant to check whether the timeout is reached aproppriately after the first message is received. The timeout is set to 0 as to make sure that it has to be reached. In this case the expected return value is 1 as the second message is not supposed be received after the timeout is reached. * Note: No matter how small the timeout is, one message is always gonna have to be received because the timeout is checked only after a received message. This is an existing bug for syscall 'recvmmsg()': https://man7.org/linux/man-pages/man2/recvmmsg.2.html#BUGS This patch introduces new test files for these syscalls (sendmmsg02.c and recvmmsg01.c). This test file is meant to check whether the aproppriate errno is set in some sitautions when these syscalls fail. These situations include: bad socket file descriptor (EBADF), bad message vector address (EFAULT), bad timeout value (EINVAL), bad timeout address (EFAULT). Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com> --- runtest/syscalls | 3 + testcases/kernel/syscalls/recvmmsg/Makefile | 7 + .../kernel/syscalls/recvmmsg/recvmmsg01.c | 146 ++++++++++++++++++ testcases/kernel/syscalls/sendmmsg/.gitignore | 1 + testcases/kernel/syscalls/sendmmsg/sendmmsg.h | 45 ++++++ .../kernel/syscalls/sendmmsg/sendmmsg01.c | 111 ++++++------- .../kernel/syscalls/sendmmsg/sendmmsg02.c | 87 +++++++++++ 7 files changed, 347 insertions(+), 53 deletions(-) create mode 100644 testcases/kernel/syscalls/recvmmsg/Makefile create mode 100644 testcases/kernel/syscalls/recvmmsg/recvmmsg01.c create mode 100644 testcases/kernel/syscalls/sendmmsg/sendmmsg.h create mode 100644 testcases/kernel/syscalls/sendmmsg/sendmmsg02.c