Date: Mon, 13 Jun 2011 19:33:13 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r223054 - in stable/8/sys: fs/nfsclient fs/nwfs fs/smbfs nfsclient vm Message-ID: <201106131933.p5DJXDgW095638@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106131933.p5DJXDgW095638>