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_ */
_______________________________________________
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