Module Name:    src
Committed By:   pooka
Date:           Sun Feb 27 13:37:39 UTC 2011

Modified Files:
        src/sys/rump/librump/rumpvfs: vm_vfs.c

Log Message:
tmpfs has two layers of uvm objects (vnode->uobj and the anon object
in tmpfs_node), so when playing with pages make sure we lock the
uvm object the pages belong to instead of the vnode's uvm object.

per test from Nicolas Joly (which I'm sure he will commit soon ;)


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/sys/rump/librump/rumpvfs/vm_vfs.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/rump/librump/rumpvfs/vm_vfs.c
diff -u src/sys/rump/librump/rumpvfs/vm_vfs.c:1.25 src/sys/rump/librump/rumpvfs/vm_vfs.c:1.26
--- src/sys/rump/librump/rumpvfs/vm_vfs.c:1.25	Tue Feb 22 20:17:37 2011
+++ src/sys/rump/librump/rumpvfs/vm_vfs.c	Sun Feb 27 13:37:39 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: vm_vfs.c,v 1.25 2011/02/22 20:17:37 pooka Exp $	*/
+/*	$NetBSD: vm_vfs.c,v 1.26 2011/02/27 13:37:39 pooka Exp $	*/
 
 /*
  * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_vfs.c,v 1.25 2011/02/22 20:17:37 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_vfs.c,v 1.26 2011/02/27 13:37:39 pooka Exp $");
 
 #include <sys/param.h>
 
@@ -109,6 +109,7 @@
 {
 	struct uvm_object *uobj = &vp->v_uobj;
 	struct vm_page **pgs;
+	struct uvm_object *pguobj;
 	int maxpages = MIN(32, round_page(len) >> PAGE_SHIFT);
 	int rv, npages, i;
 
@@ -125,7 +126,7 @@
 		    0, PAGERFLAGS | PGO_PASTEOF);
 		KASSERT(npages > 0);
 
-		for (i = 0; i < npages; i++) {
+		for (i = 0, pguobj = NULL; i < npages; i++) {
 			struct vm_page *pg;
 			uint8_t *start;
 			size_t chunkoff, chunklen;
@@ -133,6 +134,9 @@
 			pg = pgs[i];
 			if (pg == NULL)
 				break;
+			if (pguobj == NULL)
+				pguobj = pg->uobject;
+			KASSERT(pguobj == pg->uobject);
 
 			chunkoff = off & PAGE_MASK;
 			chunklen = MIN(PAGE_SIZE - chunkoff, len);
@@ -144,8 +148,12 @@
 			off += chunklen;
 			len -= chunklen;
 		}
-		mutex_enter(&uobj->vmobjlock);
+		mutex_enter(&pguobj->vmobjlock);
 		uvm_page_unbusy(pgs, npages);
+		if (pguobj != uobj) {
+			mutex_exit(&pguobj->vmobjlock);
+			mutex_enter(&uobj->vmobjlock);
+		}
 	}
 	mutex_exit(&uobj->vmobjlock);
 	kmem_free(pgs, maxpages * sizeof(pgs));
@@ -161,6 +169,7 @@
 	int advice, int flags)
 {
 	struct vm_page **pgs;
+	struct uvm_object *pguobj;
 	int npages = len2npages(uio->uio_offset, todo);
 	size_t pgalloc;
 	int i, rv, pagerflags;
@@ -184,7 +193,7 @@
 		if (rv)
 			goto out;
 
-		for (i = 0; i < npages; i++) {
+		for (i = 0, pguobj = NULL; i < npages; i++) {
 			struct vm_page *pg;
 			size_t xfersize;
 			off_t pageoff;
@@ -192,6 +201,9 @@
 			pg = pgs[i];
 			if (pg == NULL)
 				break;
+			if (pguobj == NULL)
+				pguobj = pg->uobject;
+			KASSERT(pguobj == pg->uobject);
 
 			pageoff = uio->uio_offset & PAGE_MASK;
 			xfersize = MIN(MIN(todo, PAGE_SIZE), PAGE_SIZE-pageoff);
@@ -199,17 +211,21 @@
 			rv = uiomove((uint8_t *)pg->uanon + pageoff,
 			    xfersize, uio);
 			if (rv) {
-				mutex_enter(&uobj->vmobjlock);
+				mutex_enter(&pguobj->vmobjlock);
 				uvm_page_unbusy(pgs, npages);
-				mutex_exit(&uobj->vmobjlock);
+				mutex_exit(&pguobj->vmobjlock);
 				goto out;
 			}
 			if (uio->uio_rw == UIO_WRITE)
 				pg->flags &= ~(PG_CLEAN | PG_FAKE);
 			todo -= xfersize;
 		}
-		mutex_enter(&uobj->vmobjlock);
+		mutex_enter(&pguobj->vmobjlock);
 		uvm_page_unbusy(pgs, npages);
+		if (pguobj != uobj) {
+			mutex_exit(&pguobj->vmobjlock);
+			mutex_enter(&uobj->vmobjlock);
+		}
 	} while (todo);
 	mutex_exit(&uobj->vmobjlock);
 

Reply via email to