An inflight async io could keep the filesystem busy and cause umount -EBUSY errors after process exit. When the async io process is killed forcibly with SIGKILL, it doesn't get a chance to wait for ios to complete. With this patch, instead of killing the children processes, we let them exit on their own after the timeout expires. Signed-off-by: Tahsin Erdogan <tahsin@xxxxxxxxxx> --- src/aio-dio-regress/aio-dio-invalidate-failure.c | 89 ++++++++++++++---------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/aio-dio-regress/aio-dio-invalidate-failure.c b/src/aio-dio-regress/aio-dio-invalidate-failure.c index 24f3e3c..474a83c 100644 --- a/src/aio-dio-regress/aio-dio-invalidate-failure.c +++ b/src/aio-dio-regress/aio-dio-invalidate-failure.c @@ -62,6 +62,26 @@ static unsigned char buf[GINORMOUS] __attribute((aligned (4096))); exit(1); \ } while (0) + +volatile int timeout_reached = 0; + +static void alarm_handler(int signum) +{ + timeout_reached = 1; +} + +void set_timeout(unsigned int seconds) +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = alarm_handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGALRM, &sa, NULL) == -1) + fail("sigaction: %d\n", errno); + + alarm(seconds); +} + void spin_dio(int fd) { io_context_t ctx; @@ -70,18 +90,28 @@ void spin_dio(int fd) struct io_event event; int ret; + set_timeout(SECONDS); + io_prep_pwrite(&iocb, fd, buf, GINORMOUS, 0); ret = io_queue_init(1, &ctx); if (ret) fail("io_queue_init returned %d", ret); - while (1) { + while (!timeout_reached) { ret = io_submit(ctx, 1, iocbs); if (ret != 1) fail("io_submit returned %d instead of 1", ret); - ret = io_getevents(ctx, 1, 1, &event, NULL); + /* + * Retry io_getevents() if it gets interrupted by alarm signal. + * We don't want to leave behind uncompleted async io requests + * that could cause umount -EBUSY errors. + */ + do { + ret = io_getevents(ctx, 1, 1, &event, NULL); + } while (ret == -EINTR && timeout_reached); + if (ret != 1) fail("io_getevents returned %d instead of 1", ret); @@ -99,17 +129,15 @@ void spin_buffered(int fd) { int ret; - while (1) { + set_timeout(SECONDS); + + while (!timeout_reached) { ret = pwrite(fd, buf, GINORMOUS, 0); if (ret != GINORMOUS) fail("buffered write returned %d", ret); } } -static void alarm_handler(int signum) -{ -} - int main(int argc, char **argv) { pid_t buffered_pid; @@ -118,7 +146,8 @@ int main(int argc, char **argv) int fd; int fd2; int status; - struct sigaction sa; + int dio_exit; + int buffered_exit; if (argc != 2) fail("only arg should be file name"); @@ -152,38 +181,28 @@ int main(int argc, char **argv) exit(0); } - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = alarm_handler; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGALRM, &sa, NULL) == -1) - fail("sigaction: %d\n", errno); - alarm(SECONDS); + /* Child processes will exit on their own when timeout expires. */ + pid = waitpid(dio_pid, &status, 0); + printf("dio_pid %d, pid %d, status %#x\n", dio_pid, pid, status); - pid = wait(&status); - if (pid < 0 && errno == EINTR) { - /* if we timed out then we're done */ - kill(buffered_pid, SIGKILL); - kill(dio_pid, SIGKILL); + dio_exit = (pid == dio_pid && WIFEXITED(status)) ? + WEXITSTATUS(status) : 1; - waitpid(buffered_pid, NULL, 0); - waitpid(dio_pid, NULL, 0); + pid = waitpid(buffered_pid, &status, 0); + printf("buffered_pid %d, pid %d, status %#x\n", buffered_pid, pid, status); - printf("ran for %d seconds without error, passing\n", SECONDS); - exit(0); - } + buffered_exit = (pid == buffered_pid && WIFEXITED(status)) ? + WEXITSTATUS(status) : 1; - if (pid == dio_pid) { - kill(buffered_pid, SIGKILL); - waitpid(buffered_pid, NULL, 0); - } else { - kill(dio_pid, SIGKILL); - waitpid(dio_pid, NULL, 0); + if (dio_exit || buffered_exit) { + /* + * pass on the child's pass/fail return code or fail if the + * child didn't exit cleanly. + */ + exit(dio_exit || buffered_exit); } - /* - * pass on the child's pass/fail return code or fail if the child - * didn't exit cleanly. - */ - exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1); + printf("ran for %d seconds without error, passing\n", SECONDS); + exit(0); } -- 2.8.0.rc3.226.g39d4020 -- To unsubscribe from this list: send the line "unsubscribe fstests" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html