From: mpi Date: Tue, 2 Mar 2021 10:12:37 +0000 (+0000) Subject: Fix the deadlock between uvn_io() and uvn_flush() by restarting the fault. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=3426345d211be9d90bb8991ff6daa953ea3b752a;p=openbsd 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. ok anton@ Reported-by: syzbot+e63407b35dff08dbee02@syzkaller.appspotmail.com --- diff --git a/sys/uvm/uvm_pager.h b/sys/uvm/uvm_pager.h index 6c847c60a8f..e9ce8b989fb 100644 --- a/sys/uvm/uvm_pager.h +++ b/sys/uvm/uvm_pager.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pager.h,v 1.29 2014/07/11 16:35:40 jsg Exp $ */ +/* $OpenBSD: uvm_pager.h,v 1.30 2021/03/02 10:12:37 mpi Exp $ */ /* $NetBSD: uvm_pager.h,v 1.20 2000/11/27 08:40:05 chs Exp $ */ /* @@ -111,6 +111,7 @@ struct uvm_pagerops { #define PGO_LOCKED 0x040 /* fault data structures are locked [get] */ #define PGO_PDFREECLUST 0x080 /* daemon's free cluster flag [uvm_pager_put] */ #define PGO_REALLOCSWAP 0x100 /* reallocate swap area [pager_dropcluster] */ +#define PGO_NOWAIT 0x200 /* do not wait for inode lock */ /* page we are not interested in getting */ #define PGO_DONTCARE ((struct vm_page *) -1L) /* [get only] */ diff --git a/sys/uvm/uvm_vnode.c b/sys/uvm/uvm_vnode.c index be013aae187..75760347835 100644 --- a/sys/uvm/uvm_vnode.c +++ b/sys/uvm/uvm_vnode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_vnode.c,v 1.109 2021/03/02 10:09:20 mpi Exp $ */ +/* $OpenBSD: uvm_vnode.c,v 1.110 2021/03/02 10:12:38 mpi Exp $ */ /* $NetBSD: uvm_vnode.c,v 1.36 2000/11/24 20:34:01 chs Exp $ */ /* @@ -878,6 +878,7 @@ uvn_put(struct uvm_object *uobj, struct vm_page **pps, int npages, int flags) int retval; KERNEL_ASSERT_LOCKED(); + retval = uvn_io((struct uvm_vnode*)uobj, pps, npages, flags, UIO_WRITE); return(retval); @@ -1059,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 @@ -1119,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; @@ -1198,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) @@ -1246,6 +1247,9 @@ 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);