summaryrefslogtreecommitdiff
path: root/sys/uvm
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2021-03-02 10:12:39 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2021-03-02 10:12:39 +0000
commitc91a20e6a8f647178970099b66a17921061e3e55 (patch)
tree985314f33bdddb96b4b0e6bd07d802f84ba0a0e5 /sys/uvm
parentdba9ec58ea229df5f0f8207a469da3ade65b9e16 (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. ok anton@ Reported-by: syzbot+e63407b35dff08dbee02@syzkaller.appspotmail.com
Diffstat (limited to 'sys/uvm')
-rw-r--r--sys/uvm/uvm_pager.h3
-rw-r--r--sys/uvm/uvm_vnode.c12
2 files changed, 10 insertions, 5 deletions
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);