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_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to