From owner-svn-src-all@freebsd.org Sat Apr 16 00:01:17 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id BD7A0AED26E; Sat, 16 Apr 2016 00:01:17 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 744CB1C11; Sat, 16 Apr 2016 00:01:17 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u3G01G1O041080; Sat, 16 Apr 2016 00:01:16 GMT (envelope-from jhb@FreeBSD.org) Received: (from jhb@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u3G01GiA041079; Sat, 16 Apr 2016 00:01:16 GMT (envelope-from jhb@FreeBSD.org) Message-Id: <201604160001.u3G01GiA041079@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jhb set sender to jhb@FreeBSD.org using -f From: John Baldwin Date: Sat, 16 Apr 2016 00:01:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298090 - head/tests/sys/aio X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 16 Apr 2016 00:01:17 -0000 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()); }