Author: kib Date: Thu Nov 18 21:09:02 2010 New Revision: 215471 URL: http://svn.freebsd.org/changeset/base/215471
Log: vm_pageout_flush() might cache the pages that finished write to the backing storage. Such pages might be then reused, racing with the assert in vm_object_page_collect_flush() that verified that dirty pages from the run (most likely, pages with VM_PAGER_AGAIN status) are write-protected still. In fact, the page indexes for the pages that were removed from the object page list should be ignored by vm_object_page_clean(). Return the length of successfully written run from vm_pageout_flush(), that is, the count of pages between requested page and first page after requested with status VM_PAGER_AGAIN. Supply the requested page index in the array to vm_pageout_flush(). Use the returned run length to forward the index of next page to clean in vm_object_page_clean(). Reported by: avg Reviewed by: alc MFC after: 1 week Modified: head/sys/vm/vm_contig.c head/sys/vm/vm_object.c head/sys/vm/vm_pageout.c head/sys/vm/vm_pageout.h Modified: head/sys/vm/vm_contig.c ============================================================================== --- head/sys/vm/vm_contig.c Thu Nov 18 21:02:40 2010 (r215470) +++ head/sys/vm/vm_contig.c Thu Nov 18 21:09:02 2010 (r215471) @@ -140,7 +140,7 @@ vm_contig_launder_page(vm_page_t m, vm_p object->type == OBJT_DEFAULT) { vm_page_unlock_queues(); m_tmp = m; - vm_pageout_flush(&m_tmp, 1, VM_PAGER_PUT_SYNC); + vm_pageout_flush(&m_tmp, 1, VM_PAGER_PUT_SYNC, 0, NULL); VM_OBJECT_UNLOCK(object); vm_page_lock_queues(); return (0); Modified: head/sys/vm/vm_object.c ============================================================================== --- head/sys/vm/vm_object.c Thu Nov 18 21:02:40 2010 (r215470) +++ head/sys/vm/vm_object.c Thu Nov 18 21:09:02 2010 (r215471) @@ -884,30 +884,9 @@ vm_object_page_collect_flush(vm_object_t index = (maxb + i) + 1; ma[index] = maf[i]; } - runlen = maxb + maxf + 1; - vm_pageout_flush(ma, runlen, pagerflags); - for (i = 0; i < runlen; i++) { - if (ma[i]->dirty != 0) { - KASSERT((ma[i]->flags & PG_WRITEABLE) == 0, - ("vm_object_page_collect_flush: page %p is not write protected", - ma[i])); - } - } - for (i = 0; i < maxf; i++) { - if (ma[i + maxb + 1]->dirty != 0) { - /* - * maxf will end up being the actual number of pages - * we wrote out contiguously, non-inclusive of the - * first page. We do not count look-behind pages. - */ - if (maxf > i) { - maxf = i; - break; - } - } - } - return (maxf + 1); + vm_pageout_flush(ma, maxb + maxf + 1, pagerflags, maxb + 1, &runlen); + return (runlen); } /* Modified: head/sys/vm/vm_pageout.c ============================================================================== --- head/sys/vm/vm_pageout.c Thu Nov 18 21:02:40 2010 (r215470) +++ head/sys/vm/vm_pageout.c Thu Nov 18 21:09:02 2010 (r215471) @@ -438,7 +438,7 @@ more: /* * we allow reads during pageouts... */ - return (vm_pageout_flush(&mc[page_base], pageout_count, 0)); + return (vm_pageout_flush(&mc[page_base], pageout_count, 0, 0, NULL)); } /* @@ -449,14 +449,17 @@ more: * reference count all in here rather then in the parent. If we want * the parent to do more sophisticated things we may have to change * the ordering. + * + * Returned runlen is the count of pages between mreq and first + * page after mreq with status VM_PAGER_AGAIN. */ int -vm_pageout_flush(vm_page_t *mc, int count, int flags) +vm_pageout_flush(vm_page_t *mc, int count, int flags, int mreq, int *prunlen) { vm_object_t object = mc[0]->object; int pageout_status[count]; int numpagedout = 0; - int i; + int i, runlen; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); mtx_assert(&vm_page_queue_mtx, MA_NOTOWNED); @@ -482,6 +485,7 @@ vm_pageout_flush(vm_page_t *mc, int coun vm_pager_put_pages(object, mc, count, flags, pageout_status); + runlen = count - mreq; for (i = 0; i < count; i++) { vm_page_t mt = mc[i]; @@ -513,6 +517,8 @@ vm_pageout_flush(vm_page_t *mc, int coun vm_page_unlock(mt); break; case VM_PAGER_AGAIN: + if (i >= mreq && i - mreq < runlen) + runlen = i - mreq; break; } @@ -532,6 +538,8 @@ vm_pageout_flush(vm_page_t *mc, int coun } } } + if (prunlen != NULL) + *prunlen = runlen; return (numpagedout); } Modified: head/sys/vm/vm_pageout.h ============================================================================== --- head/sys/vm/vm_pageout.h Thu Nov 18 21:02:40 2010 (r215470) +++ head/sys/vm/vm_pageout.h Thu Nov 18 21:09:02 2010 (r215471) @@ -102,7 +102,7 @@ extern void vm_waitpfault(void); #ifdef _KERNEL boolean_t vm_pageout_fallback_object_lock(vm_page_t, vm_page_t *); -int vm_pageout_flush(vm_page_t *, int, int); +int vm_pageout_flush(vm_page_t *, int, int, int, int *); void vm_pageout_oom(int shortage); boolean_t vm_pageout_page_lock(vm_page_t, vm_page_t *); void vm_contig_grow_cache(int, vm_paddr_t, vm_paddr_t); _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"