diff options
author | ngie <ngie@FreeBSD.org> | 2017-05-30 03:09:01 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2017-05-30 03:09:01 +0000 |
commit | e998daeb8b5f271fd1713c069a5626be410a8e10 (patch) | |
tree | 57d354dd25c273f6b4ea134782eb80efc43491a8 /tests/sys | |
parent | 6932de11ab5641f9c4a00a5be42b2a3b55c6d81c (diff) | |
download | FreeBSD-src-e998daeb8b5f271fd1713c069a5626be410a8e10.zip FreeBSD-src-e998daeb8b5f271fd1713c069a5626be410a8e10.tar.gz |
MFC r312913,r318100,r318107:
r312913 (by asomers):
Improve the aio tests
* Add tests for aio_suspend(2).
* Add tests for polled completion notification.
* Test the full matrix of file descriptor types and completion notification
mechanisms.
* Don't bother with mkstemp, because ATF runs every test in its own temp dir.
* Fix some typos.
* Remove extraneous ATF_REQUIRE_KERNEL_MODULE calls.
r318100:
style(9): move function definition curly braces to column 0
r318107:
Remove unused constant (PATH_TEMPLATE)
It was made unnecessary in r312913.
MFC with: r312913
Diffstat (limited to 'tests/sys')
-rw-r--r-- | tests/sys/aio/aio_test.c | 341 |
1 files changed, 247 insertions, 94 deletions
diff --git a/tests/sys/aio/aio_test.c b/tests/sys/aio/aio_test.c index 33ccd7d..b06fb57 100644 --- a/tests/sys/aio/aio_test.c +++ b/tests/sys/aio/aio_test.c @@ -33,7 +33,7 @@ * reading it from a second descriptor using AIO. For some targets, the same * fd is used for write and read (i.e., file, md device), but for others the * operation is performed on a peer (pty, socket, fifo, etc). A timeout is - * initiated to detect undo blocking. This test does not attempt to exercise + * initiated to detect undue blocking. This test does not attempt to exercise * error cases or more subtle asynchronous behavior, just make sure that the * basic operations work on some basic object types. */ @@ -63,8 +63,6 @@ #include "freebsd_test_suite/macros.h" #include "local.h" -#define PATH_TEMPLATE "aio.XXXXXXXXXX" - /* * GLOBAL_MAX sets the largest usable buffer size to be read and written, as * it sizes ac_buffer in the aio_context structure. It is also the default @@ -74,6 +72,13 @@ #define GLOBAL_MAX 16384 #define BUFFER_MAX GLOBAL_MAX + +/* + * A completion function will block until the aio has completed, then return + * the result of the aio. errno will be set appropriately. + */ +typedef ssize_t (*completion)(struct aiocb*); + struct aio_context { int ac_read_fd, ac_write_fd; long ac_seed; @@ -179,6 +184,48 @@ aio_context_init(struct aio_context *ac, int read_fd, ac->ac_cleanup_arg = cleanup_arg; } +static ssize_t +poll(struct aiocb *aio) +{ + int err; + + while ((err = aio_error(aio)) == EINPROGRESS && !aio_timedout) + usleep(25000); + switch (err) { + case EINPROGRESS: + errno = EINTR; + return (-1); + case 0: + return (aio_return(aio)); + default: + return (err); + } +} + +static ssize_t +suspend(struct aiocb *aio) +{ + const struct aiocb *const iocbs[] = {aio}; + int err; + + err = aio_suspend(iocbs, 1, NULL); + if (err == 0) + return (aio_return(aio)); + else + return (err); +} + +static ssize_t +waitcomplete(struct aiocb *aio) +{ + struct aiocb *aiop; + ssize_t ret; + + ret = aio_waitcomplete(&aiop, NULL); + ATF_REQUIRE_EQ(aio, aiop); + return (ret); +} + /* * Each tester can register a callback to clean up in the event the test * fails. Preserve the value of errno so that subsequent calls to errx() @@ -201,13 +248,11 @@ aio_cleanup(struct aio_context *ac) * file descriptor. */ static void -aio_write_test(struct aio_context *ac) +aio_write_test(struct aio_context *ac, completion comp) { - struct aiocb aio, *aiop; + struct aiocb aio; ssize_t len; - ATF_REQUIRE_KERNEL_MODULE("aio"); - bzero(&aio, sizeof(aio)); aio.aio_buf = ac->ac_buffer; aio.aio_nbytes = ac->ac_buflen; @@ -227,24 +272,23 @@ aio_write_test(struct aio_context *ac) atf_tc_fail("aio_write failed: %s", strerror(errno)); } - len = aio_waitcomplete(&aiop, NULL); + len = comp(&aio); if (len < 0) { if (errno == EINTR) { if (aio_timedout) { aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete timed out"); + atf_tc_fail("aio timed out"); } } aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); + atf_tc_fail("aio failed: %s", strerror(errno)); } aio_timeout_stop(); if (len != ac->ac_buflen) { aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete short write (%jd)", - (intmax_t)len); + atf_tc_fail("aio short write (%jd)", (intmax_t)len); } } @@ -253,13 +297,11 @@ aio_write_test(struct aio_context *ac) * provided file descriptor. */ static void -aio_read_test(struct aio_context *ac) +aio_read_test(struct aio_context *ac, completion comp) { - struct aiocb aio, *aiop; + struct aiocb aio; ssize_t len; - ATF_REQUIRE_KERNEL_MODULE("aio"); - bzero(ac->ac_buffer, ac->ac_buflen); bzero(&aio, sizeof(aio)); aio.aio_buf = ac->ac_buffer; @@ -273,30 +315,30 @@ aio_read_test(struct aio_context *ac) if (errno == EINTR) { if (aio_timedout) { aio_cleanup(ac); - atf_tc_fail("aio_write timed out"); + atf_tc_fail("aio_read timed out"); } } aio_cleanup(ac); atf_tc_fail("aio_read failed: %s", strerror(errno)); } - len = aio_waitcomplete(&aiop, NULL); + len = comp(&aio); if (len < 0) { if (errno == EINTR) { if (aio_timedout) { aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete timed out"); + atf_tc_fail("aio timed out"); } } aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); + atf_tc_fail("aio failed: %s", strerror(errno)); } aio_timeout_stop(); if (len != ac->ac_buflen) { aio_cleanup(ac); - atf_tc_fail("aio_waitcomplete short read (%jd)", + atf_tc_fail("aio short read (%jd)", (intmax_t)len); } @@ -316,9 +358,11 @@ aio_read_test(struct aio_context *ac) * Test with a classic file. Assumes we can create a moderate size temporary * file. */ +#define FILE_LEN GLOBAL_MAX +#define FILE_PATHNAME "testfile" +#define FILE_TIMEOUT 30 struct aio_file_arg { int afa_fd; - char *afa_pathname; }; static void @@ -328,15 +372,12 @@ aio_file_cleanup(void *arg) afa = arg; close(afa->afa_fd); - unlink(afa->afa_pathname); + unlink(FILE_PATHNAME); } -#define FILE_LEN GLOBAL_MAX -#define FILE_TIMEOUT 30 -ATF_TC_WITHOUT_HEAD(aio_file_test); -ATF_TC_BODY(aio_file_test, tc) +static void +aio_file_test(completion comp) { - char pathname[PATH_MAX]; struct aio_file_arg arg; struct aio_context ac; int fd; @@ -344,25 +385,43 @@ ATF_TC_BODY(aio_file_test, tc) ATF_REQUIRE_KERNEL_MODULE("aio"); ATF_REQUIRE_UNSAFE_AIO(); - strcpy(pathname, PATH_TEMPLATE); - fd = mkstemp(pathname); - ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); + fd = open(FILE_PATHNAME, O_RDWR | O_CREAT); + ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); arg.afa_fd = fd; - arg.afa_pathname = pathname; aio_context_init(&ac, fd, fd, FILE_LEN, FILE_TIMEOUT, aio_file_cleanup, &arg); - aio_write_test(&ac); - aio_read_test(&ac); + aio_write_test(&ac, comp); + aio_read_test(&ac, comp); aio_file_cleanup(&arg); } +ATF_TC_WITHOUT_HEAD(file_poll); +ATF_TC_BODY(file_poll, tc) +{ + aio_file_test(poll); +} + +ATF_TC_WITHOUT_HEAD(file_suspend); +ATF_TC_BODY(file_suspend, tc) +{ + aio_file_test(suspend); +} + +ATF_TC_WITHOUT_HEAD(file_waitcomplete); +ATF_TC_BODY(file_waitcomplete, tc) +{ + aio_file_test(waitcomplete); +} + +#define FIFO_LEN 256 +#define FIFO_PATHNAME "testfifo" +#define FIFO_TIMEOUT 30 struct aio_fifo_arg { int afa_read_fd; int afa_write_fd; - char *afa_pathname; }; static void @@ -375,39 +434,25 @@ aio_fifo_cleanup(void *arg) close(afa->afa_read_fd); if (afa->afa_write_fd != -1) close(afa->afa_write_fd); - unlink(afa->afa_pathname); + unlink(FIFO_PATHNAME); } -#define FIFO_LEN 256 -#define FIFO_TIMEOUT 30 -ATF_TC_WITHOUT_HEAD(aio_fifo_test); -ATF_TC_BODY(aio_fifo_test, tc) +static void +aio_fifo_test(completion comp) { int error, read_fd = -1, write_fd = -1; struct aio_fifo_arg arg; - char pathname[PATH_MAX]; struct aio_context ac; ATF_REQUIRE_KERNEL_MODULE("aio"); ATF_REQUIRE_UNSAFE_AIO(); - /* - * In theory, mkstemp() can return a name that is then collided with. - * Because this is a regression test, we treat that as a test failure - * rather than retrying. - */ - strcpy(pathname, PATH_TEMPLATE); - ATF_REQUIRE_MSG(mkstemp(pathname) != -1, - "mkstemp failed: %s", strerror(errno)); - ATF_REQUIRE_MSG(unlink(pathname) == 0, - "unlink failed: %s", strerror(errno)); - ATF_REQUIRE_MSG(mkfifo(pathname, 0600) != -1, + ATF_REQUIRE_MSG(mkfifo(FIFO_PATHNAME, 0600) != -1, "mkfifo failed: %s", strerror(errno)); - arg.afa_pathname = pathname; arg.afa_read_fd = -1; arg.afa_write_fd = -1; - read_fd = open(pathname, O_RDONLY | O_NONBLOCK); + read_fd = open(FIFO_PATHNAME, O_RDONLY | O_NONBLOCK); if (read_fd == -1) { error = errno; aio_fifo_cleanup(&arg); @@ -417,7 +462,7 @@ ATF_TC_BODY(aio_fifo_test, tc) } arg.afa_read_fd = read_fd; - write_fd = open(pathname, O_WRONLY); + write_fd = open(FIFO_PATHNAME, O_WRONLY); if (write_fd == -1) { error = errno; aio_fifo_cleanup(&arg); @@ -429,12 +474,30 @@ ATF_TC_BODY(aio_fifo_test, tc) aio_context_init(&ac, read_fd, write_fd, FIFO_LEN, FIFO_TIMEOUT, aio_fifo_cleanup, &arg); - aio_write_test(&ac); - aio_read_test(&ac); + aio_write_test(&ac, comp); + aio_read_test(&ac, comp); aio_fifo_cleanup(&arg); } +ATF_TC_WITHOUT_HEAD(fifo_poll); +ATF_TC_BODY(fifo_poll, tc) +{ + aio_fifo_test(poll); +} + +ATF_TC_WITHOUT_HEAD(fifo_suspend); +ATF_TC_BODY(fifo_suspend, tc) +{ + aio_fifo_test(waitcomplete); +} + +ATF_TC_WITHOUT_HEAD(fifo_waitcomplete); +ATF_TC_BODY(fifo_waitcomplete, tc) +{ + aio_fifo_test(waitcomplete); +} + struct aio_unix_socketpair_arg { int asa_sockets[2]; }; @@ -451,8 +514,8 @@ aio_unix_socketpair_cleanup(void *arg) #define UNIX_SOCKETPAIR_LEN 256 #define UNIX_SOCKETPAIR_TIMEOUT 30 -ATF_TC_WITHOUT_HEAD(aio_unix_socketpair_test); -ATF_TC_BODY(aio_unix_socketpair_test, tc) +static void +aio_unix_socketpair_test(completion comp) { struct aio_unix_socketpair_arg arg; struct aio_context ac; @@ -471,12 +534,12 @@ ATF_TC_BODY(aio_unix_socketpair_test, tc) aio_unix_socketpair_cleanup, &arg); ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_before) != -1, "getrusage failed: %s", strerror(errno)); - aio_write_test(&ac); + aio_write_test(&ac, comp); ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_after) != -1, "getrusage failed: %s", strerror(errno)); ATF_REQUIRE(ru_after.ru_msgsnd == ru_before.ru_msgsnd + 1); ru_before = ru_after; - aio_read_test(&ac); + aio_read_test(&ac, comp); ATF_REQUIRE_MSG(getrusage(RUSAGE_SELF, &ru_after) != -1, "getrusage failed: %s", strerror(errno)); ATF_REQUIRE(ru_after.ru_msgrcv == ru_before.ru_msgrcv + 1); @@ -484,6 +547,24 @@ ATF_TC_BODY(aio_unix_socketpair_test, tc) aio_unix_socketpair_cleanup(&arg); } +ATF_TC_WITHOUT_HEAD(socket_poll); +ATF_TC_BODY(socket_poll, tc) +{ + aio_unix_socketpair_test(poll); +} + +ATF_TC_WITHOUT_HEAD(socket_suspend); +ATF_TC_BODY(socket_suspend, tc) +{ + aio_unix_socketpair_test(suspend); +} + +ATF_TC_WITHOUT_HEAD(socket_waitcomplete); +ATF_TC_BODY(socket_waitcomplete, tc) +{ + aio_unix_socketpair_test(waitcomplete); +} + struct aio_pty_arg { int apa_read_fd; int apa_write_fd; @@ -501,8 +582,8 @@ aio_pty_cleanup(void *arg) #define PTY_LEN 256 #define PTY_TIMEOUT 30 -ATF_TC_WITHOUT_HEAD(aio_pty_test); -ATF_TC_BODY(aio_pty_test, tc) +static void +aio_pty_test(completion comp) { struct aio_pty_arg arg; struct aio_context ac; @@ -535,12 +616,30 @@ ATF_TC_BODY(aio_pty_test, tc) aio_context_init(&ac, read_fd, write_fd, PTY_LEN, PTY_TIMEOUT, aio_pty_cleanup, &arg); - aio_write_test(&ac); - aio_read_test(&ac); + aio_write_test(&ac, comp); + aio_read_test(&ac, comp); aio_pty_cleanup(&arg); } +ATF_TC_WITHOUT_HEAD(pty_poll); +ATF_TC_BODY(pty_poll, tc) +{ + aio_pty_test(poll); +} + +ATF_TC_WITHOUT_HEAD(pty_suspend); +ATF_TC_BODY(pty_suspend, tc) +{ + aio_pty_test(suspend); +} + +ATF_TC_WITHOUT_HEAD(pty_waitcomplete); +ATF_TC_BODY(pty_waitcomplete, tc) +{ + aio_pty_test(waitcomplete); +} + static void aio_pipe_cleanup(void *arg) { @@ -552,8 +651,8 @@ aio_pipe_cleanup(void *arg) #define PIPE_LEN 256 #define PIPE_TIMEOUT 30 -ATF_TC_WITHOUT_HEAD(aio_pipe_test); -ATF_TC_BODY(aio_pipe_test, tc) +static void +aio_pipe_test(completion comp) { struct aio_context ac; int pipes[2]; @@ -566,12 +665,30 @@ ATF_TC_BODY(aio_pipe_test, tc) aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN, PIPE_TIMEOUT, aio_pipe_cleanup, pipes); - aio_write_test(&ac); - aio_read_test(&ac); + aio_write_test(&ac, comp); + aio_read_test(&ac, comp); aio_pipe_cleanup(pipes); } +ATF_TC_WITHOUT_HEAD(pipe_poll); +ATF_TC_BODY(pipe_poll, tc) +{ + aio_pipe_test(poll); +} + +ATF_TC_WITHOUT_HEAD(pipe_suspend); +ATF_TC_BODY(pipe_suspend, tc) +{ + aio_pipe_test(suspend); +} + +ATF_TC_WITHOUT_HEAD(pipe_waitcomplete); +ATF_TC_BODY(pipe_waitcomplete, tc) +{ + aio_pipe_test(waitcomplete); +} + struct aio_md_arg { int ama_mdctl_fd; int ama_unit; @@ -608,13 +725,8 @@ aio_md_cleanup(void *arg) #define MD_LEN GLOBAL_MAX #define MD_TIMEOUT 30 -ATF_TC(aio_md_test); -ATF_TC_HEAD(aio_md_test, tc) -{ - - atf_tc_set_md_var(tc, "require.user", "root"); -} -ATF_TC_BODY(aio_md_test, tc) +static void +aio_md_test(completion comp) { int error, fd, mdctl_fd, unit; char pathname[PATH_MAX]; @@ -654,16 +766,48 @@ ATF_TC_BODY(aio_md_test, tc) aio_context_init(&ac, fd, fd, MD_LEN, MD_TIMEOUT, aio_md_cleanup, &arg); - aio_write_test(&ac); - aio_read_test(&ac); + aio_write_test(&ac, comp); + aio_read_test(&ac, comp); aio_md_cleanup(&arg); } +ATF_TC(md_poll); +ATF_TC_HEAD(md_poll, tc) +{ + + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(md_poll, tc) +{ + aio_md_test(poll); +} + +ATF_TC(md_suspend); +ATF_TC_HEAD(md_suspend, tc) +{ + + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(md_suspend, tc) +{ + aio_md_test(suspend); +} + +ATF_TC(md_waitcomplete); +ATF_TC_HEAD(md_waitcomplete, tc) +{ + + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(md_waitcomplete, tc) +{ + aio_md_test(waitcomplete); +} + ATF_TC_WITHOUT_HEAD(aio_large_read_test); ATF_TC_BODY(aio_large_read_test, tc) { - char pathname[PATH_MAX]; struct aiocb cb, *cbp; ssize_t nread; size_t len; @@ -689,11 +833,10 @@ ATF_TC_BODY(aio_large_read_test, tc) len = INT_MAX; #endif - strcpy(pathname, PATH_TEMPLATE); - fd = mkstemp(pathname); - ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); + fd = open(FILE_PATHNAME, O_RDWR | O_CREAT); + ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); - unlink(pathname); + unlink(FILE_PATHNAME); memset(&cb, 0, sizeof(cb)); cb.aio_nbytes = len; @@ -937,7 +1080,6 @@ ATF_TC_BODY(aio_fsync_test, tc) char *buffer; } buffers[16]; struct stat sb; - char pathname[PATH_MAX]; ssize_t rval; unsigned i; int fd; @@ -945,10 +1087,9 @@ ATF_TC_BODY(aio_fsync_test, tc) ATF_REQUIRE_KERNEL_MODULE("aio"); ATF_REQUIRE_UNSAFE_AIO(); - strcpy(pathname, PATH_TEMPLATE); - fd = mkstemp(pathname); - ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); - unlink(pathname); + fd = open(FILE_PATHNAME, O_RDWR | O_CREAT); + ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); + unlink(FILE_PATHNAME); ATF_REQUIRE(fstat(fd, &sb) == 0); ATF_REQUIRE(sb.st_blksize != 0); @@ -1009,12 +1150,24 @@ ATF_TC_BODY(aio_fsync_test, tc) ATF_TP_ADD_TCS(tp) { - ATF_TP_ADD_TC(tp, aio_file_test); - ATF_TP_ADD_TC(tp, aio_fifo_test); - ATF_TP_ADD_TC(tp, aio_unix_socketpair_test); - ATF_TP_ADD_TC(tp, aio_pty_test); - ATF_TP_ADD_TC(tp, aio_pipe_test); - ATF_TP_ADD_TC(tp, aio_md_test); + ATF_TP_ADD_TC(tp, file_poll); + ATF_TP_ADD_TC(tp, file_suspend); + ATF_TP_ADD_TC(tp, file_waitcomplete); + ATF_TP_ADD_TC(tp, fifo_poll); + ATF_TP_ADD_TC(tp, fifo_suspend); + ATF_TP_ADD_TC(tp, fifo_waitcomplete); + ATF_TP_ADD_TC(tp, socket_poll); + ATF_TP_ADD_TC(tp, socket_suspend); + ATF_TP_ADD_TC(tp, socket_waitcomplete); + ATF_TP_ADD_TC(tp, pty_poll); + ATF_TP_ADD_TC(tp, pty_suspend); + ATF_TP_ADD_TC(tp, pty_waitcomplete); + ATF_TP_ADD_TC(tp, pipe_poll); + ATF_TP_ADD_TC(tp, pipe_suspend); + ATF_TP_ADD_TC(tp, pipe_waitcomplete); + ATF_TP_ADD_TC(tp, md_poll); + ATF_TP_ADD_TC(tp, md_suspend); + ATF_TP_ADD_TC(tp, md_waitcomplete); ATF_TP_ADD_TC(tp, aio_large_read_test); ATF_TP_ADD_TC(tp, aio_socket_two_reads); ATF_TP_ADD_TC(tp, aio_socket_blocking_short_write); |