Matt, I'm not sure if Paul mailed you yet so I thought I'd take the
initiative of bugging you about some reported problems (lockups)
when dealing with machines that have substantial MAP_NOSYNC'd
data along with a page shortage.
What seems to happen is that vm_pageout_scan (src/sys/vm/vm_pageout.c
line 618) keeps rescanning the inactive queue.
My guess is that it just doesn't expect someone to have hosed themselves
by having so many pages that need laundering (maxlaunder/launder_loop)
along with the fact that the comment and code here are doing the wrong
thing for the situation:
/*
* Figure out what to do with dirty pages when they are encountered.
* Assume that 1/3 of the pages on the inactive list are clean. If
* we think we can reach our target, disable laundering (do not
* clean any dirty pages). If we miss the target we will loop back
* up and do a laundering run.
*/
if (cnt.v_inactive_count / 3 > page_shortage) {
maxlaunder = 0;
launder_loop = 0;
} else {
maxlaunder =
(cnt.v_inactive_target > max_page_launder) ?
max_page_launder : cnt.v_inactive_target;
launder_loop = 1;
}
The problem is that there's a chance that nearly all the pages on
the inactive queue need laundering and the loop that starts with
the lable 'rescan0:' is never able to clean enough pages before
stumbling across a block that has moved to another queue. This
forces a jump back to the 'rescan0' lable with effectively nothing
accomplished.
Here's a patch that may help, it's untested, but shows what I'm
hoping to achieve which is force a maximum on the amount of times
rescan0 will be jumped to while not laundering.
Index: vm_pageout.c
===================================================================
RCS file: /home/ncvs/src/sys/vm/vm_pageout.c,v
retrieving revision 1.151.2.4
diff -u -u -r1.151.2.4 vm_pageout.c
--- vm_pageout.c 2000/08/04 22:31:11 1.151.2.4
+++ vm_pageout.c 2000/10/24 07:31:39
@@ -618,7 +618,7 @@
vm_pageout_scan()
{
vm_page_t m, next;
- int page_shortage, maxscan, pcount;
+ int page_shortage, maxscan, maxtotscan, pcount;
int addl_page_shortage, addl_page_shortage_init;
int maxlaunder;
int launder_loop = 0;
@@ -672,13 +672,23 @@
* we have scanned the entire inactive queue.
*/
+rescantot:
+ /* make sure we don't hit rescan0 too many times */
+ maxtotscan = cnt.v_inactive_count;
rescan0:
addl_page_shortage = addl_page_shortage_init;
maxscan = cnt.v_inactive_count;
+ if (maxtotscan < 1) {
+ maxlaunder =
+ (cnt.v_inactive_target > max_page_launder) ?
+ max_page_launder : cnt.v_inactive_target;
+ }
for (m = TAILQ_FIRST(&vm_page_queues[PQ_INACTIVE].pl);
m != NULL && maxscan-- > 0 && page_shortage > 0;
m = next) {
+ --maxtotscan;
+
cnt.v_pdpages++;
if (m->queue != PQ_INACTIVE) {
@@ -930,7 +940,7 @@
maxlaunder =
(cnt.v_inactive_target > max_page_launder) ?
max_page_launder : cnt.v_inactive_target;
- goto rescan0;
+ goto rescantot;
}
/*
(still talking about vm_pageout_scan()):
I'm pretty sure that there's yet another problem here, when paging
out a vnode's pages the output routine attempts to cluster them,
this could easily make 'next' point to a page that is cleaned and
put on the FREE queue, when the loop then tests it for
'm->queue != PQ_INACTIVE' it forces 'rescan0' to happen.
I think one could fix this by keeping a pointer to the previous
page then the 'goto rescan0;' test might become something like
this:
/*
* We keep a back reference just in case the vm_pageout_clean()
* happens to clean the page after the one we just cleaned
* via clustering, this would make next point to something not
* one the INACTIVE queue, as a stop-gap we keep a pointer
* to the previous page and attempt to use it as a fallback
* starting point before actually starting at the head of the
* INACTIVE queue again
*/
if (m->queue != PQ_INACTIVE) {
if (prev != NULL && prev->queue == PQ_INACTIVE) {
m = TAILQ_NEXT(prev, pageq);
if (m == NULL || m->queue != PQ_INACTIVE)
goto rescan0;
} else {
goto rescan0;
}
}
Of course we need to set 'prev' properly, but I need to get back
to my database stuff right now. :)
Also... I wish there was a good hueristic to make max_page_launder
a bit more adaptive, you've done some wonders with bufdaemon so
I'm wondering if you had some ideas about that.
--
-Alfred Perlstein - [[EMAIL PROTECTED]|[EMAIL PROTECTED]]
"I have the heart of a child; I keep it in a jar on my desk."
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message