The branch main has been updated by mckusick:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=dfd704b7fb2c81f290e1d62db081416bae0d83d3

commit dfd704b7fb2c81f290e1d62db081416bae0d83d3
Author:     Kirk McKusick <mckus...@freebsd.org>
AuthorDate: 2021-10-23 14:25:49 +0000
Commit:     Kirk McKusick <mckus...@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;

Reply via email to