diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2021-10-12 07:38:23 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2021-10-12 07:38:23 +0000 |
commit | 10b9db03e31666807fa3c9b4685a27a082b671c8 (patch) | |
tree | c252fe9096b409d651d4d4eb321e33ffc1a3105e /sys/uvm/uvm_vnode.c | |
parent | 284e6b44ece6686d91019248b16eab4eb8c276bd (diff) |
Fix the deadlock between uvn_io() and uvn_flush() by restarting the fault.
Do not allow a faulting thread to sleep on a contended vnode lock to prevent
lock ordering issues with upcoming per-uobj lock.
Also reduce the sleep value for VM_PAGER_AGAIN from 1sec to 5nsec to not add
visible slowdown when starting a multi-threaded application with threads that
fault on the same vnode (chromium, firefox, etc).
Tested by anton@, tb@, robert@ and gnezdo@
ok anton@, tb@
Reported-by: syzbot+e63407b35dff08dbee02@syzkaller.appspotmail.com
Diffstat (limited to 'sys/uvm/uvm_vnode.c')
-rw-r--r-- | sys/uvm/uvm_vnode.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/sys/uvm/uvm_vnode.c b/sys/uvm/uvm_vnode.c index 9c70fb49390..5fc969c3ff7 100644 --- a/sys/uvm/uvm_vnode.c +++ b/sys/uvm/uvm_vnode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_vnode.c,v 1.115 2021/10/12 07:37:42 mpi Exp $ */ +/* $OpenBSD: uvm_vnode.c,v 1.116 2021/10/12 07:38:22 mpi Exp $ */ /* $NetBSD: uvm_vnode.c,v 1.36 2000/11/24 20:34:01 chs Exp $ */ /* @@ -1060,7 +1060,7 @@ uvn_get(struct uvm_object *uobj, voff_t offset, struct vm_page **pps, * I/O to fill it with valid data. */ result = uvn_io((struct uvm_vnode *) uobj, &ptmp, 1, - PGO_SYNCIO, UIO_READ); + PGO_SYNCIO|PGO_NOWAIT, UIO_READ); /* * I/O done. because we used syncio the result can not be @@ -1120,6 +1120,7 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) int waitf, result, mapinflags; size_t got, wanted; int netunlocked = 0; + int lkflags = (flags & PGO_NOWAIT) ? LK_NOWAIT : 0; /* init values */ waitf = (flags & PGO_SYNCIO) ? M_WAITOK : M_NOWAIT; @@ -1199,8 +1200,7 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) */ result = 0; if ((uvn->u_flags & UVM_VNODE_VNISLOCKED) == 0) - result = vn_lock(vn, LK_EXCLUSIVE | LK_RECURSEFAIL); - + result = vn_lock(vn, LK_EXCLUSIVE | LK_RECURSEFAIL | lkflags); if (result == 0) { /* NOTE: vnode now locked! */ if (rw == UIO_READ) @@ -1247,11 +1247,14 @@ uvn_io(struct uvm_vnode *uvn, vm_page_t *pps, int npages, int flags, int rw) if (result == 0) { return VM_PAGER_OK; + } else if (result == EBUSY) { + KASSERT(flags & PGO_NOWAIT); + return VM_PAGER_AGAIN; } else { while (rebooting) tsleep_nsec(&rebooting, PVM, "uvndead", INFSLP); return VM_PAGER_ERROR; - } + } } /* |