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
This commit is contained in:
John Baldwin 2016-04-16 00:01:16 +00:00
parent 80c7cc1c8f
commit d1ad1a7394
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=298090

View File

@ -722,6 +722,65 @@ ATF_TC_BODY(aio_large_read_test, tc)
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());
}