svn commit: r312913 - head/tests/sys/aio

Alan Somers asomers at FreeBSD.org
Sat Jan 28 04:33:52 UTC 2017


Author: asomers
Date: Sat Jan 28 04:33:51 2017
New Revision: 312913
URL: https://svnweb.freebsd.org/changeset/base/312913

Log:
  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.
  
  Reviewed by:	jhb
  MFC after:	4 weeks
  Differential Revision:	https://reviews.freebsd.org/D9045

Modified:
  head/tests/sys/aio/aio_test.c

Modified: head/tests/sys/aio/aio_test.c
==============================================================================
--- head/tests/sys/aio/aio_test.c	Sat Jan 28 03:53:53 2017	(r312912)
+++ head/tests/sys/aio/aio_test.c	Sat Jan 28 04:33:51 2017	(r312913)
@@ -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.
  */
@@ -74,6 +74,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 +186,45 @@ aio_context_init(struct aio_context *ac,
 	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 +247,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 +271,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 +296,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 +314,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 +357,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 +371,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 +384,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 +433,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 +461,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 +473,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 +513,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 +533,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 +546,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 +581,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 +615,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 +650,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 +664,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 +724,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 +765,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 +832,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 +1079,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 +1086,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 +1149,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);


More information about the svn-src-head mailing list