git: dfd704b7fb2c - main - Allow biodone() to be used as a completion routine.

From: Kirk McKusick <mckusick_at_FreeBSD.org>
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;