git: 28f957b8b3a2 - main - vnode_pager_input: return runningbufspace back

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 25 Mar 2023 22:55:49 UTC
The branch main has been updated by kib:

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

commit 28f957b8b3a22086927451fee89789fdf596260b
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-03-24 21:12:21 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-03-25 22:55:29 +0000

    vnode_pager_input: return runningbufspace back
    
    Both vnode_pager_input_smlfs() and vnode_pager_generic_getpages()
    increment runningbufspace, but also both delegate io completion handling
    on the pbuf to either plain bdone() or filesystem-specific strategy
    routine. Accidentally, for e.g. UFS it is g_vfs_strategy()/g_vfs_done().
    The later calls bufdone() which handles runningbufspace reclamation.
    
    For plain bdone() io done handler, nothing would return
    accounted b_runningbufspace back. Do it in the new
    helper vnode_pager_input_bdone(), as well as in
    vnode_pager_generic_getpages_done() explicitly.
    
    Note that potential multiple calls to runningbufwakeup() for the same
    pbuf or buf completion are safe. runningbufwakeup() clears accounting
    for the buffer, so second and later calls are nop.
    
    The problem was found due to tarfs using small vnode pager input but not
    g_vfs_strategy().
    
    Reported by:    des
    Reviewed by:    markj, sjg
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D39263
---
 sys/vm/vnode_pager.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 56caf75d7f90..6103daaf13c2 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -640,6 +640,13 @@ vnode_pager_addr(struct vnode *vp, vm_ooffset_t address, daddr_t *rtaddress,
 	return (err);
 }
 
+static void
+vnode_pager_input_bdone(struct buf *bp)
+{
+	runningbufwakeup(bp);
+	bdone(bp);
+}
+
 /*
  * small block filesystem vnode pager input
  */
@@ -686,7 +693,7 @@ vnode_pager_input_smlfs(vm_object_t object, vm_page_t m)
 
 			/* build a minimal buffer header */
 			bp->b_iocmd = BIO_READ;
-			bp->b_iodone = bdone;
+			bp->b_iodone = vnode_pager_input_bdone;
 			KASSERT(bp->b_rcred == NOCRED, ("leaking read ucred"));
 			KASSERT(bp->b_wcred == NOCRED, ("leaking write ucred"));
 			bp->b_rcred = crhold(curthread->td_ucred);
@@ -1204,6 +1211,8 @@ vnode_pager_generic_getpages_done(struct buf *bp)
 	error = (bp->b_ioflags & BIO_ERROR) != 0 ? bp->b_error : 0;
 	object = bp->b_vp->v_object;
 
+	runningbufwakeup(bp);
+
 	if (error == 0 && bp->b_bcount != bp->b_npages * PAGE_SIZE) {
 		if (!buf_mapped(bp)) {
 			bp->b_data = bp->b_kvabase;