Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Apr 2016 00:01:16 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r298090 - head/tests/sys/aio
Message-ID:  <201604160001.u3G01GiA041079@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Sat Apr 16 00:01:16 2016
New Revision: 298090
URL: https://svnweb.freebsd.org/changeset/base/298090

Log:
  Add a test for cancelling an active AIO request on a socket.
  
  The older AIO code awakened all pending AIO requests on a socket
  when any data arrived.  This could result in AIO daemons blocking on
  an empty socket buffer.  These requests could not be cancelled
  which led to a deadlock during process exit.  This test reproduces
  this case.  The newer AIO code is able to cancel the pending AIO
  request correctly.
  
  Reviewed by:	ngie (-ish)
  Sponsored by:	Chelsio Communications
  Differential Revision:	https://reviews.freebsd.org/D4363

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

Modified: head/tests/sys/aio/aio_test.c
==============================================================================
--- head/tests/sys/aio/aio_test.c	Fri Apr 15 22:31:22 2016	(r298089)
+++ head/tests/sys/aio/aio_test.c	Sat Apr 16 00:01:16 2016	(r298090)
@@ -722,6 +722,65 @@ finished:
 	close(fd);
 }
 
+/*
+ * This tests for a bug where arriving socket data can wakeup multiple
+ * AIO read requests resulting in an uncancellable request.
+ */
+ATF_TC_WITHOUT_HEAD(aio_socket_two_reads);
+ATF_TC_BODY(aio_socket_two_reads, tc)
+{
+	struct ioreq {
+		struct aiocb iocb;
+		char buffer[1024];
+	} ioreq[2];
+	struct aiocb *iocb;
+	unsigned i;
+	int s[2];
+	char c;
+
+	ATF_REQUIRE_KERNEL_MODULE("aio");
+#if __FreeBSD_version < 1100101
+	aft_tc_skip("kernel version %d is too old (%d required)",
+	    __FreeBSD_version, 1100101);
+#endif
+
+	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) != -1);
+
+	/* Queue two read requests. */
+	memset(&ioreq, 0, sizeof(ioreq));
+	for (i = 0; i < nitems(ioreq); i++) {
+		ioreq[i].iocb.aio_nbytes = sizeof(ioreq[i].buffer);
+		ioreq[i].iocb.aio_fildes = s[0];
+		ioreq[i].iocb.aio_buf = ioreq[i].buffer;
+		ATF_REQUIRE(aio_read(&ioreq[i].iocb) == 0);
+	}
+
+	/* Send a single byte.  This should complete one request. */
+	c = 0xc3;
+	ATF_REQUIRE(write(s[1], &c, sizeof(c)) == 1);
+
+	ATF_REQUIRE(aio_waitcomplete(&iocb, NULL) == 1);
+
+	/* Determine which request completed and verify the data was read. */
+	if (iocb == &ioreq[0].iocb)
+		i = 0;
+	else
+		i = 1;
+	ATF_REQUIRE(ioreq[i].buffer[0] == c);
+
+	i ^= 1;
+
+	/*
+	 * Try to cancel the other request.  On broken systems this
+	 * will fail and the process will hang on exit.
+	 */
+	ATF_REQUIRE(aio_error(&ioreq[i].iocb) == EINPROGRESS);
+	ATF_REQUIRE(aio_cancel(s[0], &ioreq[i].iocb) == AIO_CANCELED);
+
+	close(s[1]);
+	close(s[0]);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 
@@ -732,6 +791,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, aio_pipe_test);
 	ATF_TP_ADD_TC(tp, aio_md_test);
 	ATF_TP_ADD_TC(tp, aio_large_read_test);
+	ATF_TP_ADD_TC(tp, aio_socket_two_reads);
 
 	return (atf_no_error());
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604160001.u3G01GiA041079>