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:
parent
80c7cc1c8f
commit
d1ad1a7394
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=298090
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user