X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=linux%2Fblkdev.c;h=709e770345f925e31101a82ea3bd5366525bb848;hb=98844616f65bee09eda791353a09b2d195f71270;hp=8139e18d3b95999d8604936b3b31c0471c9d75d5;hpb=e1ed5557bf93030017af8a866a6abb2f98c87bca;p=bcachefs-tools-debian diff --git a/linux/blkdev.c b/linux/blkdev.c index 8139e18..709e770 100644 --- a/linux/blkdev.c +++ b/linux/blkdev.c @@ -10,7 +10,9 @@ #include +#ifdef CONFIG_VALGRIND #include +#endif #include #include @@ -21,6 +23,7 @@ #include "tools-util.h" static io_context_t aio_ctx; +static atomic_t running_requests; void generic_make_request(struct bio *bio) { @@ -56,9 +59,11 @@ void generic_make_request(struct bio *bio) .iov_len = len, }; +#ifdef CONFIG_VALGRIND /* To be pedantic it should only be on IO completion. */ if (bio_op(bio) == REQ_OP_READ) VALGRIND_MAKE_MEM_DEFINED(start, len); +#endif } struct iocb iocb = { @@ -75,6 +80,7 @@ void generic_make_request(struct bio *bio) iocb.u.v.nr = i; iocb.u.v.offset = bio->bi_iter.bi_sector << 9; + atomic_inc(&running_requests); ret = io_submit(aio_ctx, 1, &iocbp); if (ret != 1) die("io_submit err: %s", strerror(-ret)); @@ -85,6 +91,7 @@ void generic_make_request(struct bio *bio) iocb.u.v.nr = i; iocb.u.v.offset = bio->bi_iter.bi_sector << 9; + atomic_inc(&running_requests); ret = io_submit(aio_ctx, 1, &iocbp); if (ret != 1) die("io_submit err: %s", strerror(-ret)); @@ -232,8 +239,9 @@ static int aio_completion_thread(void *arg) { struct io_event events[8], *ev; int ret; + bool stop = false; - while (1) { + while (!stop) { ret = io_getevents(aio_ctx, 1, ARRAY_SIZE(events), events, NULL); @@ -245,16 +253,26 @@ static int aio_completion_thread(void *arg) for (ev = events; ev < events + ret; ev++) { struct bio *bio = (struct bio *) ev->data; + /* This should only happen during blkdev_cleanup() */ + if (!bio) { + BUG_ON(atomic_read(&running_requests) != 0); + stop = true; + continue; + } + if (ev->res != bio->bi_iter.bi_size) bio->bi_status = BLK_STS_IOERR; bio_endio(bio); + atomic_dec(&running_requests); } } return 0; } +static struct task_struct *aio_task = NULL; + __attribute__((constructor(102))) static void blkdev_init(void) { @@ -265,4 +283,41 @@ static void blkdev_init(void) p = kthread_run(aio_completion_thread, NULL, "aio_completion"); BUG_ON(IS_ERR(p)); + + aio_task = p; +} + +__attribute__((destructor(102))) +static void blkdev_cleanup(void) +{ + struct task_struct *p = NULL; + swap(aio_task, p); + get_task_struct(p); + + /* I mean, really?! IO_CMD_NOOP is even defined, but not implemented. */ + int fds[2]; + int ret = pipe(fds); + if (ret != 0) + die("pipe err: %s", strerror(ret)); + + /* Wake up the completion thread with spurious work. */ + int junk = 0; + struct iocb iocb = { + .aio_lio_opcode = IO_CMD_PWRITE, + .data = NULL, /* Signal to stop */ + .aio_fildes = fds[1], + .u.c.buf = &junk, + .u.c.nbytes = 1, + }, *iocbp = &iocb; + ret = io_submit(aio_ctx, 1, &iocbp); + if (ret != 1) + die("io_submit cleanup err: %s", strerror(-ret)); + + ret = kthread_stop(p); + BUG_ON(ret); + + put_task_struct(p); + + close(fds[0]); + close(fds[1]); }