diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c index ba1fc201c2de..63ef64cda577 100644 --- a/sys/kern/kern_sendfile.c +++ b/sys/kern/kern_sendfile.c @@ -188,20 +188,51 @@ sendfile_free_mext(struct mbuf *m) static void sendfile_free_mext_pg(struct mbuf *m) { - vm_page_t pg; - int flags, i; - bool cache_last; + vm_object_t object, object1; + vm_page_t p; + int count, i; M_ASSERTEXTPG(m); - cache_last = m->m_ext.ext_flags & EXT_FLAG_CACHE_LAST; - flags = (m->m_ext.ext_flags & EXT_FLAG_NOCACHE) != 0 ? VPR_TRYFREE : 0; - - for (i = 0; i < m->m_epg_npgs; i++) { - if (cache_last && i == m->m_epg_npgs - 1) - flags = 0; - pg = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); - vm_page_release(pg, flags); + if ((m->m_ext.ext_flags & EXT_FLAG_NOCACHE) != 0) { + object = NULL; + count = m->m_epg_npgs - + ((m->m_ext.ext_flags & EXT_FLAG_CACHE_LAST) != 0 ? 1 : 0); + for (i = 0; i < count; i++) { + p = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); + if (object == NULL) { + object1 = atomic_load_ptr(&p->object); + if (__predict_false(object1 == NULL) || + !VM_OBJECT_TRYWLOCK(object1)) { + vm_page_release(p, 0); + continue; + } + if (__predict_false(object1 != + atomic_load_ptr(&p->object))) { + VM_OBJECT_WUNLOCK(object1); + vm_page_release(p, 0); + continue; + } + object = object1; + } else { + KASSERT(p->object == NULL || + p->object == object, + ("%s: page %p object %p mismatch", __func__, + p, object)); + } + vm_page_release_locked(p, VPR_TRYFREE); + } + if (__predict_true(object != NULL)) + VM_OBJECT_WUNLOCK(object); + if (i != m->m_epg_npgs) { + p = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); + vm_page_release(p, 0); + } + } else { + for (i = 0; i < m->m_epg_npgs; i++) { + p = PHYS_TO_VM_PAGE(m->m_epg_pa[i]); + vm_page_release(p, 0); + } } if (m->m_ext.ext_flags & EXT_FLAG_SYNC) {