summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2017-05-30 03:09:01 +0000
committerngie <ngie@FreeBSD.org>2017-05-30 03:09:01 +0000
commite998daeb8b5f271fd1713c069a5626be410a8e10 (patch)
tree57d354dd25c273f6b4ea134782eb80efc43491a8 /tests
parent6932de11ab5641f9c4a00a5be42b2a3b55c6d81c (diff)
downloadFreeBSD-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')
-rw-r--r--tests/sys/aio/aio_test.c341
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);
OpenPOWER on IntegriCloud