|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: vm/vm_pageout.c
54: * Author: Avadis Tevanian, Jr., Michael Wayne Young
55: * Date: 1985
56: *
57: * The proverbial page-out daemon.
58: */
59: #ifdef MACH_BSD
60: /* remove after component merge */
61: extern int vnode_pager_workaround;
62: #endif
63:
64: #include <mach_pagemap.h>
65: #include <mach_cluster_stats.h>
66: #include <mach_kdb.h>
67: #include <dipc.h>
68: #include <advisory_pageout.h>
69:
70: #include <mach/mach_types.h>
71: #include <mach/memory_object.h>
72: #include <mach/memory_object_default.h>
73: #include <mach/mach_host_server.h>
74: #include <mach/vm_param.h>
75: #include <mach/vm_statistics.h>
76: #include <kern/host_statistics.h>
77: #include <kern/counters.h>
78: #include <kern/thread.h>
79: #include <kern/thread_swap.h>
80: #include <kern/xpr.h>
81: #include <vm/pmap.h>
82: #include <vm/vm_map.h>
83: #include <vm/vm_object.h>
84: #include <vm/vm_page.h>
85: #include <vm/vm_pageout.h>
86: #include <machine/vm_tuning.h>
87: #include <kern/misc_protos.h>
88:
89: extern ipc_port_t memory_manager_default;
90:
91: #ifndef VM_PAGE_LAUNDRY_MAX
92: #define VM_PAGE_LAUNDRY_MAX 10 /* outstanding DMM page cleans */
93: #endif /* VM_PAGEOUT_LAUNDRY_MAX */
94:
95: #ifndef VM_PAGEOUT_BURST_MAX
96: #define VM_PAGEOUT_BURST_MAX 10 /* simultaneous EMM page cleans */
97: #endif /* VM_PAGEOUT_BURST_MAX */
98:
99: #ifndef VM_PAGEOUT_DISCARD_MAX
100: #define VM_PAGEOUT_DISCARD_MAX 68 /* simultaneous EMM page cleans */
101: #endif /* VM_PAGEOUT_DISCARD_MAX */
102:
103: #ifndef VM_PAGEOUT_BURST_WAIT
104: #define VM_PAGEOUT_BURST_WAIT 30 /* milliseconds per page */
105: #endif /* VM_PAGEOUT_BURST_WAIT */
106:
107: #ifndef VM_PAGEOUT_EMPTY_WAIT
108: #define VM_PAGEOUT_EMPTY_WAIT 200 /* milliseconds */
109: #endif /* VM_PAGEOUT_EMPTY_WAIT */
110:
111: /*
112: * To obtain a reasonable LRU approximation, the inactive queue
113: * needs to be large enough to give pages on it a chance to be
114: * referenced a second time. This macro defines the fraction
115: * of active+inactive pages that should be inactive.
116: * The pageout daemon uses it to update vm_page_inactive_target.
117: *
118: * If vm_page_free_count falls below vm_page_free_target and
119: * vm_page_inactive_count is below vm_page_inactive_target,
120: * then the pageout daemon starts running.
121: */
122:
123: #ifndef VM_PAGE_INACTIVE_TARGET
124: #define VM_PAGE_INACTIVE_TARGET(avail) ((avail) * 2 / 3)
125: #endif /* VM_PAGE_INACTIVE_TARGET */
126:
127: /*
128: * Once the pageout daemon starts running, it keeps going
129: * until vm_page_free_count meets or exceeds vm_page_free_target.
130: */
131:
132: #ifndef VM_PAGE_FREE_TARGET
133: #define VM_PAGE_FREE_TARGET(free) (15 + (free) / 80)
134: #endif /* VM_PAGE_FREE_TARGET */
135:
136: /*
137: * The pageout daemon always starts running once vm_page_free_count
138: * falls below vm_page_free_min.
139: */
140:
141: #ifndef VM_PAGE_FREE_MIN
142: #define VM_PAGE_FREE_MIN(free) (10 + (free) / 100)
143: #endif /* VM_PAGE_FREE_MIN */
144:
145: /*
146: * When vm_page_free_count falls below vm_page_free_reserved,
147: * only vm-privileged threads can allocate pages. vm-privilege
148: * allows the pageout daemon and default pager (and any other
149: * associated threads needed for default pageout) to continue
150: * operation by dipping into the reserved pool of pages.
151: */
152:
153: #ifndef VM_PAGE_FREE_RESERVED
154: #define VM_PAGE_FREE_RESERVED \
155: ((8 * VM_PAGE_LAUNDRY_MAX) + NCPUS)
156: #endif /* VM_PAGE_FREE_RESERVED */
157:
158:
159: /*
160: * Forward declarations for internal routines.
161: */
162: extern void vm_pageout_continue(void);
163: extern void vm_pageout_scan(void);
164: extern void vm_pageout_throttle(vm_page_t m);
165: extern vm_page_t vm_pageout_cluster_page(
166: vm_object_t object,
167: vm_offset_t offset,
168: boolean_t precious_clean);
169:
170: unsigned int vm_pageout_reserved_internal = 0;
171: unsigned int vm_pageout_reserved_really = 0;
172:
173: unsigned int vm_page_laundry_max = 0; /* # of clusters outstanding */
174: unsigned int vm_page_laundry_min = 0;
175: unsigned int vm_pageout_burst_max = 0;
176: unsigned int vm_pageout_burst_wait = 0; /* milliseconds per page */
177: unsigned int vm_pageout_empty_wait = 0; /* milliseconds */
178: unsigned int vm_pageout_burst_min = 0;
179: unsigned int vm_pageout_pause_count = 0;
180: unsigned int vm_pageout_pause_max = 0;
181: unsigned int vm_free_page_pause = 100; /* milliseconds */
182:
183: /*
184: * These variables record the pageout daemon's actions:
185: * how many pages it looks at and what happens to those pages.
186: * No locking needed because only one thread modifies the variables.
187: */
188:
189: unsigned int vm_pageout_active = 0; /* debugging */
190: unsigned int vm_pageout_inactive = 0; /* debugging */
191: unsigned int vm_pageout_inactive_throttled = 0; /* debugging */
192: unsigned int vm_pageout_inactive_forced = 0; /* debugging */
193: unsigned int vm_pageout_inactive_nolock = 0; /* debugging */
194: unsigned int vm_pageout_inactive_avoid = 0; /* debugging */
195: unsigned int vm_pageout_inactive_busy = 0; /* debugging */
196: unsigned int vm_pageout_inactive_absent = 0; /* debugging */
197: unsigned int vm_pageout_inactive_used = 0; /* debugging */
198: unsigned int vm_pageout_inactive_clean = 0; /* debugging */
199: unsigned int vm_pageout_inactive_dirty = 0; /* debugging */
200: unsigned int vm_pageout_dirty_no_pager = 0; /* debugging */
201: unsigned int vm_pageout_inactive_pinned = 0; /* debugging */
202: unsigned int vm_pageout_inactive_limbo = 0; /* debugging */
203: unsigned int vm_pageout_setup_limbo = 0; /* debugging */
204: unsigned int vm_pageout_setup_unprepped = 0; /* debugging */
205: unsigned int vm_stat_discard = 0; /* debugging */
206: unsigned int vm_stat_discard_sent = 0; /* debugging */
207: unsigned int vm_stat_discard_failure = 0; /* debugging */
208: unsigned int vm_stat_discard_throttle = 0; /* debugging */
209: unsigned int vm_pageout_scan_active_emm_throttle = 0; /* debugging */
210: unsigned int vm_pageout_scan_active_emm_throttle_success = 0; /* debugging */
211: unsigned int vm_pageout_scan_active_emm_throttle_failure = 0; /* debugging */
212: unsigned int vm_pageout_scan_inactive_emm_throttle = 0; /* debugging */
213: unsigned int vm_pageout_scan_inactive_emm_throttle_success = 0; /* debugging */
214: unsigned int vm_pageout_scan_inactive_emm_throttle_failure = 0; /* debugging */
215:
216:
217: unsigned int vm_pageout_out_of_line = 0;
218: unsigned int vm_pageout_in_place = 0;
219: /*
220: * Routine: vm_pageout_object_allocate
221: * Purpose:
222: * Allocate an object for use as out-of-line memory in a
223: * data_return/data_initialize message.
224: * The page must be in an unlocked object.
225: *
226: * If the page belongs to a trusted pager, cleaning in place
227: * will be used, which utilizes a special "pageout object"
228: * containing private alias pages for the real page frames.
229: * Untrusted pagers use normal out-of-line memory.
230: */
231: vm_object_t
232: vm_pageout_object_allocate(
233: vm_page_t m,
234: vm_size_t size,
235: vm_offset_t offset)
236: {
237: vm_object_t object = m->object;
238: vm_object_t new_object;
239:
240: assert(object->pager_ready);
241:
242: if (object->pager_trusted || object->internal)
243: vm_pageout_throttle(m);
244:
245: new_object = vm_object_allocate(size);
246:
247: if (object->pager_trusted) {
248: assert (offset < object->size);
249:
250: vm_object_lock(new_object);
251: new_object->pageout = TRUE;
252: new_object->shadow = object;
253: new_object->can_persist = FALSE;
254: new_object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
255: new_object->shadow_offset = offset;
256: vm_object_unlock(new_object);
257:
258: /*
259: * Take a paging reference on the object. This will be dropped
260: * in vm_pageout_object_terminate()
261: */
262: vm_object_lock(object);
263: vm_object_paging_begin(object);
264: vm_object_unlock(object);
265:
266: vm_pageout_in_place++;
267: } else
268: vm_pageout_out_of_line++;
269: return(new_object);
270: }
271:
272: #if MACH_CLUSTER_STATS
273: unsigned long vm_pageout_cluster_dirtied = 0;
274: unsigned long vm_pageout_cluster_cleaned = 0;
275: unsigned long vm_pageout_cluster_collisions = 0;
276: unsigned long vm_pageout_cluster_clusters = 0;
277: unsigned long vm_pageout_cluster_conversions = 0;
278: unsigned long vm_pageout_target_collisions = 0;
279: unsigned long vm_pageout_target_page_dirtied = 0;
280: unsigned long vm_pageout_target_page_freed = 0;
281: unsigned long vm_pageout_target_page_pinned = 0;
282: unsigned long vm_pageout_target_page_limbo = 0;
283: #define CLUSTER_STAT(clause) clause
284: #else /* MACH_CLUSTER_STATS */
285: #define CLUSTER_STAT(clause)
286: #endif /* MACH_CLUSTER_STATS */
287:
288: /*
289: * Routine: vm_pageout_object_terminate
290: * Purpose:
291: * Destroy the pageout_object allocated by
292: * vm_pageout_object_allocate(), and perform all of the
293: * required cleanup actions.
294: *
295: * In/Out conditions:
296: * The object must be locked, and will be returned locked.
297: */
298: void
299: vm_pageout_object_terminate(
300: vm_object_t object)
301: {
302: vm_object_t shadow_object;
303:
304: /*
305: * Deal with the deallocation (last reference) of a pageout object
306: * (used for cleaning-in-place) by dropping the paging references/
307: * freeing pages in the original object.
308: */
309:
310: assert(object->pageout);
311: shadow_object = object->shadow;
312: vm_object_lock(shadow_object);
313:
314: while (!queue_empty(&object->memq)) {
315: vm_page_t p, m;
316: vm_offset_t offset;
317:
318: p = (vm_page_t) queue_first(&object->memq);
319:
320: assert(p->private);
321: assert(p->pageout);
322: p->pageout = FALSE;
323: assert(!p->cleaning);
324:
325: offset = p->offset;
326: VM_PAGE_FREE(p);
327: p = VM_PAGE_NULL;
328:
329: m = vm_page_lookup(shadow_object,
330: offset + object->shadow_offset);
331:
332: if(m == VM_PAGE_NULL)
333: continue;
334: assert(m->cleaning);
335:
336: /*
337: * Account for the paging reference taken when
338: * m->cleaning was set on this page.
339: */
340: vm_object_paging_end(shadow_object);
341: assert((m->dirty) || (m->precious) ||
342: (m->busy && m->cleaning));
343:
344: /*
345: * Handle the trusted pager throttle.
346: */
347: vm_page_lock_queues();
348: if (m->laundry) {
349: vm_page_laundry_count--;
350: m->laundry = FALSE;
351: if (vm_page_laundry_count < vm_page_laundry_min) {
352: vm_page_laundry_min = 0;
353: thread_wakeup((event_t) &vm_page_laundry_count);
354: }
355: }
356:
357: /*
358: * Handle the "target" page(s). These pages are to be freed if
359: * successfully cleaned. Target pages are always busy, and are
360: * wired exactly once. The initial target pages are not mapped,
361: * (so cannot be referenced or modified) but converted target
362: * pages may have been modified between the selection as an
363: * adjacent page and conversion to a target.
364: */
365: if (m->pageout) {
366: assert(m->busy);
367: assert(m->wire_count == 1);
368: m->cleaning = FALSE;
369: m->pageout = FALSE;
370: #if MACH_CLUSTER_STATS
371: if (m->wanted) vm_pageout_target_collisions++;
372: #endif
373: /*
374: * Revoke all access to the page. Since the object is
375: * locked, and the page is busy, this prevents the page
376: * from being dirtied after the pmap_is_modified() call
377: * returns.
378: */
379: pmap_page_protect(m->phys_addr, VM_PROT_NONE);
380:
381: /*
382: * Since the page is left "dirty" but "not modifed", we
383: * can detect whether the page was redirtied during
384: * pageout by checking the modify state.
385: */
386: m->dirty = pmap_is_modified(m->phys_addr);
387:
388: if (m->dirty) {
389: CLUSTER_STAT(vm_pageout_target_page_dirtied++;)
390: vm_page_unwire(m);/* reactivates */
391: VM_STAT(reactivations++);
392: PAGE_WAKEUP_DONE(m);
393: } else if (m->prep_pin_count != 0) {
394: vm_page_pin_lock();
395: if (m->pin_count != 0) {
396: /* page is pinned; reactivate */
397: CLUSTER_STAT(
398: vm_pageout_target_page_pinned++;)
399: vm_page_unwire(m);/* reactivates */
400: VM_STAT(reactivations++);
401: PAGE_WAKEUP_DONE(m);
402: } else {
403: /*
404: * page is prepped but not pinned; send
405: * it into limbo. Note that
406: * vm_page_free (which will be called
407: * after releasing the pin lock) knows
408: * how to handle a page with limbo set.
409: */
410: m->limbo = TRUE;
411: CLUSTER_STAT(
412: vm_pageout_target_page_limbo++;)
413: }
414: vm_page_pin_unlock();
415: if (m->limbo)
416: vm_page_free(m);
417: } else {
418: CLUSTER_STAT(vm_pageout_target_page_freed++;)
419: vm_page_free(m);/* clears busy, etc. */
420: }
421: vm_page_unlock_queues();
422: continue;
423: }
424: /*
425: * Handle the "adjacent" pages. These pages were cleaned in
426: * place, and should be left alone.
427: * If prep_pin_count is nonzero, then someone is using the
428: * page, so make it active.
429: */
430: if (!m->active && !m->inactive) {
431: if (m->reference || m->prep_pin_count != 0)
432: vm_page_activate(m);
433: else
434: vm_page_deactivate(m);
435: }
436: if((m->busy) && (m->cleaning)) {
437:
438: /* the request_page_list case, (COPY_OUT_FROM FALSE) */
439: m->busy = FALSE;
440:
441: /* We do not re-set m->dirty ! */
442: /* The page was busy so no extraneous activity */
443: /* could have occured. COPY_INTO is a read into the */
444: /* new pages. CLEAN_IN_PLACE does actually write */
445: /* out the pages but handling outside of this code */
446: /* will take care of resetting dirty. We clear the */
447: /* modify however for the Programmed I/O case. */
448: pmap_clear_modify(m->phys_addr);
449: if(m->absent) {
450: m->absent = FALSE;
451: if(shadow_object->absent_count == 1)
452: vm_object_absent_release(shadow_object);
453: else
454: shadow_object->absent_count--;
455: }
456: m->overwriting = FALSE;
457: } else if (m->overwriting) {
458: /* alternate request page list, write to page_list */
459: /* case. Occurs when the original page was wired */
460: /* at the time of the list request */
461: assert(m->wire_count != 0);
462: vm_page_unwire(m);/* reactivates */
463: m->overwriting = FALSE;
464: } else {
465: /*
466: * Set the dirty state according to whether or not the page was
467: * modified during the pageout. Note that we purposefully do
468: * NOT call pmap_clear_modify since the page is still mapped.
469: * If the page were to be dirtied between the 2 calls, this
470: * this fact would be lost. This code is only necessary to
471: * maintain statistics, since the pmap module is always
472: * consulted if m->dirty is false.
473: */
474: #if MACH_CLUSTER_STATS
475: m->dirty = pmap_is_modified(m->phys_addr);
476:
477: if (m->dirty) vm_pageout_cluster_dirtied++;
478: else vm_pageout_cluster_cleaned++;
479: if (m->wanted) vm_pageout_cluster_collisions++;
480: #else
481: m->dirty = 0;
482: #endif
483: }
484: m->cleaning = FALSE;
485:
486:
487: /*
488: * Wakeup any thread waiting for the page to be un-cleaning.
489: */
490: PAGE_WAKEUP(m);
491: vm_page_unlock_queues();
492: }
493: /*
494: * Account for the paging reference taken in vm_paging_object_allocate.
495: */
496: vm_object_paging_end(shadow_object);
497: vm_object_unlock(shadow_object);
498:
499: assert(object->ref_count == 0);
500: assert(object->paging_in_progress == 0);
501: assert(object->resident_page_count == 0);
502: return;
503: }
504:
505: /*
506: * Routine: vm_pageout_setup
507: * Purpose:
508: * Set up a page for pageout (clean & flush).
509: *
510: * Move the page to a new object, as part of which it will be
511: * sent to its memory manager in a memory_object_data_write or
512: * memory_object_initialize message.
513: *
514: * The "new_object" and "new_offset" arguments
515: * indicate where the page should be moved.
516: *
517: * In/Out conditions:
518: * The page in question must not be on any pageout queues,
519: * and must be busy. The object to which it belongs
520: * must be unlocked, and the caller must hold a paging
521: * reference to it. The new_object must not be locked.
522: *
523: * This routine returns a pointer to a place-holder page,
524: * inserted at the same offset, to block out-of-order
525: * requests for the page. The place-holder page must
526: * be freed after the data_write or initialize message
527: * has been sent.
528: *
529: * The original page is put on a paging queue and marked
530: * not busy on exit.
531: */
532: vm_page_t
533: vm_pageout_setup(
534: register vm_page_t m,
535: register vm_object_t new_object,
536: vm_offset_t new_offset)
537: {
538: register vm_object_t old_object = m->object;
539: vm_offset_t paging_offset;
540: vm_offset_t offset;
541: register vm_page_t holding_page;
542: register vm_page_t new_m;
543: register vm_page_t new_page;
544: boolean_t need_to_wire = FALSE;
545:
546:
547: XPR(XPR_VM_PAGEOUT,
548: "vm_pageout_setup, obj 0x%X off 0x%X page 0x%X new obj 0x%X offset 0x%X\n",
549: (integer_t)m->object, (integer_t)m->offset,
550: (integer_t)m, (integer_t)new_object,
551: (integer_t)new_offset);
552: assert(m && m->busy && !m->absent && !m->fictitious && !m->error &&
553: !m->restart);
554:
555: assert(m->dirty || m->precious);
556:
557: /*
558: * Create a place-holder page where the old one was, to prevent
559: * attempted pageins of this page while we're unlocked.
560: * If the pageout daemon put this page in limbo and we're not
561: * going to clean in place, get another fictitious page to
562: * exchange for it now.
563: */
564: VM_PAGE_GRAB_FICTITIOUS(holding_page);
565:
566: if (m->limbo)
567: VM_PAGE_GRAB_FICTITIOUS(new_page);
568:
569: vm_object_lock(old_object);
570:
571: offset = m->offset;
572: paging_offset = offset + old_object->paging_offset;
573:
574: if (old_object->pager_trusted) {
575: /*
576: * This pager is trusted, so we can clean this page
577: * in place. Leave it in the old object, and mark it
578: * cleaning & pageout.
579: */
580: new_m = holding_page;
581: holding_page = VM_PAGE_NULL;
582:
583: /*
584: * If the pageout daemon put this page in limbo, exchange the
585: * identities of the limbo page and the new fictitious page,
586: * and continue with the new page, unless the prep count has
587: * gone to zero in the meantime (which means no one is
588: * interested in the page any more). In that case, just clear
589: * the limbo bit and free the extra fictitious page.
590: */
591: if (m->limbo) {
592: if (m->prep_pin_count == 0) {
593: /* page doesn't have to be in limbo any more */
594: m->limbo = FALSE;
595: vm_page_free(new_page);
596: vm_pageout_setup_unprepped++;
597: } else {
598: vm_page_lock_queues();
599: VM_PAGE_QUEUES_REMOVE(m);
600: vm_page_remove(m);
601: vm_page_limbo_exchange(m, new_page);
602: vm_pageout_setup_limbo++;
603: vm_page_release_limbo(m);
604: m = new_page;
605: vm_page_insert(m, old_object, offset);
606: vm_page_unlock_queues();
607: }
608: }
609:
610: /*
611: * Set up new page to be private shadow of real page.
612: */
613: new_m->phys_addr = m->phys_addr;
614: new_m->fictitious = FALSE;
615: new_m->private = TRUE;
616: new_m->pageout = TRUE;
617:
618: /*
619: * Mark real page as cleaning (indicating that we hold a
620: * paging reference to be released via m_o_d_r_c) and
621: * pageout (indicating that the page should be freed
622: * when the pageout completes).
623: */
624: pmap_clear_modify(m->phys_addr);
625: vm_page_lock_queues();
626: vm_page_wire(new_m);
627: m->cleaning = TRUE;
628: m->pageout = TRUE;
629:
630: vm_page_wire(m);
631: assert(m->wire_count == 1);
632: vm_page_unlock_queues();
633:
634: m->dirty = TRUE;
635: m->precious = FALSE;
636: m->page_lock = VM_PROT_NONE;
637: m->unusual = FALSE;
638: m->unlock_request = VM_PROT_NONE;
639: } else {
640: /*
641: * Cannot clean in place, so rip the old page out of the
642: * object, and stick the holding page in. Set new_m to the
643: * page in the new object.
644: */
645: vm_page_lock_queues();
646: VM_PAGE_QUEUES_REMOVE(m);
647: vm_page_remove(m);
648:
649: /*
650: * If the pageout daemon put this page in limbo, exchange the
651: * identities of the limbo page and the new fictitious page,
652: * and continue with the new page, unless the prep count has
653: * gone to zero in the meantime (which means no one is
654: * interested in the page any more). In that case, just clear
655: * the limbo bit and free the extra fictitious page.
656: */
657: if (m->limbo) {
658: if (m->prep_pin_count == 0) {
659: /* page doesn't have to be in limbo any more */
660: m->limbo = FALSE;
661: vm_page_free(new_page);
662: vm_pageout_setup_unprepped++;
663: } else {
664: vm_page_limbo_exchange(m, new_page);
665: vm_pageout_setup_limbo++;
666: vm_page_release_limbo(m);
667: m = new_page;
668: }
669: }
670:
671: vm_page_insert(holding_page, old_object, offset);
672: vm_page_unlock_queues();
673:
674: m->dirty = TRUE;
675: m->precious = FALSE;
676: new_m = m;
677: new_m->page_lock = VM_PROT_NONE;
678: new_m->unlock_request = VM_PROT_NONE;
679:
680: if (old_object->internal)
681: need_to_wire = TRUE;
682: }
683: /*
684: * Record that this page has been written out
685: */
686: #if MACH_PAGEMAP
687: vm_external_state_set(old_object->existence_map, offset);
688: #endif /* MACH_PAGEMAP */
689:
690: vm_object_unlock(old_object);
691:
692: vm_object_lock(new_object);
693:
694: /*
695: * Put the page into the new object. If it is a not wired
696: * (if it's the real page) it will be activated.
697: */
698:
699: vm_page_lock_queues();
700: vm_page_insert(new_m, new_object, new_offset);
701: if (need_to_wire)
702: vm_page_wire(new_m);
703: else
704: vm_page_activate(new_m);
705: PAGE_WAKEUP_DONE(new_m);
706: vm_page_unlock_queues();
707:
708: vm_object_unlock(new_object);
709:
710: /*
711: * Return the placeholder page to simplify cleanup.
712: */
713: return (holding_page);
714: }
715:
716: /*
717: * Routine: vm_pageclean_setup
718: *
719: * Purpose: setup a page to be cleaned (made non-dirty), but not
720: * necessarily flushed from the VM page cache.
721: * This is accomplished by cleaning in place.
722: *
723: * The page must not be busy, and the object and page
724: * queues must be locked.
725: *
726: */
727: void
728: vm_pageclean_setup(
729: vm_page_t m,
730: vm_page_t new_m,
731: vm_object_t new_object,
732: vm_offset_t new_offset)
733: {
734: vm_object_t old_object = m->object;
735: assert(!m->busy);
736: assert(!m->cleaning);
737:
738: XPR(XPR_VM_PAGEOUT,
739: "vm_pageclean_setup, obj 0x%X off 0x%X page 0x%X new 0x%X new_off 0x%X\n",
740: (integer_t)old_object, m->offset, (integer_t)m,
741: (integer_t)new_m, new_offset);
742:
743: pmap_clear_modify(m->phys_addr);
744: vm_object_paging_begin(old_object);
745:
746: /*
747: * Record that this page has been written out
748: */
749: #if MACH_PAGEMAP
750: vm_external_state_set(old_object->existence_map, m->offset);
751: #endif /*MACH_PAGEMAP*/
752:
753: /*
754: * Mark original page as cleaning in place.
755: */
756: m->cleaning = TRUE;
757: m->dirty = TRUE;
758: m->precious = FALSE;
759:
760: /*
761: * Convert the fictitious page to a private shadow of
762: * the real page.
763: */
764: assert(new_m->fictitious);
765: new_m->fictitious = FALSE;
766: new_m->private = TRUE;
767: new_m->pageout = TRUE;
768: new_m->phys_addr = m->phys_addr;
769: vm_page_wire(new_m);
770:
771: vm_page_insert(new_m, new_object, new_offset);
772: assert(!new_m->wanted);
773: new_m->busy = FALSE;
774: }
775:
776: void
777: vm_pageclean_copy(
778: vm_page_t m,
779: vm_page_t new_m,
780: vm_object_t new_object,
781: vm_offset_t new_offset)
782: {
783: XPR(XPR_VM_PAGEOUT,
784: "vm_pageclean_copy, page 0x%X new_m 0x%X new_obj 0x%X offset 0x%X\n",
785: m, new_m, new_object, new_offset, 0);
786:
787: assert((!m->busy) && (!m->cleaning));
788:
789: assert(!new_m->private && !new_m->fictitious);
790:
791: pmap_clear_modify(m->phys_addr);
792:
793: m->busy = TRUE;
794: vm_object_paging_begin(m->object);
795: vm_page_unlock_queues();
796: vm_object_unlock(m->object);
797:
798: /*
799: * Copy the original page to the new page.
800: */
801: vm_page_copy(m, new_m);
802:
803: /*
804: * Mark the old page as clean. A request to pmap_is_modified
805: * will get the right answer.
806: */
807: vm_object_lock(m->object);
808: m->dirty = FALSE;
809:
810: vm_object_paging_end(m->object);
811:
812: vm_page_lock_queues();
813: if (!m->active && !m->inactive)
814: vm_page_activate(m);
815: PAGE_WAKEUP_DONE(m);
816:
817: vm_page_insert(new_m, new_object, new_offset);
818: vm_page_activate(new_m);
819: new_m->busy = FALSE; /* No other thread can be waiting */
820: }
821:
822:
823: /*
824: * Routine: vm_pageout_initialize_page
825: * Purpose:
826: * Causes the specified page to be initialized in
827: * the appropriate memory object. This routine is used to push
828: * pages into a copy-object when they are modified in the
829: * permanent object.
830: *
831: * The page is moved to a temporary object and paged out.
832: *
833: * In/out conditions:
834: * The page in question must not be on any pageout queues.
835: * The object to which it belongs must be locked.
836: * The page must be busy, but not hold a paging reference.
837: *
838: * Implementation:
839: * Move this page to a completely new object.
840: */
841: void
842: vm_pageout_initialize_page(
843: vm_page_t m)
844: {
845: vm_map_copy_t copy;
846: vm_object_t new_object;
847: vm_object_t object;
848: vm_offset_t paging_offset;
849: vm_page_t holding_page;
850:
851:
852: XPR(XPR_VM_PAGEOUT,
853: "vm_pageout_initialize_page, page 0x%X\n",
854: (integer_t)m, 0, 0, 0, 0);
855: assert(m->busy);
856:
857: /*
858: * Verify that we really want to clean this page
859: */
860: assert(!m->absent);
861: assert(!m->error);
862: assert(m->dirty);
863:
864: /*
865: * Create a paging reference to let us play with the object.
866: */
867: object = m->object;
868: paging_offset = m->offset + object->paging_offset;
869: vm_object_paging_begin(object);
870: vm_object_unlock(object);
871: if (m->absent || m->error || m->restart ||
872: (!m->dirty && !m->precious)) {
873: VM_PAGE_FREE(m);
874: panic("reservation without pageout?"); /* alan */
875: return;
876: }
877:
878: /* set the page for future call to vm_fault_list_request */
879: holding_page = NULL;
880: vm_object_lock(m->object);
881: vm_page_lock_queues();
882: pmap_clear_modify(m->phys_addr);
883: m->dirty = TRUE;
884: m->busy = TRUE;
885: m->list_req_pending = TRUE;
886: m->cleaning = TRUE;
887: m->pageout = TRUE;
888: vm_page_wire(m);
889: vm_page_unlock_queues();
890: vm_object_unlock(m->object);
891: vm_pageout_throttle(m);
892: copy = NULL;
893:
894: VM_STAT(pageouts++);
895: /* VM_STAT(pages_pagedout++); */
896:
897: /*
898: * Write the data to its pager.
899: * Note that the data is passed by naming the new object,
900: * not a virtual address; the pager interface has been
901: * manipulated to use the "internal memory" data type.
902: * [The object reference from its allocation is donated
903: * to the eventual recipient.]
904: */
905: memory_object_data_initialize(object->pager,
906: object->pager_request,
907: paging_offset,
908: POINTER_T(copy),
909: PAGE_SIZE);
910:
911: vm_object_lock(object);
912: }
913:
914: #if MACH_CLUSTER_STATS
915: #define MAXCLUSTERPAGES 16
916: struct {
917: unsigned long pages_in_cluster;
918: unsigned long pages_at_higher_offsets;
919: unsigned long pages_at_lower_offsets;
920: } cluster_stats[MAXCLUSTERPAGES];
921: #endif /* MACH_CLUSTER_STATS */
922:
923: boolean_t allow_clustered_pageouts = TRUE;
924:
925: /*
926: * vm_pageout_cluster:
927: *
928: * Given a page, page it out, and attempt to clean adjacent pages
929: * in the same operation.
930: *
931: * The page must be busy, and the object unlocked w/ paging reference
932: * to prevent deallocation or collapse. The page must not be on any
933: * pageout queue.
934: */
935: void
936: vm_pageout_cluster(
937: vm_page_t m)
938: {
939: vm_object_t object = m->object;
940: vm_offset_t offset = m->offset; /* from vm_object start */
941: vm_offset_t paging_offset = m->offset + object->paging_offset;
942: vm_object_t new_object;
943: vm_offset_t new_offset;
944: vm_size_t cluster_size;
945: vm_offset_t cluster_offset; /* from memory_object start */
946: vm_offset_t cluster_lower_bound; /* from vm_object_start */
947: vm_offset_t cluster_upper_bound; /* from vm_object_start */
948: vm_offset_t cluster_start, cluster_end; /* from vm_object start */
949: vm_offset_t offset_within_cluster;
950: vm_size_t length_of_data;
951: vm_page_t friend, holding_page;
952: vm_map_copy_t copy;
953: kern_return_t rc;
954: boolean_t precious_clean = FALSE;
955: int pages_in_cluster;
956:
957: CLUSTER_STAT(int pages_at_higher_offsets = 0;)
958: CLUSTER_STAT(int pages_at_lower_offsets = 0;)
959:
960: XPR(XPR_VM_PAGEOUT,
961: "vm_pageout_cluster, object 0x%X offset 0x%X page 0x%X\n",
962: (integer_t)object, offset, (integer_t)m, 0, 0);
963:
964: CLUSTER_STAT(vm_pageout_cluster_clusters++;)
965: /*
966: * Only a certain kind of page is appreciated here.
967: */
968: assert(m->busy && (m->dirty || m->precious) && (m->wire_count == 0));
969: assert(!m->cleaning && !m->pageout && !m->inactive && !m->active);
970:
971: vm_object_lock(object);
972: cluster_size = object->cluster_size;
973:
974: assert(cluster_size >= PAGE_SIZE);
975: if (cluster_size < PAGE_SIZE) cluster_size = PAGE_SIZE;
976: assert(object->pager_created && object->pager_initialized);
977: assert(object->internal || object->pager_ready);
978:
979: if (m->precious && !m->dirty)
980: precious_clean = TRUE;
981:
982: if (!object->pager_trusted || !allow_clustered_pageouts)
983: cluster_size = PAGE_SIZE;
984: vm_object_unlock(object);
985:
986: cluster_offset = paging_offset & (cluster_size - 1);
987: /* bytes from beginning of cluster */
988: /*
989: * Due to unaligned mappings, we have to be careful
990: * of negative offsets into the VM object. Clip the cluster
991: * boundary to the VM object, not the memory object.
992: */
993: if (offset > cluster_offset) {
994: cluster_lower_bound = offset - cluster_offset;
995: /* from vm_object */
996: } else {
997: cluster_lower_bound = 0;
998: }
999: cluster_upper_bound = (offset - cluster_offset) + cluster_size;
1000:
1001: /* set the page for future call to vm_fault_list_request */
1002: holding_page = NULL;
1003: vm_object_lock(m->object);
1004: vm_page_lock_queues();
1005: pmap_clear_modify(m->phys_addr);
1006: m->dirty = TRUE;
1007: m->busy = TRUE;
1008: m->list_req_pending = TRUE;
1009: m->cleaning = TRUE;
1010: m->pageout = TRUE;
1011: vm_page_wire(m);
1012: vm_page_unlock_queues();
1013: vm_object_unlock(m->object);
1014: vm_pageout_throttle(m);
1015:
1016: /*
1017: * Search backward for adjacent eligible pages to clean in
1018: * this operation.
1019: */
1020:
1021: cluster_start = offset;
1022: if (offset) { /* avoid wrap-around at zero */
1023: for (cluster_start = offset - PAGE_SIZE;
1024: cluster_start >= cluster_lower_bound;
1025: cluster_start -= PAGE_SIZE) {
1026: assert(cluster_size > PAGE_SIZE);
1027:
1028: vm_object_lock(object);
1029: vm_page_lock_queues();
1030:
1031: if ((friend = vm_pageout_cluster_page(object, cluster_start,
1032: precious_clean)) == VM_PAGE_NULL) {
1033: vm_page_unlock_queues();
1034: vm_object_unlock(object);
1035: break;
1036: }
1037: new_offset = (cluster_start + object->paging_offset)
1038: & (cluster_size - 1);
1039:
1040: assert(new_offset < cluster_offset);
1041: pmap_clear_modify(m->phys_addr);
1042: m->dirty = TRUE;
1043: m->list_req_pending = TRUE;
1044: m->cleaning = TRUE;
1045: /* do nothing except advance the write request, all we really need to */
1046: /* do is push the target page and let the code at the other end decide */
1047: /* what is really the right size */
1048: if (vm_page_free_count <= vm_page_free_reserved) {
1049: m->busy = TRUE;
1050: m->pageout = TRUE;
1051: vm_page_wire(m);
1052: }
1053:
1054: vm_page_unlock_queues();
1055: vm_object_unlock(object);
1056: CLUSTER_STAT(pages_at_lower_offsets++;)
1057:
1058: }
1059: cluster_start += PAGE_SIZE;
1060: }
1061: assert(cluster_start >= cluster_lower_bound);
1062: assert(cluster_start <= offset);
1063: /*
1064: * Search forward for adjacent eligible pages to clean in
1065: * this operation.
1066: */
1067: for (cluster_end = offset + PAGE_SIZE;
1068: cluster_end < cluster_upper_bound;
1069: cluster_end += PAGE_SIZE) {
1070: assert(cluster_size > PAGE_SIZE);
1071:
1072: vm_object_lock(object);
1073: vm_page_lock_queues();
1074:
1075: if ((friend = vm_pageout_cluster_page(object, cluster_end,
1076: precious_clean)) == VM_PAGE_NULL) {
1077: vm_page_unlock_queues();
1078: vm_object_unlock(object);
1079: break;
1080: }
1081: new_offset = (cluster_end + object->paging_offset)
1082: & (cluster_size - 1);
1083:
1084: assert(new_offset < cluster_size);
1085:
1086: pmap_clear_modify(m->phys_addr);
1087: m->dirty = TRUE;
1088: m->list_req_pending = TRUE;
1089: m->cleaning = TRUE;
1090: /* do nothing except advance the write request, all we really need to */
1091: /* do is push the target page and let the code at the other end decide */
1092: /* what is really the right size */
1093: if (vm_page_free_count <= vm_page_free_reserved) {
1094: m->busy = TRUE;
1095: m->pageout = TRUE;
1096: vm_page_wire(m);
1097: }
1098:
1099: vm_page_unlock_queues();
1100: vm_object_unlock(object);
1101: CLUSTER_STAT(pages_at_higher_offsets++;)
1102: }
1103: assert(cluster_end <= cluster_upper_bound);
1104: assert(cluster_end >= offset + PAGE_SIZE);
1105:
1106: /*
1107: * (offset - cluster_offset) is beginning of cluster_object
1108: * relative to vm_object start.
1109: */
1110: offset_within_cluster = cluster_start - (offset - cluster_offset);
1111: length_of_data = cluster_end - cluster_start;
1112:
1113: assert(offset_within_cluster < cluster_size);
1114: assert((offset_within_cluster + length_of_data) <= cluster_size);
1115:
1116: rc = KERN_SUCCESS;
1117: assert(rc == KERN_SUCCESS);
1118:
1119: pages_in_cluster = length_of_data/PAGE_SIZE;
1120: VM_STAT(pageouts++);
1121: /* VM_STAT(pages_pagedout += pages_in_cluster); */
1122:
1123: #if MACH_CLUSTER_STATS
1124: (cluster_stats[pages_at_lower_offsets].pages_at_lower_offsets)++;
1125: (cluster_stats[pages_at_higher_offsets].pages_at_higher_offsets)++;
1126: (cluster_stats[pages_in_cluster].pages_in_cluster)++;
1127: #endif /* MACH_CLUSTER_STATS */
1128:
1129: /*
1130: * Send the data to the pager.
1131: */
1132: paging_offset = cluster_start + object->paging_offset;
1133: #ifdef MACH_BSD
1134: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) ==
1135: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1136: rc = vnode_pager_data_return(object->pager,
1137: object->pager_request,
1138: paging_offset,
1139: POINTER_T(copy),
1140: length_of_data,
1141: !precious_clean,
1142: FALSE);
1143: } else {
1144: rc = memory_object_data_return(object->pager,
1145: object->pager_request,
1146: paging_offset,
1147: POINTER_T(copy),
1148: length_of_data,
1149: !precious_clean,
1150: FALSE);
1151: }
1152: #else
1153: rc = memory_object_data_return(object->pager,
1154: object->pager_request,
1155: paging_offset,
1156: POINTER_T(copy),
1157: length_of_data,
1158: !precious_clean,
1159: FALSE);
1160: #endif
1161: vm_object_paging_end(object);
1162:
1163: if (rc != KERN_SUCCESS)
1164: vm_map_copy_discard(copy);
1165:
1166: if (holding_page) {
1167: assert(!object->pager_trusted);
1168: vm_object_lock(object);
1169: VM_PAGE_FREE(holding_page);
1170: vm_object_paging_end(object);
1171: vm_object_unlock(object);
1172: }
1173: }
1174:
1175: /*
1176: * vm_pageout_return_write_pages
1177: * Recover pages from an aborted write attempt
1178: *
1179: */
1180:
1181: vm_pageout_return_write_pages(
1182: ipc_port_t control_port,
1183: vm_offset_t object_offset,
1184: vm_map_copy_t copy)
1185: {
1186: vm_object_t object;
1187: int offset;
1188: int size;
1189: int shadow_offset;
1190: int copy_offset;
1191: int j;
1192: vm_page_t m;
1193:
1194:
1195: object = copy->cpy_object;
1196: copy_offset = copy->offset;
1197: size = copy->size;
1198:
1199: if((copy->type != VM_MAP_COPY_OBJECT) || (object->shadow == 0)) {
1200: object = (vm_object_t)control_port->ip_kobject;
1201: shadow_offset = (object_offset - object->paging_offset)
1202: - copy->offset;
1203: } else {
1204: /* get the offset from the copy object */
1205: shadow_offset = object->shadow_offset;
1206: /* find the backing object */
1207: object = object->shadow;
1208: }
1209: vm_object_lock(object);
1210:
1211: for(offset = 0, j=0; offset < size; offset+=page_size, j++) {
1212: m = vm_page_lookup(object,
1213: offset + shadow_offset + copy_offset);
1214: if((m == VM_PAGE_NULL) || m->fictitious) {
1215:
1216: vm_page_t p;
1217: int i;
1218: vm_object_t copy_object;
1219:
1220: /* m might be fictitious if the original page */
1221: /* was found to be in limbo at the time of */
1222: /* vm_pageout_setup */
1223:
1224: if((m != VM_PAGE_NULL) && m->fictitious) {
1225: m->cleaning = FALSE;
1226: vm_page_remove(m);
1227: /* if object is not pager trusted then */
1228: /* this fictitious page will be removed */
1229: /* as the holding page in vm_pageout_cluster */
1230: if (object->pager_trusted)
1231: vm_page_free(m);
1232: if(vm_page_laundry_count)
1233: vm_page_laundry_count--;
1234: if (vm_page_laundry_count
1235: < vm_page_laundry_min) {
1236: vm_page_laundry_min = 0;
1237: thread_wakeup((event_t)
1238: &vm_page_laundry_count);
1239: }
1240: }
1241: else if ((object->pager_trusted) &&
1242: (copy->type == VM_MAP_COPY_OBJECT)) {
1243: vm_object_paging_end(object);
1244: }
1245:
1246: copy_object = copy->cpy_object;
1247:
1248: if(copy->type == VM_MAP_COPY_OBJECT) {
1249: p = (vm_page_t) queue_first(©_object->memq);
1250:
1251: for(i = 0;
1252: i < copy_object->resident_page_count;
1253: i++) {
1254: if(p->offset == (offset + copy_offset))
1255: break;
1256: p = (vm_page_t) queue_next(&p->listq);
1257: }
1258:
1259: vm_page_remove(p);
1260: } else {
1261: p = copy->cpy_page_list[j];
1262: copy->cpy_page_list[j] = 0;
1263: p->gobbled = FALSE;
1264: }
1265:
1266: vm_page_insert(p, object,
1267: offset + shadow_offset + copy_offset);
1268: p->busy = TRUE;
1269: p->dirty = TRUE;
1270: p->laundry = FALSE;
1271: if (p->pageout) {
1272: p->pageout = FALSE; /*dont throw away target*/
1273: vm_page_unwire(p);/* reactivates */
1274: }
1275: } else if(m->pageout) {
1276: m->pageout = FALSE; /* dont throw away target pages */
1277: vm_page_unwire(m);/* reactivates */
1278: }
1279: }
1280:
1281: vm_object_unlock(object);
1282: vm_map_copy_discard(copy);
1283: vm_object_lock(object);
1284:
1285: for(offset = 0; offset < size; offset+=page_size) {
1286: m = vm_page_lookup(object,
1287: offset + shadow_offset + copy_offset);
1288: m->dirty = TRUE; /* we'll send the pages home later */
1289: m->busy = FALSE; /* allow system access again */
1290: }
1291:
1292: vm_object_unlock(object);
1293: }
1294:
1295: /*
1296: * Trusted pager throttle.
1297: * Object must be unlocked, page queues must be unlocked.
1298: */
1299: void
1300: vm_pageout_throttle(
1301: register vm_page_t m)
1302: {
1303: vm_page_lock_queues();
1304: assert(!m->laundry);
1305: m->laundry = TRUE;
1306: while (vm_page_laundry_count >= vm_page_laundry_max) {
1307: /*
1308: * Set the threshold for when vm_page_free()
1309: * should wake us up.
1310: */
1311: vm_page_laundry_min = vm_page_laundry_max/2;
1312: assert_wait((event_t) &vm_page_laundry_count, THREAD_UNINT);
1313: vm_page_unlock_queues();
1314:
1315: /*
1316: * Pause to let the default pager catch up.
1317: */
1318: thread_block((void (*)(void)) 0);
1319: vm_page_lock_queues();
1320: }
1321: vm_page_laundry_count++;
1322: vm_page_unlock_queues();
1323: }
1324:
1325: /*
1326: * The global variable vm_pageout_clean_active_pages controls whether
1327: * active pages are considered valid to be cleaned in place during a
1328: * clustered pageout. Performance measurements are necessary to determine
1329: * the best policy.
1330: */
1331: int vm_pageout_clean_active_pages = 1;
1332: /*
1333: * vm_pageout_cluster_page: [Internal]
1334: *
1335: * return a vm_page_t to the page at (object,offset) if it is appropriate
1336: * to clean in place. Pages that are non-existent, busy, absent, already
1337: * cleaning, or not dirty are not eligible to be cleaned as an adjacent
1338: * page in a cluster.
1339: *
1340: * The object must be locked on entry, and remains locked throughout
1341: * this call.
1342: */
1343:
1344: vm_page_t
1345: vm_pageout_cluster_page(
1346: vm_object_t object,
1347: vm_offset_t offset,
1348: boolean_t precious_clean)
1349: {
1350: vm_page_t m;
1351:
1352: XPR(XPR_VM_PAGEOUT,
1353: "vm_pageout_cluster_page, object 0x%X offset 0x%X\n",
1354: (integer_t)object, offset, 0, 0, 0);
1355:
1356: if ((m = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
1357: return(VM_PAGE_NULL);
1358:
1359: if (m->busy || m->absent || m->cleaning ||
1360: m->prep_pin_count != 0 ||
1361: (m->wire_count != 0) || m->error)
1362: return(VM_PAGE_NULL);
1363:
1364: if (vm_pageout_clean_active_pages) {
1365: if (!m->active && !m->inactive) return(VM_PAGE_NULL);
1366: } else {
1367: if (!m->inactive) return(VM_PAGE_NULL);
1368: }
1369:
1370: assert(!m->private);
1371: assert(!m->fictitious);
1372:
1373: if (!m->dirty) m->dirty = pmap_is_modified(m->phys_addr);
1374:
1375: if (precious_clean) {
1376: if (!m->precious || m->dirty)
1377: return(VM_PAGE_NULL);
1378: } else {
1379: if (!m->dirty)
1380: return(VM_PAGE_NULL);
1381: }
1382: return(m);
1383: }
1384:
1385: /*
1386: * vm_pageout_scan does the dirty work for the pageout daemon.
1387: * It returns with vm_page_queue_free_lock held and
1388: * vm_page_free_wanted == 0.
1389: */
1390: extern void vm_pageout_scan_continue(void); /* forward; */
1391:
1392: void
1393: vm_pageout_scan(void)
1394: {
1395: unsigned int burst_count;
1396: boolean_t now = FALSE;
1397: unsigned int laundry_pages;
1398: boolean_t need_more_inactive_pages;
1399: unsigned int loop_detect;
1400:
1401: XPR(XPR_VM_PAGEOUT, "vm_pageout_scan\n", 0, 0, 0, 0, 0);
1402:
1403: /*???*/ /*
1404: * We want to gradually dribble pages from the active queue
1405: * to the inactive queue. If we let the inactive queue get
1406: * very small, and then suddenly dump many pages into it,
1407: * those pages won't get a sufficient chance to be referenced
1408: * before we start taking them from the inactive queue.
1409: *
1410: * We must limit the rate at which we send pages to the pagers.
1411: * data_write messages consume memory, for message buffers and
1412: * for map-copy objects. If we get too far ahead of the pagers,
1413: * we can potentially run out of memory.
1414: *
1415: * We can use the laundry count to limit directly the number
1416: * of pages outstanding to the default pager. A similar
1417: * strategy for external pagers doesn't work, because
1418: * external pagers don't have to deallocate the pages sent them,
1419: * and because we might have to send pages to external pagers
1420: * even if they aren't processing writes. So we also
1421: * use a burst count to limit writes to external pagers.
1422: *
1423: * When memory is very tight, we can't rely on external pagers to
1424: * clean pages. They probably aren't running, because they
1425: * aren't vm-privileged. If we kept sending dirty pages to them,
1426: * we could exhaust the free list. However, we can't just ignore
1427: * pages belonging to external objects, because there might be no
1428: * pages belonging to internal objects. Hence, we get the page
1429: * into an internal object and then immediately double-page it,
1430: * sending it to the default pager.
1431: *
1432: * consider_zone_gc should be last, because the other operations
1433: * might return memory to zones.
1434: */
1435:
1436: Restart:
1437:
1438: mutex_lock(&vm_page_queue_free_lock);
1439: now = (vm_page_free_count < vm_page_free_min);
1440: mutex_unlock(&vm_page_queue_free_lock);
1441: #if THREAD_SWAPPER
1442: swapout_threads(now);
1443: #endif /* THREAD_SWAPPER */
1444:
1445: stack_collect();
1446: consider_task_collect();
1447: consider_thread_collect();
1448: cleanup_limbo_queue();
1449: consider_zone_gc();
1450: consider_machine_collect();
1451:
1452: loop_detect = vm_page_active_count + vm_page_inactive_count;
1453:
1454: if (vm_page_free_count <= vm_page_free_reserved) {
1455: need_more_inactive_pages = TRUE;
1456: } else {
1457: need_more_inactive_pages = FALSE;
1458: }
1459: for (burst_count = 0;;) {
1460: register vm_page_t m;
1461: register vm_object_t object;
1462: unsigned int free_count;
1463:
1464: /*
1465: * Recalculate vm_page_inactivate_target.
1466: */
1467:
1468: vm_page_lock_queues();
1469: vm_page_inactive_target =
1470: VM_PAGE_INACTIVE_TARGET(vm_page_active_count +
1471: vm_page_inactive_count);
1472:
1473: /*
1474: * Move pages from active to inactive.
1475: */
1476:
1477: while ((vm_page_inactive_count < vm_page_inactive_target ||
1478: need_more_inactive_pages) &&
1479: !queue_empty(&vm_page_queue_active)) {
1480: register vm_object_t object;
1481:
1482: vm_pageout_active++;
1483: m = (vm_page_t) queue_first(&vm_page_queue_active);
1484:
1485: /*
1486: * If we're getting really low on memory,
1487: * try selecting a page that will go
1488: * directly to the default_pager.
1489: * If there are no such pages, we have to
1490: * page out a page backed by an EMM,
1491: * so that the default_pager can recover
1492: * it eventually.
1493: */
1494: if (need_more_inactive_pages &&
1495: (IP_VALID(memory_manager_default))) {
1496: vm_pageout_scan_active_emm_throttle++;
1497: do {
1498: assert(m->active && !m->inactive);
1499: object = m->object;
1500:
1501: if (vm_object_lock_try(object)) {
1502: if (object->pager_trusted ||
1503: object->internal) {
1504: /* found one ! */
1505: vm_pageout_scan_active_emm_throttle_success++;
1506: goto object_locked_active;
1507: }
1508: vm_object_unlock(object);
1509: }
1510: m = (vm_page_t) queue_next(&m->pageq);
1511: } while (!queue_end(&vm_page_queue_active,
1512: (queue_entry_t) m));
1513: if (queue_end(&vm_page_queue_active,
1514: (queue_entry_t) m)) {
1515: vm_pageout_scan_active_emm_throttle_failure++;
1516: m = (vm_page_t)
1517: queue_first(&vm_page_queue_active);
1518: }
1519: }
1520:
1521: assert(m->active && !m->inactive);
1522:
1523: object = m->object;
1524: if (!vm_object_lock_try(object)) {
1525: /*
1526: * Move page to end and continue.
1527: */
1528:
1529: queue_remove(&vm_page_queue_active, m,
1530: vm_page_t, pageq);
1531: queue_enter(&vm_page_queue_active, m,
1532: vm_page_t, pageq);
1533: vm_page_unlock_queues();
1534: mutex_pause();
1535: vm_page_lock_queues();
1536: continue;
1537: }
1538:
1539: object_locked_active:
1540: /*
1541: * If the page is busy, then we pull it
1542: * off the active queue and leave it alone.
1543: */
1544:
1545: if (m->busy) {
1546: vm_object_unlock(object);
1547: queue_remove(&vm_page_queue_active, m,
1548: vm_page_t, pageq);
1549: m->active = FALSE;
1550: if (!m->fictitious)
1551: vm_page_active_count--;
1552: continue;
1553: }
1554:
1555: /*
1556: * Deactivate the page while holding the object
1557: * locked, so we know the page is still not busy.
1558: * This should prevent races between pmap_enter
1559: * and pmap_clear_reference. The page might be
1560: * absent or fictitious, but vm_page_deactivate
1561: * can handle that.
1562: */
1563:
1564: vm_page_deactivate(m);
1565: vm_object_unlock(object);
1566: }
1567:
1568: /*
1569: * We are done if we have met our target *and*
1570: * nobody is still waiting for a page.
1571: */
1572:
1573: mutex_lock(&vm_page_queue_free_lock);
1574: free_count = vm_page_free_count;
1575: if ((free_count >= vm_page_free_target) &&
1576: (vm_page_free_wanted == 0)) {
1577: vm_page_unlock_queues();
1578: break;
1579: }
1580: mutex_unlock(&vm_page_queue_free_lock);
1581:
1582: /*
1583: * Sometimes we have to pause:
1584: * 1) No inactive pages - nothing to do.
1585: * 2) Flow control - wait for untrusted pagers to catch up.
1586: */
1587:
1588: if (queue_empty(&vm_page_queue_inactive) ||
1589: ((--loop_detect) == 0) ||
1590: (burst_count >= vm_pageout_burst_max)) {
1591: unsigned int pages, msecs;
1592:
1593: /*
1594: * vm_pageout_burst_wait is msecs/page.
1595: * If there is nothing for us to do, we wait
1596: * at least vm_pageout_empty_wait msecs.
1597: */
1598: pages = burst_count;
1599:
1600: if (loop_detect == 0) {
1601: printf("Warning: No physical memory suitable for pageout or reclaim, pageout thread temporarily going to sleep\n");
1602: msecs = vm_free_page_pause;
1603: }
1604: else {
1605: msecs = burst_count * vm_pageout_burst_wait;
1606: }
1607:
1608: if (queue_empty(&vm_page_queue_inactive) &&
1609: (msecs < vm_pageout_empty_wait))
1610: msecs = vm_pageout_empty_wait;
1611: vm_page_unlock_queues();
1612: assert_wait_timeout(msecs, THREAD_INTERRUPTIBLE);
1613: counter(c_vm_pageout_scan_block++);
1614:
1615: /*
1616: * Unfortunately, we don't have call_continuation
1617: * so we can't rely on tail-recursion.
1618: */
1619: thread_block((void (*)(void)) 0);
1620: thread_cancel_timer();
1621: vm_pageout_scan_continue();
1622: goto Restart;
1623: /*NOTREACHED*/
1624: }
1625:
1626: vm_pageout_inactive++;
1627: m = (vm_page_t) queue_first(&vm_page_queue_inactive);
1628:
1629: if ((vm_page_free_count <= vm_page_free_reserved) &&
1630: (IP_VALID(memory_manager_default))) {
1631: /*
1632: * We're really low on memory. Try to select a page that
1633: * would go directly to the default_pager.
1634: * If there are no such pages, we have to page out a
1635: * page backed by an EMM, so that the default_pager
1636: * can recover it eventually.
1637: */
1638: vm_pageout_scan_inactive_emm_throttle++;
1639: do {
1640: assert(!m->active && m->inactive);
1641: object = m->object;
1642:
1643: if (vm_object_lock_try(object)) {
1644: if (object->pager_trusted ||
1645: object->internal) {
1646: /* found one ! */
1647: vm_pageout_scan_inactive_emm_throttle_success++;
1648: goto object_locked_inactive;
1649: }
1650: vm_object_unlock(object);
1651: }
1652: m = (vm_page_t) queue_next(&m->pageq);
1653: } while (!queue_end(&vm_page_queue_inactive,
1654: (queue_entry_t) m));
1655: if (queue_end(&vm_page_queue_inactive,
1656: (queue_entry_t) m)) {
1657: vm_pageout_scan_inactive_emm_throttle_failure++;
1658: /*
1659: * We should check the "active" queue
1660: * for good candidates to page out.
1661: */
1662: need_more_inactive_pages = TRUE;
1663:
1664: m = (vm_page_t)
1665: queue_first(&vm_page_queue_inactive);
1666: }
1667: }
1668:
1669: assert(!m->active && m->inactive);
1670: object = m->object;
1671:
1672: /*
1673: * Try to lock object; since we've got the
1674: * page queues lock, we can only try for this one.
1675: */
1676:
1677: if (!vm_object_lock_try(object)) {
1678: /*
1679: * Move page to end and continue.
1680: */
1681: queue_remove(&vm_page_queue_inactive, m,
1682: vm_page_t, pageq);
1683: queue_enter(&vm_page_queue_inactive, m,
1684: vm_page_t, pageq);
1685: vm_page_unlock_queues();
1686: mutex_pause();
1687: vm_pageout_inactive_nolock++;
1688: continue;
1689: }
1690:
1691: object_locked_inactive:
1692: /*
1693: * Paging out pages of objects which pager is being
1694: * created by another thread must be avoided, because
1695: * this thread may claim for memory, thus leading to a
1696: * possible dead lock between it and the pageout thread
1697: * which will wait for pager creation, if such pages are
1698: * finally chosen. The remaining assumption is that there
1699: * will finally be enough available pages in the inactive
1700: * pool to page out in order to satisfy all memory claimed
1701: * by the thread which concurrently creates the pager.
1702: */
1703:
1704: if (!object->pager_initialized && object->pager_created) {
1705: /*
1706: * Move page to end and continue, hoping that
1707: * there will be enough other inactive pages to
1708: * page out so that the thread which currently
1709: * initializes the pager will succeed.
1710: */
1711: queue_remove(&vm_page_queue_inactive, m,
1712: vm_page_t, pageq);
1713: queue_enter(&vm_page_queue_inactive, m,
1714: vm_page_t, pageq);
1715: vm_page_unlock_queues();
1716: vm_object_unlock(object);
1717: vm_pageout_inactive_avoid++;
1718: continue;
1719: }
1720:
1721: /*
1722: * Remove the page from the inactive list.
1723: */
1724:
1725: queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
1726: m->inactive = FALSE;
1727: if (!m->fictitious)
1728: vm_page_inactive_count--;
1729:
1730: if (m->busy || !object->alive) {
1731: /*
1732: * Somebody is already playing with this page.
1733: * Leave it off the pageout queues.
1734: */
1735:
1736: vm_page_unlock_queues();
1737: vm_object_unlock(object);
1738: vm_pageout_inactive_busy++;
1739: continue;
1740: }
1741:
1742: /*
1743: * If it's absent or in error, we can reclaim the page.
1744: */
1745:
1746: if (m->absent || m->error) {
1747: vm_pageout_inactive_absent++;
1748: reclaim_page:
1749: vm_page_free(m);
1750: vm_page_unlock_queues();
1751: vm_object_unlock(object);
1752: continue;
1753: }
1754:
1755: assert(!m->private);
1756: assert(!m->fictitious);
1757:
1758: /*
1759: * If already cleaning this page in place, convert from
1760: * "adjacent" to "target". We can leave the page mapped,
1761: * and vm_pageout_object_terminate will determine whether
1762: * to free or reactivate.
1763: */
1764:
1765: if (m->cleaning) {
1766: #if MACH_CLUSTER_STATS
1767: vm_pageout_cluster_conversions++;
1768: #endif
1769: if (m->prep_pin_count == 0) {
1770: m->busy = TRUE;
1771: m->pageout = TRUE;
1772: vm_page_wire(m);
1773: }
1774: vm_object_unlock(object);
1775: vm_page_unlock_queues();
1776: continue;
1777: }
1778:
1779: /*
1780: * If it's being used, reactivate.
1781: * (Fictitious pages are either busy or absent.)
1782: */
1783:
1784: if (m->reference || pmap_is_referenced(m->phys_addr)) {
1785: vm_pageout_inactive_used++;
1786: reactivate_page:
1787: #if ADVISORY_PAGEOUT
1788: if (m->discard_request) {
1789: m->discard_request = FALSE;
1790: }
1791: #endif /* ADVISORY_PAGEOUT */
1792: vm_object_unlock(object);
1793: vm_page_activate(m);
1794: VM_STAT(reactivations++);
1795: vm_page_unlock_queues();
1796: continue;
1797: }
1798:
1799: if (m->prep_pin_count != 0) {
1800: boolean_t pinned = FALSE;
1801:
1802: vm_page_pin_lock();
1803: if (m->pin_count != 0) {
1804: /* skip and reactivate pinned page */
1805: pinned = TRUE;
1806: vm_pageout_inactive_pinned++;
1807: } else {
1808: /* page is prepped; send it into limbo */
1809: m->limbo = TRUE;
1810: vm_pageout_inactive_limbo++;
1811: }
1812: vm_page_pin_unlock();
1813: if (pinned)
1814: goto reactivate_page;
1815: }
1816:
1817: #if ADVISORY_PAGEOUT
1818: if (object->advisory_pageout) {
1819: boolean_t do_throttle;
1820: ipc_port_t port;
1821: vm_offset_t discard_offset;
1822:
1823: if (m->discard_request) {
1824: vm_stat_discard_failure++;
1825: goto mandatory_pageout;
1826: }
1827:
1828: assert(object->pager_initialized);
1829: m->discard_request = TRUE;
1830: port = object->pager;
1831:
1832: /* system-wide throttle */
1833: do_throttle = (vm_page_free_count <=
1834: vm_page_free_reserved);
1835: if (!do_throttle) {
1836: /* throttle on this pager */
1837: /* XXX lock ordering ? */
1838: ip_lock(port);
1839: do_throttle= imq_full(&port->ip_messages);
1840: ip_unlock(port);
1841: }
1842: if (do_throttle) {
1843: vm_stat_discard_throttle++;
1844: #if 0
1845: /* ignore this page and skip to next */
1846: vm_page_unlock_queues();
1847: vm_object_unlock(object);
1848: continue;
1849: #else
1850: /* force mandatory pageout */
1851: goto mandatory_pageout;
1852: #endif
1853: }
1854:
1855: /* proceed with discard_request */
1856: vm_page_activate(m);
1857: vm_stat_discard++;
1858: VM_STAT(reactivations++);
1859: discard_offset = m->offset + object->paging_offset;
1860: vm_stat_discard_sent++;
1861: vm_page_unlock_queues();
1862: vm_object_unlock(object);
1863: memory_object_discard_request(object->pager,
1864: object->pager_request,
1865: discard_offset,
1866: PAGE_SIZE);
1867: continue;
1868: }
1869: mandatory_pageout:
1870: #endif /* ADVISORY_PAGEOUT */
1871:
1872: XPR(XPR_VM_PAGEOUT,
1873: "vm_pageout_scan, replace object 0x%X offset 0x%X page 0x%X\n",
1874: (integer_t)object, (integer_t)m->offset, (integer_t)m, 0,0);
1875:
1876: /*
1877: * Eliminate all mappings.
1878: */
1879:
1880: m->busy = TRUE;
1881: pmap_page_protect(m->phys_addr, VM_PROT_NONE);
1882: if (!m->dirty)
1883: m->dirty = pmap_is_modified(m->phys_addr);
1884:
1885: /*
1886: * If it's clean and not precious, we can free the page.
1887: */
1888:
1889: if (!m->dirty && !m->precious) {
1890: vm_pageout_inactive_clean++;
1891: goto reclaim_page;
1892: }
1893: vm_page_unlock_queues();
1894:
1895: /*
1896: * If there is no memory object for the page, create
1897: * one and hand it to the default pager.
1898: * [First try to collapse, so we don't create
1899: * one unnecessarily.]
1900: */
1901:
1902: if (!object->pager_initialized)
1903: vm_object_collapse(object);
1904: if (!object->pager_initialized)
1905: vm_object_pager_create(object);
1906: if (!object->pager_initialized) {
1907: /*
1908: * Still no pager for the object.
1909: * Reactivate the page.
1910: *
1911: * Should only happen if there is no
1912: * default pager.
1913: */
1914: vm_page_lock_queues();
1915: vm_page_activate(m);
1916: vm_page_unlock_queues();
1917:
1918: /*
1919: * And we are done with it.
1920: */
1921: PAGE_WAKEUP_DONE(m);
1922: vm_object_unlock(object);
1923:
1924: /*
1925: * break here to get back to the preemption
1926: * point in the outer loop so that we don't
1927: * spin forever if there is no default pager.
1928: */
1929: vm_pageout_dirty_no_pager++;
1930: /*
1931: * Well there's no pager, but we can still reclaim
1932: * free pages out of the inactive list. Go back
1933: * to top of loop and look for suitable pages.
1934: */
1935: continue;
1936: }
1937:
1938: if (object->pager_initialized && object->pager == IP_NULL) {
1939: /*
1940: * This pager has been destroyed by either
1941: * memory_object_destroy or vm_object_destroy, and
1942: * so there is nowhere for the page to go.
1943: * Just free the page.
1944: */
1945: VM_PAGE_FREE(m);
1946: vm_object_unlock(object);
1947: continue;
1948: }
1949:
1950: vm_pageout_inactive_dirty++;
1951: if (!object->internal)
1952: burst_count++;
1953: vm_object_paging_begin(object);
1954: vm_object_unlock(object);
1955: vm_pageout_cluster(m); /* flush it */
1956: }
1957: }
1958:
1959: counter(unsigned int c_vm_pageout_scan_continue = 0;)
1960:
1961: void
1962: vm_pageout_scan_continue(void)
1963: {
1964: /*
1965: * We just paused to let the pagers catch up.
1966: * If vm_page_laundry_count is still high,
1967: * then we aren't waiting long enough.
1968: * If we have paused some vm_pageout_pause_max times without
1969: * adjusting vm_pageout_burst_wait, it might be too big,
1970: * so we decrease it.
1971: */
1972:
1973: vm_page_lock_queues();
1974: counter(++c_vm_pageout_scan_continue);
1975: if (vm_page_laundry_count > vm_pageout_burst_min) {
1976: vm_pageout_burst_wait++;
1977: vm_pageout_pause_count = 0;
1978: } else if (++vm_pageout_pause_count > vm_pageout_pause_max) {
1979: vm_pageout_burst_wait = (vm_pageout_burst_wait * 3) / 4;
1980: if (vm_pageout_burst_wait < 1)
1981: vm_pageout_burst_wait = 1;
1982: vm_pageout_pause_count = 0;
1983: }
1984: vm_page_unlock_queues();
1985: }
1986:
1987: void vm_page_free_reserve(int pages);
1988: int vm_page_free_count_init;
1989:
1990: void
1991: vm_page_free_reserve(
1992: int pages)
1993: {
1994: int free_after_reserve;
1995:
1996: vm_page_free_reserved += pages;
1997:
1998: free_after_reserve = vm_page_free_count_init - vm_page_free_reserved;
1999:
2000: vm_page_free_min = vm_page_free_reserved +
2001: VM_PAGE_FREE_MIN(free_after_reserve);
2002:
2003: vm_page_free_target = vm_page_free_reserved +
2004: VM_PAGE_FREE_TARGET(free_after_reserve);
2005:
2006: if (vm_page_free_target < vm_page_free_min + 5)
2007: vm_page_free_target = vm_page_free_min + 5;
2008: }
2009:
2010: /*
2011: * vm_pageout is the high level pageout daemon.
2012: */
2013:
2014:
2015: void
2016: vm_pageout(void)
2017: {
2018: thread_t thread;
2019: processor_set_t pset;
2020: kern_return_t ret;
2021: policy_base_t base;
2022: policy_limit_t limit;
2023: policy_fifo_base_data_t fifo_base;
2024: policy_fifo_limit_data_t fifo_limit;
2025:
2026: /*
2027: * Set thread privileges.
2028: */
2029: thread = current_thread();
2030: thread->vm_privilege = TRUE;
2031: stack_privilege(thread);
2032: thread_swappable(current_act(), FALSE);
2033:
2034: /*
2035: * Set thread scheduling priority and policy.
2036: */
2037: pset = thread->processor_set;
2038: base = (policy_base_t) &fifo_base;
2039: limit = (policy_limit_t) &fifo_limit;
2040: fifo_base.base_priority = BASEPRI_SYSTEM;
2041: fifo_limit.max_priority = BASEPRI_SYSTEM;
2042: ret = thread_set_policy(thread->top_act, pset, POLICY_FIFO,
2043: base, POLICY_TIMESHARE_BASE_COUNT,
2044: limit, POLICY_TIMESHARE_LIMIT_COUNT);
2045: if (ret != KERN_SUCCESS)
2046: printf("WARNING: vm_pageout_thread is being TIMESHARED!\n");
2047:
2048: /*
2049: * Initialize some paging parameters.
2050: */
2051:
2052: if (vm_page_laundry_max == 0)
2053: vm_page_laundry_max = VM_PAGE_LAUNDRY_MAX;
2054:
2055: if (vm_pageout_burst_max == 0)
2056: vm_pageout_burst_max = VM_PAGEOUT_BURST_MAX;
2057:
2058: if (vm_pageout_burst_wait == 0)
2059: vm_pageout_burst_wait = VM_PAGEOUT_BURST_WAIT;
2060:
2061: if (vm_pageout_empty_wait == 0)
2062: vm_pageout_empty_wait = VM_PAGEOUT_EMPTY_WAIT;
2063:
2064: vm_page_free_count_init = vm_page_free_count;
2065: /*
2066: * even if we've already called vm_page_free_reserve
2067: * call it again here to insure that the targets are
2068: * accurately calculated (it uses vm_page_free_count_init)
2069: * calling it with an arg of 0 will not change the reserve
2070: * but will re-calculate free_min and free_target
2071: */
2072: if (vm_page_free_reserved < VM_PAGE_FREE_RESERVED)
2073: vm_page_free_reserve(VM_PAGE_FREE_RESERVED - vm_page_free_reserved);
2074: else
2075: vm_page_free_reserve(0);
2076:
2077: /*
2078: * vm_pageout_scan will set vm_page_inactive_target.
2079: *
2080: * The pageout daemon is never done, so loop forever.
2081: * We should call vm_pageout_scan at least once each
2082: * time we are woken, even if vm_page_free_wanted is
2083: * zero, to check vm_page_free_target and
2084: * vm_page_inactive_target.
2085: */
2086: for (;;) {
2087: vm_pageout_scan();
2088: /* we hold vm_page_queue_free_lock now */
2089: assert(vm_page_free_wanted == 0);
2090: assert_wait((event_t) &vm_page_free_wanted, THREAD_UNINT);
2091: mutex_unlock(&vm_page_queue_free_lock);
2092: counter(c_vm_pageout_block++);
2093: thread_block((void (*)(void)) 0);
2094: }
2095: /*NOTREACHED*/
2096: }
2097:
2098:
2099:
2100: /*
2101: * Routine: vm_fault_list_request
2102: * Purpose:
2103: * Cause the population of a portion of a vm_object.
2104: * Depending on the nature of the request, the pages
2105: * returned may be contain valid data or be uninitialized.
2106: * A page list structure, listing the physical pages
2107: * will be returned upon request.
2108: * This function is called by the file system or any other
2109: * supplier of backing store to a pager.
2110: * IMPORTANT NOTE: The caller must still respect the relationship
2111: * between the vm_object and its backing memory object. The
2112: * caller MUST NOT substitute changes in the backing file
2113: * without first doing a memory_object_lock_request on the
2114: * target range unless it is know that the pages are not
2115: * shared with another entity at the pager level.
2116: * Copy_in_to:
2117: * if a page list structure is present
2118: * return the mapped physical pages, where a
2119: * page is not present, return a non-initialized
2120: * one. If the no_sync bit is turned on, don't
2121: * call the pager unlock to synchronize with other
2122: * possible copies of the page. Leave pages busy
2123: * in the original object, if a page list structure
2124: * was specified. When a commit of the page list
2125: * pages is done, the dirty bit will be set for each one.
2126: * Copy_out_from:
2127: * If a page list structure is present, return
2128: * all mapped pages. Where a page does not exist
2129: * map a zero filled one. Leave pages busy in
2130: * the original object. If a page list structure
2131: * is not specified, this call is a no-op.
2132: *
2133: * Note: access of default pager objects has a rather interesting
2134: * twist. The caller of this routine, presumably the file system
2135: * page cache handling code, will never actually make a request
2136: * against a default pager backed object. Only the default
2137: * pager will make requests on backing store related vm_objects
2138: * In this way the default pager can maintain the relationship
2139: * between backing store files (abstract memory objects) and
2140: * the vm_objects (cache objects), they support.
2141: *
2142: */
2143: kern_return_t
2144: vm_fault_list_request(
2145: vm_object_t object,
2146: vm_object_offset_t offset,
2147: vm_size_t size,
2148: upl_t *upl_ptr,
2149: upl_page_info_t **user_page_list_ptr,
2150: int page_list_count,
2151: int cntrl_flags)
2152: {
2153: vm_page_t dst_page;
2154: vm_object_offset_t dst_offset = offset;
2155: upl_page_info_t *user_page_list;
2156: vm_size_t xfer_size = size;
2157: boolean_t do_m_lock = FALSE;
2158: boolean_t dirty;
2159: upl_t upl = NULL;
2160: int entry;
2161:
2162: if(cntrl_flags & UPL_SET_INTERNAL)
2163: page_list_count = 20;
2164: if(user_page_list_ptr && (page_list_count < (size/page_size)))
2165: return KERN_INVALID_ARGUMENT;
2166:
2167: if((!object->internal) && (object->paging_offset != 0))
2168: panic("vm_fault_list_request: vnode object with non-zero paging offset\n");
2169:
2170: if((cntrl_flags & UPL_COPYOUT_FROM) && (upl_ptr == NULL)) {
2171: return KERN_SUCCESS;
2172: }
2173: if(upl_ptr) {
2174: if(cntrl_flags & UPL_SET_INTERNAL) {
2175: upl = upl_create(TRUE);
2176: user_page_list = (upl_page_info_t *)
2177: (((vm_offset_t)upl) + sizeof(struct upl));
2178: if(user_page_list_ptr)
2179: *user_page_list_ptr = user_page_list;
2180: else
2181: user_page_list = NULL;
2182: upl->flags |= UPL_INTERNAL;
2183: } else {
2184: upl = upl_create(FALSE);
2185: if(user_page_list_ptr)
2186: user_page_list = *user_page_list_ptr;
2187: else
2188: user_page_list = NULL;
2189: }
2190: upl->map_object = vm_object_allocate(size);
2191: vm_object_lock(upl->map_object);
2192: upl->map_object->shadow = object;
2193: upl->size = size;
2194: upl->offset = offset + object->paging_offset;
2195: upl->map_object->pageout = TRUE;
2196: upl->map_object->can_persist = FALSE;
2197: upl->map_object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
2198: upl->map_object->shadow_offset = offset;
2199: vm_object_unlock(upl->map_object);
2200: *upl_ptr = upl;
2201: }
2202: vm_object_lock(object);
2203: vm_object_paging_begin(object);
2204: entry = 0;
2205: if(cntrl_flags & UPL_COPYOUT_FROM) {
2206: while (xfer_size) {
2207: vm_page_t alias_page;
2208:
2209: if(((dst_page = vm_page_lookup(object,
2210: dst_offset)) == VM_PAGE_NULL) ||
2211: dst_page->fictitious ||
2212: dst_page->absent ||
2213: dst_page->error ||
2214: (dst_page->wire_count != 0 &&
2215: !dst_page->pageout) ||
2216: ((!(dst_page->dirty || dst_page->precious)) &&
2217: (cntrl_flags & UPL_RET_ONLY_DIRTY))) {
2218: if(user_page_list)
2219: user_page_list[entry].phys_addr = 0;
2220: } else {
2221:
2222: if(dst_page->busy &&
2223: (!(dst_page->list_req_pending &&
2224: dst_page->pageout))) {
2225: if(cntrl_flags & UPL_NOBLOCK) {
2226: if(user_page_list)
2227: user_page_list[entry]
2228: .phys_addr = 0;
2229: entry++;
2230: dst_offset += PAGE_SIZE;
2231: xfer_size -= PAGE_SIZE;
2232: continue;
2233: }
2234: /*someone else is playing with the */
2235: /* page. We will have to wait. */
2236: PAGE_ASSERT_WAIT(
2237: dst_page, THREAD_UNINT);
2238: vm_object_unlock(object);
2239: thread_block((void(*)(void))0);
2240: vm_object_lock(object);
2241: continue;
2242: }
2243: /* Someone else already cleaning the page? */
2244: if((dst_page->cleaning || dst_page->absent ||
2245: dst_page->prep_pin_count != 0 ||
2246: dst_page->wire_count != 0) &&
2247: !dst_page->list_req_pending) {
2248: if(user_page_list)
2249: user_page_list[entry].phys_addr = 0;
2250: entry++;
2251: dst_offset += PAGE_SIZE;
2252: xfer_size -= PAGE_SIZE;
2253: continue;
2254: }
2255: VM_PAGE_GRAB_FICTITIOUS(alias_page);
2256:
2257: /* eliminate all mappings from the */
2258: /* original object and its prodigy */
2259:
2260: vm_page_lock_queues();
2261: pmap_page_protect(dst_page->phys_addr,
2262: VM_PROT_NONE);
2263: /* Turn off busy indication on pending */
2264: /* pageout. Note: we can only get here */
2265: /* in the request pending case. */
2266: dst_page->list_req_pending = FALSE;
2267: dst_page->busy = FALSE;
2268: dst_page->cleaning = FALSE;
2269:
2270: dirty = pmap_is_modified(dst_page->phys_addr);
2271: dirty = dirty ? TRUE : dst_page->dirty;
2272:
2273: /* use pageclean setup, it is more convenient */
2274: /* even for the pageout cases here */
2275: vm_pageclean_setup(dst_page, alias_page,
2276: upl->map_object, size - xfer_size);
2277:
2278: if(!dirty) {
2279: dst_page->dirty = FALSE;
2280: dst_page->precious = TRUE;
2281: }
2282:
2283: if(dst_page->pageout)
2284: dst_page->busy = TRUE;
2285:
2286: alias_page->absent = FALSE;
2287: if(!(cntrl_flags & UPL_CLEAN_IN_PLACE)) {
2288: /* deny access to the target page */
2289: /* while it is being worked on */
2290: if((!dst_page->pageout) &&
2291: (dst_page->wire_count == 0)) {
2292: dst_page->busy = TRUE;
2293: dst_page->pageout = TRUE;
2294: vm_page_wire(dst_page);
2295: }
2296: }
2297: if(user_page_list) {
2298: user_page_list[entry].phys_addr
2299: = dst_page->phys_addr;
2300: user_page_list[entry].dirty =
2301: dst_page->dirty;
2302: user_page_list[entry].pageout =
2303: dst_page->pageout;
2304: user_page_list[entry].absent =
2305: dst_page->absent;
2306: }
2307:
2308: vm_page_unlock_queues();
2309: }
2310: entry++;
2311: dst_offset += PAGE_SIZE;
2312: xfer_size -= PAGE_SIZE;
2313: }
2314: } else {
2315: while (xfer_size) {
2316: dst_page = vm_page_lookup(object, dst_offset);
2317: if(dst_page != VM_PAGE_NULL) {
2318: if((dst_page->cleaning) &&
2319: !(dst_page->list_req_pending)) {
2320: /*someone else is writing to the */
2321: /* page. We will have to wait. */
2322: PAGE_ASSERT_WAIT(dst_page, THREAD_UNINT);
2323: vm_object_unlock(object);
2324: thread_block((void(*)(void))0);
2325: vm_object_lock(object);
2326: continue;
2327: }
2328: if ((dst_page->fictitious &&
2329: dst_page->list_req_pending)) {
2330: /* dump the fictitious page */
2331: dst_page->list_req_pending = FALSE;
2332: dst_page->clustered = FALSE;
2333: vm_page_lock_queues();
2334: vm_page_free(dst_page);
2335: vm_page_unlock_queues();
2336: } else if ((dst_page->absent &&
2337: dst_page->list_req_pending)) {
2338: /* the default_pager case */
2339: dst_page->list_req_pending = FALSE;
2340: dst_page->busy = FALSE;
2341: dst_page->clustered = FALSE;
2342: }
2343: }
2344: if((dst_page = vm_page_lookup(
2345: object, dst_offset)) == VM_PAGE_NULL) {
2346: /* need to allocate a page */
2347: dst_page = vm_page_alloc(object, dst_offset);
2348: if (dst_page == VM_PAGE_NULL) {
2349: vm_object_unlock(object);
2350: VM_PAGE_WAIT();
2351: vm_object_lock(object);
2352: continue;
2353: }
2354: dst_page->busy = FALSE;
2355: if(cntrl_flags & UPL_NO_SYNC) {
2356: dst_page->page_lock = 0;
2357: dst_page->unlock_request = 0;
2358: }
2359: dst_page->absent = TRUE;
2360: object->absent_count++;
2361: }
2362: dst_page->overwriting = TRUE;
2363: if(dst_page->fictitious) {
2364: panic("need corner case for fictitious page");
2365: }
2366: if(dst_page->page_lock) {
2367: do_m_lock = TRUE;
2368: }
2369: if(upl_ptr) {
2370: vm_page_t alias_page;
2371:
2372: VM_PAGE_GRAB_FICTITIOUS(alias_page);
2373: /* eliminate all mappings from the */
2374: /* original object and its prodigy */
2375:
2376: if(dst_page->busy) {
2377: /*someone else is playing with the */
2378: /* page. We will have to wait. */
2379: PAGE_ASSERT_WAIT(
2380: dst_page, THREAD_UNINT);
2381: vm_object_unlock(object);
2382: thread_block((void(*)(void))0);
2383: vm_object_lock(object);
2384: continue;
2385: }
2386:
2387: vm_page_lock_queues();
2388: pmap_page_protect(dst_page->phys_addr,
2389: VM_PROT_NONE);
2390: dirty = pmap_is_modified(dst_page->phys_addr);
2391: dirty = dirty ? TRUE : dst_page->dirty;
2392:
2393: vm_pageclean_setup(dst_page, alias_page,
2394: upl->map_object, size - xfer_size);
2395:
2396: if(cntrl_flags & UPL_CLEAN_IN_PLACE) {
2397: /* clean in place for read implies */
2398: /* that a write will be done on all */
2399: /* the pages that are dirty before */
2400: /* a upl commit is done. The caller */
2401: /* is obligated to preserve the */
2402: /* contents of all pages marked */
2403: /* dirty. */
2404: upl->flags |= UPL_CLEAR_DIRTY;
2405: }
2406:
2407: if(!dirty) {
2408: dst_page->dirty = FALSE;
2409: dst_page->precious = TRUE;
2410: }
2411:
2412: if (dst_page->wire_count == 0) {
2413: /* deny access to the target page while */
2414: /* it is being worked on */
2415: dst_page->busy = TRUE;
2416: } else {
2417: vm_page_wire(dst_page);
2418: }
2419: /* expect the page to be used */
2420: dst_page->reference = TRUE;
2421: dst_page->precious =
2422: (cntrl_flags & UPL_PRECIOUS)
2423: ? TRUE : FALSE;
2424: alias_page->absent = FALSE;
2425: if(user_page_list) {
2426: user_page_list[entry].phys_addr
2427: = dst_page->phys_addr;
2428: user_page_list[entry].dirty =
2429: dst_page->dirty;
2430: user_page_list[entry].pageout =
2431: dst_page->pageout;
2432: user_page_list[entry].absent =
2433: dst_page->absent;
2434: }
2435: vm_page_unlock_queues();
2436: }
2437: entry++;
2438: dst_offset += PAGE_SIZE;
2439: xfer_size -= PAGE_SIZE;
2440: }
2441: }
2442: if(do_m_lock) {
2443: vm_prot_t access_required;
2444: /* call back all associated pages from other users of the pager */
2445: /* all future updates will be on data which is based on the */
2446: /* changes we are going to make here. Note: it is assumed that */
2447: /* we already hold copies of the data so we will not be seeing */
2448: /* an avalanche of incoming data from the pager */
2449: access_required = (cntrl_flags & UPL_COPYOUT_FROM)
2450: ? VM_PROT_READ : VM_PROT_WRITE;
2451: while (TRUE) {
2452: kern_return_t rc;
2453: thread_t thread;
2454:
2455: if(!object->pager_ready) {
2456: thread = current_thread();
2457: vm_object_assert_wait(object,
2458: VM_OBJECT_EVENT_PAGER_READY, THREAD_UNINT);
2459: vm_object_unlock(object);
2460: thread_block((void (*)(void))0);
2461: if (thread->wait_result != THREAD_AWAKENED) {
2462: return(KERN_FAILURE);
2463: }
2464: vm_object_lock(object);
2465: continue;
2466: }
2467:
2468: vm_object_unlock(object);
2469:
2470: if (rc = memory_object_data_unlock(
2471: object->pager,
2472: object->pager_request,
2473: dst_offset + object->paging_offset,
2474: size,
2475: access_required)) {
2476: if (rc == MACH_SEND_INTERRUPTED)
2477: continue;
2478: else
2479: return KERN_FAILURE;
2480: }
2481: break;
2482:
2483: }
2484: /* lets wait on the last page requested */
2485: /* NOTE: we will have to update lock completed routine to signal */
2486: if(dst_page != VM_PAGE_NULL &&
2487: (access_required & dst_page->page_lock) != access_required) {
2488: PAGE_ASSERT_WAIT(dst_page, THREAD_UNINT);
2489: thread_block((void (*)(void))0);
2490: vm_object_lock(object);
2491: }
2492: }
2493: vm_object_unlock(object);
2494: return KERN_SUCCESS;
2495: }
2496:
2497: kern_return_t
2498: upl_system_list_request(
2499: vm_object_t object,
2500: vm_object_offset_t offset,
2501: vm_size_t size,
2502: vm_size_t super_cluster,
2503: upl_t *upl,
2504: upl_page_info_t **user_page_list_ptr,
2505: int page_list_count,
2506: int cntrl_flags)
2507: {
2508: if(object->paging_offset > offset)
2509: return KERN_FAILURE;
2510: offset = offset - object->paging_offset;
2511:
2512: /* turns off super cluster exercised by the default_pager */
2513: /*
2514: super_cluster = size;
2515: */
2516: if ((super_cluster > size) &&
2517: (vm_page_free_count > vm_page_free_reserved)) {
2518:
2519: vm_offset_t base_offset;
2520: vm_size_t super_size;
2521:
2522: base_offset = (vm_offset_t)(offset &
2523: ~((vm_offset_t) super_cluster - 1));
2524: super_size = (offset+size) > (base_offset + super_cluster) ?
2525: super_cluster<<1 : super_cluster;
2526: super_size = ((base_offset + super_size) > object->size) ?
2527: (object->size - base_offset) : super_size;
2528: if(offset > (base_offset + super_size))
2529: panic("upl_system_list_request: Missed target pageout 0x%x,0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", offset, base_offset, super_size, super_cluster, size, object->paging_offset);
2530: /* apparently there is a case where the vm requests a */
2531: /* page to be written out who's offset is beyond the */
2532: /* object size */
2533: if((offset + size) > (base_offset + super_size))
2534: super_size = (offset + size) - base_offset;
2535:
2536: offset = base_offset;
2537: size = super_size;
2538: }
2539: vm_fault_list_request(object, offset, size, upl, user_page_list_ptr,
2540: page_list_count, cntrl_flags);
2541: }
2542:
2543:
2544: kern_return_t
2545: upl_map(
2546: vm_map_t map,
2547: upl_t upl,
2548: vm_offset_t *dst_addr)
2549: {
2550: vm_size_t size;
2551: vm_offset_t offset;
2552: vm_offset_t addr;
2553: vm_page_t m;
2554: kern_return_t kr;
2555:
2556: /* check to see if already mapped */
2557: if(UPL_PAGE_LIST_MAPPED & upl->flags)
2558: return KERN_FAILURE;
2559:
2560: offset = 0; /* Always map the entire object */
2561: size = upl->size;
2562:
2563: vm_object_lock(upl->map_object);
2564: upl->map_object->ref_count++;
2565: vm_object_res_reference(upl->map_object);
2566: vm_object_unlock(upl->map_object);
2567:
2568: *dst_addr = 0;
2569:
2570:
2571: /* NEED A UPL_MAP ALIAS */
2572: kr = vm_map_enter(map, dst_addr, size, (vm_offset_t) 0, TRUE,
2573: upl->map_object, offset, FALSE,
2574: VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
2575:
2576: if (kr != KERN_SUCCESS)
2577: return(kr);
2578:
2579: for(addr=*dst_addr; size > 0; size-=PAGE_SIZE,addr+=PAGE_SIZE) {
2580: m = vm_page_lookup(upl->map_object, offset);
2581: if(m) {
2582: PMAP_ENTER(map->pmap, addr, m, VM_PROT_ALL, TRUE);
2583: }
2584: offset+=PAGE_SIZE;
2585: }
2586:
2587: upl->flags |= UPL_PAGE_LIST_MAPPED;
2588: upl->kaddr = *dst_addr;
2589: return KERN_SUCCESS;
2590: }
2591:
2592:
2593: kern_return_t
2594: upl_un_map(
2595: vm_map_t map,
2596: upl_t upl)
2597: {
2598: vm_size_t size;
2599:
2600: if(upl->flags & UPL_PAGE_LIST_MAPPED) {
2601: size = upl->size;
2602: vm_deallocate(map, upl->kaddr, size);
2603: upl->flags &= ~UPL_PAGE_LIST_MAPPED;
2604: upl->kaddr = (vm_offset_t) 0;
2605: return KERN_SUCCESS;
2606: } else {
2607: return KERN_FAILURE;
2608: }
2609: }
2610:
2611: kern_return_t
2612: upl_commit_range(
2613: upl_t upl,
2614: vm_offset_t offset,
2615: vm_size_t size,
2616: boolean_t free_on_empty,
2617: upl_page_info_t *page_list)
2618: {
2619: vm_offset_t xfer_size = size;
2620: vm_object_t shadow_object = upl->map_object->shadow;
2621: vm_object_t object = upl->map_object;
2622: vm_offset_t target_offset;
2623: vm_offset_t page_offset;
2624: int entry;
2625:
2626: if ((offset + size) > upl->size)
2627: return KERN_FAILURE;
2628:
2629: vm_object_lock(shadow_object);
2630:
2631: entry = offset/PAGE_SIZE;
2632: target_offset = offset;
2633: while(xfer_size) {
2634: vm_page_t t,m;
2635: upl_page_info_t *p;
2636:
2637: if((t = vm_page_lookup(object,
2638: (vm_offset_t)target_offset)) != NULL) {
2639:
2640: t->pageout = FALSE;
2641: page_offset = (vm_offset_t)t->offset;
2642: VM_PAGE_FREE(t);
2643: t = VM_PAGE_NULL;
2644: m = vm_page_lookup(shadow_object,
2645: page_offset + object->shadow_offset);
2646: if(m != VM_PAGE_NULL) {
2647: vm_object_paging_end(shadow_object);
2648: vm_page_lock_queues();
2649: if (upl->flags & UPL_CLEAR_DIRTY) {
2650: pmap_clear_modify(m->phys_addr);
2651: m->dirty = FALSE;
2652: }
2653: if(page_list) {
2654: p = &(page_list[entry]);
2655: if(p->phys_addr && p->pageout && !m->pageout) {
2656: m->busy = TRUE;
2657: m->pageout = TRUE;
2658: vm_page_wire(m);
2659: } else if (page_list[entry].phys_addr &&
2660: !p->pageout && m->pageout) {
2661: m->pageout = FALSE;
2662: vm_page_unwire(m);
2663: PAGE_WAKEUP_DONE(m);
2664: }
2665: page_list[entry].phys_addr = 0;
2666: }
2667: if(m->laundry) {
2668: vm_page_laundry_count--;
2669: m->laundry = FALSE;
2670: if (vm_page_laundry_count < vm_page_laundry_min) {
2671: vm_page_laundry_min = 0;
2672: thread_wakeup((event_t)
2673: &vm_page_laundry_count);
2674: }
2675: }
2676: if(m->pageout) {
2677: m->cleaning = FALSE;
2678: m->pageout = FALSE;
2679: #if MACH_CLUSTER_STATS
2680: if (m->wanted) vm_pageout_target_collisions++;
2681: #endif
2682: pmap_page_protect(m->phys_addr, VM_PROT_NONE);
2683: m->dirty = pmap_is_modified(m->phys_addr);
2684: if(m->dirty) {
2685: CLUSTER_STAT(
2686: vm_pageout_target_page_dirtied++;)
2687: vm_page_unwire(m);/* reactivates */
2688: VM_STAT(reactivations++);
2689: PAGE_WAKEUP_DONE(m);
2690: } else if (m->prep_pin_count != 0) {
2691: vm_page_pin_lock();
2692: if (m->pin_count != 0) {
2693: /* page is pinned; reactivate */
2694: CLUSTER_STAT(
2695: vm_pageout_target_page_pinned++;)
2696: vm_page_unwire(m);/* reactivates */
2697: VM_STAT(reactivations++);
2698: PAGE_WAKEUP_DONE(m);
2699: } else {
2700: /*
2701: * page is prepped but not pinned;
2702: * send it into limbo. Note that
2703: * vm_page_free (which will be
2704: * called after releasing the pin
2705: * lock) knows how to handle a page
2706: * with limbo set.
2707: */
2708: m->limbo = TRUE;
2709: CLUSTER_STAT(
2710: vm_pageout_target_page_limbo++;)
2711: }
2712: vm_page_pin_unlock();
2713: if (m->limbo)
2714: vm_page_free(m);
2715: } else {
2716: CLUSTER_STAT(
2717: vm_pageout_target_page_freed++;)
2718: vm_page_free(m);/* clears busy, etc. */
2719: }
2720: vm_page_unlock_queues();
2721: target_offset += PAGE_SIZE;
2722: xfer_size -= PAGE_SIZE;
2723: entry++;
2724: continue;
2725: }
2726: if (!m->active && !m->inactive) {
2727: if (m->reference || m->prep_pin_count != 0)
2728: vm_page_activate(m);
2729: else
2730: vm_page_deactivate(m);
2731: }
2732: #if MACH_CLUSTER_STATS
2733: m->dirty = pmap_is_modified(m->phys_addr);
2734:
2735: if (m->dirty) vm_pageout_cluster_dirtied++;
2736: else vm_pageout_cluster_cleaned++;
2737: if (m->wanted) vm_pageout_cluster_collisions++;
2738: #else
2739: m->dirty = 0;
2740: #endif
2741:
2742: if((m->busy) && (m->cleaning)) {
2743: /* the request_page_list case */
2744: if(m->absent) {
2745: m->absent = FALSE;
2746: if(shadow_object->absent_count == 1)
2747: vm_object_absent_release(shadow_object);
2748: else
2749: shadow_object->absent_count--;
2750: }
2751: m->overwriting = FALSE;
2752: m->busy = FALSE;
2753: m->dirty = FALSE;
2754: }
2755: else if (m->overwriting) {
2756: /* alternate request page list, write to
2757: /* page_list case. Occurs when the original
2758: /* page was wired at the time of the list
2759: /* request */
2760: assert(m->wire_count != 0);
2761: vm_page_unwire(m);/* reactivates */
2762: m->overwriting = FALSE;
2763: }
2764: m->cleaning = FALSE;
2765: /*
2766: * Wakeup any thread waiting for the page to be un-cleaning.
2767: */
2768: PAGE_WAKEUP(m);
2769: vm_page_unlock_queues();
2770:
2771: }
2772: }
2773: target_offset += PAGE_SIZE;
2774: xfer_size -= PAGE_SIZE;
2775: entry++;
2776: }
2777:
2778: vm_object_unlock(shadow_object);
2779: if(free_on_empty) {
2780: if(queue_empty(&upl->map_object->memq)) {
2781: upl_destroy(upl);
2782: }
2783: }
2784: return KERN_SUCCESS;
2785: }
2786:
2787: upl_abort_range(
2788: upl_t upl,
2789: vm_offset_t offset,
2790: vm_size_t size,
2791: int error)
2792: {
2793: vm_offset_t xfer_size = size;
2794: vm_object_t shadow_object = upl->map_object->shadow;
2795: vm_object_t object = upl->map_object;
2796: vm_offset_t target_offset;
2797: vm_offset_t page_offset;
2798: int entry;
2799:
2800: if ((offset + size) > upl->size)
2801: return KERN_FAILURE;
2802:
2803: vm_object_lock(shadow_object);
2804:
2805: entry = offset/PAGE_SIZE;
2806: target_offset = offset;
2807: while(xfer_size) {
2808: vm_page_t t,m;
2809: upl_page_info_t *p;
2810:
2811: if((t = vm_page_lookup(object,
2812: (vm_offset_t)target_offset)) != NULL) {
2813:
2814: t->pageout = FALSE;
2815: page_offset = (vm_offset_t)t->offset;
2816: VM_PAGE_FREE(t);
2817: t = VM_PAGE_NULL;
2818: m = vm_page_lookup(shadow_object,
2819: page_offset + object->shadow_offset);
2820: if(m != VM_PAGE_NULL) {
2821: vm_object_paging_end(m->object);
2822: vm_page_lock_queues();
2823: if(m->absent) {
2824: /* COPYOUT = FALSE case */
2825: /* check for error conditions which must */
2826: /* be passed back to the pages customer */
2827: if(error & UPL_ABORT_RESTART) {
2828: m->restart = TRUE;
2829: m->absent = FALSE;
2830: vm_object_absent_release(m->object);
2831: m->page_error = KERN_MEMORY_ERROR;
2832: m->error = TRUE;
2833: } else if(error & UPL_ABORT_UNAVAILABLE) {
2834: m->restart = FALSE;
2835: m->unusual = TRUE;
2836: m->clustered = FALSE;
2837: } else if(error & UPL_ABORT_ERROR) {
2838: m->restart = FALSE;
2839: m->absent = FALSE;
2840: vm_object_absent_release(m->object);
2841: m->page_error = KERN_MEMORY_ERROR;
2842: m->error = TRUE;
2843: } else {
2844: m->clustered = TRUE;
2845: }
2846:
2847:
2848: m->cleaning = FALSE;
2849: m->overwriting = FALSE;
2850: PAGE_WAKEUP_DONE(m);
2851: if(m->clustered) {
2852: vm_page_free(m);
2853: } else {
2854: vm_page_activate(m);
2855: }
2856:
2857: vm_page_unlock_queues();
2858: target_offset += PAGE_SIZE;
2859: xfer_size -= PAGE_SIZE;
2860: entry++;
2861: continue;
2862: }
2863: /*
2864: * Handle the trusted pager throttle.
2865: */
2866: if (m->laundry) {
2867: vm_page_laundry_count--;
2868: m->laundry = FALSE;
2869: if (vm_page_laundry_count
2870: < vm_page_laundry_min) {
2871: vm_page_laundry_min = 0;
2872: thread_wakeup((event_t)
2873: &vm_page_laundry_count);
2874: }
2875: }
2876: if(m->pageout) {
2877: assert(m->busy);
2878: assert(m->wire_count == 1);
2879: m->pageout = FALSE;
2880: vm_page_unwire(m);
2881: }
2882: m->dirty = TRUE;
2883: m->cleaning = FALSE;
2884: m->busy = FALSE;
2885: m->overwriting = FALSE;
2886: PAGE_WAKEUP(m);
2887: vm_page_unlock_queues();
2888: }
2889: }
2890: target_offset += PAGE_SIZE;
2891: xfer_size -= PAGE_SIZE;
2892: entry++;
2893: }
2894: vm_object_unlock(shadow_object);
2895: if(error & UPL_ABORT_FREE_ON_EMPTY) {
2896: if(queue_empty(&upl->map_object->memq)) {
2897: upl_destroy(upl);
2898: }
2899: }
2900: return KERN_SUCCESS;
2901: }
2902:
2903: kern_return_t
2904: upl_abort(
2905: upl_t upl,
2906: int error)
2907: {
2908: vm_object_t object = NULL;
2909: vm_object_t shadow_object = NULL;
2910: vm_offset_t offset;
2911: vm_object_offset_t shadow_offset;
2912: vm_object_offset_t target_offset;
2913: int i;
2914: vm_page_t t,m;
2915:
2916: object = upl->map_object;
2917:
2918: if(object == NULL) {
2919: panic("upl_abort: upl object is not backed by an object");
2920: return KERN_INVALID_ARGUMENT;
2921: }
2922:
2923: shadow_object = upl->map_object->shadow;
2924: shadow_offset = upl->map_object->shadow_offset;
2925: offset = 0;
2926: vm_object_lock(shadow_object);
2927: for(i = 0; i<(upl->size); i+=PAGE_SIZE) {
2928: if((t = vm_page_lookup(object,
2929: (vm_offset_t)offset)) != NULL) {
2930: target_offset = t->offset + shadow_offset;
2931: if((m = vm_page_lookup(shadow_object, target_offset)) != NULL) {
2932: vm_object_paging_end(m->object);
2933: vm_page_lock_queues();
2934: if(m->absent) {
2935: /* COPYOUT = FALSE case */
2936: /* check for error conditions which must */
2937: /* be passed back to the pages customer */
2938: if(error & UPL_ABORT_RESTART) {
2939: m->restart = TRUE;
2940: m->absent = FALSE;
2941: vm_object_absent_release(m->object);
2942: m->page_error = KERN_MEMORY_ERROR;
2943: m->error = TRUE;
2944: } else if(error & UPL_ABORT_UNAVAILABLE) {
2945: m->restart = FALSE;
2946: m->unusual = TRUE;
2947: m->clustered = FALSE;
2948: } else if(error & UPL_ABORT_ERROR) {
2949: m->restart = FALSE;
2950: m->absent = FALSE;
2951: vm_object_absent_release(m->object);
2952: m->page_error = KERN_MEMORY_ERROR;
2953: m->error = TRUE;
2954: } else {
2955: m->clustered = TRUE;
2956: }
2957:
2958:
2959: m->cleaning = FALSE;
2960: m->overwriting = FALSE;
2961: PAGE_WAKEUP_DONE(m);
2962: if(m->clustered) {
2963: vm_page_free(m);
2964: } else {
2965: vm_page_activate(m);
2966: }
2967:
2968: vm_page_unlock_queues();
2969: continue;
2970: }
2971: /*
2972: * Handle the trusted pager throttle.
2973: */
2974: if (m->laundry) {
2975: vm_page_laundry_count--;
2976: m->laundry = FALSE;
2977: if (vm_page_laundry_count
2978: < vm_page_laundry_min) {
2979: vm_page_laundry_min = 0;
2980: thread_wakeup((event_t)
2981: &vm_page_laundry_count);
2982: }
2983: }
2984: if(m->pageout) {
2985: assert(m->busy);
2986: assert(m->wire_count == 1);
2987: m->pageout = FALSE;
2988: vm_page_unwire(m);
2989: }
2990: m->dirty = TRUE;
2991: m->cleaning = FALSE;
2992: m->busy = FALSE;
2993: m->overwriting = FALSE;
2994: PAGE_WAKEUP(m);
2995: vm_page_unlock_queues();
2996: }
2997: }
2998: offset += PAGE_SIZE;
2999: }
3000: vm_object_unlock(shadow_object);
3001: /* Remove all the pages from the map object so */
3002: /* vm_pageout_object_terminate will work properly. */
3003: while (!queue_empty(&upl->map_object->memq)) {
3004: vm_page_t p;
3005:
3006: p = (vm_page_t) queue_first(&upl->map_object->memq);
3007:
3008: assert(p->private);
3009: assert(p->pageout);
3010: p->pageout = FALSE;
3011: assert(!p->cleaning);
3012:
3013: VM_PAGE_FREE(p);
3014: }
3015: upl_destroy(upl);
3016: return KERN_SUCCESS;
3017: }
3018:
3019: /* an option on commit should be wire */
3020: kern_return_t
3021: upl_commit(
3022: upl_t upl,
3023: upl_page_info_t *page_list)
3024: {
3025: if (upl->flags & UPL_CLEAR_DIRTY) {
3026: vm_object_t shadow_object = upl->map_object->shadow;
3027: vm_object_t object = upl->map_object;
3028: vm_object_offset_t target_offset;
3029: vm_size_t xfer_end;
3030:
3031: vm_page_t t,m;
3032:
3033: vm_object_lock(shadow_object);
3034:
3035: target_offset = object->shadow_offset;
3036: xfer_end = upl->size + object->shadow_offset;
3037:
3038: while(target_offset <= xfer_end) {
3039: if ((t = vm_page_lookup(object,
3040: target_offset - object->shadow_offset))
3041: != NULL) {
3042: m = vm_page_lookup(
3043: shadow_object, target_offset);
3044: if(m != VM_PAGE_NULL) {
3045: pmap_clear_modify(m->phys_addr);
3046: m->dirty = FALSE;
3047: }
3048: }
3049: target_offset += PAGE_SIZE;
3050: }
3051: vm_object_unlock(shadow_object);
3052: }
3053: if (page_list) {
3054: vm_object_t shadow_object = upl->map_object->shadow;
3055: vm_object_t object = upl->map_object;
3056: vm_object_offset_t target_offset;
3057: vm_size_t xfer_end;
3058: int entry;
3059:
3060: vm_page_t m;
3061: upl_page_info_t *p;
3062:
3063: vm_object_lock(shadow_object);
3064:
3065: entry = 0;
3066: target_offset = object->shadow_offset;
3067: xfer_end = upl->size + object->shadow_offset;
3068:
3069: while(target_offset <= xfer_end) {
3070:
3071: m = vm_page_lookup(shadow_object, target_offset);
3072: if(m != VM_PAGE_NULL) {
3073: p = &(page_list[entry]);
3074: if(page_list[entry].phys_addr &&
3075: p->pageout && !m->pageout) {
3076: vm_page_lock_queues();
3077: m->busy = TRUE;
3078: m->pageout = TRUE;
3079: vm_page_wire(m);
3080: vm_page_unlock_queues();
3081: } else if (page_list[entry].phys_addr &&
3082: !p->pageout && m->pageout) {
3083: vm_page_lock_queues();
3084: m->pageout = FALSE;
3085: vm_page_unwire(m);
3086: PAGE_WAKEUP_DONE(m);
3087: vm_page_unlock_queues();
3088: }
3089: page_list[entry].phys_addr = 0;
3090: }
3091: target_offset += PAGE_SIZE;
3092: entry++;
3093: }
3094:
3095: vm_object_unlock(shadow_object);
3096: }
3097: upl_destroy(upl);
3098: return KERN_SUCCESS;
3099: }
3100:
3101: upl_t
3102: upl_create(
3103: boolean_t internal)
3104: {
3105: upl_t upl;
3106:
3107: if(internal) {
3108: upl = (upl_t)kalloc(sizeof(struct upl)
3109: + (sizeof(struct upl_page_info)*20));
3110: } else {
3111: upl = (upl_t)kalloc(sizeof(struct upl));
3112: }
3113: upl->flags = 0;
3114: upl->src_object = NULL;
3115: upl->kaddr = (vm_offset_t)0;
3116: upl->size = 0;
3117: upl->map_object = NULL;
3118: upl->ref_count = 1;
3119: upl_lock_init(upl);
3120: return(upl);
3121: }
3122:
3123: void
3124: upl_destroy(
3125: upl_t upl)
3126: {
3127: vm_object_deallocate(upl->map_object);
3128: if(upl->flags & UPL_INTERNAL) {
3129: kfree((vm_offset_t)upl,
3130: sizeof(struct upl) + (sizeof(struct upl_page_info)*20));
3131: } else {
3132: kfree((vm_offset_t)upl, sizeof(struct upl));
3133: }
3134: }
3135:
3136: vm_size_t
3137: upl_get_internal_pagelist_offset()
3138: {
3139: return sizeof(struct upl);
3140: }
3141:
3142: void
3143: upl_set_dirty(
3144: upl_t upl)
3145: {
3146: upl->flags |= UPL_CLEAR_DIRTY;
3147: }
3148:
3149: void
3150: upl_clear_dirty(
3151: upl_t upl)
3152: {
3153: upl->flags &= ~UPL_CLEAR_DIRTY;
3154: }
3155:
3156:
3157:
3158:
3159: #if MACH_KDB
3160: #include <ddb/db_output.h>
3161: #include <ddb/db_print.h>
3162: #include <vm/vm_print.h>
3163:
3164: #define printf kdbprintf
3165: extern int db_indent;
3166: void db_pageout(void);
3167:
3168: void
3169: db_vm(void)
3170: {
3171: extern int vm_page_gobble_count;
3172: extern int vm_page_limbo_count, vm_page_limbo_real_count;
3173: extern int vm_page_pin_count;
3174:
3175: iprintf("VM Statistics:\n");
3176: db_indent += 2;
3177: iprintf("pages:\n");
3178: db_indent += 2;
3179: iprintf("activ %5d inact %5d free %5d",
3180: vm_page_active_count, vm_page_inactive_count,
3181: vm_page_free_count);
3182: printf(" wire %5d gobbl %5d\n",
3183: vm_page_wire_count, vm_page_gobble_count);
3184: iprintf("laund %5d limbo %5d lim_r %5d pin %5d\n",
3185: vm_page_laundry_count, vm_page_limbo_count,
3186: vm_page_limbo_real_count, vm_page_pin_count);
3187: db_indent -= 2;
3188: iprintf("target:\n");
3189: db_indent += 2;
3190: iprintf("min %5d inact %5d free %5d",
3191: vm_page_free_min, vm_page_inactive_target,
3192: vm_page_free_target);
3193: printf(" resrv %5d\n", vm_page_free_reserved);
3194: db_indent -= 2;
3195:
3196: iprintf("burst:\n");
3197: db_indent += 2;
3198: iprintf("max %5d min %5d wait %5d empty %5d\n",
3199: vm_pageout_burst_max, vm_pageout_burst_min,
3200: vm_pageout_burst_wait, vm_pageout_empty_wait);
3201: db_indent -= 2;
3202: iprintf("pause:\n");
3203: db_indent += 2;
3204: iprintf("count %5d max %5d\n",
3205: vm_pageout_pause_count, vm_pageout_pause_max);
3206: #if MACH_COUNTERS
3207: iprintf("scan_continue called %8d\n", c_vm_pageout_scan_continue);
3208: #endif /* MACH_COUNTERS */
3209: db_indent -= 2;
3210: db_pageout();
3211: db_indent -= 2;
3212: }
3213:
3214: void
3215: db_pageout(void)
3216: {
3217: extern int c_limbo_page_free;
3218: extern int c_limbo_convert;
3219: #if MACH_COUNTERS
3220: extern int c_laundry_pages_freed;
3221: #endif /* MACH_COUNTERS */
3222:
3223: iprintf("Pageout Statistics:\n");
3224: db_indent += 2;
3225: iprintf("active %5d inactv %5d\n",
3226: vm_pageout_active, vm_pageout_inactive);
3227: iprintf("nolock %5d avoid %5d busy %5d absent %5d\n",
3228: vm_pageout_inactive_nolock, vm_pageout_inactive_avoid,
3229: vm_pageout_inactive_busy, vm_pageout_inactive_absent);
3230: iprintf("used %5d clean %5d dirty %5d\n",
3231: vm_pageout_inactive_used, vm_pageout_inactive_clean,
3232: vm_pageout_inactive_dirty);
3233: iprintf("pinned %5d limbo %5d setup_limbo %5d setup_unprep %5d\n",
3234: vm_pageout_inactive_pinned, vm_pageout_inactive_limbo,
3235: vm_pageout_setup_limbo, vm_pageout_setup_unprepped);
3236: iprintf("limbo_page_free %5d limbo_convert %5d\n",
3237: c_limbo_page_free, c_limbo_convert);
3238: #if MACH_COUNTERS
3239: iprintf("laundry_pages_freed %d\n", c_laundry_pages_freed);
3240: #endif /* MACH_COUNTERS */
3241: #if MACH_CLUSTER_STATS
3242: iprintf("Cluster Statistics:\n");
3243: db_indent += 2;
3244: iprintf("dirtied %5d cleaned %5d collisions %5d\n",
3245: vm_pageout_cluster_dirtied, vm_pageout_cluster_cleaned,
3246: vm_pageout_cluster_collisions);
3247: iprintf("clusters %5d conversions %5d\n",
3248: vm_pageout_cluster_clusters, vm_pageout_cluster_conversions);
3249: db_indent -= 2;
3250: iprintf("Target Statistics:\n");
3251: db_indent += 2;
3252: iprintf("collisions %5d page_dirtied %5d page_freed %5d\n",
3253: vm_pageout_target_collisions, vm_pageout_target_page_dirtied,
3254: vm_pageout_target_page_freed);
3255: iprintf("page_pinned %5d page_limbo %5d\n",
3256: vm_pageout_target_page_pinned, vm_pageout_target_page_limbo);
3257: db_indent -= 2;
3258: #endif /* MACH_CLUSTER_STATS */
3259: db_indent -= 2;
3260: }
3261:
3262: #if MACH_CLUSTER_STATS
3263: unsigned long vm_pageout_cluster_dirtied = 0;
3264: unsigned long vm_pageout_cluster_cleaned = 0;
3265: unsigned long vm_pageout_cluster_collisions = 0;
3266: unsigned long vm_pageout_cluster_clusters = 0;
3267: unsigned long vm_pageout_cluster_conversions = 0;
3268: unsigned long vm_pageout_target_collisions = 0;
3269: unsigned long vm_pageout_target_page_dirtied = 0;
3270: unsigned long vm_pageout_target_page_freed = 0;
3271: unsigned long vm_pageout_target_page_pinned = 0;
3272: unsigned long vm_pageout_target_page_limbo = 0;
3273: #define CLUSTER_STAT(clause) clause
3274: #else /* MACH_CLUSTER_STATS */
3275: #define CLUSTER_STAT(clause)
3276: #endif /* MACH_CLUSTER_STATS */
3277:
3278: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.