Date: Sun, 27 Sep 2015 05:16:07 +0000 (UTC) From: Jeff Roberson <jeff@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r288299 - head/sys/kern Message-ID: <201509270516.t8R5G7s2091316@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jeff Date: Sun Sep 27 05:16:06 2015 New Revision: 288299 URL: https://svnweb.freebsd.org/changeset/base/288299 Log: - Collapse vfs_vmio_truncate & vfs_vmio_release into a single function. - Allow vfs_vmio_invalidate() to free the pages, leaving us with a single loop and bufobj lock when B_NOCACHE/B_INVAL is used. - Eliminate the special B_ASYNC handling on free that has not been relevant for some time. - Remove the extraneous page busy from vfs_vmio_truncate(). Reviewed by: kib Tested by: pho Sponsored by: EMC / Isilon storage division Modified: head/sys/kern/vfs_bio.c Modified: head/sys/kern/vfs_bio.c ============================================================================== --- head/sys/kern/vfs_bio.c Sun Sep 27 04:55:43 2015 (r288298) +++ head/sys/kern/vfs_bio.c Sun Sep 27 05:16:06 2015 (r288299) @@ -111,7 +111,6 @@ static void vfs_page_set_validclean(stru static void vfs_clean_pages_dirty_buf(struct buf *bp); static void vfs_setdirty_locked_object(struct buf *bp); static void vfs_vmio_invalidate(struct buf *bp); -static void vfs_vmio_release(struct buf *bp); static void vfs_vmio_truncate(struct buf *bp, int npages); static void vfs_vmio_extend(struct buf *bp, int npages, int size); static int vfs_bio_clcheck(struct vnode *vp, int size, @@ -1830,20 +1829,19 @@ brelse(struct buf *bp) bdirtysub(); bp->b_flags &= ~(B_DELWRI | B_CACHE); if ((bp->b_flags & B_VMIO) == 0) { - if (bp->b_bufsize) - allocbuf(bp, 0); + allocbuf(bp, 0); if (bp->b_vp) brelvp(bp); } } /* - * We must clear B_RELBUF if B_DELWRI is set. If vfs_vmio_release() + * We must clear B_RELBUF if B_DELWRI is set. If vfs_vmio_truncate() * is called with B_DELWRI set, the underlying pages may wind up * getting freed causing a previous write (bdwrite()) to get 'lost' * because pages associated with a B_DELWRI bp are marked clean. * - * We still allow the B_INVAL case to call vfs_vmio_release(), even + * We still allow the B_INVAL case to call vfs_vmio_truncate(), even * if B_DELWRI is set. */ if (bp->b_flags & B_DELWRI) @@ -1870,14 +1868,13 @@ brelse(struct buf *bp) (bp->b_ioflags & BIO_ERROR && bp->b_iocmd == BIO_READ)) && !(bp->b_vp->v_mount != NULL && (bp->b_vp->v_mount->mnt_vfc->vfc_flags & VFCF_NETWORK) != 0 && - !vn_isdisk(bp->b_vp, NULL) && (bp->b_flags & B_DELWRI))) + !vn_isdisk(bp->b_vp, NULL) && (bp->b_flags & B_DELWRI))) { vfs_vmio_invalidate(bp); + allocbuf(bp, 0); + } if ((bp->b_flags & (B_INVAL | B_RELBUF)) != 0) { - if (bp->b_flags & B_VMIO) - vfs_vmio_release(bp); - if (bp->b_bufsize != 0) - allocbuf(bp, 0); + allocbuf(bp, 0); if (bp->b_vp != NULL) brelvp(bp); } @@ -2059,8 +2056,41 @@ vfs_vmio_iodone(struct buf *bp) } /* + * Unwire a page held by a buf and place it on the appropriate vm queue. + */ +static void +vfs_vmio_unwire(struct buf *bp, vm_page_t m) +{ + bool freed; + + vm_page_lock(m); + if (vm_page_unwire(m, PQ_NONE)) { + /* + * Determine if the page should be freed before adding + * it to the inactive queue. + */ + if (m->valid == 0) { + freed = !vm_page_busied(m); + if (freed) + vm_page_free(m); + } else if ((bp->b_flags & B_DIRECT) != 0) + freed = vm_page_try_to_free(m); + else + freed = false; + if (!freed) { + /* + * In order to maintain LRU page ordering, put + * the page at the tail of the inactive queue. + */ + vm_page_deactivate(m); + } + } + vm_page_unlock(m); +} + +/* * Perform page invalidation when a buffer is released. The fully invalid - * pages will be reclaimed later in vfs_vmio_release(). + * pages will be reclaimed later in vfs_vmio_truncate(). */ static void vfs_vmio_invalidate(struct buf *bp) @@ -2069,6 +2099,11 @@ vfs_vmio_invalidate(struct buf *bp) vm_page_t m; int i, resid, poffset, presid; + if (buf_mapped(bp)) { + BUF_CHECK_MAPPED(bp); + pmap_qremove(trunc_page((vm_offset_t)bp->b_data), bp->b_npages); + } else + BUF_CHECK_UNMAPPED(bp); /* * Get the base offset and length of the buffer. Note that * in the VMIO case if the buffer block size is not @@ -2089,6 +2124,7 @@ vfs_vmio_invalidate(struct buf *bp) m = bp->b_pages[i]; if (m == bogus_page) panic("vfs_vmio_invalidate: Unexpected bogus page."); + bp->b_pages[i] = NULL; presid = resid > (PAGE_SIZE - poffset) ? (PAGE_SIZE - poffset) : resid; @@ -2101,63 +2137,12 @@ vfs_vmio_invalidate(struct buf *bp) } if (pmap_page_wired_mappings(m) == 0) vm_page_set_invalid(m, poffset, presid); + vfs_vmio_unwire(bp, m); resid -= presid; poffset = 0; } VM_OBJECT_WUNLOCK(obj); -} - -/* Give pages used by the bp back to the VM system (where possible) */ -static void -vfs_vmio_release(struct buf *bp) -{ - vm_object_t obj; - vm_page_t m; - int i; - bool freed; - - if (buf_mapped(bp)) { - BUF_CHECK_MAPPED(bp); - pmap_qremove(trunc_page((vm_offset_t)bp->b_data), bp->b_npages); - } else - BUF_CHECK_UNMAPPED(bp); - obj = bp->b_bufobj->bo_object; - if (obj != NULL) - VM_OBJECT_WLOCK(obj); - for (i = 0; i < bp->b_npages; i++) { - m = bp->b_pages[i]; - bp->b_pages[i] = NULL; - vm_page_lock(m); - if (vm_page_unwire(m, PQ_NONE)) { - /* - * Determine if the page should be freed before adding - * it to the inactive queue. - */ - if ((bp->b_flags & B_ASYNC) == 0 && m->valid == 0) { - freed = !vm_page_busied(m); - if (freed) - vm_page_free(m); - } else if ((bp->b_flags & B_DIRECT) != 0) - freed = vm_page_try_to_free(m); - else - freed = false; - if (!freed) { - /* - * In order to maintain LRU page ordering, put - * the page at the tail of the inactive queue. - */ - vm_page_deactivate(m); - } - } - vm_page_unlock(m); - } - if (obj != NULL) - VM_OBJECT_WUNLOCK(obj); - - if (bp->b_bufsize) - bufspaceadjust(bp, 0); bp->b_npages = 0; - bp->b_flags &= ~B_VMIO; } /* @@ -2166,6 +2151,7 @@ vfs_vmio_release(struct buf *bp) static void vfs_vmio_truncate(struct buf *bp, int desiredpages) { + vm_object_t obj; vm_page_t m; int i; @@ -2178,22 +2164,17 @@ vfs_vmio_truncate(struct buf *bp, int de (desiredpages << PAGE_SHIFT), bp->b_npages - desiredpages); } else BUF_CHECK_UNMAPPED(bp); - VM_OBJECT_WLOCK(bp->b_bufobj->bo_object); + obj = bp->b_bufobj->bo_object; + if (obj != NULL) + VM_OBJECT_WLOCK(obj); for (i = desiredpages; i < bp->b_npages; i++) { - /* - * The page is not freed here -- it is the responsibility of - * vnode_pager_setsize. - */ m = bp->b_pages[i]; KASSERT(m != bogus_page, ("allocbuf: bogus page found")); - while (vm_page_sleep_if_busy(m, "biodep")) - continue; bp->b_pages[i] = NULL; - vm_page_lock(m); - vm_page_unwire(m, PQ_INACTIVE); - vm_page_unlock(m); + vfs_vmio_unwire(bp, m); } - VM_OBJECT_WUNLOCK(bp->b_bufobj->bo_object); + if (obj != NULL) + VM_OBJECT_WUNLOCK(obj); bp->b_npages = desiredpages; } @@ -2478,11 +2459,12 @@ getnewbuf_reuse_bp(struct buf *bp, int q KASSERT((bp->b_flags & B_DELWRI) == 0, ("delwri buffer %p found in queue %d", bp, qindex)); + /* + * When recycling a clean buffer we have to truncate it and + * release the vnode. + */ if (qindex == QUEUE_CLEAN) { - if (bp->b_flags & B_VMIO) { - bp->b_flags &= ~B_ASYNC; - vfs_vmio_release(bp); - } + allocbuf(bp, 0); if (bp->b_vp != NULL) brelvp(bp); } @@ -2491,7 +2473,6 @@ getnewbuf_reuse_bp(struct buf *bp, int q * Get the rest of the buffer freed up. b_kva* is still valid * after this operation. */ - if (bp->b_rcred != NOCRED) { crfree(bp->b_rcred); bp->b_rcred = NOCRED; @@ -2508,9 +2489,8 @@ getnewbuf_reuse_bp(struct buf *bp, int q bp, bp->b_vp, qindex)); KASSERT((bp->b_xflags & (BX_VNCLEAN|BX_VNDIRTY)) == 0, ("bp: %p still on a buffer list. xflags %X", bp, bp->b_xflags)); - - if (bp->b_bufsize) - allocbuf(bp, 0); + KASSERT(bp->b_npages == 0, + ("bp: %p still has %d vm pages\n", bp, bp->b_npages)); bp->b_flags = 0; bp->b_ioflags = 0; @@ -3426,8 +3406,7 @@ loop: * cleared. If the size has not changed, B_CACHE remains * unchanged from its previous state. */ - if (bp->b_bcount != size) - allocbuf(bp, size); + allocbuf(bp, size); KASSERT(bp->b_offset != NOOFFSET, ("getblk: no buffer offset")); @@ -3678,6 +3657,9 @@ allocbuf(struct buf *bp, int size) BUF_ASSERT_HELD(bp); + if (bp->b_bcount == size) + return (1); + if (bp->b_kvasize != 0 && bp->b_kvasize < size) panic("allocbuf: buffer too small"); @@ -3716,7 +3698,7 @@ allocbuf(struct buf *bp, int size) bufspaceadjust(bp, newbsize); } bp->b_bcount = size; /* requested buffer size. */ - return 1; + return (1); } extern int inflight_transient_maps;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509270516.t8R5G7s2091316>