The branch main has been updated by kib:

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

commit bf0db19339e770a82236b74f523be4b572bde15d
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2021-01-30 02:10:34 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2021-02-12 01:02:19 +0000

    buf SU hooks: track buf_start() calls with B_IOSTARTED flag
    
    and only call buf_complete() if previously started.  Some error paths,
    like CoW failire, might skip buf_start() and do bufdone(), which itself
    call buf_complete().
    
    Various SU handle_written_XXX() functions check that io was started
    and incomplete parts of the buffer data reverted before restoring them.
    This is a useful invariant that B_IO_STARTED on buffer layer allows to
    keep instead of changing check and panic into check and return.
    
    Reported by:    pho
    Reviewed by:    chs, mckusick
    Tested by:      pho
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundations
---
 sys/kern/vfs_bio.c       | 14 ++++++++++++++
 sys/sys/buf.h            | 16 +++++++++++-----
 sys/ufs/ffs/ffs_vfsops.c |  4 ++--
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index ff25e5b0043c..45be14b47207 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -2639,6 +2639,13 @@ brelse(struct buf *bp)
                return;
        }
 
+       if (LIST_EMPTY(&bp->b_dep)) {
+               bp->b_flags &= ~B_IOSTARTED;
+       } else {
+               KASSERT((bp->b_flags & B_IOSTARTED) == 0,
+                   ("brelse: SU io not finished bp %p", bp));
+       }
+
        if ((bp->b_vflags & (BV_BKGRDINPROG | BV_BKGRDERR)) == BV_BKGRDERR) {
                BO_LOCK(bp->b_bufobj);
                bp->b_vflags &= ~BV_BKGRDERR;
@@ -2826,6 +2833,13 @@ bqrelse(struct buf *bp)
        bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF);
        bp->b_xflags &= ~(BX_CVTENXIO);
 
+       if (LIST_EMPTY(&bp->b_dep)) {
+               bp->b_flags &= ~B_IOSTARTED;
+       } else {
+               KASSERT((bp->b_flags & B_IOSTARTED) == 0,
+                   ("bqrelse: SU io not finished bp %p", bp));
+       }
+
        if (bp->b_flags & B_MANAGED) {
                if (bp->b_flags & B_REMFREE)
                        bremfreef(bp);
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index 50fa0f35491e..2997560b9ab3 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -232,7 +232,7 @@ struct buf {
 #define        B_MALLOC        0x00010000      /* malloced b_data */
 #define        B_CLUSTEROK     0x00020000      /* Pagein op, so swap() can 
count it. */
 #define        B_INVALONERR    0x00040000      /* Invalidate on write error. */
-#define        B_00080000      0x00080000      /* Available flag. */
+#define        B_IOSTARTED     0x00080000      /* buf_start() called */
 #define        B_00100000      0x00100000      /* Available flag. */
 #define        B_MAXPHYS       0x00200000      /* nitems(b_pages[]) = 
atop(MAXPHYS). */
 #define        B_RELBUF        0x00400000      /* Release VMIO buffer. */
@@ -248,8 +248,8 @@ struct buf {
 
 #define PRINT_BUF_FLAGS "\20\40remfree\37cluster\36vmio\35ram\34managed" \
        "\33paging\32infreecnt\31nocopy\30b23\27relbuf\26maxphys\25b20" \
-       "\24b19\23invalonerr\22clusterok\21malloc\20nocache\17b14\16inval" \
-       "\15reuse\14noreuse\13eintr\12done\11b8\10delwri" \
+       "\24iostarted\23invalonerr\22clusterok\21malloc\20nocache\17b14" \
+       "\16inval\15reuse\14noreuse\13eintr\12done\11b8\10delwri" \
        "\7validsuspwrt\6cache\5deferred\4direct\3async\2needcommit\1age"
 
 /*
@@ -434,6 +434,9 @@ bstrategy(struct buf *bp)
 static __inline void
 buf_start(struct buf *bp)
 {
+       KASSERT((bp->b_flags & B_IOSTARTED) == 0,
+           ("recursed buf_start %p", bp));
+       bp->b_flags |= B_IOSTARTED;
        if (bioops.io_start)
                (*bioops.io_start)(bp);
 }
@@ -441,8 +444,11 @@ buf_start(struct buf *bp)
 static __inline void
 buf_complete(struct buf *bp)
 {
-       if (bioops.io_complete)
-               (*bioops.io_complete)(bp);
+       if ((bp->b_flags & B_IOSTARTED) != 0) {
+               bp->b_flags &= ~B_IOSTARTED;
+               if (bioops.io_complete)
+                       (*bioops.io_complete)(bp);
+       }
 }
 
 static __inline void
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 60d4dad57d03..04afbfd4d6e4 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -2393,10 +2393,10 @@ ffs_backgroundwritedone(struct buf *bp)
 #endif
        /*
         * This buffer is marked B_NOCACHE so when it is released
-        * by biodone it will be tossed.
+        * by biodone it will be tossed.  Clear B_IOSTARTED in case of error.
         */
        bp->b_flags |= B_NOCACHE;
-       bp->b_flags &= ~B_CACHE;
+       bp->b_flags &= ~(B_CACHE | B_IOSTARTED);
        pbrelvp(bp);
 
        /*
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to