svn commit: r223054 - in stable/8/sys: fs/nfsclient fs/nwfs fs/smbfs nfsclient vm

Konstantin Belousov kib at FreeBSD.org
Mon Jun 13 19:33:13 UTC 2011


Author: kib
Date: Mon Jun 13 19:33:13 2011
New Revision: 223054
URL: http://svn.freebsd.org/changeset/base/223054

Log:
  MFC r222586:
  Fix an infinite loop in vm_object_page_clean() when the
  filesystem returns permanent errors for some page writes.
  
  To accomodate the stable/8 locking requirements, vm page queue lock
  is taken around the loop in vnode_pager_undirty_pages() which modifies
  m->dirty field.
  
  Reviewed by:	alc

Modified:
  stable/8/sys/fs/nfsclient/nfs_clbio.c
  stable/8/sys/fs/nwfs/nwfs_io.c
  stable/8/sys/fs/smbfs/smbfs_io.c
  stable/8/sys/nfsclient/nfs_bio.c
  stable/8/sys/vm/vm_object.c
  stable/8/sys/vm/vnode_pager.c
  stable/8/sys/vm/vnode_pager.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- stable/8/sys/fs/nfsclient/nfs_clbio.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/fs/nfsclient/nfs_clbio.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -298,7 +298,7 @@ ncl_putpages(struct vop_putpages_args *a
 	}
 
 	for (i = 0; i < npages; i++)
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 
 	/*
 	 * When putting pages, do not extend file past EOF.
@@ -341,16 +341,9 @@ ncl_putpages(struct vop_putpages_args *a
 	pmap_qremove(kva, npages);
 	relpbuf(bp, &ncl_pbuf_freecnt);
 
-	if (!error) {
-		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
-		for (i = 0; i < nwritten; i++) {
-			rtvals[i] = VM_PAGER_OK;
-			vm_page_undirty(pages[i]);
-		}
-		if (must_commit) {
-			ncl_clearcommit(vp->v_mount);
-		}
-	}
+	vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
+	if (must_commit)
+		ncl_clearcommit(vp->v_mount);
 	return rtvals[0];
 }
 

Modified: stable/8/sys/fs/nwfs/nwfs_io.c
==============================================================================
--- stable/8/sys/fs/nwfs/nwfs_io.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/fs/nwfs/nwfs_io.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -553,7 +553,7 @@ nwfs_putpages(ap)
 	npages = btoc(count);
 
 	for (i = 0; i < npages; i++) {
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 	}
 
 	bp = getpbuf(&nwfs_pbuf_freecnt);
@@ -578,15 +578,8 @@ nwfs_putpages(ap)
 	pmap_qremove(kva, npages);
 	relpbuf(bp, &nwfs_pbuf_freecnt);
 
-	if (!error) {
-		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
-		vm_page_lock_queues();
-		for (i = 0; i < nwritten; i++) {
-			rtvals[i] = VM_PAGER_OK;
-			vm_page_undirty(pages[i]);
-		}
-		vm_page_unlock_queues();
-	}
+	if (!error)
+		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
 	return rtvals[0];
 #endif /* NWFS_RWCACHE */
 }

Modified: stable/8/sys/fs/smbfs/smbfs_io.c
==============================================================================
--- stable/8/sys/fs/smbfs/smbfs_io.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/fs/smbfs/smbfs_io.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -618,7 +618,7 @@ smbfs_putpages(ap)
 	npages = btoc(count);
 
 	for (i = 0; i < npages; i++) {
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 	}
 
 	bp = getpbuf(&smbfs_pbuf_freecnt);
@@ -648,15 +648,8 @@ smbfs_putpages(ap)
 
 	relpbuf(bp, &smbfs_pbuf_freecnt);
 
-	if (!error) {
-		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
-		vm_page_lock_queues();
-		for (i = 0; i < nwritten; i++) {
-			rtvals[i] = VM_PAGER_OK;
-			vm_page_undirty(pages[i]);
-		}
-		vm_page_unlock_queues();
-	}
+	 if (!error)
+		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
 	return rtvals[0];
 #endif /* SMBFS_RWGENERIC */
 }

Modified: stable/8/sys/nfsclient/nfs_bio.c
==============================================================================
--- stable/8/sys/nfsclient/nfs_bio.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/nfsclient/nfs_bio.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -295,7 +295,7 @@ nfs_putpages(struct vop_putpages_args *a
 	}
 
 	for (i = 0; i < npages; i++)
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 
 	/*
 	 * When putting pages, do not extend file past EOF.
@@ -339,11 +339,7 @@ nfs_putpages(struct vop_putpages_args *a
 	relpbuf(bp, &nfs_pbuf_freecnt);
 
 	if (!error) {
-		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
-		for (i = 0; i < nwritten; i++) {
-			rtvals[i] = VM_PAGER_OK;
-			vm_page_undirty(pages[i]);
-		}
+		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
 		if (must_commit) {
 			nfs_clearcommit(vp->v_mount);
 		}

Modified: stable/8/sys/vm/vm_object.c
==============================================================================
--- stable/8/sys/vm/vm_object.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/vm/vm_object.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -843,6 +843,21 @@ rescan:
 		    flags, &clearobjflags);
 		if (object->generation != curgeneration)
 			goto rescan;
+
+		/*
+		 * If the VOP_PUTPAGES() did a truncated write, so
+		 * that even the first page of the run is not fully
+		 * written, vm_pageout_flush() returns 0 as the run
+		 * length.  Since the condition that caused truncated
+		 * write may be permanent, e.g. exhausted free space,
+		 * accepting n == 0 would cause an infinite loop.
+		 *
+		 * Forwarding the iterator leaves the unwritten page
+		 * behind, but there is not much we can do there if
+		 * filesystem refuses to write it.
+		 */
+		if (n == 0)
+			n = 1;
 		np = vm_page_find_least(object, pi + n);
 	}
 	vm_page_unlock_queues();

Modified: stable/8/sys/vm/vnode_pager.c
==============================================================================
--- stable/8/sys/vm/vnode_pager.c	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/vm/vnode_pager.c	Mon Jun 13 19:33:13 2011	(r223054)
@@ -1080,7 +1080,7 @@ vnode_pager_generic_putpages(vp, m, byte
 	count = bytecount / PAGE_SIZE;
 
 	for (i = 0; i < count; i++)
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 
 	if ((int64_t)m[0]->pindex < 0) {
 		printf("vnode_pager_putpages: attempt to write meta-data!!! -- 0x%lx(%lx)\n",
@@ -1171,3 +1171,22 @@ vnode_pager_generic_putpages(vp, m, byte
 	}
 	return rtvals[0];
 }
+
+void
+vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written)
+{
+	int i, pos;
+
+	vm_page_lock_queues();
+	for (i = 0, pos = 0; pos < written; i++, pos += PAGE_SIZE) {
+		if (pos < trunc_page(written)) {
+			rtvals[i] = VM_PAGER_OK;
+			vm_page_undirty(ma[i]);
+		} else {
+			/* Partially written page. */
+			rtvals[i] = VM_PAGER_AGAIN;
+			vm_page_clear_dirty(ma[i], 0, written & PAGE_MASK);
+		}
+	}
+	vm_page_unlock_queues();
+}

Modified: stable/8/sys/vm/vnode_pager.h
==============================================================================
--- stable/8/sys/vm/vnode_pager.h	Mon Jun 13 18:27:09 2011	(r223053)
+++ stable/8/sys/vm/vnode_pager.h	Mon Jun 13 19:33:13 2011	(r223054)
@@ -49,5 +49,8 @@ int vnode_pager_generic_getpages(struct 
 int vnode_pager_generic_putpages(struct vnode *vp, vm_page_t *m,
 					  int count, boolean_t sync,
 					  int *rtvals);
+
+void vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written);
+
 #endif				/* _KERNEL */
 #endif				/* _VNODE_PAGER_ */


More information about the svn-src-stable-8 mailing list