Changeset View
Changeset View
Standalone View
Standalone View
tests/sys/aio/aio_test.c
Show First 20 Lines • Show All 1,049 Lines • ▼ Show 20 Lines | ATF_TC_BODY(aio_fsync_errors, tc) | ||||
ATF_REQUIRE_KERNEL_MODULE("aio"); | ATF_REQUIRE_KERNEL_MODULE("aio"); | ||||
ATF_REQUIRE_UNSAFE_AIO(); | ATF_REQUIRE_UNSAFE_AIO(); | ||||
fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600); | fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600); | ||||
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); | ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); | ||||
unlink(FILE_PATHNAME); | unlink(FILE_PATHNAME); | ||||
/* aio_fsync should return EINVAL unless op is O_SYNC */ | /* aio_fsync should return EINVAL unless op is O_SYNC or O_DSYNC */ | ||||
memset(&iocb, 0, sizeof(iocb)); | memset(&iocb, 0, sizeof(iocb)); | ||||
iocb.aio_fildes = fd; | iocb.aio_fildes = fd; | ||||
ATF_CHECK_EQ(-1, aio_fsync(666, &iocb)); | ATF_CHECK_EQ(-1, aio_fsync(666, &iocb)); | ||||
ATF_CHECK_EQ(EINVAL, errno); | ATF_CHECK_EQ(EINVAL, errno); | ||||
/* aio_fsync should return EBADF if fd is not a valid descriptor */ | /* aio_fsync should return EBADF if fd is not a valid descriptor */ | ||||
memset(&iocb, 0, sizeof(iocb)); | memset(&iocb, 0, sizeof(iocb)); | ||||
iocb.aio_fildes = 666; | iocb.aio_fildes = 666; | ||||
ATF_CHECK_EQ(-1, aio_fsync(O_SYNC, &iocb)); | ATF_CHECK_EQ(-1, aio_fsync(O_SYNC, &iocb)); | ||||
ATF_CHECK_EQ(EBADF, errno); | ATF_CHECK_EQ(EBADF, errno); | ||||
/* aio_fsync should return EINVAL if sigev_notify is invalid */ | /* aio_fsync should return EINVAL if sigev_notify is invalid */ | ||||
memset(&iocb, 0, sizeof(iocb)); | memset(&iocb, 0, sizeof(iocb)); | ||||
iocb.aio_fildes = fd; | iocb.aio_fildes = fd; | ||||
iocb.aio_sigevent.sigev_notify = 666; | iocb.aio_sigevent.sigev_notify = 666; | ||||
ATF_CHECK_EQ(-1, aio_fsync(666, &iocb)); | ATF_CHECK_EQ(-1, aio_fsync(666, &iocb)); | ||||
ATF_CHECK_EQ(EINVAL, errno); | ATF_CHECK_EQ(EINVAL, errno); | ||||
} | } | ||||
struct aio_buffer { | |||||
struct aiocb ab_iocb; | |||||
bool ab_done; | |||||
char *ab_buffer; | |||||
}; | |||||
static void | |||||
queue_random_writes(struct aio_buffer *buffers, size_t nbuffers, | |||||
size_t blksize, int fd) | |||||
{ | |||||
size_t i; | |||||
for (i = 0; i < nbuffers; i++) { | |||||
buffers[i].ab_done = false; | |||||
memset(&buffers[i].ab_iocb, 0, sizeof(buffers[i].ab_iocb)); | |||||
buffers[i].ab_buffer = malloc(blksize); | |||||
aio_fill_buffer(buffers[i].ab_buffer, blksize, random()); | |||||
buffers[i].ab_iocb.aio_fildes = fd; | |||||
buffers[i].ab_iocb.aio_buf = buffers[i].ab_buffer; | |||||
buffers[i].ab_iocb.aio_nbytes = blksize; | |||||
buffers[i].ab_iocb.aio_offset = blksize * i; | |||||
ATF_REQUIRE(aio_write(&buffers[i].ab_iocb) == 0); | |||||
} | |||||
} | |||||
static void | |||||
check_fsync_completion(struct aio_buffer *buffers, size_t nbuffers, | |||||
size_t blksize, struct aiocb *synccb) | |||||
{ | |||||
struct aiocb *iocbp; | |||||
ssize_t rval; | |||||
size_t i; | |||||
for (;;) { | |||||
next: | |||||
rval = aio_waitcomplete(&iocbp, NULL); | |||||
ATF_REQUIRE(iocbp != NULL); | |||||
/* If it was the sync, then we are done. */ | |||||
if (iocbp == synccb) { | |||||
ATF_REQUIRE(rval == 0); | |||||
break; | |||||
} | |||||
/* A write: find it and mark it completed. */ | |||||
for (i = 0; i < nbuffers; i++) { | |||||
if (iocbp == &buffers[i].ab_iocb) { | |||||
ATF_REQUIRE(buffers[i].ab_done == false); | |||||
ATF_REQUIRE(rval == (ssize_t)blksize); | |||||
buffers[i].ab_done = true; | |||||
goto next; | |||||
} | |||||
} | |||||
ATF_REQUIRE_MSG(false, "unmatched AIO request"); | |||||
} | |||||
/* Writes should have completed before the sync did. */ | |||||
for (i = 0; i < nbuffers; i++) { | |||||
ATF_REQUIRE_MSG(buffers[i].ab_done, | |||||
"AIO request %zu did not complete", i); | |||||
free(buffers[i].ab_buffer); | |||||
} | |||||
} | |||||
static void | |||||
queue_fsync(int op, int fd, struct aiocb *synccb) | |||||
{ | |||||
memset(synccb, 0, sizeof(*synccb)); | |||||
synccb->aio_fildes = fd; | |||||
ATF_REQUIRE(aio_fsync(op, synccb) == 0); | |||||
} | |||||
/* | /* | ||||
* This test just performs a basic test of aio_fsync(). | * This test just performs a basic test of aio_fsync(). | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(aio_fsync_test); | ATF_TC_WITHOUT_HEAD(aio_fsync_test); | ||||
ATF_TC_BODY(aio_fsync_test, tc) | ATF_TC_BODY(aio_fsync_test, tc) | ||||
{ | { | ||||
struct aiocb synccb, *iocbp; | struct aiocb synccb; | ||||
struct { | struct aio_buffer buffers[16]; | ||||
struct aiocb iocb; | |||||
bool done; | |||||
char *buffer; | |||||
} buffers[16]; | |||||
struct stat sb; | struct stat sb; | ||||
ssize_t rval; | |||||
unsigned i; | |||||
int fd; | int fd; | ||||
ATF_REQUIRE_KERNEL_MODULE("aio"); | ATF_REQUIRE_KERNEL_MODULE("aio"); | ||||
ATF_REQUIRE_UNSAFE_AIO(); | ATF_REQUIRE_UNSAFE_AIO(); | ||||
fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600); | fd = open(FILE_PATHNAME, O_RDWR | O_CREAT, 0600); | ||||
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); | ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); | ||||
unlink(FILE_PATHNAME); | unlink(FILE_PATHNAME); | ||||
ATF_REQUIRE(fstat(fd, &sb) == 0); | ATF_REQUIRE(fstat(fd, &sb) == 0); | ||||
ATF_REQUIRE(sb.st_blksize != 0); | ATF_REQUIRE(sb.st_blksize != 0); | ||||
ATF_REQUIRE(ftruncate(fd, sb.st_blksize * nitems(buffers)) == 0); | ATF_REQUIRE(ftruncate(fd, sb.st_blksize * nitems(buffers)) == 0); | ||||
srandomdev(); | |||||
/* | /* | ||||
* Queue several asynchronous write requests. Hopefully this | * Queue several asynchronous write requests. Hopefully this | ||||
* forces the aio_fsync() request to be deferred. There is no | * forces the aio_fsync() request to be deferred. There is no | ||||
* reliable way to guarantee that however. | * reliable way to guarantee that however. | ||||
*/ | */ | ||||
srandomdev(); | queue_random_writes(buffers, nitems(buffers), sb.st_blksize, fd); | ||||
asomers: This test is doing way too much stuff now. You should split it into two test cases. And it… | |||||
Not Done Inline ActionsWhat do you think about this refactoring? tmunro: What do you think about this refactoring? | |||||
Not Done Inline ActionsIt certainly reduces line count. But my bigger point was that there's too much stuff happening in that one ATF test case. I think you should split the test case into two. asomers: It certainly reduces line count. But my bigger point was that there's too much stuff happening… | |||||
Not Done Inline ActionsI agree that the refactoring is good, and that it would be better to use two test cases: 1 for O_SYNC and 1 for O_DSYNC. jhb: I agree that the refactoring is good, and that it would be better to use two test cases: 1 for… | |||||
for (i = 0; i < nitems(buffers); i++) { | queue_fsync(O_SYNC, fd, &synccb); | ||||
buffers[i].done = false; | check_fsync_completion(buffers, nitems(buffers), sb.st_blksize, &synccb); | ||||
memset(&buffers[i].iocb, 0, sizeof(buffers[i].iocb)); | |||||
buffers[i].buffer = malloc(sb.st_blksize); | |||||
aio_fill_buffer(buffers[i].buffer, sb.st_blksize, random()); | |||||
buffers[i].iocb.aio_fildes = fd; | |||||
buffers[i].iocb.aio_buf = buffers[i].buffer; | |||||
buffers[i].iocb.aio_nbytes = sb.st_blksize; | |||||
buffers[i].iocb.aio_offset = sb.st_blksize * i; | |||||
ATF_REQUIRE(aio_write(&buffers[i].iocb) == 0); | |||||
} | |||||
/* Queue the aio_fsync request. */ | /* Same again, but this time with O_DSYNC. */ | ||||
memset(&synccb, 0, sizeof(synccb)); | queue_random_writes(buffers, nitems(buffers), sb.st_blksize, fd); | ||||
synccb.aio_fildes = fd; | queue_fsync(O_DSYNC, fd, &synccb); | ||||
ATF_REQUIRE(aio_fsync(O_SYNC, &synccb) == 0); | check_fsync_completion(buffers, nitems(buffers), sb.st_blksize, &synccb); | ||||
/* Wait for requests to complete. */ | |||||
for (;;) { | |||||
next: | |||||
rval = aio_waitcomplete(&iocbp, NULL); | |||||
ATF_REQUIRE(iocbp != NULL); | |||||
if (iocbp == &synccb) { | |||||
ATF_REQUIRE(rval == 0); | |||||
break; | |||||
} | |||||
for (i = 0; i < nitems(buffers); i++) { | |||||
if (iocbp == &buffers[i].iocb) { | |||||
ATF_REQUIRE(buffers[i].done == false); | |||||
ATF_REQUIRE(rval == sb.st_blksize); | |||||
buffers[i].done = true; | |||||
goto next; | |||||
} | |||||
} | |||||
ATF_REQUIRE_MSG(false, "unmatched AIO request"); | |||||
} | |||||
for (i = 0; i < nitems(buffers); i++) | |||||
ATF_REQUIRE_MSG(buffers[i].done, | |||||
"AIO request %u did not complete", i); | |||||
close(fd); | close(fd); | ||||
} | } | ||||
ATF_TP_ADD_TCS(tp) | ATF_TP_ADD_TCS(tp) | ||||
{ | { | ||||
ATF_TP_ADD_TC(tp, file_poll); | ATF_TP_ADD_TC(tp, file_poll); | ||||
Show All 38 Lines |
This test is doing way too much stuff now. You should split it into two test cases. And it should be possible to share most of the code, rather than copy it.