git: dfd704b7fb2c - main - Allow biodone() to be used as a completion routine.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 24 Oct 2021 04:11:34 UTC
The branch main has been updated by mckusick:
URL: https://cgit.FreeBSD.org/src/commit/?id=dfd704b7fb2c81f290e1d62db081416bae0d83d3
commit dfd704b7fb2c81f290e1d62db081416bae0d83d3
Author: Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2021-10-23 14:25:49 +0000
Commit: Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2021-10-23 21:11:57 +0000
Allow biodone() to be used as a completion routine.
An ordered series of BIO_READ and BIO_WRITE operations are
typically done as:
while (work to do) {
setup bp for I/O
g_io_request(bp, consumer);
biowait(bp);
}
Here you need to have biodone() called at the completion of
the I/O to set the BIO_DONE flag and awaken the biowait(). The
obvious way to do this would be to set bio_done = biodone, but
biodone() will only take the desired action if bio_done == NULL.
The relevant code at the end of biodone() is:
done = bp->bio_done;
if (done == NULL) {
mtxp = mtx_pool_find(mtxpool_sleep, bp);
mtx_lock(mtxp);
bp->bio_flags |= BIO_DONE;
wakeup(bp);
mtx_unlock(mtxp);
} else
done(bp);
This code would infinitely recurse if biodone() is specified as the
routine to use at completion. So before this change, a wrapper done
function had to be written:
static void
g_io_done(struct bio *bp)
{
bp->bio_done = NULL;
biodone(bp);
bp->bio_done = g_io_done;
}
This commit changes
if (done == NULL)
to
if (done == NULL || done == biodone)
which eliminates the need for the wrapper function.
Reviewed by: kib
Sponsored by: Netflix
---
sys/kern/vfs_bio.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 352c341d05f7..034bbccc437d 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -4384,7 +4384,11 @@ biodone(struct bio *bp)
atomic_add_int(&inflight_transient_maps, -1);
}
done = bp->bio_done;
- if (done == NULL) {
+ /*
+ * The check for done == biodone is to allow biodone to be
+ * used as a bio_done routine.
+ */
+ if (done == NULL || done == biodone) {
mtxp = mtx_pool_find(mtxpool_sleep, bp);
mtx_lock(mtxp);
bp->bio_flags |= BIO_DONE;