diff options
Diffstat (limited to 'sys/vm/vnode_pager.c')
-rw-r--r-- | sys/vm/vnode_pager.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index a6d78f4..1e3f4b4 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -373,6 +373,7 @@ vnode_pager_setsize(vp, nsize) vm_ooffset_t nsize; { vm_object_t object; + struct vnode *drop; vm_page_t m; vm_pindex_t nobjsize; @@ -398,16 +399,41 @@ vnode_pager_setsize(vp, nsize) /* * this gets rid of garbage at the end of a page that is now * only partially backed by the vnode. - * - * XXX for some reason (I don't know yet), if we take a - * completely invalid page and mark it partially valid - * it can screw up NFS reads, so we don't allow the case. */ if ((nsize & PAGE_MASK) && - (m = vm_page_lookup(object, OFF_TO_IDX(nsize))) != NULL && - m->valid != 0) { - int base = (int)nsize & PAGE_MASK; - int size = PAGE_SIZE - base; + (m = vm_radix_lookup(&object->rtree, OFF_TO_IDX(nsize), + VM_RADIX_ANY)) != NULL) { + int base; + int size; + + /* + * Eliminate any cached page as we would have to + * do too much work to save it. + */ + if (m->flags & PG_CACHED) { + drop = NULL; + mtx_lock(&vm_page_queue_free_mtx); + if (m->object == object) { + vm_page_cache_free(m); + if (object->cached_page_count == 0) + drop = vp; + } + mtx_unlock(&vm_page_queue_free_mtx); + if (drop) + vdrop(drop); + goto out; + } + /* + * XXX for some reason (I don't know yet), if we take a + * completely invalid page and mark it partially valid + * it can screw up NFS reads, so we don't allow the + * case. + */ + if (m->valid != 0 || m->object != object) + goto out; + + base = (int)nsize & PAGE_MASK; + size = PAGE_SIZE - base; /* * Clear out partial-page garbage in case @@ -437,12 +463,9 @@ vnode_pager_setsize(vp, nsize) * replacement from working properly. */ vm_page_clear_dirty(m, base, PAGE_SIZE - base); - } else if ((nsize & PAGE_MASK) && - vm_page_is_cached(object, OFF_TO_IDX(nsize))) { - vm_page_cache_free(object, OFF_TO_IDX(nsize), - nobjsize); } } +out: object->un_pager.vnp.vnp_size = nsize; object->size = nobjsize; VM_OBJECT_UNLOCK(object); |