diff options
author | dillon <dillon@FreeBSD.org> | 2000-01-21 20:17:01 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2000-01-21 20:17:01 +0000 |
commit | cacb1b6d5fff5e1b1a2abfe09c90f2465863d4fd (patch) | |
tree | bd8ecae6ce67984f39cbd92f096f9de8db35914b /sys/vm | |
parent | 9f5625a6c5f75cdc10e4e8a3057875594a8cc610 (diff) | |
download | FreeBSD-src-cacb1b6d5fff5e1b1a2abfe09c90f2465863d4fd.zip FreeBSD-src-cacb1b6d5fff5e1b1a2abfe09c90f2465863d4fd.tar.gz |
Fix a deadlock between msync(..., MS_INVALIDATE) and vm_fault. The
invalidation code cannot wait for paging to complete while holding a
vnode lock, so we don't wait. Instead we simply allow the lower level
code to simply block on any busy pages it encounters. I think Yahoo
may be the only entity in the entire world that actually uses this
msync feature :-).
Bug reported by: Paul Saab <paul@mu.org>
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_map.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index a1f422d3..3f5382e 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -1636,35 +1636,39 @@ vm_map_clean(map, start, end, syncio, invalidate) if (object->size < OFF_TO_IDX( offset + size)) size = IDX_TO_OFF(object->size) - offset; } - if (object && (object->type == OBJT_VNODE)) { + if (object && (object->type == OBJT_VNODE) && + (current->protection & VM_PROT_WRITE)) { /* - * Flush pages if writing is allowed. XXX should we continue - * on an error? + * Flush pages if writing is allowed, invalidate them + * if invalidation requested. Pages undergoing I/O + * will be ignored by vm_object_page_remove(). * - * XXX Doing async I/O and then removing all the pages from - * the object before it completes is probably a very bad - * idea. + * We cannot lock the vnode and then wait for paging + * to complete without deadlocking against vm_fault. + * Instead we simply call vm_object_page_remove() and + * allow it to block internally on a page-by-page + * basis when it encounters pages undergoing async + * I/O. */ - if (current->protection & VM_PROT_WRITE) { - int flags; - if (object->type == OBJT_VNODE) - vn_lock(object->handle, LK_EXCLUSIVE | LK_RETRY, curproc); - flags = (syncio || invalidate) ? OBJPC_SYNC : 0; - flags |= invalidate ? OBJPC_INVAL : 0; - vm_object_page_clean(object, - OFF_TO_IDX(offset), - OFF_TO_IDX(offset + size + PAGE_MASK), - flags); - if (invalidate) { - vm_object_pip_wait(object, "objmcl"); - vm_object_page_remove(object, - OFF_TO_IDX(offset), - OFF_TO_IDX(offset + size + PAGE_MASK), - FALSE); - } - if (object->type == OBJT_VNODE) - VOP_UNLOCK(object->handle, 0, curproc); + int flags; + + vm_object_reference(object); + vn_lock(object->handle, LK_EXCLUSIVE | LK_RETRY, curproc); + flags = (syncio || invalidate) ? OBJPC_SYNC : 0; + flags |= invalidate ? OBJPC_INVAL : 0; + vm_object_page_clean(object, + OFF_TO_IDX(offset), + OFF_TO_IDX(offset + size + PAGE_MASK), + flags); + if (invalidate) { + /*vm_object_pip_wait(object, "objmcl");*/ + vm_object_page_remove(object, + OFF_TO_IDX(offset), + OFF_TO_IDX(offset + size + PAGE_MASK), + FALSE); } + VOP_UNLOCK(object->handle, 0, curproc); + vm_object_deallocate(object); } start += size; } |