Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Jun 2011 21:00:28 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r222586 - in head/sys: fs/nfsclient fs/nwfs fs/smbfs nfsclient vm
Message-ID:  <201106012100.p51L0Sga086688@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Jun  1 21:00:28 2011
New Revision: 222586
URL: http://svn.freebsd.org/changeset/base/222586

Log:
  In the VOP_PUTPAGES() implementations, change the default error from
  VM_PAGER_AGAIN to VM_PAGER_ERROR for the uwritten pages. Return
  VM_PAGER_AGAIN for the partially written page. Always forward at least
  one page in the loop of vm_object_page_clean().
  
  VM_PAGER_ERROR causes the page reactivation and does not clear the
  page dirty state, so the write is not lost.
  
  The change fixes an infinite loop in vm_object_page_clean() when the
  filesystem returns permanent errors for some page writes.
  
  Reported and tested by:	gavin
  Reviewed by:	alc, rmacklem
  MFC after:	1 week

Modified:
  head/sys/fs/nfsclient/nfs_clbio.c
  head/sys/fs/nwfs/nwfs_io.c
  head/sys/fs/smbfs/smbfs_io.c
  head/sys/nfsclient/nfs_bio.c
  head/sys/vm/vm_object.c
  head/sys/vm/vnode_pager.c
  head/sys/vm/vnode_pager.h

Modified: head/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clbio.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/fs/nfsclient/nfs_clbio.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -302,7 +302,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.
@@ -345,16 +345,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: head/sys/fs/nwfs/nwfs_io.c
==============================================================================
--- head/sys/fs/nwfs/nwfs_io.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/fs/nwfs/nwfs_io.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -544,7 +544,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);
@@ -569,13 +569,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;
-		for (i = 0; i < nwritten; i++) {
-			rtvals[i] = VM_PAGER_OK;
-			vm_page_undirty(pages[i]);
-		}
-	}
+	if (!error)
+		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
 	return rtvals[0];
 #endif /* NWFS_RWCACHE */
 }

Modified: head/sys/fs/smbfs/smbfs_io.c
==============================================================================
--- head/sys/fs/smbfs/smbfs_io.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/fs/smbfs/smbfs_io.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -609,7 +609,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);
@@ -639,13 +639,8 @@ smbfs_putpages(ap)
 
 	relpbuf(bp, &smbfs_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 (!error)
+		vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
 	return rtvals[0];
 #endif /* SMBFS_RWGENERIC */
 }

Modified: head/sys/nfsclient/nfs_bio.c
==============================================================================
--- head/sys/nfsclient/nfs_bio.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/nfsclient/nfs_bio.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -300,7 +300,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.
@@ -344,11 +344,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: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/vm/vm_object.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -852,6 +852,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);
 	}
 #if 0

Modified: head/sys/vm/vnode_pager.c
==============================================================================
--- head/sys/vm/vnode_pager.c	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/vm/vnode_pager.c	Wed Jun  1 21:00:28 2011	(r222586)
@@ -1089,7 +1089,7 @@ vnode_pager_generic_putpages(struct vnod
 	count = bytecount / PAGE_SIZE;
 
 	for (i = 0; i < count; i++)
-		rtvals[i] = VM_PAGER_AGAIN;
+		rtvals[i] = VM_PAGER_ERROR;
 
 	if ((int64_t)ma[0]->pindex < 0) {
 		printf("vnode_pager_putpages: attempt to write meta-data!!! -- 0x%lx(%lx)\n",
@@ -1191,3 +1191,20 @@ vnode_pager_generic_putpages(struct vnod
 	}
 	return rtvals[0];
 }
+
+void
+vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written)
+{
+	int i, pos;
+
+	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);
+		}
+	}
+}

Modified: head/sys/vm/vnode_pager.h
==============================================================================
--- head/sys/vm/vnode_pager.h	Wed Jun  1 20:09:49 2011	(r222585)
+++ head/sys/vm/vnode_pager.h	Wed Jun  1 21:00:28 2011	(r222586)
@@ -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_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106012100.p51L0Sga086688>