]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/vm_pageout.c
xnu-517.tar.gz
[apple/xnu.git] / osfmk / vm / vm_pageout.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53/*
54 */
55/*
56 * File: vm/vm_pageout.c
57 * Author: Avadis Tevanian, Jr., Michael Wayne Young
58 * Date: 1985
59 *
60 * The proverbial page-out daemon.
61 */
1c79356b
A
62
63#include <mach_pagemap.h>
64#include <mach_cluster_stats.h>
65#include <mach_kdb.h>
66#include <advisory_pageout.h>
67
68#include <mach/mach_types.h>
69#include <mach/memory_object.h>
70#include <mach/memory_object_default.h>
0b4e3aa0 71#include <mach/memory_object_control_server.h>
1c79356b
A
72#include <mach/mach_host_server.h>
73#include <mach/vm_param.h>
74#include <mach/vm_statistics.h>
75#include <kern/host_statistics.h>
76#include <kern/counters.h>
77#include <kern/thread.h>
1c79356b
A
78#include <kern/xpr.h>
79#include <vm/pmap.h>
55e303ae 80#include <vm/vm_fault.h>
1c79356b
A
81#include <vm/vm_map.h>
82#include <vm/vm_object.h>
83#include <vm/vm_page.h>
84#include <vm/vm_pageout.h>
85#include <machine/vm_tuning.h>
86#include <kern/misc_protos.h>
87
55e303ae 88
1c79356b
A
89extern ipc_port_t memory_manager_default;
90
91#ifndef VM_PAGE_LAUNDRY_MAX
55e303ae 92#define VM_PAGE_LAUNDRY_MAX 16 /* outstanding DMM+EMM page cleans */
1c79356b
A
93#endif /* VM_PAGEOUT_LAUNDRY_MAX */
94
95#ifndef VM_PAGEOUT_BURST_MAX
55e303ae 96#define VM_PAGEOUT_BURST_MAX 6 /* simultaneous EMM page cleans */
1c79356b
A
97#endif /* VM_PAGEOUT_BURST_MAX */
98
1c79356b
A
99#ifndef VM_PAGEOUT_BURST_WAIT
100#define VM_PAGEOUT_BURST_WAIT 30 /* milliseconds per page */
101#endif /* VM_PAGEOUT_BURST_WAIT */
102
103#ifndef VM_PAGEOUT_EMPTY_WAIT
104#define VM_PAGEOUT_EMPTY_WAIT 200 /* milliseconds */
105#endif /* VM_PAGEOUT_EMPTY_WAIT */
106
107/*
108 * To obtain a reasonable LRU approximation, the inactive queue
109 * needs to be large enough to give pages on it a chance to be
110 * referenced a second time. This macro defines the fraction
111 * of active+inactive pages that should be inactive.
112 * The pageout daemon uses it to update vm_page_inactive_target.
113 *
114 * If vm_page_free_count falls below vm_page_free_target and
115 * vm_page_inactive_count is below vm_page_inactive_target,
116 * then the pageout daemon starts running.
117 */
118
119#ifndef VM_PAGE_INACTIVE_TARGET
120#define VM_PAGE_INACTIVE_TARGET(avail) ((avail) * 1 / 3)
121#endif /* VM_PAGE_INACTIVE_TARGET */
122
123/*
124 * Once the pageout daemon starts running, it keeps going
125 * until vm_page_free_count meets or exceeds vm_page_free_target.
126 */
127
128#ifndef VM_PAGE_FREE_TARGET
129#define VM_PAGE_FREE_TARGET(free) (15 + (free) / 80)
130#endif /* VM_PAGE_FREE_TARGET */
131
132/*
133 * The pageout daemon always starts running once vm_page_free_count
134 * falls below vm_page_free_min.
135 */
136
137#ifndef VM_PAGE_FREE_MIN
138#define VM_PAGE_FREE_MIN(free) (10 + (free) / 100)
139#endif /* VM_PAGE_FREE_MIN */
140
141/*
142 * When vm_page_free_count falls below vm_page_free_reserved,
143 * only vm-privileged threads can allocate pages. vm-privilege
144 * allows the pageout daemon and default pager (and any other
145 * associated threads needed for default pageout) to continue
146 * operation by dipping into the reserved pool of pages.
147 */
148
149#ifndef VM_PAGE_FREE_RESERVED
150#define VM_PAGE_FREE_RESERVED \
55e303ae 151 ((6 * VM_PAGE_LAUNDRY_MAX) + NCPUS)
1c79356b
A
152#endif /* VM_PAGE_FREE_RESERVED */
153
0b4e3aa0
A
154/*
155 * Exported variable used to broadcast the activation of the pageout scan
156 * Working Set uses this to throttle its use of pmap removes. In this
157 * way, code which runs within memory in an uncontested context does
158 * not keep encountering soft faults.
159 */
160
161unsigned int vm_pageout_scan_event_counter = 0;
1c79356b
A
162
163/*
164 * Forward declarations for internal routines.
165 */
166extern void vm_pageout_continue(void);
167extern void vm_pageout_scan(void);
168extern void vm_pageout_throttle(vm_page_t m);
169extern vm_page_t vm_pageout_cluster_page(
170 vm_object_t object,
171 vm_object_offset_t offset,
172 boolean_t precious_clean);
173
174unsigned int vm_pageout_reserved_internal = 0;
175unsigned int vm_pageout_reserved_really = 0;
176
177unsigned int vm_page_laundry_max = 0; /* # of clusters outstanding */
178unsigned int vm_page_laundry_min = 0;
55e303ae 179unsigned int vm_pageout_empty_wait = 0; /* milliseconds */
1c79356b
A
180unsigned int vm_pageout_burst_max = 0;
181unsigned int vm_pageout_burst_wait = 0; /* milliseconds per page */
1c79356b 182unsigned int vm_pageout_burst_min = 0;
55e303ae 183unsigned int vm_pageout_burst_loop_throttle = 4096;
1c79356b
A
184unsigned int vm_pageout_pause_count = 0;
185unsigned int vm_pageout_pause_max = 0;
186unsigned int vm_free_page_pause = 100; /* milliseconds */
187
9bccf70c
A
188/*
189 * Protection against zero fill flushing live working sets derived
190 * from existing backing store and files
191 */
192unsigned int vm_accellerate_zf_pageout_trigger = 400;
193unsigned int vm_zf_iterator;
194unsigned int vm_zf_iterator_count = 40;
195unsigned int last_page_zf;
196unsigned int vm_zf_count = 0;
197
1c79356b
A
198/*
199 * These variables record the pageout daemon's actions:
200 * how many pages it looks at and what happens to those pages.
201 * No locking needed because only one thread modifies the variables.
202 */
203
204unsigned int vm_pageout_active = 0; /* debugging */
205unsigned int vm_pageout_inactive = 0; /* debugging */
206unsigned int vm_pageout_inactive_throttled = 0; /* debugging */
207unsigned int vm_pageout_inactive_forced = 0; /* debugging */
208unsigned int vm_pageout_inactive_nolock = 0; /* debugging */
209unsigned int vm_pageout_inactive_avoid = 0; /* debugging */
210unsigned int vm_pageout_inactive_busy = 0; /* debugging */
211unsigned int vm_pageout_inactive_absent = 0; /* debugging */
212unsigned int vm_pageout_inactive_used = 0; /* debugging */
213unsigned int vm_pageout_inactive_clean = 0; /* debugging */
214unsigned int vm_pageout_inactive_dirty = 0; /* debugging */
215unsigned int vm_pageout_dirty_no_pager = 0; /* debugging */
1c79356b
A
216unsigned int vm_stat_discard = 0; /* debugging */
217unsigned int vm_stat_discard_sent = 0; /* debugging */
218unsigned int vm_stat_discard_failure = 0; /* debugging */
219unsigned int vm_stat_discard_throttle = 0; /* debugging */
220unsigned int vm_pageout_scan_active_emm_throttle = 0; /* debugging */
221unsigned int vm_pageout_scan_active_emm_throttle_success = 0; /* debugging */
222unsigned int vm_pageout_scan_active_emm_throttle_failure = 0; /* debugging */
223unsigned int vm_pageout_scan_inactive_emm_throttle = 0; /* debugging */
224unsigned int vm_pageout_scan_inactive_emm_throttle_success = 0; /* debugging */
225unsigned int vm_pageout_scan_inactive_emm_throttle_failure = 0; /* debugging */
226
55e303ae
A
227/*
228 * Backing store throttle when BS is exhausted
229 */
230unsigned int vm_backing_store_low = 0;
1c79356b
A
231
232unsigned int vm_pageout_out_of_line = 0;
233unsigned int vm_pageout_in_place = 0;
55e303ae
A
234
235
236/*
237 * Routine: vm_backing_store_disable
238 * Purpose:
239 * Suspend non-privileged threads wishing to extend
240 * backing store when we are low on backing store
241 * (Synchronized by caller)
242 */
243void
244vm_backing_store_disable(
245 boolean_t disable)
246{
247 if(disable) {
248 vm_backing_store_low = 1;
249 } else {
250 if(vm_backing_store_low) {
251 vm_backing_store_low = 0;
252 thread_wakeup((event_t) &vm_backing_store_low);
253 }
254 }
255}
256
257
1c79356b
A
258/*
259 * Routine: vm_pageout_object_allocate
260 * Purpose:
261 * Allocate an object for use as out-of-line memory in a
262 * data_return/data_initialize message.
263 * The page must be in an unlocked object.
264 *
265 * If the page belongs to a trusted pager, cleaning in place
266 * will be used, which utilizes a special "pageout object"
267 * containing private alias pages for the real page frames.
268 * Untrusted pagers use normal out-of-line memory.
269 */
270vm_object_t
271vm_pageout_object_allocate(
272 vm_page_t m,
273 vm_size_t size,
274 vm_object_offset_t offset)
275{
276 vm_object_t object = m->object;
277 vm_object_t new_object;
278
279 assert(object->pager_ready);
280
1c79356b
A
281 new_object = vm_object_allocate(size);
282
283 if (object->pager_trusted) {
284 assert (offset < object->size);
285
286 vm_object_lock(new_object);
287 new_object->pageout = TRUE;
288 new_object->shadow = object;
289 new_object->can_persist = FALSE;
290 new_object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
291 new_object->shadow_offset = offset;
292 vm_object_unlock(new_object);
293
294 /*
295 * Take a paging reference on the object. This will be dropped
296 * in vm_pageout_object_terminate()
297 */
298 vm_object_lock(object);
299 vm_object_paging_begin(object);
55e303ae
A
300 vm_page_lock_queues();
301 vm_pageout_throttle(m);
302 vm_page_unlock_queues();
1c79356b
A
303 vm_object_unlock(object);
304
305 vm_pageout_in_place++;
306 } else
307 vm_pageout_out_of_line++;
308 return(new_object);
309}
310
311#if MACH_CLUSTER_STATS
312unsigned long vm_pageout_cluster_dirtied = 0;
313unsigned long vm_pageout_cluster_cleaned = 0;
314unsigned long vm_pageout_cluster_collisions = 0;
315unsigned long vm_pageout_cluster_clusters = 0;
316unsigned long vm_pageout_cluster_conversions = 0;
317unsigned long vm_pageout_target_collisions = 0;
318unsigned long vm_pageout_target_page_dirtied = 0;
319unsigned long vm_pageout_target_page_freed = 0;
1c79356b
A
320#define CLUSTER_STAT(clause) clause
321#else /* MACH_CLUSTER_STATS */
322#define CLUSTER_STAT(clause)
323#endif /* MACH_CLUSTER_STATS */
324
325/*
326 * Routine: vm_pageout_object_terminate
327 * Purpose:
328 * Destroy the pageout_object allocated by
329 * vm_pageout_object_allocate(), and perform all of the
330 * required cleanup actions.
331 *
332 * In/Out conditions:
333 * The object must be locked, and will be returned locked.
334 */
335void
336vm_pageout_object_terminate(
337 vm_object_t object)
338{
339 vm_object_t shadow_object;
55e303ae 340 boolean_t shadow_internal;
1c79356b
A
341
342 /*
343 * Deal with the deallocation (last reference) of a pageout object
344 * (used for cleaning-in-place) by dropping the paging references/
345 * freeing pages in the original object.
346 */
347
348 assert(object->pageout);
349 shadow_object = object->shadow;
350 vm_object_lock(shadow_object);
55e303ae 351 shadow_internal = shadow_object->internal;
1c79356b
A
352
353 while (!queue_empty(&object->memq)) {
354 vm_page_t p, m;
355 vm_object_offset_t offset;
356
357 p = (vm_page_t) queue_first(&object->memq);
358
359 assert(p->private);
360 assert(p->pageout);
361 p->pageout = FALSE;
362 assert(!p->cleaning);
363
364 offset = p->offset;
365 VM_PAGE_FREE(p);
366 p = VM_PAGE_NULL;
367
368 m = vm_page_lookup(shadow_object,
369 offset + object->shadow_offset);
370
371 if(m == VM_PAGE_NULL)
372 continue;
373 assert(m->cleaning);
0b4e3aa0
A
374 /* used as a trigger on upl_commit etc to recognize the */
375 /* pageout daemon's subseqent desire to pageout a cleaning */
376 /* page. When the bit is on the upl commit code will */
377 /* respect the pageout bit in the target page over the */
378 /* caller's page list indication */
379 m->dump_cleaning = FALSE;
1c79356b
A
380
381 /*
382 * Account for the paging reference taken when
383 * m->cleaning was set on this page.
384 */
385 vm_object_paging_end(shadow_object);
386 assert((m->dirty) || (m->precious) ||
387 (m->busy && m->cleaning));
388
389 /*
390 * Handle the trusted pager throttle.
55e303ae 391 * Also decrement the burst throttle (if external).
1c79356b
A
392 */
393 vm_page_lock_queues();
394 if (m->laundry) {
55e303ae
A
395 if (!shadow_internal)
396 vm_page_burst_count--;
1c79356b
A
397 vm_page_laundry_count--;
398 m->laundry = FALSE;
399 if (vm_page_laundry_count < vm_page_laundry_min) {
400 vm_page_laundry_min = 0;
401 thread_wakeup((event_t) &vm_page_laundry_count);
402 }
403 }
404
405 /*
406 * Handle the "target" page(s). These pages are to be freed if
407 * successfully cleaned. Target pages are always busy, and are
408 * wired exactly once. The initial target pages are not mapped,
409 * (so cannot be referenced or modified) but converted target
410 * pages may have been modified between the selection as an
411 * adjacent page and conversion to a target.
412 */
413 if (m->pageout) {
414 assert(m->busy);
415 assert(m->wire_count == 1);
416 m->cleaning = FALSE;
417 m->pageout = FALSE;
418#if MACH_CLUSTER_STATS
419 if (m->wanted) vm_pageout_target_collisions++;
420#endif
421 /*
422 * Revoke all access to the page. Since the object is
423 * locked, and the page is busy, this prevents the page
424 * from being dirtied after the pmap_is_modified() call
425 * returns.
426 */
55e303ae 427 pmap_page_protect(m->phys_page, VM_PROT_NONE);
1c79356b
A
428
429 /*
430 * Since the page is left "dirty" but "not modifed", we
431 * can detect whether the page was redirtied during
432 * pageout by checking the modify state.
433 */
55e303ae 434 m->dirty = pmap_is_modified(m->phys_page);
1c79356b
A
435
436 if (m->dirty) {
437 CLUSTER_STAT(vm_pageout_target_page_dirtied++;)
438 vm_page_unwire(m);/* reactivates */
439 VM_STAT(reactivations++);
440 PAGE_WAKEUP_DONE(m);
1c79356b
A
441 } else {
442 CLUSTER_STAT(vm_pageout_target_page_freed++;)
443 vm_page_free(m);/* clears busy, etc. */
444 }
445 vm_page_unlock_queues();
446 continue;
447 }
448 /*
449 * Handle the "adjacent" pages. These pages were cleaned in
450 * place, and should be left alone.
451 * If prep_pin_count is nonzero, then someone is using the
452 * page, so make it active.
453 */
0b4e3aa0
A
454 if (!m->active && !m->inactive && !m->private) {
455 if (m->reference)
1c79356b
A
456 vm_page_activate(m);
457 else
458 vm_page_deactivate(m);
459 }
460 if((m->busy) && (m->cleaning)) {
461
462 /* the request_page_list case, (COPY_OUT_FROM FALSE) */
463 m->busy = FALSE;
464
465 /* We do not re-set m->dirty ! */
466 /* The page was busy so no extraneous activity */
467 /* could have occured. COPY_INTO is a read into the */
468 /* new pages. CLEAN_IN_PLACE does actually write */
469 /* out the pages but handling outside of this code */
470 /* will take care of resetting dirty. We clear the */
471 /* modify however for the Programmed I/O case. */
55e303ae 472 pmap_clear_modify(m->phys_page);
1c79356b
A
473 if(m->absent) {
474 m->absent = FALSE;
475 if(shadow_object->absent_count == 1)
476 vm_object_absent_release(shadow_object);
477 else
478 shadow_object->absent_count--;
479 }
480 m->overwriting = FALSE;
481 } else if (m->overwriting) {
482 /* alternate request page list, write to page_list */
483 /* case. Occurs when the original page was wired */
484 /* at the time of the list request */
485 assert(m->wire_count != 0);
486 vm_page_unwire(m);/* reactivates */
487 m->overwriting = FALSE;
488 } else {
489 /*
490 * Set the dirty state according to whether or not the page was
491 * modified during the pageout. Note that we purposefully do
492 * NOT call pmap_clear_modify since the page is still mapped.
493 * If the page were to be dirtied between the 2 calls, this
494 * this fact would be lost. This code is only necessary to
495 * maintain statistics, since the pmap module is always
496 * consulted if m->dirty is false.
497 */
498#if MACH_CLUSTER_STATS
55e303ae 499 m->dirty = pmap_is_modified(m->phys_page);
1c79356b
A
500
501 if (m->dirty) vm_pageout_cluster_dirtied++;
502 else vm_pageout_cluster_cleaned++;
503 if (m->wanted) vm_pageout_cluster_collisions++;
504#else
505 m->dirty = 0;
506#endif
507 }
508 m->cleaning = FALSE;
509
1c79356b
A
510 /*
511 * Wakeup any thread waiting for the page to be un-cleaning.
512 */
513 PAGE_WAKEUP(m);
514 vm_page_unlock_queues();
515 }
516 /*
517 * Account for the paging reference taken in vm_paging_object_allocate.
518 */
519 vm_object_paging_end(shadow_object);
520 vm_object_unlock(shadow_object);
521
522 assert(object->ref_count == 0);
523 assert(object->paging_in_progress == 0);
524 assert(object->resident_page_count == 0);
525 return;
526}
527
528/*
529 * Routine: vm_pageout_setup
530 * Purpose:
531 * Set up a page for pageout (clean & flush).
532 *
533 * Move the page to a new object, as part of which it will be
534 * sent to its memory manager in a memory_object_data_write or
535 * memory_object_initialize message.
536 *
537 * The "new_object" and "new_offset" arguments
538 * indicate where the page should be moved.
539 *
540 * In/Out conditions:
541 * The page in question must not be on any pageout queues,
542 * and must be busy. The object to which it belongs
543 * must be unlocked, and the caller must hold a paging
544 * reference to it. The new_object must not be locked.
545 *
546 * This routine returns a pointer to a place-holder page,
547 * inserted at the same offset, to block out-of-order
548 * requests for the page. The place-holder page must
549 * be freed after the data_write or initialize message
550 * has been sent.
551 *
552 * The original page is put on a paging queue and marked
553 * not busy on exit.
554 */
555vm_page_t
556vm_pageout_setup(
557 register vm_page_t m,
558 register vm_object_t new_object,
559 vm_object_offset_t new_offset)
560{
561 register vm_object_t old_object = m->object;
562 vm_object_offset_t paging_offset;
563 vm_object_offset_t offset;
564 register vm_page_t holding_page;
565 register vm_page_t new_m;
566 register vm_page_t new_page;
567 boolean_t need_to_wire = FALSE;
568
569
570 XPR(XPR_VM_PAGEOUT,
571 "vm_pageout_setup, obj 0x%X off 0x%X page 0x%X new obj 0x%X offset 0x%X\n",
572 (integer_t)m->object, (integer_t)m->offset,
573 (integer_t)m, (integer_t)new_object,
574 (integer_t)new_offset);
575 assert(m && m->busy && !m->absent && !m->fictitious && !m->error &&
576 !m->restart);
577
578 assert(m->dirty || m->precious);
579
580 /*
581 * Create a place-holder page where the old one was, to prevent
582 * attempted pageins of this page while we're unlocked.
1c79356b
A
583 */
584 VM_PAGE_GRAB_FICTITIOUS(holding_page);
585
1c79356b
A
586 vm_object_lock(old_object);
587
588 offset = m->offset;
589 paging_offset = offset + old_object->paging_offset;
590
591 if (old_object->pager_trusted) {
592 /*
593 * This pager is trusted, so we can clean this page
594 * in place. Leave it in the old object, and mark it
595 * cleaning & pageout.
596 */
597 new_m = holding_page;
598 holding_page = VM_PAGE_NULL;
599
1c79356b
A
600 /*
601 * Set up new page to be private shadow of real page.
602 */
55e303ae 603 new_m->phys_page = m->phys_page;
1c79356b 604 new_m->fictitious = FALSE;
1c79356b
A
605 new_m->pageout = TRUE;
606
607 /*
608 * Mark real page as cleaning (indicating that we hold a
609 * paging reference to be released via m_o_d_r_c) and
610 * pageout (indicating that the page should be freed
611 * when the pageout completes).
612 */
55e303ae 613 pmap_clear_modify(m->phys_page);
1c79356b 614 vm_page_lock_queues();
0b4e3aa0 615 new_m->private = TRUE;
1c79356b
A
616 vm_page_wire(new_m);
617 m->cleaning = TRUE;
618 m->pageout = TRUE;
619
620 vm_page_wire(m);
621 assert(m->wire_count == 1);
622 vm_page_unlock_queues();
623
624 m->dirty = TRUE;
625 m->precious = FALSE;
626 m->page_lock = VM_PROT_NONE;
627 m->unusual = FALSE;
628 m->unlock_request = VM_PROT_NONE;
629 } else {
630 /*
631 * Cannot clean in place, so rip the old page out of the
632 * object, and stick the holding page in. Set new_m to the
633 * page in the new object.
634 */
635 vm_page_lock_queues();
636 VM_PAGE_QUEUES_REMOVE(m);
637 vm_page_remove(m);
638
1c79356b
A
639 vm_page_insert(holding_page, old_object, offset);
640 vm_page_unlock_queues();
641
642 m->dirty = TRUE;
643 m->precious = FALSE;
644 new_m = m;
645 new_m->page_lock = VM_PROT_NONE;
646 new_m->unlock_request = VM_PROT_NONE;
647
648 if (old_object->internal)
649 need_to_wire = TRUE;
650 }
651 /*
652 * Record that this page has been written out
653 */
654#if MACH_PAGEMAP
655 vm_external_state_set(old_object->existence_map, offset);
656#endif /* MACH_PAGEMAP */
657
658 vm_object_unlock(old_object);
659
660 vm_object_lock(new_object);
661
662 /*
663 * Put the page into the new object. If it is a not wired
664 * (if it's the real page) it will be activated.
665 */
666
667 vm_page_lock_queues();
668 vm_page_insert(new_m, new_object, new_offset);
669 if (need_to_wire)
670 vm_page_wire(new_m);
671 else
672 vm_page_activate(new_m);
673 PAGE_WAKEUP_DONE(new_m);
674 vm_page_unlock_queues();
675
676 vm_object_unlock(new_object);
677
678 /*
679 * Return the placeholder page to simplify cleanup.
680 */
681 return (holding_page);
682}
683
684/*
685 * Routine: vm_pageclean_setup
686 *
687 * Purpose: setup a page to be cleaned (made non-dirty), but not
688 * necessarily flushed from the VM page cache.
689 * This is accomplished by cleaning in place.
690 *
691 * The page must not be busy, and the object and page
692 * queues must be locked.
693 *
694 */
695void
696vm_pageclean_setup(
697 vm_page_t m,
698 vm_page_t new_m,
699 vm_object_t new_object,
700 vm_object_offset_t new_offset)
701{
702 vm_object_t old_object = m->object;
703 assert(!m->busy);
704 assert(!m->cleaning);
705
706 XPR(XPR_VM_PAGEOUT,
707 "vm_pageclean_setup, obj 0x%X off 0x%X page 0x%X new 0x%X new_off 0x%X\n",
708 (integer_t)old_object, m->offset, (integer_t)m,
709 (integer_t)new_m, new_offset);
710
55e303ae 711 pmap_clear_modify(m->phys_page);
1c79356b
A
712 vm_object_paging_begin(old_object);
713
714 /*
715 * Record that this page has been written out
716 */
717#if MACH_PAGEMAP
718 vm_external_state_set(old_object->existence_map, m->offset);
719#endif /*MACH_PAGEMAP*/
720
721 /*
722 * Mark original page as cleaning in place.
723 */
724 m->cleaning = TRUE;
725 m->dirty = TRUE;
726 m->precious = FALSE;
727
728 /*
729 * Convert the fictitious page to a private shadow of
730 * the real page.
731 */
732 assert(new_m->fictitious);
733 new_m->fictitious = FALSE;
734 new_m->private = TRUE;
735 new_m->pageout = TRUE;
55e303ae 736 new_m->phys_page = m->phys_page;
1c79356b
A
737 vm_page_wire(new_m);
738
739 vm_page_insert(new_m, new_object, new_offset);
740 assert(!new_m->wanted);
741 new_m->busy = FALSE;
742}
743
744void
745vm_pageclean_copy(
746 vm_page_t m,
747 vm_page_t new_m,
748 vm_object_t new_object,
749 vm_object_offset_t new_offset)
750{
751 XPR(XPR_VM_PAGEOUT,
752 "vm_pageclean_copy, page 0x%X new_m 0x%X new_obj 0x%X offset 0x%X\n",
753 m, new_m, new_object, new_offset, 0);
754
755 assert((!m->busy) && (!m->cleaning));
756
757 assert(!new_m->private && !new_m->fictitious);
758
55e303ae 759 pmap_clear_modify(m->phys_page);
1c79356b
A
760
761 m->busy = TRUE;
762 vm_object_paging_begin(m->object);
763 vm_page_unlock_queues();
764 vm_object_unlock(m->object);
765
766 /*
767 * Copy the original page to the new page.
768 */
769 vm_page_copy(m, new_m);
770
771 /*
772 * Mark the old page as clean. A request to pmap_is_modified
773 * will get the right answer.
774 */
775 vm_object_lock(m->object);
776 m->dirty = FALSE;
777
778 vm_object_paging_end(m->object);
779
780 vm_page_lock_queues();
781 if (!m->active && !m->inactive)
782 vm_page_activate(m);
783 PAGE_WAKEUP_DONE(m);
784
785 vm_page_insert(new_m, new_object, new_offset);
786 vm_page_activate(new_m);
787 new_m->busy = FALSE; /* No other thread can be waiting */
788}
789
790
791/*
792 * Routine: vm_pageout_initialize_page
793 * Purpose:
794 * Causes the specified page to be initialized in
795 * the appropriate memory object. This routine is used to push
796 * pages into a copy-object when they are modified in the
797 * permanent object.
798 *
799 * The page is moved to a temporary object and paged out.
800 *
801 * In/out conditions:
802 * The page in question must not be on any pageout queues.
803 * The object to which it belongs must be locked.
804 * The page must be busy, but not hold a paging reference.
805 *
806 * Implementation:
807 * Move this page to a completely new object.
808 */
809void
810vm_pageout_initialize_page(
811 vm_page_t m)
812{
813 vm_map_copy_t copy;
814 vm_object_t new_object;
815 vm_object_t object;
816 vm_object_offset_t paging_offset;
817 vm_page_t holding_page;
818
819
820 XPR(XPR_VM_PAGEOUT,
821 "vm_pageout_initialize_page, page 0x%X\n",
822 (integer_t)m, 0, 0, 0, 0);
823 assert(m->busy);
824
825 /*
826 * Verify that we really want to clean this page
827 */
828 assert(!m->absent);
829 assert(!m->error);
830 assert(m->dirty);
831
832 /*
833 * Create a paging reference to let us play with the object.
834 */
835 object = m->object;
836 paging_offset = m->offset + object->paging_offset;
837 vm_object_paging_begin(object);
1c79356b
A
838 if (m->absent || m->error || m->restart ||
839 (!m->dirty && !m->precious)) {
840 VM_PAGE_FREE(m);
841 panic("reservation without pageout?"); /* alan */
55e303ae 842 vm_object_unlock(object);
1c79356b
A
843 return;
844 }
845
846 /* set the page for future call to vm_fault_list_request */
847 holding_page = NULL;
1c79356b 848 vm_page_lock_queues();
55e303ae 849 pmap_clear_modify(m->phys_page);
1c79356b 850 m->dirty = TRUE;
55e303ae
A
851 m->busy = TRUE;
852 m->list_req_pending = TRUE;
853 m->cleaning = TRUE;
1c79356b
A
854 m->pageout = TRUE;
855 vm_page_wire(m);
1c79356b 856 vm_pageout_throttle(m);
55e303ae
A
857 vm_page_unlock_queues();
858 vm_object_unlock(object);
1c79356b
A
859
860 /*
861 * Write the data to its pager.
862 * Note that the data is passed by naming the new object,
863 * not a virtual address; the pager interface has been
864 * manipulated to use the "internal memory" data type.
865 * [The object reference from its allocation is donated
866 * to the eventual recipient.]
867 */
868 memory_object_data_initialize(object->pager,
1c79356b 869 paging_offset,
1c79356b
A
870 PAGE_SIZE);
871
872 vm_object_lock(object);
873}
874
875#if MACH_CLUSTER_STATS
876#define MAXCLUSTERPAGES 16
877struct {
878 unsigned long pages_in_cluster;
879 unsigned long pages_at_higher_offsets;
880 unsigned long pages_at_lower_offsets;
881} cluster_stats[MAXCLUSTERPAGES];
882#endif /* MACH_CLUSTER_STATS */
883
884boolean_t allow_clustered_pageouts = FALSE;
885
886/*
887 * vm_pageout_cluster:
888 *
889 * Given a page, page it out, and attempt to clean adjacent pages
890 * in the same operation.
891 *
55e303ae
A
892 * The page must be busy, and the object locked. We will take a
893 * paging reference to prevent deallocation or collapse when we
894 * temporarily release the object lock.
895 *
896 * The page must not be on any pageout queue.
1c79356b
A
897 */
898void
899vm_pageout_cluster(
900 vm_page_t m)
901{
902 vm_object_t object = m->object;
903 vm_object_offset_t offset = m->offset; /* from vm_object start */
55e303ae 904 vm_object_offset_t paging_offset;
1c79356b
A
905 vm_object_t new_object;
906 vm_object_offset_t new_offset;
907 vm_size_t cluster_size;
908 vm_object_offset_t cluster_offset; /* from memory_object start */
909 vm_object_offset_t cluster_lower_bound; /* from vm_object_start */
910 vm_object_offset_t cluster_upper_bound; /* from vm_object_start */
911 vm_object_offset_t cluster_start, cluster_end;/* from vm_object start */
912 vm_object_offset_t offset_within_cluster;
913 vm_size_t length_of_data;
914 vm_page_t friend, holding_page;
1c79356b
A
915 kern_return_t rc;
916 boolean_t precious_clean = TRUE;
917 int pages_in_cluster;
918
919 CLUSTER_STAT(int pages_at_higher_offsets = 0;)
920 CLUSTER_STAT(int pages_at_lower_offsets = 0;)
921
922 XPR(XPR_VM_PAGEOUT,
923 "vm_pageout_cluster, object 0x%X offset 0x%X page 0x%X\n",
924 (integer_t)object, offset, (integer_t)m, 0, 0);
925
926 CLUSTER_STAT(vm_pageout_cluster_clusters++;)
55e303ae
A
927
928 /*
929 * protect the object from collapse -
930 * locking in the object's paging_offset.
931 */
932 vm_object_paging_begin(object);
933 paging_offset = m->offset + object->paging_offset;
934
1c79356b
A
935 /*
936 * Only a certain kind of page is appreciated here.
937 */
938 assert(m->busy && (m->dirty || m->precious) && (m->wire_count == 0));
939 assert(!m->cleaning && !m->pageout && !m->inactive && !m->active);
940
1c79356b
A
941 cluster_size = object->cluster_size;
942
943 assert(cluster_size >= PAGE_SIZE);
944 if (cluster_size < PAGE_SIZE) cluster_size = PAGE_SIZE;
945 assert(object->pager_created && object->pager_initialized);
946 assert(object->internal || object->pager_ready);
947
948 if (m->precious && !m->dirty)
949 precious_clean = TRUE;
950
951 if (!object->pager_trusted || !allow_clustered_pageouts)
952 cluster_size = PAGE_SIZE;
1c79356b
A
953
954 cluster_offset = paging_offset & (vm_object_offset_t)(cluster_size - 1);
955 /* bytes from beginning of cluster */
956 /*
957 * Due to unaligned mappings, we have to be careful
958 * of negative offsets into the VM object. Clip the cluster
959 * boundary to the VM object, not the memory object.
960 */
961 if (offset > cluster_offset) {
962 cluster_lower_bound = offset - cluster_offset;
963 /* from vm_object */
964 } else {
965 cluster_lower_bound = 0;
966 }
967 cluster_upper_bound = (offset - cluster_offset) +
968 (vm_object_offset_t)cluster_size;
969
970 /* set the page for future call to vm_fault_list_request */
971 holding_page = NULL;
1c79356b 972 vm_page_lock_queues();
55e303ae
A
973 m->busy = TRUE;
974 m->list_req_pending = TRUE;
975 m->cleaning = TRUE;
1c79356b
A
976 m->pageout = TRUE;
977 vm_page_wire(m);
1c79356b 978 vm_pageout_throttle(m);
55e303ae
A
979 vm_page_unlock_queues();
980 vm_object_unlock(object);
1c79356b
A
981
982 /*
983 * Search backward for adjacent eligible pages to clean in
984 * this operation.
985 */
986
987 cluster_start = offset;
988 if (offset) { /* avoid wrap-around at zero */
989 for (cluster_start = offset - PAGE_SIZE_64;
990 cluster_start >= cluster_lower_bound;
991 cluster_start -= PAGE_SIZE_64) {
992 assert(cluster_size > PAGE_SIZE);
993
994 vm_object_lock(object);
995 vm_page_lock_queues();
996
997 if ((friend = vm_pageout_cluster_page(object, cluster_start,
998 precious_clean)) == VM_PAGE_NULL) {
999 vm_page_unlock_queues();
1000 vm_object_unlock(object);
1001 break;
1002 }
1003 new_offset = (cluster_start + object->paging_offset)
1004 & (cluster_size - 1);
1005
1006 assert(new_offset < cluster_offset);
1007 m->list_req_pending = TRUE;
1008 m->cleaning = TRUE;
1009/* do nothing except advance the write request, all we really need to */
1010/* do is push the target page and let the code at the other end decide */
1011/* what is really the right size */
1012 if (vm_page_free_count <= vm_page_free_reserved) {
1013 m->busy = TRUE;
1014 m->pageout = TRUE;
1015 vm_page_wire(m);
1016 }
1017
1018 vm_page_unlock_queues();
1019 vm_object_unlock(object);
1020 if(m->dirty || m->object->internal) {
1021 CLUSTER_STAT(pages_at_lower_offsets++;)
1022 }
1023
1024 }
1025 cluster_start += PAGE_SIZE_64;
1026 }
1027 assert(cluster_start >= cluster_lower_bound);
1028 assert(cluster_start <= offset);
1029 /*
1030 * Search forward for adjacent eligible pages to clean in
1031 * this operation.
1032 */
1033 for (cluster_end = offset + PAGE_SIZE_64;
1034 cluster_end < cluster_upper_bound;
1035 cluster_end += PAGE_SIZE_64) {
1036 assert(cluster_size > PAGE_SIZE);
1037
1038 vm_object_lock(object);
1039 vm_page_lock_queues();
1040
1041 if ((friend = vm_pageout_cluster_page(object, cluster_end,
1042 precious_clean)) == VM_PAGE_NULL) {
1043 vm_page_unlock_queues();
1044 vm_object_unlock(object);
1045 break;
1046 }
1047 new_offset = (cluster_end + object->paging_offset)
1048 & (cluster_size - 1);
1049
1050 assert(new_offset < cluster_size);
1051 m->list_req_pending = TRUE;
1052 m->cleaning = TRUE;
1053/* do nothing except advance the write request, all we really need to */
1054/* do is push the target page and let the code at the other end decide */
1055/* what is really the right size */
1056 if (vm_page_free_count <= vm_page_free_reserved) {
1057 m->busy = TRUE;
1058 m->pageout = TRUE;
1059 vm_page_wire(m);
1060 }
1061
1062 vm_page_unlock_queues();
1063 vm_object_unlock(object);
1064
1065 if(m->dirty || m->object->internal) {
1066 CLUSTER_STAT(pages_at_higher_offsets++;)
1067 }
1068 }
1069 assert(cluster_end <= cluster_upper_bound);
1070 assert(cluster_end >= offset + PAGE_SIZE);
1071
1072 /*
1073 * (offset - cluster_offset) is beginning of cluster_object
1074 * relative to vm_object start.
1075 */
1076 offset_within_cluster = cluster_start - (offset - cluster_offset);
1077 length_of_data = cluster_end - cluster_start;
1078
1079 assert(offset_within_cluster < cluster_size);
1080 assert((offset_within_cluster + length_of_data) <= cluster_size);
1081
1082 rc = KERN_SUCCESS;
1083 assert(rc == KERN_SUCCESS);
1084
1085 pages_in_cluster = length_of_data/PAGE_SIZE;
1c79356b
A
1086
1087#if MACH_CLUSTER_STATS
1088 (cluster_stats[pages_at_lower_offsets].pages_at_lower_offsets)++;
1089 (cluster_stats[pages_at_higher_offsets].pages_at_higher_offsets)++;
1090 (cluster_stats[pages_in_cluster].pages_in_cluster)++;
1091#endif /* MACH_CLUSTER_STATS */
1092
1093 /*
1094 * Send the data to the pager.
1095 */
1096 paging_offset = cluster_start + object->paging_offset;
0b4e3aa0 1097
1c79356b 1098 rc = memory_object_data_return(object->pager,
1c79356b 1099 paging_offset,
1c79356b
A
1100 length_of_data,
1101 !precious_clean,
1102 FALSE);
0b4e3aa0 1103
1c79356b
A
1104 vm_object_lock(object);
1105 vm_object_paging_end(object);
1106
1107 if (holding_page) {
1108 assert(!object->pager_trusted);
1109 VM_PAGE_FREE(holding_page);
1110 vm_object_paging_end(object);
1111 }
1c79356b
A
1112}
1113
1c79356b
A
1114/*
1115 * Trusted pager throttle.
55e303ae 1116 * Object and page queues must be locked.
1c79356b
A
1117 */
1118void
1119vm_pageout_throttle(
1120 register vm_page_t m)
1121{
1c79356b
A
1122 assert(!m->laundry);
1123 m->laundry = TRUE;
1124 while (vm_page_laundry_count >= vm_page_laundry_max) {
1125 /*
1126 * Set the threshold for when vm_page_free()
1127 * should wake us up.
1128 */
1129 vm_page_laundry_min = vm_page_laundry_max/2;
0b4e3aa0 1130
1c79356b
A
1131 assert_wait((event_t) &vm_page_laundry_count, THREAD_UNINT);
1132 vm_page_unlock_queues();
55e303ae 1133 vm_object_unlock(m->object);
1c79356b
A
1134 /*
1135 * Pause to let the default pager catch up.
1136 */
1137 thread_block((void (*)(void)) 0);
55e303ae
A
1138
1139 vm_object_lock(m->object);
1c79356b
A
1140 vm_page_lock_queues();
1141 }
55e303ae
A
1142 if (!m->object->internal)
1143 vm_page_burst_count++;
1c79356b 1144 vm_page_laundry_count++;
1c79356b
A
1145}
1146
1147/*
1148 * The global variable vm_pageout_clean_active_pages controls whether
1149 * active pages are considered valid to be cleaned in place during a
1150 * clustered pageout. Performance measurements are necessary to determine
1151 * the best policy.
1152 */
1153int vm_pageout_clean_active_pages = 1;
1154/*
1155 * vm_pageout_cluster_page: [Internal]
1156 *
1157 * return a vm_page_t to the page at (object,offset) if it is appropriate
1158 * to clean in place. Pages that are non-existent, busy, absent, already
1159 * cleaning, or not dirty are not eligible to be cleaned as an adjacent
1160 * page in a cluster.
1161 *
1162 * The object must be locked on entry, and remains locked throughout
1163 * this call.
1164 */
1165
1166vm_page_t
1167vm_pageout_cluster_page(
1168 vm_object_t object,
1169 vm_object_offset_t offset,
1170 boolean_t precious_clean)
1171{
1172 vm_page_t m;
1173
1174 XPR(XPR_VM_PAGEOUT,
1175 "vm_pageout_cluster_page, object 0x%X offset 0x%X\n",
1176 (integer_t)object, offset, 0, 0, 0);
1177
1178 if ((m = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
1179 return(VM_PAGE_NULL);
1180
1181 if (m->busy || m->absent || m->cleaning ||
1c79356b
A
1182 (m->wire_count != 0) || m->error)
1183 return(VM_PAGE_NULL);
1184
1185 if (vm_pageout_clean_active_pages) {
1186 if (!m->active && !m->inactive) return(VM_PAGE_NULL);
1187 } else {
1188 if (!m->inactive) return(VM_PAGE_NULL);
1189 }
1190
1191 assert(!m->private);
1192 assert(!m->fictitious);
1193
55e303ae 1194 if (!m->dirty) m->dirty = pmap_is_modified(m->phys_page);
1c79356b
A
1195
1196 if (precious_clean) {
1197 if (!m->precious || !m->dirty)
1198 return(VM_PAGE_NULL);
1199 } else {
1200 if (!m->dirty)
1201 return(VM_PAGE_NULL);
1202 }
1203 return(m);
1204}
1205
1206/*
1207 * vm_pageout_scan does the dirty work for the pageout daemon.
1208 * It returns with vm_page_queue_free_lock held and
1209 * vm_page_free_wanted == 0.
1210 */
1211extern void vm_pageout_scan_continue(void); /* forward; */
1212
55e303ae
A
1213#define DELAYED_UNLOCK_LIMIT 50
1214#define LOCAL_FREED_LIMIT 50
1215
1c79356b
A
1216void
1217vm_pageout_scan(void)
1218{
1c79356b
A
1219 boolean_t now = FALSE;
1220 unsigned int laundry_pages;
55e303ae
A
1221 int loop_count = 0;
1222 int loop_bursted_count = 0;
1223 int active_loop_detect;
1224 vm_page_t local_freeq = 0;
1225 int local_freed = 0;
1226 int delayed_unlock = 0;
1227 int need_internal_inactive = 0;
1228 int need_pause;
1c79356b
A
1229
1230 XPR(XPR_VM_PAGEOUT, "vm_pageout_scan\n", 0, 0, 0, 0, 0);
1231
1232/*???*/ /*
1233 * We want to gradually dribble pages from the active queue
1234 * to the inactive queue. If we let the inactive queue get
1235 * very small, and then suddenly dump many pages into it,
1236 * those pages won't get a sufficient chance to be referenced
1237 * before we start taking them from the inactive queue.
1238 *
1239 * We must limit the rate at which we send pages to the pagers.
1240 * data_write messages consume memory, for message buffers and
1241 * for map-copy objects. If we get too far ahead of the pagers,
1242 * we can potentially run out of memory.
1243 *
1244 * We can use the laundry count to limit directly the number
1245 * of pages outstanding to the default pager. A similar
1246 * strategy for external pagers doesn't work, because
1247 * external pagers don't have to deallocate the pages sent them,
1248 * and because we might have to send pages to external pagers
1249 * even if they aren't processing writes. So we also
1250 * use a burst count to limit writes to external pagers.
1251 *
1252 * When memory is very tight, we can't rely on external pagers to
1253 * clean pages. They probably aren't running, because they
1254 * aren't vm-privileged. If we kept sending dirty pages to them,
55e303ae 1255 * we could exhaust the free list.
1c79356b
A
1256 *
1257 * consider_zone_gc should be last, because the other operations
1258 * might return memory to zones.
1259 */
1c79356b
A
1260 Restart:
1261
1c79356b
A
1262 stack_collect();
1263 consider_task_collect();
1c79356b 1264 consider_machine_collect();
55e303ae 1265 consider_zone_gc();
1c79356b 1266
55e303ae 1267 for (;;) {
1c79356b
A
1268 register vm_page_t m;
1269 register vm_object_t object;
1c79356b
A
1270
1271 /*
1272 * Recalculate vm_page_inactivate_target.
1273 */
55e303ae
A
1274 if (delayed_unlock == 0)
1275 vm_page_lock_queues();
1c79356b
A
1276 vm_page_inactive_target =
1277 VM_PAGE_INACTIVE_TARGET(vm_page_active_count +
1278 vm_page_inactive_count);
1279
55e303ae 1280 active_loop_detect = vm_page_active_count;
1c79356b
A
1281 /*
1282 * Move pages from active to inactive.
1283 */
55e303ae
A
1284 while ((need_internal_inactive ||
1285 vm_page_inactive_count < vm_page_inactive_target) &&
1286 !queue_empty(&vm_page_queue_active) &&
1287 ((active_loop_detect--) > 0)) {
1c79356b 1288
55e303ae 1289 need_pause = 1;
1c79356b 1290 vm_pageout_active++;
55e303ae 1291
1c79356b 1292 m = (vm_page_t) queue_first(&vm_page_queue_active);
55e303ae 1293 object = m->object;
1c79356b
A
1294
1295 /*
1296 * If we're getting really low on memory,
55e303ae
A
1297 * or we have already exceed the burst
1298 * count for the external pagers,
1299 * try skipping to a page that will go
1c79356b 1300 * directly to the default_pager.
1c79356b 1301 */
55e303ae
A
1302 if (need_internal_inactive &&
1303 IP_VALID(memory_manager_default)) {
1c79356b 1304 vm_pageout_scan_active_emm_throttle++;
1c79356b 1305
55e303ae
A
1306 assert(m->active && !m->inactive);
1307
1308 if (vm_object_lock_try(object)) {
1309 if (object->internal)
1310 goto object_locked_active;
1311
1312 if (!m->dirty)
1313 m->dirty = pmap_is_modified(m->phys_page);
1314 if (!m->dirty && !m->precious)
1315 goto object_locked_active;
1316
1317 vm_object_unlock(object);
1318
1319 need_pause = 0;
1c79356b 1320 }
55e303ae 1321 goto object_lock_try_active_failed;
1c79356b 1322 }
1c79356b
A
1323 assert(m->active && !m->inactive);
1324
1c79356b
A
1325 if (!vm_object_lock_try(object)) {
1326 /*
1327 * Move page to end and continue.
1328 */
55e303ae 1329object_lock_try_active_failed:
1c79356b
A
1330 queue_remove(&vm_page_queue_active, m,
1331 vm_page_t, pageq);
1332 queue_enter(&vm_page_queue_active, m,
1333 vm_page_t, pageq);
0b4e3aa0 1334
55e303ae
A
1335 if (local_freeq) {
1336 vm_page_free_list(local_freeq);
1337
1338 local_freeq = 0;
1339 local_freed = 0;
1340 }
1341 if (need_pause) {
1342 delayed_unlock = 0;
1343
1344 vm_page_unlock_queues();
1345 mutex_pause();
1346 vm_page_lock_queues();
1347 }
1c79356b
A
1348 continue;
1349 }
1350
1351 object_locked_active:
1352 /*
1353 * If the page is busy, then we pull it
1354 * off the active queue and leave it alone.
1355 */
1356
1357 if (m->busy) {
1358 vm_object_unlock(object);
1359 queue_remove(&vm_page_queue_active, m,
1360 vm_page_t, pageq);
1361 m->active = FALSE;
1362 if (!m->fictitious)
1363 vm_page_active_count--;
1364 continue;
1365 }
1366
1367 /*
1368 * Deactivate the page while holding the object
1369 * locked, so we know the page is still not busy.
1370 * This should prevent races between pmap_enter
1371 * and pmap_clear_reference. The page might be
1372 * absent or fictitious, but vm_page_deactivate
1373 * can handle that.
1374 */
1375
55e303ae
A
1376 if (need_internal_inactive) {
1377 /* found one ! */
1378 vm_pageout_scan_active_emm_throttle_success++;
1379 need_internal_inactive--;
1380 }
1c79356b
A
1381 vm_page_deactivate(m);
1382 vm_object_unlock(object);
1383 }
1c79356b
A
1384 /*
1385 * We are done if we have met our target *and*
1386 * nobody is still waiting for a page.
1387 */
55e303ae
A
1388 if (vm_page_free_count + local_freed >= vm_page_free_target) {
1389 if (local_freeq) {
1390 vm_page_free_list(local_freeq);
1391
1392 local_freeq = 0;
1393 local_freed = 0;
1394 }
1395
1396 consider_machine_adjust();
1397
0b4e3aa0 1398 mutex_lock(&vm_page_queue_free_lock);
55e303ae 1399
0b4e3aa0
A
1400 if ((vm_page_free_count >= vm_page_free_target) &&
1401 (vm_page_free_wanted == 0)) {
55e303ae
A
1402
1403 delayed_unlock = 0;
0b4e3aa0
A
1404 vm_page_unlock_queues();
1405 break;
1406 }
1407 mutex_unlock(&vm_page_queue_free_lock);
1c79356b 1408 }
55e303ae 1409
1c79356b
A
1410 /*
1411 * Sometimes we have to pause:
1412 * 1) No inactive pages - nothing to do.
55e303ae
A
1413 * 2) Flow control - nothing but external pages and
1414 * we have to wait for untrusted pagers to catch up.
1c79356b
A
1415 */
1416
55e303ae 1417 loop_count++;
9bccf70c 1418 if ((queue_empty(&vm_page_queue_inactive) &&
55e303ae
A
1419 queue_empty(&vm_page_queue_zf)) ||
1420 loop_bursted_count >= vm_pageout_burst_loop_throttle) {
1421
1c79356b
A
1422 unsigned int pages, msecs;
1423 int wait_result;
55e303ae 1424
1c79356b
A
1425 consider_machine_adjust();
1426 /*
1427 * vm_pageout_burst_wait is msecs/page.
1428 * If there is nothing for us to do, we wait
1429 * at least vm_pageout_empty_wait msecs.
1430 */
55e303ae 1431 pages = vm_page_burst_count;
1c79356b 1432
55e303ae
A
1433 if (pages) {
1434 msecs = pages * vm_pageout_burst_wait;
1435 } else {
1c79356b
A
1436 printf("Warning: No physical memory suitable for pageout or reclaim, pageout thread temporarily going to sleep\n");
1437 msecs = vm_free_page_pause;
1438 }
1c79356b
A
1439
1440 if (queue_empty(&vm_page_queue_inactive) &&
9bccf70c 1441 queue_empty(&vm_page_queue_zf) &&
1c79356b
A
1442 (msecs < vm_pageout_empty_wait))
1443 msecs = vm_pageout_empty_wait;
55e303ae
A
1444
1445 if (local_freeq) {
1446 vm_page_free_list(local_freeq);
1447
1448 local_freeq = 0;
1449 local_freed = 0;
1450 }
1451 delayed_unlock = 0;
1c79356b 1452 vm_page_unlock_queues();
0b4e3aa0 1453
1c79356b
A
1454 assert_wait_timeout(msecs, THREAD_INTERRUPTIBLE);
1455 counter(c_vm_pageout_scan_block++);
1456
1457 /*
1458 * Unfortunately, we don't have call_continuation
1459 * so we can't rely on tail-recursion.
1460 */
1461 wait_result = thread_block((void (*)(void)) 0);
1462 if (wait_result != THREAD_TIMED_OUT)
1463 thread_cancel_timer();
1464 vm_pageout_scan_continue();
0b4e3aa0 1465
55e303ae
A
1466 if (loop_count >= vm_page_inactive_count) {
1467 if (vm_page_burst_count >= vm_pageout_burst_max) {
1468 /*
1469 * Make sure we move enough "appropriate"
1470 * pages to the inactive queue before trying
1471 * again.
1472 */
1473 need_internal_inactive = vm_page_laundry_max;
1474 }
1475 loop_count = 0;
1476 }
1477 loop_bursted_count = 0;
1c79356b
A
1478 goto Restart;
1479 /*NOTREACHED*/
1480 }
1481
1482 vm_pageout_inactive++;
9bccf70c
A
1483
1484 if (vm_zf_count < vm_accellerate_zf_pageout_trigger) {
1485 vm_zf_iterator = 0;
1486 } else {
1487 last_page_zf = 0;
1488 if((vm_zf_iterator+=1) >= vm_zf_iterator_count) {
1489 vm_zf_iterator = 0;
1490 }
1491 }
1492 if(queue_empty(&vm_page_queue_zf) ||
1493 (((last_page_zf) || (vm_zf_iterator == 0)) &&
1494 !queue_empty(&vm_page_queue_inactive))) {
1495 m = (vm_page_t) queue_first(&vm_page_queue_inactive);
1496 last_page_zf = 0;
1497 } else {
1498 m = (vm_page_t) queue_first(&vm_page_queue_zf);
1499 last_page_zf = 1;
1500 }
55e303ae 1501 object = m->object;
1c79356b 1502
55e303ae
A
1503 need_pause = 1;
1504
1505 if (vm_page_burst_count >= vm_pageout_burst_max &&
1506 IP_VALID(memory_manager_default)) {
1c79356b 1507 /*
55e303ae
A
1508 * We're throttling external pagers.
1509 * Try to select a page that would
1510 * go directly to the default_pager
1511 * or that is clean...
1c79356b
A
1512 */
1513 vm_pageout_scan_inactive_emm_throttle++;
1c79356b 1514
55e303ae 1515 assert(!m->active && m->inactive);
1c79356b 1516
55e303ae
A
1517 if (vm_object_lock_try(object)) {
1518 if (object->internal) {
1519 /* found one ! */
1520 vm_pageout_scan_inactive_emm_throttle_success++;
1521 goto object_locked_inactive;
9bccf70c 1522 }
55e303ae
A
1523 if (!m->dirty)
1524 m->dirty = pmap_is_modified(m->phys_page);
1525 if (!m->dirty && !m->precious) {
1526 /* found one ! */
1527 vm_pageout_scan_inactive_emm_throttle_success++;
1528 goto object_locked_inactive;
1529 }
1530 vm_object_unlock(object);
1531
1532 need_pause = 0;
1c79356b 1533 }
55e303ae
A
1534 loop_bursted_count++;
1535 goto object_lock_try_inactive_failed;
1c79356b
A
1536 }
1537
1538 assert(!m->active && m->inactive);
1c79356b
A
1539
1540 /*
1541 * Try to lock object; since we've got the
1542 * page queues lock, we can only try for this one.
1543 */
1544
1545 if (!vm_object_lock_try(object)) {
55e303ae 1546object_lock_try_inactive_failed:
1c79356b
A
1547 /*
1548 * Move page to end and continue.
0b4e3aa0 1549 * Don't re-issue ticket
1c79356b 1550 */
55e303ae 1551 if (m->zero_fill) {
9bccf70c
A
1552 queue_remove(&vm_page_queue_zf, m,
1553 vm_page_t, pageq);
1554 queue_enter(&vm_page_queue_zf, m,
1555 vm_page_t, pageq);
1556 } else {
1557 queue_remove(&vm_page_queue_inactive, m,
1c79356b 1558 vm_page_t, pageq);
9bccf70c 1559 queue_enter(&vm_page_queue_inactive, m,
1c79356b 1560 vm_page_t, pageq);
9bccf70c 1561 }
55e303ae
A
1562 if (local_freeq) {
1563 vm_page_free_list(local_freeq);
1564
1565 local_freeq = 0;
1566 local_freed = 0;
1567 }
1568 delayed_unlock = 0;
1c79356b 1569 vm_page_unlock_queues();
0b4e3aa0 1570
55e303ae
A
1571 if (need_pause) {
1572 mutex_pause();
1573 vm_pageout_inactive_nolock++;
1574 }
1c79356b
A
1575 continue;
1576 }
1577
1578 object_locked_inactive:
1579 /*
55e303ae
A
1580 * Paging out pages of external objects which
1581 * are currently being created must be avoided.
1582 * The pager may claim for memory, thus leading to a
1583 * possible dead lock between it and the pageout thread,
1584 * if such pages are finally chosen. The remaining assumption
1585 * is that there will finally be enough available pages in the
1586 * inactive pool to page out in order to satisfy all memory
1587 * claimed by the thread which concurrently creates the pager.
1c79356b 1588 */
1c79356b
A
1589 if (!object->pager_initialized && object->pager_created) {
1590 /*
1591 * Move page to end and continue, hoping that
1592 * there will be enough other inactive pages to
1593 * page out so that the thread which currently
1594 * initializes the pager will succeed.
0b4e3aa0
A
1595 * Don't re-grant the ticket, the page should
1596 * pulled from the queue and paged out whenever
1597 * one of its logically adjacent fellows is
1598 * targeted.
1c79356b 1599 */
9bccf70c
A
1600 if(m->zero_fill) {
1601 queue_remove(&vm_page_queue_zf, m,
1602 vm_page_t, pageq);
1603 queue_enter(&vm_page_queue_zf, m,
1604 vm_page_t, pageq);
1605 last_page_zf = 1;
1606 vm_zf_iterator = vm_zf_iterator_count - 1;
1607 } else {
1608 queue_remove(&vm_page_queue_inactive, m,
1609 vm_page_t, pageq);
1610 queue_enter(&vm_page_queue_inactive, m,
1611 vm_page_t, pageq);
1612 last_page_zf = 0;
1613 vm_zf_iterator = 1;
1614 }
55e303ae
A
1615 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1616 delayed_unlock = 0;
1617 vm_page_unlock_queues();
1618 }
1c79356b
A
1619 vm_object_unlock(object);
1620 vm_pageout_inactive_avoid++;
1621 continue;
1622 }
1623
1624 /*
1625 * Remove the page from the inactive list.
1626 */
1627
9bccf70c
A
1628 if(m->zero_fill) {
1629 queue_remove(&vm_page_queue_zf, m, vm_page_t, pageq);
1630 } else {
1631 queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
1632 }
1c79356b
A
1633 m->inactive = FALSE;
1634 if (!m->fictitious)
1635 vm_page_inactive_count--;
1636
1637 if (m->busy || !object->alive) {
1638 /*
1639 * Somebody is already playing with this page.
1640 * Leave it off the pageout queues.
1641 */
1642
55e303ae
A
1643 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1644 delayed_unlock = 0;
1645 vm_page_unlock_queues();
1646 }
1c79356b
A
1647 vm_object_unlock(object);
1648 vm_pageout_inactive_busy++;
1649 continue;
1650 }
1651
1652 /*
1653 * If it's absent or in error, we can reclaim the page.
1654 */
1655
1656 if (m->absent || m->error) {
1657 vm_pageout_inactive_absent++;
1658 reclaim_page:
55e303ae
A
1659
1660 if (m->tabled)
1661 vm_page_remove(m); /* clears tabled, object, offset */
1662 if (m->absent)
1663 vm_object_absent_release(object);
1664
1665 m->pageq.next = (queue_entry_t)local_freeq;
1666 local_freeq = m;
1667
1668 if (local_freed++ > LOCAL_FREED_LIMIT) {
1669 vm_page_free_list(local_freeq);
1670
1671 local_freeq = 0;
1672 local_freed = 0;
1673 }
1674 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1675 delayed_unlock = 0;
1676 vm_page_unlock_queues();
1677 }
1c79356b 1678 vm_object_unlock(object);
55e303ae 1679 loop_bursted_count = 0;
1c79356b
A
1680 continue;
1681 }
1682
1683 assert(!m->private);
1684 assert(!m->fictitious);
1685
1686 /*
1687 * If already cleaning this page in place, convert from
1688 * "adjacent" to "target". We can leave the page mapped,
1689 * and vm_pageout_object_terminate will determine whether
1690 * to free or reactivate.
1691 */
1692
1693 if (m->cleaning) {
1694#if MACH_CLUSTER_STATS
1695 vm_pageout_cluster_conversions++;
1696#endif
0b4e3aa0
A
1697 m->busy = TRUE;
1698 m->pageout = TRUE;
1699 m->dump_cleaning = TRUE;
1700 vm_page_wire(m);
1c79356b 1701 vm_object_unlock(object);
55e303ae
A
1702
1703 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1704 delayed_unlock = 0;
1705 vm_page_unlock_queues();
1706 }
1707 loop_bursted_count = 0;
1c79356b
A
1708 continue;
1709 }
1710
1711 /*
1712 * If it's being used, reactivate.
1713 * (Fictitious pages are either busy or absent.)
1714 */
1715
55e303ae 1716 if (m->reference || pmap_is_referenced(m->phys_page)) {
1c79356b
A
1717 vm_pageout_inactive_used++;
1718 reactivate_page:
1719#if ADVISORY_PAGEOUT
1720 if (m->discard_request) {
1721 m->discard_request = FALSE;
1722 }
1723#endif /* ADVISORY_PAGEOUT */
9bccf70c 1724 last_page_zf = 0;
1c79356b
A
1725 vm_object_unlock(object);
1726 vm_page_activate(m);
1727 VM_STAT(reactivations++);
55e303ae
A
1728
1729 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1730 delayed_unlock = 0;
1731 vm_page_unlock_queues();
1732 }
1c79356b
A
1733 continue;
1734 }
1735
1c79356b
A
1736#if ADVISORY_PAGEOUT
1737 if (object->advisory_pageout) {
1738 boolean_t do_throttle;
0b4e3aa0 1739 memory_object_t pager;
1c79356b
A
1740 vm_object_offset_t discard_offset;
1741
1742 if (m->discard_request) {
1743 vm_stat_discard_failure++;
1744 goto mandatory_pageout;
1745 }
1746
1747 assert(object->pager_initialized);
1748 m->discard_request = TRUE;
0b4e3aa0 1749 pager = object->pager;
1c79356b
A
1750
1751 /* system-wide throttle */
1752 do_throttle = (vm_page_free_count <=
1753 vm_page_free_reserved);
0b4e3aa0
A
1754
1755#if 0
1756 /*
1757 * JMM - Do we need a replacement throttle
1758 * mechanism for pagers?
1759 */
1c79356b
A
1760 if (!do_throttle) {
1761 /* throttle on this pager */
1762 /* XXX lock ordering ? */
1763 ip_lock(port);
1764 do_throttle= imq_full(&port->ip_messages);
1765 ip_unlock(port);
1766 }
0b4e3aa0
A
1767#endif
1768
1c79356b
A
1769 if (do_throttle) {
1770 vm_stat_discard_throttle++;
1771#if 0
1772 /* ignore this page and skip to next */
55e303ae
A
1773 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1774 delayed_unlock = 0;
1775 vm_page_unlock_queues();
1776 }
1c79356b
A
1777 vm_object_unlock(object);
1778 continue;
1779#else
1780 /* force mandatory pageout */
1781 goto mandatory_pageout;
1782#endif
1783 }
1784
1785 /* proceed with discard_request */
1786 vm_page_activate(m);
1787 vm_stat_discard++;
1788 VM_STAT(reactivations++);
1789 discard_offset = m->offset + object->paging_offset;
1790 vm_stat_discard_sent++;
55e303ae
A
1791
1792 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
1793 delayed_unlock = 0;
1794 vm_page_unlock_queues();
1795 }
1c79356b 1796 vm_object_unlock(object);
0b4e3aa0 1797
1c79356b
A
1798/*
1799 memory_object_discard_request(object->pager,
1c79356b
A
1800 discard_offset,
1801 PAGE_SIZE);
1802*/
1803 continue;
1804 }
1805 mandatory_pageout:
1806#endif /* ADVISORY_PAGEOUT */
1807
1808 XPR(XPR_VM_PAGEOUT,
1809 "vm_pageout_scan, replace object 0x%X offset 0x%X page 0x%X\n",
1810 (integer_t)object, (integer_t)m->offset, (integer_t)m, 0,0);
1811
1812 /*
1813 * Eliminate all mappings.
1814 */
1815
1816 m->busy = TRUE;
55e303ae
A
1817
1818 if (m->no_isync == FALSE)
1819 pmap_page_protect(m->phys_page, VM_PROT_NONE);
0b4e3aa0 1820
1c79356b 1821 if (!m->dirty)
55e303ae 1822 m->dirty = pmap_is_modified(m->phys_page);
1c79356b
A
1823 /*
1824 * If it's clean and not precious, we can free the page.
1825 */
1826
1827 if (!m->dirty && !m->precious) {
1828 vm_pageout_inactive_clean++;
1829 goto reclaim_page;
1830 }
55e303ae
A
1831 if (local_freeq) {
1832 vm_page_free_list(local_freeq);
1833
1834 local_freeq = 0;
1835 local_freed = 0;
1836 }
1837 delayed_unlock = 0;
1c79356b
A
1838 vm_page_unlock_queues();
1839
1840 /*
1841 * If there is no memory object for the page, create
1842 * one and hand it to the default pager.
1843 */
1844
1845 if (!object->pager_initialized)
55e303ae 1846 vm_object_collapse(object, (vm_object_offset_t)0);
1c79356b
A
1847 if (!object->pager_initialized)
1848 vm_object_pager_create(object);
1849 if (!object->pager_initialized) {
1850 /*
1851 * Still no pager for the object.
1852 * Reactivate the page.
1853 *
1854 * Should only happen if there is no
1855 * default pager.
1856 */
1857 vm_page_lock_queues();
1858 vm_page_activate(m);
1859 vm_page_unlock_queues();
1860
1861 /*
1862 * And we are done with it.
1863 */
1864 PAGE_WAKEUP_DONE(m);
1865 vm_object_unlock(object);
1866
1867 /*
1868 * break here to get back to the preemption
1869 * point in the outer loop so that we don't
1870 * spin forever if there is no default pager.
1871 */
1872 vm_pageout_dirty_no_pager++;
1873 /*
1874 * Well there's no pager, but we can still reclaim
1875 * free pages out of the inactive list. Go back
1876 * to top of loop and look for suitable pages.
1877 */
1878 continue;
55e303ae 1879 } else if (object->pager == MEMORY_OBJECT_NULL) {
1c79356b
A
1880 /*
1881 * This pager has been destroyed by either
1882 * memory_object_destroy or vm_object_destroy, and
1883 * so there is nowhere for the page to go.
1884 * Just free the page.
1885 */
1886 VM_PAGE_FREE(m);
1887 vm_object_unlock(object);
55e303ae 1888 loop_bursted_count = 0;
1c79356b
A
1889 continue;
1890 }
1891
1892 vm_pageout_inactive_dirty++;
1c79356b 1893 vm_pageout_cluster(m); /* flush it */
55e303ae
A
1894 vm_object_unlock(object);
1895 loop_bursted_count = 0;
1c79356b 1896 }
1c79356b
A
1897}
1898
1899counter(unsigned int c_vm_pageout_scan_continue = 0;)
1900
1901void
1902vm_pageout_scan_continue(void)
1903{
1904 /*
1905 * We just paused to let the pagers catch up.
1906 * If vm_page_laundry_count is still high,
1907 * then we aren't waiting long enough.
1908 * If we have paused some vm_pageout_pause_max times without
1909 * adjusting vm_pageout_burst_wait, it might be too big,
1910 * so we decrease it.
1911 */
1912
1913 vm_page_lock_queues();
1914 counter(++c_vm_pageout_scan_continue);
1915 if (vm_page_laundry_count > vm_pageout_burst_min) {
1916 vm_pageout_burst_wait++;
1917 vm_pageout_pause_count = 0;
1918 } else if (++vm_pageout_pause_count > vm_pageout_pause_max) {
1919 vm_pageout_burst_wait = (vm_pageout_burst_wait * 3) / 4;
1920 if (vm_pageout_burst_wait < 1)
1921 vm_pageout_burst_wait = 1;
1922 vm_pageout_pause_count = 0;
1923 }
1924 vm_page_unlock_queues();
1925}
1926
1927void vm_page_free_reserve(int pages);
1928int vm_page_free_count_init;
1929
1930void
1931vm_page_free_reserve(
1932 int pages)
1933{
1934 int free_after_reserve;
1935
1936 vm_page_free_reserved += pages;
1937
1938 free_after_reserve = vm_page_free_count_init - vm_page_free_reserved;
1939
1940 vm_page_free_min = vm_page_free_reserved +
1941 VM_PAGE_FREE_MIN(free_after_reserve);
1942
1943 vm_page_free_target = vm_page_free_reserved +
1944 VM_PAGE_FREE_TARGET(free_after_reserve);
1945
1946 if (vm_page_free_target < vm_page_free_min + 5)
1947 vm_page_free_target = vm_page_free_min + 5;
1948}
1949
1950/*
1951 * vm_pageout is the high level pageout daemon.
1952 */
1953
55e303ae
A
1954void
1955vm_pageout_continue(void)
1956{
1957 vm_pageout_scan_event_counter++;
1958 vm_pageout_scan();
1959 /* we hold vm_page_queue_free_lock now */
1960 assert(vm_page_free_wanted == 0);
1961 assert_wait((event_t) &vm_page_free_wanted, THREAD_UNINT);
1962 mutex_unlock(&vm_page_queue_free_lock);
1963
1964 counter(c_vm_pageout_block++);
1965 thread_block(vm_pageout_continue);
1966 /*NOTREACHED*/
1967}
1c79356b
A
1968
1969void
1970vm_pageout(void)
1971{
1972 thread_t self = current_thread();
0b4e3aa0 1973 spl_t s;
1c79356b
A
1974
1975 /*
1976 * Set thread privileges.
1977 */
1978 self->vm_privilege = TRUE;
0b4e3aa0
A
1979
1980 s = splsched();
1981 thread_lock(self);
0b4e3aa0 1982 self->priority = BASEPRI_PREEMPT - 1;
9bccf70c 1983 set_sched_pri(self, self->priority);
0b4e3aa0
A
1984 thread_unlock(self);
1985 splx(s);
1c79356b
A
1986
1987 /*
1988 * Initialize some paging parameters.
1989 */
1990
1991 if (vm_page_laundry_max == 0)
1992 vm_page_laundry_max = VM_PAGE_LAUNDRY_MAX;
1993
1994 if (vm_pageout_burst_max == 0)
1995 vm_pageout_burst_max = VM_PAGEOUT_BURST_MAX;
1996
1997 if (vm_pageout_burst_wait == 0)
1998 vm_pageout_burst_wait = VM_PAGEOUT_BURST_WAIT;
1999
2000 if (vm_pageout_empty_wait == 0)
2001 vm_pageout_empty_wait = VM_PAGEOUT_EMPTY_WAIT;
2002
55e303ae
A
2003 /*
2004 * Set kernel task to low backing store privileged
2005 * status
2006 */
2007 task_lock(kernel_task);
2008 kernel_task->priv_flags |= VM_BACKING_STORE_PRIV;
2009 task_unlock(kernel_task);
2010
1c79356b 2011 vm_page_free_count_init = vm_page_free_count;
9bccf70c 2012 vm_zf_iterator = 0;
1c79356b
A
2013 /*
2014 * even if we've already called vm_page_free_reserve
2015 * call it again here to insure that the targets are
2016 * accurately calculated (it uses vm_page_free_count_init)
2017 * calling it with an arg of 0 will not change the reserve
2018 * but will re-calculate free_min and free_target
2019 */
55e303ae
A
2020 if (vm_page_free_reserved < VM_PAGE_FREE_RESERVED) {
2021 int scale;
2022
2023 /*
2024 * HFS Journaling exists on the vm_pageout path...
2025 * it can need to allocate a lot more memory than a
2026 * typical driver/filesystem... if it can't allocate
2027 * the transaction buffer(s), we will deadlock...
2028 * the amount is scaled
2029 * based on the physical footprint of the system, so
2030 * let's double our reserve on systems with > 512Mbytes
2031 */
2032 if (vm_page_free_count > (512 * 1024 * 1024) / PAGE_SIZE)
2033 scale = 2;
2034 else
2035 scale = 1;
2036 vm_page_free_reserve((VM_PAGE_FREE_RESERVED * scale) - vm_page_free_reserved);
2037 } else
1c79356b
A
2038 vm_page_free_reserve(0);
2039
55e303ae 2040 vm_pageout_continue();
1c79356b
A
2041 /*NOTREACHED*/
2042}
2043
9bccf70c
A
2044kern_return_t
2045vm_pageout_emergency_availability_request()
2046{
2047 vm_page_t m;
2048 vm_object_t object;
2049
2050 vm_page_lock_queues();
2051 m = (vm_page_t) queue_first(&vm_page_queue_inactive);
2052
2053 while (!queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) {
55e303ae
A
2054
2055 object = m->object;
2056
2057 if ( !vm_object_lock_try(object)) {
9bccf70c
A
2058 m = (vm_page_t) queue_next(&m->pageq);
2059 continue;
2060 }
55e303ae
A
2061 if ((!object->alive) || (object->pageout)) {
2062 vm_object_unlock(object);
2063
2064 m = (vm_page_t) queue_next(&m->pageq);
2065 continue;
2066 }
2067 if (m->dirty || m->busy || m->wire_count || m->absent || m->fictitious
9bccf70c
A
2068 || m->precious || m->cleaning
2069 || m->dump_cleaning || m->error
2070 || m->pageout || m->laundry
2071 || m->list_req_pending
2072 || m->overwriting) {
55e303ae
A
2073 vm_object_unlock(object);
2074
9bccf70c
A
2075 m = (vm_page_t) queue_next(&m->pageq);
2076 continue;
2077 }
55e303ae
A
2078 m->busy = TRUE;
2079 pmap_page_protect(m->phys_page, VM_PROT_NONE);
2080 m->dirty = pmap_is_modified(m->phys_page);
9bccf70c 2081
55e303ae
A
2082 if (m->dirty) {
2083 PAGE_WAKEUP_DONE(m);
9bccf70c 2084 vm_object_unlock(object);
55e303ae
A
2085
2086 m = (vm_page_t) queue_next(&m->pageq);
2087 continue;
9bccf70c 2088 }
55e303ae
A
2089 vm_page_free(m);
2090 vm_object_unlock(object);
2091 vm_page_unlock_queues();
9bccf70c 2092
55e303ae
A
2093 return KERN_SUCCESS;
2094 }
9bccf70c
A
2095 m = (vm_page_t) queue_first(&vm_page_queue_active);
2096
2097 while (!queue_end(&vm_page_queue_active, (queue_entry_t) m)) {
55e303ae
A
2098
2099 object = m->object;
2100
2101 if ( !vm_object_lock_try(object)) {
9bccf70c
A
2102 m = (vm_page_t) queue_next(&m->pageq);
2103 continue;
2104 }
55e303ae
A
2105 if ((!object->alive) || (object->pageout)) {
2106 vm_object_unlock(object);
2107
2108 m = (vm_page_t) queue_next(&m->pageq);
2109 continue;
2110 }
2111 if (m->dirty || m->busy || m->wire_count || m->absent || m->fictitious
9bccf70c
A
2112 || m->precious || m->cleaning
2113 || m->dump_cleaning || m->error
2114 || m->pageout || m->laundry
2115 || m->list_req_pending
2116 || m->overwriting) {
55e303ae
A
2117 vm_object_unlock(object);
2118
9bccf70c
A
2119 m = (vm_page_t) queue_next(&m->pageq);
2120 continue;
2121 }
55e303ae
A
2122 m->busy = TRUE;
2123 pmap_page_protect(m->phys_page, VM_PROT_NONE);
2124 m->dirty = pmap_is_modified(m->phys_page);
9bccf70c 2125
55e303ae
A
2126 if (m->dirty) {
2127 PAGE_WAKEUP_DONE(m);
9bccf70c 2128 vm_object_unlock(object);
55e303ae
A
2129
2130 m = (vm_page_t) queue_next(&m->pageq);
2131 continue;
9bccf70c 2132 }
55e303ae
A
2133 vm_page_free(m);
2134 vm_object_unlock(object);
2135 vm_page_unlock_queues();
2136
2137 return KERN_SUCCESS;
9bccf70c
A
2138 }
2139 vm_page_unlock_queues();
55e303ae 2140
9bccf70c
A
2141 return KERN_FAILURE;
2142}
2143
1c79356b 2144
0b4e3aa0
A
2145static upl_t
2146upl_create(
55e303ae 2147 int flags,
9bccf70c 2148 vm_size_t size)
0b4e3aa0
A
2149{
2150 upl_t upl;
55e303ae 2151 int page_field_size; /* bit field in word size buf */
0b4e3aa0 2152
55e303ae
A
2153 page_field_size = 0;
2154 if (flags & UPL_CREATE_LITE) {
2155 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2156 page_field_size = (page_field_size + 3) & 0xFFFFFFFC;
2157 }
2158 if(flags & UPL_CREATE_INTERNAL) {
0b4e3aa0 2159 upl = (upl_t)kalloc(sizeof(struct upl)
55e303ae
A
2160 + (sizeof(struct upl_page_info)*(size/PAGE_SIZE))
2161 + page_field_size);
0b4e3aa0 2162 } else {
55e303ae 2163 upl = (upl_t)kalloc(sizeof(struct upl) + page_field_size);
0b4e3aa0
A
2164 }
2165 upl->flags = 0;
2166 upl->src_object = NULL;
2167 upl->kaddr = (vm_offset_t)0;
2168 upl->size = 0;
2169 upl->map_object = NULL;
2170 upl->ref_count = 1;
2171 upl_lock_init(upl);
2172#ifdef UBC_DEBUG
2173 upl->ubc_alias1 = 0;
2174 upl->ubc_alias2 = 0;
2175#endif /* UBC_DEBUG */
2176 return(upl);
2177}
2178
2179static void
2180upl_destroy(
2181 upl_t upl)
2182{
55e303ae 2183 int page_field_size; /* bit field in word size buf */
0b4e3aa0
A
2184
2185#ifdef UBC_DEBUG
2186 {
2187 upl_t upl_ele;
55e303ae
A
2188 vm_object_t object;
2189 if (upl->map_object->pageout) {
2190 object = upl->map_object->shadow;
2191 } else {
2192 object = upl->map_object;
2193 }
2194 vm_object_lock(object);
2195 queue_iterate(&object->uplq, upl_ele, upl_t, uplq) {
0b4e3aa0 2196 if(upl_ele == upl) {
55e303ae
A
2197 queue_remove(&object->uplq,
2198 upl_ele, upl_t, uplq);
0b4e3aa0
A
2199 break;
2200 }
2201 }
55e303ae 2202 vm_object_unlock(object);
0b4e3aa0
A
2203 }
2204#endif /* UBC_DEBUG */
55e303ae
A
2205 /* drop a reference on the map_object whether or */
2206 /* not a pageout object is inserted */
2207 if(upl->map_object->pageout)
0b4e3aa0 2208 vm_object_deallocate(upl->map_object);
55e303ae
A
2209
2210 page_field_size = 0;
2211 if (upl->flags & UPL_LITE) {
2212 page_field_size = ((upl->size/PAGE_SIZE) + 7) >> 3;
2213 page_field_size = (page_field_size + 3) & 0xFFFFFFFC;
2214 }
0b4e3aa0
A
2215 if(upl->flags & UPL_INTERNAL) {
2216 kfree((vm_offset_t)upl,
2217 sizeof(struct upl) +
55e303ae
A
2218 (sizeof(struct upl_page_info) * (upl->size/PAGE_SIZE))
2219 + page_field_size);
0b4e3aa0 2220 } else {
55e303ae 2221 kfree((vm_offset_t)upl, sizeof(struct upl) + page_field_size);
0b4e3aa0
A
2222 }
2223}
2224
2225__private_extern__ void
2226uc_upl_dealloc(
1c79356b
A
2227 upl_t upl)
2228{
2229 upl->ref_count -= 1;
2230 if(upl->ref_count == 0) {
2231 upl_destroy(upl);
2232 }
2233}
2234
0b4e3aa0
A
2235void
2236upl_deallocate(
2237 upl_t upl)
2238{
2239
2240 upl->ref_count -= 1;
2241 if(upl->ref_count == 0) {
2242 upl_destroy(upl);
2243 }
2244}
1c79356b
A
2245
2246/*
0b4e3aa0 2247 * Routine: vm_object_upl_request
1c79356b
A
2248 * Purpose:
2249 * Cause the population of a portion of a vm_object.
2250 * Depending on the nature of the request, the pages
2251 * returned may be contain valid data or be uninitialized.
2252 * A page list structure, listing the physical pages
2253 * will be returned upon request.
2254 * This function is called by the file system or any other
2255 * supplier of backing store to a pager.
2256 * IMPORTANT NOTE: The caller must still respect the relationship
2257 * between the vm_object and its backing memory object. The
2258 * caller MUST NOT substitute changes in the backing file
2259 * without first doing a memory_object_lock_request on the
2260 * target range unless it is know that the pages are not
2261 * shared with another entity at the pager level.
2262 * Copy_in_to:
2263 * if a page list structure is present
2264 * return the mapped physical pages, where a
2265 * page is not present, return a non-initialized
2266 * one. If the no_sync bit is turned on, don't
2267 * call the pager unlock to synchronize with other
2268 * possible copies of the page. Leave pages busy
2269 * in the original object, if a page list structure
2270 * was specified. When a commit of the page list
2271 * pages is done, the dirty bit will be set for each one.
2272 * Copy_out_from:
2273 * If a page list structure is present, return
2274 * all mapped pages. Where a page does not exist
2275 * map a zero filled one. Leave pages busy in
2276 * the original object. If a page list structure
2277 * is not specified, this call is a no-op.
2278 *
2279 * Note: access of default pager objects has a rather interesting
2280 * twist. The caller of this routine, presumably the file system
2281 * page cache handling code, will never actually make a request
2282 * against a default pager backed object. Only the default
2283 * pager will make requests on backing store related vm_objects
2284 * In this way the default pager can maintain the relationship
2285 * between backing store files (abstract memory objects) and
2286 * the vm_objects (cache objects), they support.
2287 *
2288 */
0b4e3aa0
A
2289__private_extern__ kern_return_t
2290vm_object_upl_request(
1c79356b 2291 vm_object_t object,
0b4e3aa0
A
2292 vm_object_offset_t offset,
2293 vm_size_t size,
1c79356b 2294 upl_t *upl_ptr,
0b4e3aa0
A
2295 upl_page_info_array_t user_page_list,
2296 unsigned int *page_list_count,
2297 int cntrl_flags)
1c79356b
A
2298{
2299 vm_page_t dst_page;
2300 vm_object_offset_t dst_offset = offset;
1c79356b
A
2301 vm_size_t xfer_size = size;
2302 boolean_t do_m_lock = FALSE;
2303 boolean_t dirty;
55e303ae 2304 boolean_t hw_dirty;
1c79356b
A
2305 upl_t upl = NULL;
2306 int entry;
2307 boolean_t encountered_lrp = FALSE;
2308
2309 vm_page_t alias_page = NULL;
0b4e3aa0 2310 int page_ticket;
55e303ae 2311 wpl_array_t lite_list;
0b4e3aa0
A
2312
2313 page_ticket = (cntrl_flags & UPL_PAGE_TICKET_MASK)
2314 >> UPL_PAGE_TICKET_SHIFT;
2315
55e303ae
A
2316 if(((size/PAGE_SIZE) > MAX_UPL_TRANSFER) && !object->phys_contiguous) {
2317 size = MAX_UPL_TRANSFER * PAGE_SIZE;
0b4e3aa0 2318 }
1c79356b
A
2319
2320 if(cntrl_flags & UPL_SET_INTERNAL)
0b4e3aa0
A
2321 if(page_list_count != NULL)
2322 *page_list_count = MAX_UPL_TRANSFER;
2323 if(((cntrl_flags & UPL_SET_INTERNAL) && !(object->phys_contiguous)) &&
2324 ((page_list_count != NULL) && (*page_list_count != 0)
2325 && *page_list_count < (size/page_size)))
1c79356b
A
2326 return KERN_INVALID_ARGUMENT;
2327
2328 if((!object->internal) && (object->paging_offset != 0))
0b4e3aa0 2329 panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
1c79356b
A
2330
2331 if((cntrl_flags & UPL_COPYOUT_FROM) && (upl_ptr == NULL)) {
2332 return KERN_SUCCESS;
2333 }
55e303ae 2334
1c79356b 2335 if(upl_ptr) {
0b4e3aa0 2336 if(cntrl_flags & UPL_SET_INTERNAL) {
55e303ae
A
2337 if(cntrl_flags & UPL_SET_LITE) {
2338 vm_offset_t page_field_size;
2339 upl = upl_create(
2340 UPL_CREATE_INTERNAL | UPL_CREATE_LITE,
2341 size);
2342 user_page_list = (upl_page_info_t *)
2343 (((vm_offset_t)upl) + sizeof(struct upl));
2344 lite_list = (wpl_array_t)
2345 (((vm_offset_t)user_page_list) +
2346 ((size/PAGE_SIZE) *
2347 sizeof(upl_page_info_t)));
2348 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2349 page_field_size =
2350 (page_field_size + 3) & 0xFFFFFFFC;
2351 bzero((char *)lite_list, page_field_size);
2352 upl->flags =
2353 UPL_LITE | UPL_INTERNAL;
2354 } else {
2355 upl = upl_create(UPL_CREATE_INTERNAL, size);
2356 user_page_list = (upl_page_info_t *)
2357 (((vm_offset_t)upl)
2358 + sizeof(struct upl));
2359 upl->flags = UPL_INTERNAL;
2360 }
1c79356b 2361 } else {
55e303ae
A
2362 if(cntrl_flags & UPL_SET_LITE) {
2363 vm_offset_t page_field_size;
2364 upl = upl_create(UPL_CREATE_LITE, size);
2365 lite_list = (wpl_array_t)
2366 (((vm_offset_t)upl) + sizeof(struct upl));
2367 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
2368 page_field_size =
2369 (page_field_size + 3) & 0xFFFFFFFC;
2370 bzero((char *)lite_list, page_field_size);
2371 upl->flags = UPL_LITE;
2372 } else {
2373 upl = upl_create(UPL_CREATE_EXTERNAL, size);
2374 upl->flags = 0;
2375 }
0b4e3aa0 2376 }
55e303ae 2377
0b4e3aa0 2378 if(object->phys_contiguous) {
55e303ae
A
2379 upl->map_object = object;
2380 /* don't need any shadow mappings for this one */
2381 /* since it is already I/O memory */
2382 upl->flags |= UPL_DEVICE_MEMORY;
2383
2384 vm_object_lock(object);
2385 vm_object_paging_begin(object);
2386 vm_object_unlock(object);
2387
2388 /* paging_in_progress protects paging_offset */
0b4e3aa0 2389 upl->offset = offset + object->paging_offset;
55e303ae 2390 upl->size = size;
0b4e3aa0
A
2391 *upl_ptr = upl;
2392 if(user_page_list) {
2393 user_page_list[0].phys_addr =
55e303ae 2394 (offset + object->shadow_offset)>>12;
0b4e3aa0 2395 user_page_list[0].device = TRUE;
1c79356b 2396 }
55e303ae
A
2397
2398 if(page_list_count != NULL) {
2399 if (upl->flags & UPL_INTERNAL) {
2400 *page_list_count = 0;
2401 } else {
2402 *page_list_count = 1;
2403 }
2404 }
2405 return KERN_SUCCESS;
2406 }
2407 if(user_page_list)
2408 user_page_list[0].device = FALSE;
2409
2410 if(cntrl_flags & UPL_SET_LITE) {
2411 upl->map_object = object;
2412 } else {
0b4e3aa0
A
2413 upl->map_object = vm_object_allocate(size);
2414 vm_object_lock(upl->map_object);
2415 upl->map_object->shadow = object;
0b4e3aa0
A
2416 upl->map_object->pageout = TRUE;
2417 upl->map_object->can_persist = FALSE;
55e303ae
A
2418 upl->map_object->copy_strategy =
2419 MEMORY_OBJECT_COPY_NONE;
0b4e3aa0 2420 upl->map_object->shadow_offset = offset;
55e303ae 2421 upl->map_object->wimg_bits = object->wimg_bits;
0b4e3aa0 2422 vm_object_unlock(upl->map_object);
0b4e3aa0 2423 }
55e303ae
A
2424 }
2425 if (!(cntrl_flags & UPL_SET_LITE)) {
2426 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2427 }
2428 vm_object_lock(object);
2429 vm_object_paging_begin(object);
2430
2431 /* we can lock in the paging_offset once paging_in_progress is set */
2432 if(upl_ptr) {
1c79356b
A
2433 upl->size = size;
2434 upl->offset = offset + object->paging_offset;
1c79356b 2435 *upl_ptr = upl;
1c79356b 2436#ifdef UBC_DEBUG
1c79356b
A
2437 queue_enter(&object->uplq, upl, upl_t, uplq);
2438#endif /* UBC_DEBUG */
55e303ae
A
2439 }
2440
1c79356b
A
2441 entry = 0;
2442 if(cntrl_flags & UPL_COPYOUT_FROM) {
2443 upl->flags |= UPL_PAGE_SYNC_DONE;
55e303ae 2444
1c79356b 2445 while (xfer_size) {
55e303ae
A
2446 if((alias_page == NULL) &&
2447 !(cntrl_flags & UPL_SET_LITE)) {
1c79356b
A
2448 vm_object_unlock(object);
2449 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2450 vm_object_lock(object);
2451 }
2452 if(((dst_page = vm_page_lookup(object,
2453 dst_offset)) == VM_PAGE_NULL) ||
2454 dst_page->fictitious ||
2455 dst_page->absent ||
2456 dst_page->error ||
2457 (dst_page->wire_count != 0 &&
2458 !dst_page->pageout) ||
2459 ((!(dst_page->dirty || dst_page->precious ||
55e303ae 2460 pmap_is_modified(dst_page->phys_page)))
0b4e3aa0
A
2461 && (cntrl_flags & UPL_RET_ONLY_DIRTY)) ||
2462 ((!(dst_page->inactive))
2463 && (dst_page->page_ticket != page_ticket)
2464 && ((dst_page->page_ticket+1) != page_ticket)
55e303ae
A
2465 && (cntrl_flags & UPL_FOR_PAGEOUT)) ||
2466 ((!dst_page->list_req_pending) && (cntrl_flags & UPL_FOR_PAGEOUT) &&
0b4e3aa0 2467 (cntrl_flags & UPL_RET_ONLY_DIRTY) &&
55e303ae
A
2468 pmap_is_referenced(dst_page->phys_page))) {
2469 if(user_page_list) {
1c79356b 2470 user_page_list[entry].phys_addr = 0;
55e303ae 2471 }
1c79356b
A
2472 } else {
2473
2474 if(dst_page->busy &&
2475 (!(dst_page->list_req_pending &&
2476 dst_page->pageout))) {
2477 if(cntrl_flags & UPL_NOBLOCK) {
55e303ae
A
2478 if(user_page_list) {
2479 user_page_list[entry].phys_addr = 0;
2480 }
1c79356b
A
2481 entry++;
2482 dst_offset += PAGE_SIZE_64;
2483 xfer_size -= PAGE_SIZE;
2484 continue;
2485 }
2486 /*someone else is playing with the */
2487 /* page. We will have to wait. */
9bccf70c 2488 PAGE_SLEEP(object, dst_page, THREAD_UNINT);
1c79356b
A
2489 continue;
2490 }
2491 /* Someone else already cleaning the page? */
2492 if((dst_page->cleaning || dst_page->absent ||
1c79356b
A
2493 dst_page->wire_count != 0) &&
2494 !dst_page->list_req_pending) {
55e303ae 2495 if(user_page_list) {
1c79356b 2496 user_page_list[entry].phys_addr = 0;
55e303ae 2497 }
1c79356b
A
2498 entry++;
2499 dst_offset += PAGE_SIZE_64;
2500 xfer_size -= PAGE_SIZE;
2501 continue;
2502 }
2503 /* eliminate all mappings from the */
2504 /* original object and its prodigy */
2505
2506 vm_page_lock_queues();
55e303ae 2507
1c79356b
A
2508 /* pageout statistics gathering. count */
2509 /* all the pages we will page out that */
2510 /* were not counted in the initial */
2511 /* vm_pageout_scan work */
2512 if(dst_page->list_req_pending)
2513 encountered_lrp = TRUE;
2514 if((dst_page->dirty ||
2515 (dst_page->object->internal &&
2516 dst_page->precious)) &&
2517 (dst_page->list_req_pending
2518 == FALSE)) {
2519 if(encountered_lrp) {
2520 CLUSTER_STAT
2521 (pages_at_higher_offsets++;)
2522 } else {
2523 CLUSTER_STAT
2524 (pages_at_lower_offsets++;)
2525 }
2526 }
2527
2528 /* Turn off busy indication on pending */
2529 /* pageout. Note: we can only get here */
2530 /* in the request pending case. */
2531 dst_page->list_req_pending = FALSE;
2532 dst_page->busy = FALSE;
2533 dst_page->cleaning = FALSE;
2534
55e303ae
A
2535 hw_dirty = pmap_is_modified(dst_page->phys_page);
2536 dirty = hw_dirty ? TRUE : dst_page->dirty;
2537
2538 if(cntrl_flags & UPL_SET_LITE) {
2539 int pg_num;
2540 pg_num = (dst_offset-offset)/PAGE_SIZE;
2541 lite_list[pg_num>>5] |=
2542 1 << (pg_num & 31);
2543 if (hw_dirty)
2544 pmap_clear_modify(dst_page->phys_page);
2545 /*
2546 * Record that this page has been
2547 * written out
2548 */
2549#if MACH_PAGEMAP
2550 vm_external_state_set(
2551 object->existence_map,
2552 dst_page->offset);
2553#endif /*MACH_PAGEMAP*/
2554
2555 /*
2556 * Mark original page as cleaning
2557 * in place.
2558 */
2559 dst_page->cleaning = TRUE;
2560 dst_page->dirty = TRUE;
2561 dst_page->precious = FALSE;
2562 } else {
2563 /* use pageclean setup, it is more */
2564 /* convenient even for the pageout */
2565 /* cases here */
2566 vm_pageclean_setup(dst_page,
2567 alias_page, upl->map_object,
2568 size - xfer_size);
2569
2570 alias_page->absent = FALSE;
2571 alias_page = NULL;
2572 }
1c79356b
A
2573
2574 if(!dirty) {
2575 dst_page->dirty = FALSE;
2576 dst_page->precious = TRUE;
2577 }
2578
2579 if(dst_page->pageout)
2580 dst_page->busy = TRUE;
2581
0b4e3aa0 2582 if((!(cntrl_flags & UPL_CLEAN_IN_PLACE))
55e303ae 2583 || (cntrl_flags & UPL_FOR_PAGEOUT)) {
1c79356b
A
2584 /* deny access to the target page */
2585 /* while it is being worked on */
2586 if((!dst_page->pageout) &&
2587 (dst_page->wire_count == 0)) {
2588 dst_page->busy = TRUE;
2589 dst_page->pageout = TRUE;
2590 vm_page_wire(dst_page);
2591 }
2592 }
2593 if(user_page_list) {
2594 user_page_list[entry].phys_addr
55e303ae 2595 = dst_page->phys_page;
1c79356b
A
2596 user_page_list[entry].dirty =
2597 dst_page->dirty;
2598 user_page_list[entry].pageout =
2599 dst_page->pageout;
2600 user_page_list[entry].absent =
2601 dst_page->absent;
2602 user_page_list[entry].precious =
2603 dst_page->precious;
2604 }
1c79356b
A
2605 vm_page_unlock_queues();
2606 }
2607 entry++;
2608 dst_offset += PAGE_SIZE_64;
2609 xfer_size -= PAGE_SIZE;
2610 }
2611 } else {
2612 while (xfer_size) {
55e303ae
A
2613 if((alias_page == NULL) &&
2614 !(cntrl_flags & UPL_SET_LITE)) {
1c79356b
A
2615 vm_object_unlock(object);
2616 VM_PAGE_GRAB_FICTITIOUS(alias_page);
2617 vm_object_lock(object);
2618 }
2619 dst_page = vm_page_lookup(object, dst_offset);
55e303ae 2620
1c79356b 2621 if(dst_page != VM_PAGE_NULL) {
9bccf70c
A
2622 if((cntrl_flags & UPL_RET_ONLY_ABSENT) &&
2623 !((dst_page->list_req_pending)
2624 && (dst_page->absent))) {
2625 /* we are doing extended range */
2626 /* requests. we want to grab */
2627 /* pages around some which are */
2628 /* already present. */
55e303ae 2629 if(user_page_list) {
9bccf70c 2630 user_page_list[entry].phys_addr = 0;
55e303ae 2631 }
9bccf70c
A
2632 entry++;
2633 dst_offset += PAGE_SIZE_64;
2634 xfer_size -= PAGE_SIZE;
2635 continue;
2636 }
0b4e3aa0
A
2637 if((dst_page->cleaning) &&
2638 !(dst_page->list_req_pending)) {
2639 /*someone else is writing to the */
2640 /* page. We will have to wait. */
9bccf70c 2641 PAGE_SLEEP(object,dst_page,THREAD_UNINT);
0b4e3aa0
A
2642 continue;
2643 }
2644 if ((dst_page->fictitious &&
2645 dst_page->list_req_pending)) {
2646 /* dump the fictitious page */
2647 dst_page->list_req_pending = FALSE;
2648 dst_page->clustered = FALSE;
55e303ae 2649
0b4e3aa0
A
2650 vm_page_lock_queues();
2651 vm_page_free(dst_page);
2652 vm_page_unlock_queues();
55e303ae 2653
0b4e3aa0
A
2654 } else if ((dst_page->absent &&
2655 dst_page->list_req_pending)) {
2656 /* the default_pager case */
2657 dst_page->list_req_pending = FALSE;
2658 dst_page->busy = FALSE;
2659 dst_page->clustered = FALSE;
2660 }
1c79356b 2661 }
0b4e3aa0
A
2662 if((dst_page = vm_page_lookup(object, dst_offset)) ==
2663 VM_PAGE_NULL) {
2664 if(object->private) {
2665 /*
2666 * This is a nasty wrinkle for users
2667 * of upl who encounter device or
2668 * private memory however, it is
2669 * unavoidable, only a fault can
2670 * reslove the actual backing
2671 * physical page by asking the
2672 * backing device.
2673 */
55e303ae
A
2674 if(user_page_list) {
2675 user_page_list[entry].phys_addr = 0;
2676 }
0b4e3aa0
A
2677 entry++;
2678 dst_offset += PAGE_SIZE_64;
2679 xfer_size -= PAGE_SIZE;
2680 continue;
2681 }
1c79356b
A
2682 /* need to allocate a page */
2683 dst_page = vm_page_alloc(object, dst_offset);
2684 if (dst_page == VM_PAGE_NULL) {
0b4e3aa0
A
2685 vm_object_unlock(object);
2686 VM_PAGE_WAIT();
2687 vm_object_lock(object);
2688 continue;
1c79356b
A
2689 }
2690 dst_page->busy = FALSE;
2691#if 0
2692 if(cntrl_flags & UPL_NO_SYNC) {
2693 dst_page->page_lock = 0;
2694 dst_page->unlock_request = 0;
2695 }
2696#endif
2697 dst_page->absent = TRUE;
2698 object->absent_count++;
2699 }
2700#if 1
2701 if(cntrl_flags & UPL_NO_SYNC) {
2702 dst_page->page_lock = 0;
2703 dst_page->unlock_request = 0;
2704 }
2705#endif /* 1 */
2706 dst_page->overwriting = TRUE;
2707 if(dst_page->fictitious) {
2708 panic("need corner case for fictitious page");
2709 }
2710 if(dst_page->page_lock) {
2711 do_m_lock = TRUE;
2712 }
2713 if(upl_ptr) {
2714
2715 /* eliminate all mappings from the */
2716 /* original object and its prodigy */
2717
2718 if(dst_page->busy) {
2719 /*someone else is playing with the */
2720 /* page. We will have to wait. */
9bccf70c 2721 PAGE_SLEEP(object, dst_page, THREAD_UNINT);
1c79356b
A
2722 continue;
2723 }
1c79356b 2724 vm_page_lock_queues();
55e303ae 2725
9bccf70c 2726 if( !(cntrl_flags & UPL_FILE_IO)) {
55e303ae
A
2727 pmap_page_protect(dst_page->phys_page, VM_PROT_NONE);
2728 }
2729 hw_dirty = pmap_is_modified(dst_page->phys_page);
2730 dirty = hw_dirty ? TRUE : dst_page->dirty;
2731
2732 if(cntrl_flags & UPL_SET_LITE) {
2733 int pg_num;
2734 pg_num = (dst_offset-offset)/PAGE_SIZE;
2735 lite_list[pg_num>>5] |=
2736 1 << (pg_num & 31);
2737 if (hw_dirty)
2738 pmap_clear_modify(dst_page->phys_page);
2739 /*
2740 * Record that this page has been
2741 * written out
2742 */
2743#if MACH_PAGEMAP
2744 vm_external_state_set(
2745 object->existence_map,
2746 dst_page->offset);
2747#endif /*MACH_PAGEMAP*/
2748
2749 /*
2750 * Mark original page as cleaning
2751 * in place.
2752 */
2753 dst_page->cleaning = TRUE;
2754 dst_page->dirty = TRUE;
2755 dst_page->precious = FALSE;
2756 } else {
2757 /* use pageclean setup, it is more */
2758 /* convenient even for the pageout */
2759 /* cases here */
2760 vm_pageclean_setup(dst_page,
2761 alias_page, upl->map_object,
2762 size - xfer_size);
2763
2764 alias_page->absent = FALSE;
2765 alias_page = NULL;
9bccf70c 2766 }
1c79356b
A
2767
2768 if(cntrl_flags & UPL_CLEAN_IN_PLACE) {
2769 /* clean in place for read implies */
2770 /* that a write will be done on all */
2771 /* the pages that are dirty before */
2772 /* a upl commit is done. The caller */
2773 /* is obligated to preserve the */
2774 /* contents of all pages marked */
2775 /* dirty. */
2776 upl->flags |= UPL_CLEAR_DIRTY;
2777 }
2778
2779 if(!dirty) {
2780 dst_page->dirty = FALSE;
2781 dst_page->precious = TRUE;
2782 }
2783
2784 if (dst_page->wire_count == 0) {
2785 /* deny access to the target page while */
2786 /* it is being worked on */
2787 dst_page->busy = TRUE;
2788 } else {
2789 vm_page_wire(dst_page);
2790 }
55e303ae
A
2791 /*
2792 * expect the page to be used
2793 */
1c79356b
A
2794 dst_page->reference = TRUE;
2795 dst_page->precious =
2796 (cntrl_flags & UPL_PRECIOUS)
2797 ? TRUE : FALSE;
1c79356b
A
2798 if(user_page_list) {
2799 user_page_list[entry].phys_addr
55e303ae 2800 = dst_page->phys_page;
1c79356b 2801 user_page_list[entry].dirty =
0b4e3aa0 2802 dst_page->dirty;
1c79356b
A
2803 user_page_list[entry].pageout =
2804 dst_page->pageout;
2805 user_page_list[entry].absent =
2806 dst_page->absent;
2807 user_page_list[entry].precious =
2808 dst_page->precious;
2809 }
2810 vm_page_unlock_queues();
2811 }
2812 entry++;
2813 dst_offset += PAGE_SIZE_64;
2814 xfer_size -= PAGE_SIZE;
2815 }
2816 }
0b4e3aa0
A
2817 if (upl->flags & UPL_INTERNAL) {
2818 if(page_list_count != NULL)
2819 *page_list_count = 0;
2820 } else if (*page_list_count > entry) {
2821 if(page_list_count != NULL)
2822 *page_list_count = entry;
2823 }
2824
1c79356b
A
2825 if(alias_page != NULL) {
2826 vm_page_lock_queues();
2827 vm_page_free(alias_page);
2828 vm_page_unlock_queues();
2829 }
0b4e3aa0 2830
1c79356b
A
2831 if(do_m_lock) {
2832 vm_prot_t access_required;
2833 /* call back all associated pages from other users of the pager */
2834 /* all future updates will be on data which is based on the */
2835 /* changes we are going to make here. Note: it is assumed that */
2836 /* we already hold copies of the data so we will not be seeing */
2837 /* an avalanche of incoming data from the pager */
2838 access_required = (cntrl_flags & UPL_COPYOUT_FROM)
2839 ? VM_PROT_READ : VM_PROT_WRITE;
2840 while (TRUE) {
2841 kern_return_t rc;
1c79356b
A
2842
2843 if(!object->pager_ready) {
9bccf70c
A
2844 wait_result_t wait_result;
2845
2846 wait_result = vm_object_sleep(object,
2847 VM_OBJECT_EVENT_PAGER_READY,
2848 THREAD_UNINT);
2849 if (wait_result != THREAD_AWAKENED) {
2850 vm_object_unlock(object);
2851 return(KERN_FAILURE);
1c79356b 2852 }
1c79356b
A
2853 continue;
2854 }
2855
2856 vm_object_unlock(object);
2857
2858 if (rc = memory_object_data_unlock(
2859 object->pager,
1c79356b
A
2860 dst_offset + object->paging_offset,
2861 size,
2862 access_required)) {
2863 if (rc == MACH_SEND_INTERRUPTED)
2864 continue;
2865 else
2866 return KERN_FAILURE;
2867 }
2868 break;
2869
2870 }
2871 /* lets wait on the last page requested */
2872 /* NOTE: we will have to update lock completed routine to signal */
2873 if(dst_page != VM_PAGE_NULL &&
2874 (access_required & dst_page->page_lock) != access_required) {
2875 PAGE_ASSERT_WAIT(dst_page, THREAD_UNINT);
2876 thread_block((void (*)(void))0);
2877 vm_object_lock(object);
2878 }
2879 }
2880 vm_object_unlock(object);
2881 return KERN_SUCCESS;
2882}
2883
0b4e3aa0 2884/* JMM - Backward compatability for now */
1c79356b 2885kern_return_t
0b4e3aa0
A
2886vm_fault_list_request(
2887 memory_object_control_t control,
1c79356b
A
2888 vm_object_offset_t offset,
2889 vm_size_t size,
0b4e3aa0 2890 upl_t *upl_ptr,
1c79356b
A
2891 upl_page_info_t **user_page_list_ptr,
2892 int page_list_count,
2893 int cntrl_flags)
2894{
0b4e3aa0
A
2895 int local_list_count;
2896 upl_page_info_t *user_page_list;
2897 kern_return_t kr;
2898
2899 if (user_page_list_ptr != NULL) {
2900 local_list_count = page_list_count;
2901 user_page_list = *user_page_list_ptr;
2902 } else {
2903 local_list_count = 0;
2904 user_page_list = NULL;
2905 }
2906 kr = memory_object_upl_request(control,
2907 offset,
2908 size,
2909 upl_ptr,
2910 user_page_list,
2911 &local_list_count,
2912 cntrl_flags);
2913
2914 if(kr != KERN_SUCCESS)
2915 return kr;
2916
2917 if ((user_page_list_ptr != NULL) && (cntrl_flags & UPL_INTERNAL)) {
2918 *user_page_list_ptr = UPL_GET_INTERNAL_PAGE_LIST(*upl_ptr);
2919 }
2920
2921 return KERN_SUCCESS;
2922}
2923
2924
2925
2926/*
2927 * Routine: vm_object_super_upl_request
2928 * Purpose:
2929 * Cause the population of a portion of a vm_object
2930 * in much the same way as memory_object_upl_request.
2931 * Depending on the nature of the request, the pages
2932 * returned may be contain valid data or be uninitialized.
2933 * However, the region may be expanded up to the super
2934 * cluster size provided.
2935 */
2936
2937__private_extern__ kern_return_t
2938vm_object_super_upl_request(
2939 vm_object_t object,
2940 vm_object_offset_t offset,
2941 vm_size_t size,
2942 vm_size_t super_cluster,
2943 upl_t *upl,
2944 upl_page_info_t *user_page_list,
2945 unsigned int *page_list_count,
2946 int cntrl_flags)
2947{
2948 vm_page_t target_page;
2949 int ticket;
2950
1c79356b
A
2951 if(object->paging_offset > offset)
2952 return KERN_FAILURE;
0b4e3aa0 2953
55e303ae 2954 assert(object->paging_in_progress);
1c79356b 2955 offset = offset - object->paging_offset;
55e303ae 2956 if(cntrl_flags & UPL_FOR_PAGEOUT) {
0b4e3aa0
A
2957 if((target_page = vm_page_lookup(object, offset))
2958 != VM_PAGE_NULL) {
2959 ticket = target_page->page_ticket;
2960 cntrl_flags = cntrl_flags & ~(int)UPL_PAGE_TICKET_MASK;
2961 cntrl_flags = cntrl_flags |
2962 ((ticket << UPL_PAGE_TICKET_SHIFT)
2963 & UPL_PAGE_TICKET_MASK);
2964 }
2965 }
2966
1c79356b
A
2967
2968/* turns off super cluster exercised by the default_pager */
2969/*
2970super_cluster = size;
2971*/
2972 if ((super_cluster > size) &&
2973 (vm_page_free_count > vm_page_free_reserved)) {
2974
2975 vm_object_offset_t base_offset;
2976 vm_size_t super_size;
2977
2978 base_offset = (offset &
2979 ~((vm_object_offset_t) super_cluster - 1));
2980 super_size = (offset+size) > (base_offset + super_cluster) ?
2981 super_cluster<<1 : super_cluster;
2982 super_size = ((base_offset + super_size) > object->size) ?
2983 (object->size - base_offset) : super_size;
2984 if(offset > (base_offset + super_size))
0b4e3aa0 2985 panic("vm_object_super_upl_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);
1c79356b
A
2986 /* apparently there is a case where the vm requests a */
2987 /* page to be written out who's offset is beyond the */
2988 /* object size */
2989 if((offset + size) > (base_offset + super_size))
2990 super_size = (offset + size) - base_offset;
2991
2992 offset = base_offset;
2993 size = super_size;
2994 }
0b4e3aa0
A
2995 vm_object_upl_request(object, offset, size,
2996 upl, user_page_list, page_list_count,
2997 cntrl_flags);
1c79356b
A
2998}
2999
3000
3001kern_return_t
0b4e3aa0 3002vm_upl_map(
1c79356b
A
3003 vm_map_t map,
3004 upl_t upl,
3005 vm_offset_t *dst_addr)
3006{
3007 vm_size_t size;
3008 vm_object_offset_t offset;
3009 vm_offset_t addr;
3010 vm_page_t m;
3011 kern_return_t kr;
3012
0b4e3aa0
A
3013 if (upl == UPL_NULL)
3014 return KERN_INVALID_ARGUMENT;
3015
3016 upl_lock(upl);
3017
1c79356b 3018 /* check to see if already mapped */
0b4e3aa0
A
3019 if(UPL_PAGE_LIST_MAPPED & upl->flags) {
3020 upl_unlock(upl);
1c79356b 3021 return KERN_FAILURE;
0b4e3aa0 3022 }
1c79356b 3023
55e303ae
A
3024 if((!(upl->map_object->pageout)) &&
3025 !((upl->flags & (UPL_DEVICE_MEMORY | UPL_IO_WIRE)) ||
3026 (upl->map_object->phys_contiguous))) {
3027 vm_object_t object;
3028 vm_page_t alias_page;
3029 vm_object_offset_t new_offset;
3030 int pg_num;
3031 wpl_array_t lite_list;
3032
3033 if(upl->flags & UPL_INTERNAL) {
3034 lite_list = (wpl_array_t)
3035 ((((vm_offset_t)upl) + sizeof(struct upl))
3036 + ((upl->size/PAGE_SIZE)
3037 * sizeof(upl_page_info_t)));
3038 } else {
3039 lite_list = (wpl_array_t)
3040 (((vm_offset_t)upl) + sizeof(struct upl));
3041 }
3042 object = upl->map_object;
3043 upl->map_object = vm_object_allocate(upl->size);
3044 vm_object_lock(upl->map_object);
3045 upl->map_object->shadow = object;
3046 upl->map_object->pageout = TRUE;
3047 upl->map_object->can_persist = FALSE;
3048 upl->map_object->copy_strategy =
3049 MEMORY_OBJECT_COPY_NONE;
3050 upl->map_object->shadow_offset =
3051 upl->offset - object->paging_offset;
3052 upl->map_object->wimg_bits = object->wimg_bits;
3053 vm_object_unlock(upl->map_object);
3054 offset = upl->map_object->shadow_offset;
3055 new_offset = 0;
3056 size = upl->size;
3057 vm_object_lock(object);
3058 while(size) {
3059 pg_num = (new_offset)/PAGE_SIZE;
3060 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3061 vm_object_unlock(object);
3062 VM_PAGE_GRAB_FICTITIOUS(alias_page);
3063 vm_object_lock(object);
3064 m = vm_page_lookup(object, offset);
3065 if (m == VM_PAGE_NULL) {
3066 panic("vm_upl_map: page missing\n");
3067 }
3068
3069 vm_object_paging_begin(object);
3070
3071 /*
3072 * Convert the fictitious page to a private
3073 * shadow of the real page.
3074 */
3075 assert(alias_page->fictitious);
3076 alias_page->fictitious = FALSE;
3077 alias_page->private = TRUE;
3078 alias_page->pageout = TRUE;
3079 alias_page->phys_page = m->phys_page;
3080 vm_page_wire(alias_page);
3081
3082 vm_page_insert(alias_page,
3083 upl->map_object, new_offset);
3084 assert(!alias_page->wanted);
3085 alias_page->busy = FALSE;
3086 alias_page->absent = FALSE;
3087 }
3088
3089 size -= PAGE_SIZE;
3090 offset += PAGE_SIZE_64;
3091 new_offset += PAGE_SIZE_64;
3092 }
3093 vm_object_unlock(object);
3094 }
3095 if ((upl->flags & (UPL_DEVICE_MEMORY | UPL_IO_WIRE)) || upl->map_object->phys_contiguous)
3096 offset = upl->offset - upl->map_object->paging_offset;
3097 else
3098 offset = 0;
3099
1c79356b
A
3100 size = upl->size;
3101
3102 vm_object_lock(upl->map_object);
3103 upl->map_object->ref_count++;
3104 vm_object_res_reference(upl->map_object);
3105 vm_object_unlock(upl->map_object);
3106
3107 *dst_addr = 0;
3108
3109
3110 /* NEED A UPL_MAP ALIAS */
3111 kr = vm_map_enter(map, dst_addr, size, (vm_offset_t) 0, TRUE,
3112 upl->map_object, offset, FALSE,
3113 VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
3114
0b4e3aa0
A
3115 if (kr != KERN_SUCCESS) {
3116 upl_unlock(upl);
1c79356b 3117 return(kr);
0b4e3aa0 3118 }
1c79356b
A
3119
3120 for(addr=*dst_addr; size > 0; size-=PAGE_SIZE,addr+=PAGE_SIZE) {
3121 m = vm_page_lookup(upl->map_object, offset);
3122 if(m) {
9bccf70c
A
3123 unsigned int cache_attr;
3124 cache_attr = ((unsigned int)m->object->wimg_bits) & VM_WIMG_MASK;
3125
3126 PMAP_ENTER(map->pmap, addr,
3127 m, VM_PROT_ALL,
3128 cache_attr, TRUE);
1c79356b
A
3129 }
3130 offset+=PAGE_SIZE_64;
3131 }
0b4e3aa0 3132 upl->ref_count++; /* hold a reference for the mapping */
1c79356b
A
3133 upl->flags |= UPL_PAGE_LIST_MAPPED;
3134 upl->kaddr = *dst_addr;
0b4e3aa0 3135 upl_unlock(upl);
1c79356b
A
3136 return KERN_SUCCESS;
3137}
3138
3139
3140kern_return_t
0b4e3aa0 3141vm_upl_unmap(
1c79356b
A
3142 vm_map_t map,
3143 upl_t upl)
3144{
0b4e3aa0 3145 vm_address_t addr;
1c79356b
A
3146 vm_size_t size;
3147
0b4e3aa0
A
3148 if (upl == UPL_NULL)
3149 return KERN_INVALID_ARGUMENT;
3150
3151 upl_lock(upl);
1c79356b 3152 if(upl->flags & UPL_PAGE_LIST_MAPPED) {
0b4e3aa0 3153 addr = upl->kaddr;
1c79356b 3154 size = upl->size;
0b4e3aa0
A
3155 assert(upl->ref_count > 1);
3156 upl->ref_count--; /* removing mapping ref */
1c79356b
A
3157 upl->flags &= ~UPL_PAGE_LIST_MAPPED;
3158 upl->kaddr = (vm_offset_t) 0;
0b4e3aa0
A
3159 upl_unlock(upl);
3160
3161 vm_deallocate(map, addr, size);
1c79356b 3162 return KERN_SUCCESS;
1c79356b 3163 }
0b4e3aa0
A
3164 upl_unlock(upl);
3165 return KERN_FAILURE;
1c79356b
A
3166}
3167
3168kern_return_t
0b4e3aa0 3169upl_commit_range(
1c79356b
A
3170 upl_t upl,
3171 vm_offset_t offset,
3172 vm_size_t size,
3173 int flags,
0b4e3aa0
A
3174 upl_page_info_t *page_list,
3175 mach_msg_type_number_t count,
3176 boolean_t *empty)
1c79356b
A
3177{
3178 vm_size_t xfer_size = size;
55e303ae 3179 vm_object_t shadow_object;
1c79356b
A
3180 vm_object_t object = upl->map_object;
3181 vm_object_offset_t target_offset;
1c79356b 3182 int entry;
55e303ae
A
3183 wpl_array_t lite_list;
3184 int occupied;
3185 int delayed_unlock = 0;
3186 boolean_t shadow_internal;
1c79356b 3187
0b4e3aa0
A
3188 *empty = FALSE;
3189
3190 if (upl == UPL_NULL)
3191 return KERN_INVALID_ARGUMENT;
3192
55e303ae 3193
0b4e3aa0
A
3194 if (count == 0)
3195 page_list = NULL;
3196
55e303ae
A
3197 if(object->pageout) {
3198 shadow_object = object->shadow;
3199 } else {
3200 shadow_object = object;
3201 }
3202
0b4e3aa0 3203 upl_lock(upl);
55e303ae
A
3204
3205 if (upl->flags & UPL_CLEAR_DIRTY)
3206 flags |= UPL_COMMIT_CLEAR_DIRTY;
3207
3208 if (upl->flags & UPL_DEVICE_MEMORY) {
1c79356b
A
3209 xfer_size = 0;
3210 } else if ((offset + size) > upl->size) {
0b4e3aa0 3211 upl_unlock(upl);
1c79356b
A
3212 return KERN_FAILURE;
3213 }
3214
55e303ae
A
3215 if (upl->flags & UPL_INTERNAL) {
3216 lite_list = (wpl_array_t)
3217 ((((vm_offset_t)upl) + sizeof(struct upl))
3218 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
3219 } else {
3220 lite_list = (wpl_array_t)
3221 (((vm_offset_t)upl) + sizeof(struct upl));
3222 }
3223
1c79356b 3224 vm_object_lock(shadow_object);
55e303ae 3225 shadow_internal = shadow_object->internal;
1c79356b
A
3226
3227 entry = offset/PAGE_SIZE;
3228 target_offset = (vm_object_offset_t)offset;
55e303ae 3229
1c79356b
A
3230 while(xfer_size) {
3231 vm_page_t t,m;
3232 upl_page_info_t *p;
3233
55e303ae 3234 m = VM_PAGE_NULL;
d7e50217 3235
55e303ae
A
3236 if (upl->flags & UPL_LITE) {
3237 int pg_num;
3238
3239 pg_num = target_offset/PAGE_SIZE;
3240
3241 if (lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3242 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
3243 m = vm_page_lookup(shadow_object,
3244 target_offset + (upl->offset -
3245 shadow_object->paging_offset));
3246 }
3247 }
3248 if (object->pageout) {
3249 if ((t = vm_page_lookup(object, target_offset)) != NULL) {
3250 t->pageout = FALSE;
3251
3252 if (delayed_unlock) {
3253 delayed_unlock = 0;
3254 vm_page_unlock_queues();
3255 }
3256 VM_PAGE_FREE(t);
3257
3258 if (m == NULL) {
3259 m = vm_page_lookup(
3260 shadow_object,
3261 target_offset +
3262 object->shadow_offset);
de355530 3263 }
55e303ae
A
3264 if (m != VM_PAGE_NULL)
3265 vm_object_paging_end(m->object);
3266 }
3267 }
3268 if (m != VM_PAGE_NULL) {
3269
3270 if (upl->flags & UPL_IO_WIRE) {
3271
3272 if (delayed_unlock == 0)
3273 vm_page_lock_queues();
3274
3275 vm_page_unwire(m);
3276
3277 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
3278 delayed_unlock = 0;
3279 vm_page_unlock_queues();
3280 }
3281 if (page_list) {
de355530 3282 page_list[entry].phys_addr = 0;
55e303ae
A
3283 }
3284 if (flags & UPL_COMMIT_SET_DIRTY) {
3285 m->dirty = TRUE;
3286 } else if (flags & UPL_COMMIT_CLEAR_DIRTY) {
3287 m->dirty = FALSE;
3288 pmap_clear_modify(m->phys_page);
3289 }
3290 if (flags & UPL_COMMIT_INACTIVATE) {
3291 m->reference = FALSE;
3292 vm_page_deactivate(m);
3293 pmap_clear_reference(m->phys_page);
3294 }
3295 target_offset += PAGE_SIZE_64;
3296 xfer_size -= PAGE_SIZE;
3297 entry++;
3298 continue;
3299 }
3300 if (delayed_unlock == 0)
3301 vm_page_lock_queues();
3302 /*
3303 * make sure to clear the hardware
3304 * modify or reference bits before
3305 * releasing the BUSY bit on this page
3306 * otherwise we risk losing a legitimate
3307 * change of state
3308 */
3309 if (flags & UPL_COMMIT_CLEAR_DIRTY) {
3310 m->dirty = FALSE;
3311 pmap_clear_modify(m->phys_page);
3312 }
3313 if (flags & UPL_COMMIT_INACTIVATE)
3314 pmap_clear_reference(m->phys_page);
3315
3316 if (page_list) {
3317 p = &(page_list[entry]);
3318 if(p->phys_addr && p->pageout && !m->pageout) {
3319 m->busy = TRUE;
3320 m->pageout = TRUE;
3321 vm_page_wire(m);
3322 } else if (page_list[entry].phys_addr &&
3323 !p->pageout && m->pageout &&
3324 !m->dump_cleaning) {
3325 m->pageout = FALSE;
3326 m->absent = FALSE;
3327 m->overwriting = FALSE;
3328 vm_page_unwire(m);
3329 PAGE_WAKEUP_DONE(m);
3330 }
3331 page_list[entry].phys_addr = 0;
3332 }
3333 m->dump_cleaning = FALSE;
3334 if(m->laundry) {
3335 if (!shadow_internal)
3336 vm_page_burst_count--;
3337 vm_page_laundry_count--;
3338 m->laundry = FALSE;
3339 if (vm_page_laundry_count < vm_page_laundry_min) {
3340 vm_page_laundry_min = 0;
3341 thread_wakeup((event_t)
3342 &vm_page_laundry_count);
3343 }
3344 }
3345 if(m->pageout) {
3346 m->cleaning = FALSE;
3347 m->pageout = FALSE;
1c79356b 3348#if MACH_CLUSTER_STATS
55e303ae 3349 if (m->wanted) vm_pageout_target_collisions++;
1c79356b 3350#endif
55e303ae
A
3351 pmap_page_protect(m->phys_page, VM_PROT_NONE);
3352 m->dirty = pmap_is_modified(m->phys_page);
3353 if(m->dirty) {
3354 CLUSTER_STAT(
3355 vm_pageout_target_page_dirtied++;)
3356 vm_page_unwire(m);/* reactivates */
3357 VM_STAT(reactivations++);
3358 PAGE_WAKEUP_DONE(m);
3359 } else {
3360 CLUSTER_STAT(
3361 vm_pageout_target_page_freed++;)
3362 vm_page_free(m);/* clears busy, etc. */
3363
3364 if (page_list[entry].dirty)
3365 VM_STAT(pageouts++);
3366 }
3367 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
3368 delayed_unlock = 0;
3369 vm_page_unlock_queues();
3370 }
3371 target_offset += PAGE_SIZE_64;
3372 xfer_size -= PAGE_SIZE;
3373 entry++;
3374 continue;
3375 }
1c79356b 3376#if MACH_CLUSTER_STATS
55e303ae 3377 m->dirty = pmap_is_modified(m->phys_page);
1c79356b 3378
55e303ae
A
3379 if (m->dirty) vm_pageout_cluster_dirtied++;
3380 else vm_pageout_cluster_cleaned++;
3381 if (m->wanted) vm_pageout_cluster_collisions++;
1c79356b 3382#else
55e303ae 3383 m->dirty = 0;
1c79356b
A
3384#endif
3385
55e303ae
A
3386 if((m->busy) && (m->cleaning)) {
3387 /* the request_page_list case */
3388 if(m->absent) {
3389 m->absent = FALSE;
3390 if(shadow_object->absent_count == 1)
1c79356b 3391 vm_object_absent_release(shadow_object);
55e303ae 3392 else
1c79356b 3393 shadow_object->absent_count--;
de355530 3394 }
55e303ae
A
3395 m->overwriting = FALSE;
3396 m->busy = FALSE;
3397 m->dirty = FALSE;
3398 } else if (m->overwriting) {
3399 /* alternate request page list, write to
3400 /* page_list case. Occurs when the original
3401 /* page was wired at the time of the list
3402 /* request */
3403 assert(m->wire_count != 0);
3404 vm_page_unwire(m);/* reactivates */
3405 m->overwriting = FALSE;
3406 }
3407 m->cleaning = FALSE;
3408
3409 /* It is a part of the semantic of COPYOUT_FROM */
3410 /* UPLs that a commit implies cache sync */
3411 /* between the vm page and the backing store */
3412 /* this can be used to strip the precious bit */
3413 /* as well as clean */
3414 if (upl->flags & UPL_PAGE_SYNC_DONE)
3415 m->precious = FALSE;
3416
3417 if (flags & UPL_COMMIT_SET_DIRTY)
3418 m->dirty = TRUE;
3419
3420 if (flags & UPL_COMMIT_INACTIVATE) {
3421 m->reference = FALSE;
3422 vm_page_deactivate(m);
3423 } else if (!m->active && !m->inactive) {
3424 if (m->reference)
3425 vm_page_activate(m);
3426 else
3427 vm_page_deactivate(m);
3428 }
3429 /*
3430 * Wakeup any thread waiting for the page to be un-cleaning.
3431 */
3432 PAGE_WAKEUP(m);
3433
3434 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
3435 delayed_unlock = 0;
3436 vm_page_unlock_queues();
3437 }
1c79356b
A
3438 }
3439 target_offset += PAGE_SIZE_64;
3440 xfer_size -= PAGE_SIZE;
3441 entry++;
3442 }
55e303ae
A
3443 if (delayed_unlock)
3444 vm_page_unlock_queues();
3445
3446 occupied = 1;
3447
3448 if (upl->flags & UPL_DEVICE_MEMORY) {
3449 occupied = 0;
3450 } else if (upl->flags & UPL_LITE) {
3451 int pg_num;
3452 int i;
3453 pg_num = upl->size/PAGE_SIZE;
3454 pg_num = (pg_num + 31) >> 5;
3455 occupied = 0;
3456 for(i= 0; i<pg_num; i++) {
3457 if(lite_list[i] != 0) {
3458 occupied = 1;
3459 break;
3460 }
3461 }
3462 } else {
3463 if(queue_empty(&upl->map_object->memq)) {
3464 occupied = 0;
3465 }
3466 }
1c79356b 3467
55e303ae
A
3468 if(occupied == 0) {
3469 if(upl->flags & UPL_COMMIT_NOTIFY_EMPTY) {
0b4e3aa0 3470 *empty = TRUE;
55e303ae
A
3471 }
3472 if(object == shadow_object)
3473 vm_object_paging_end(shadow_object);
1c79356b 3474 }
55e303ae 3475 vm_object_unlock(shadow_object);
0b4e3aa0
A
3476 upl_unlock(upl);
3477
1c79356b
A
3478 return KERN_SUCCESS;
3479}
3480
0b4e3aa0
A
3481kern_return_t
3482upl_abort_range(
1c79356b
A
3483 upl_t upl,
3484 vm_offset_t offset,
3485 vm_size_t size,
0b4e3aa0
A
3486 int error,
3487 boolean_t *empty)
1c79356b
A
3488{
3489 vm_size_t xfer_size = size;
55e303ae 3490 vm_object_t shadow_object;
1c79356b
A
3491 vm_object_t object = upl->map_object;
3492 vm_object_offset_t target_offset;
3493 vm_object_offset_t page_offset;
3494 int entry;
55e303ae
A
3495 wpl_array_t lite_list;
3496 int occupied;
3497 boolean_t shadow_internal;
1c79356b 3498
0b4e3aa0
A
3499 *empty = FALSE;
3500
3501 if (upl == UPL_NULL)
3502 return KERN_INVALID_ARGUMENT;
3503
55e303ae
A
3504 if (upl->flags & UPL_IO_WIRE) {
3505 return upl_commit_range(upl,
3506 offset, size, 0,
3507 NULL, 0, empty);
3508 }
3509
3510 if(object->pageout) {
3511 shadow_object = object->shadow;
3512 } else {
3513 shadow_object = object;
3514 }
3515
0b4e3aa0 3516 upl_lock(upl);
1c79356b
A
3517 if(upl->flags & UPL_DEVICE_MEMORY) {
3518 xfer_size = 0;
3519 } else if ((offset + size) > upl->size) {
0b4e3aa0 3520 upl_unlock(upl);
1c79356b
A
3521 return KERN_FAILURE;
3522 }
3523
1c79356b 3524 vm_object_lock(shadow_object);
55e303ae
A
3525 shadow_internal = shadow_object->internal;
3526
3527 if(upl->flags & UPL_INTERNAL) {
3528 lite_list = (wpl_array_t)
3529 ((((vm_offset_t)upl) + sizeof(struct upl))
3530 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
3531 } else {
3532 lite_list = (wpl_array_t)
3533 (((vm_offset_t)upl) + sizeof(struct upl));
3534 }
1c79356b
A
3535
3536 entry = offset/PAGE_SIZE;
3537 target_offset = (vm_object_offset_t)offset;
3538 while(xfer_size) {
3539 vm_page_t t,m;
3540 upl_page_info_t *p;
3541
55e303ae
A
3542 m = VM_PAGE_NULL;
3543 if(upl->flags & UPL_LITE) {
3544 int pg_num;
3545 pg_num = target_offset/PAGE_SIZE;
3546 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3547 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
3548 m = vm_page_lookup(shadow_object,
3549 target_offset + (upl->offset -
3550 shadow_object->paging_offset));
3551 }
3552 }
3553 if(object->pageout) {
3554 if ((t = vm_page_lookup(object, target_offset))
3555 != NULL) {
3556 t->pageout = FALSE;
3557 VM_PAGE_FREE(t);
3558 if(m == NULL) {
3559 m = vm_page_lookup(
3560 shadow_object,
3561 target_offset +
3562 object->shadow_offset);
3563 }
3564 if(m != VM_PAGE_NULL)
3565 vm_object_paging_end(m->object);
3566 }
3567 }
3568 if(m != VM_PAGE_NULL) {
1c79356b
A
3569 vm_page_lock_queues();
3570 if(m->absent) {
3571 /* COPYOUT = FALSE case */
3572 /* check for error conditions which must */
3573 /* be passed back to the pages customer */
3574 if(error & UPL_ABORT_RESTART) {
3575 m->restart = TRUE;
3576 m->absent = FALSE;
3577 vm_object_absent_release(m->object);
3578 m->page_error = KERN_MEMORY_ERROR;
3579 m->error = TRUE;
3580 } else if(error & UPL_ABORT_UNAVAILABLE) {
3581 m->restart = FALSE;
3582 m->unusual = TRUE;
3583 m->clustered = FALSE;
3584 } else if(error & UPL_ABORT_ERROR) {
3585 m->restart = FALSE;
3586 m->absent = FALSE;
3587 vm_object_absent_release(m->object);
3588 m->page_error = KERN_MEMORY_ERROR;
3589 m->error = TRUE;
3590 } else if(error & UPL_ABORT_DUMP_PAGES) {
3591 m->clustered = TRUE;
3592 } else {
3593 m->clustered = TRUE;
3594 }
3595
3596
3597 m->cleaning = FALSE;
3598 m->overwriting = FALSE;
3599 PAGE_WAKEUP_DONE(m);
3600 if(m->clustered) {
3601 vm_page_free(m);
3602 } else {
3603 vm_page_activate(m);
3604 }
3605
3606 vm_page_unlock_queues();
3607 target_offset += PAGE_SIZE_64;
3608 xfer_size -= PAGE_SIZE;
3609 entry++;
3610 continue;
3611 }
3612 /*
55e303ae
A
3613 * Handle the trusted pager throttle.
3614 */
3615 if (m->laundry) {
3616 if (!shadow_internal)
3617 vm_page_burst_count--;
1c79356b
A
3618 vm_page_laundry_count--;
3619 m->laundry = FALSE;
3620 if (vm_page_laundry_count
55e303ae 3621 < vm_page_laundry_min) {
1c79356b
A
3622 vm_page_laundry_min = 0;
3623 thread_wakeup((event_t)
3624 &vm_page_laundry_count);
3625 }
3626 }
3627 if(m->pageout) {
3628 assert(m->busy);
3629 assert(m->wire_count == 1);
3630 m->pageout = FALSE;
3631 vm_page_unwire(m);
3632 }
0b4e3aa0 3633 m->dump_cleaning = FALSE;
1c79356b
A
3634 m->cleaning = FALSE;
3635 m->busy = FALSE;
3636 m->overwriting = FALSE;
3637#if MACH_PAGEMAP
3638 vm_external_state_clr(
3639 m->object->existence_map, m->offset);
3640#endif /* MACH_PAGEMAP */
3641 if(error & UPL_ABORT_DUMP_PAGES) {
3642 vm_page_free(m);
55e303ae 3643 pmap_page_protect(m->phys_page, VM_PROT_NONE);
1c79356b
A
3644 } else {
3645 PAGE_WAKEUP(m);
3646 }
3647 vm_page_unlock_queues();
3648 }
55e303ae
A
3649 target_offset += PAGE_SIZE_64;
3650 xfer_size -= PAGE_SIZE;
3651 entry++;
d7e50217 3652 }
55e303ae
A
3653 occupied = 1;
3654 if (upl->flags & UPL_DEVICE_MEMORY) {
3655 occupied = 0;
3656 } else if (upl->flags & UPL_LITE) {
3657 int pg_num;
3658 int i;
3659 pg_num = upl->size/PAGE_SIZE;
3660 pg_num = (pg_num + 31) >> 5;
3661 occupied = 0;
3662 for(i= 0; i<pg_num; i++) {
3663 if(lite_list[i] != 0) {
3664 occupied = 1;
3665 break;
3666 }
3667 }
3668 } else {
3669 if(queue_empty(&upl->map_object->memq)) {
3670 occupied = 0;
3671 }
3672 }
3673
3674 if(occupied == 0) {
3675 if(upl->flags & UPL_COMMIT_NOTIFY_EMPTY) {
0b4e3aa0 3676 *empty = TRUE;
55e303ae
A
3677 }
3678 if(object == shadow_object)
3679 vm_object_paging_end(shadow_object);
1c79356b 3680 }
55e303ae
A
3681 vm_object_unlock(shadow_object);
3682
0b4e3aa0 3683 upl_unlock(upl);
55e303ae 3684
1c79356b
A
3685 return KERN_SUCCESS;
3686}
3687
3688kern_return_t
0b4e3aa0 3689upl_abort(
1c79356b
A
3690 upl_t upl,
3691 int error)
3692{
3693 vm_object_t object = NULL;
3694 vm_object_t shadow_object = NULL;
3695 vm_object_offset_t offset;
3696 vm_object_offset_t shadow_offset;
3697 vm_object_offset_t target_offset;
3698 int i;
55e303ae 3699 wpl_array_t lite_list;
1c79356b 3700 vm_page_t t,m;
55e303ae
A
3701 int occupied;
3702 boolean_t shadow_internal;
1c79356b 3703
0b4e3aa0
A
3704 if (upl == UPL_NULL)
3705 return KERN_INVALID_ARGUMENT;
3706
55e303ae
A
3707 if (upl->flags & UPL_IO_WIRE) {
3708 boolean_t empty;
3709 return upl_commit_range(upl,
3710 0, upl->size, 0,
3711 NULL, 0, &empty);
3712 }
3713
0b4e3aa0 3714 upl_lock(upl);
1c79356b 3715 if(upl->flags & UPL_DEVICE_MEMORY) {
0b4e3aa0 3716 upl_unlock(upl);
1c79356b
A
3717 return KERN_SUCCESS;
3718 }
0b4e3aa0 3719
1c79356b
A
3720 object = upl->map_object;
3721
0b4e3aa0 3722 if (object == NULL) {
1c79356b 3723 panic("upl_abort: upl object is not backed by an object");
0b4e3aa0 3724 upl_unlock(upl);
1c79356b
A
3725 return KERN_INVALID_ARGUMENT;
3726 }
3727
55e303ae
A
3728 if(object->pageout) {
3729 shadow_object = object->shadow;
3730 shadow_offset = object->shadow_offset;
3731 } else {
3732 shadow_object = object;
3733 shadow_offset = upl->offset - object->paging_offset;
3734 }
3735
3736 if(upl->flags & UPL_INTERNAL) {
3737 lite_list = (wpl_array_t)
3738 ((((vm_offset_t)upl) + sizeof(struct upl))
3739 + ((upl->size/PAGE_SIZE) * sizeof(upl_page_info_t)));
3740 } else {
3741 lite_list = (wpl_array_t)
3742 (((vm_offset_t)upl) + sizeof(struct upl));
3743 }
1c79356b
A
3744 offset = 0;
3745 vm_object_lock(shadow_object);
55e303ae
A
3746 shadow_internal = shadow_object->internal;
3747
1c79356b 3748 for(i = 0; i<(upl->size); i+=PAGE_SIZE, offset += PAGE_SIZE_64) {
55e303ae
A
3749 m = VM_PAGE_NULL;
3750 target_offset = offset + shadow_offset;
3751 if(upl->flags & UPL_LITE) {
3752 int pg_num;
3753 pg_num = offset/PAGE_SIZE;
3754 if(lite_list[pg_num>>5] & (1 << (pg_num & 31))) {
3755 lite_list[pg_num>>5] &= ~(1 << (pg_num & 31));
3756 m = vm_page_lookup(
3757 shadow_object, target_offset);
3758 }
3759 }
3760 if(object->pageout) {
3761 if ((t = vm_page_lookup(object, offset)) != NULL) {
3762 t->pageout = FALSE;
3763 VM_PAGE_FREE(t);
3764 if(m == NULL) {
3765 m = vm_page_lookup(
3766 shadow_object, target_offset);
3767 }
3768 if(m != VM_PAGE_NULL)
3769 vm_object_paging_end(m->object);
3770 }
3771 }
3772 if(m != VM_PAGE_NULL) {
1c79356b
A
3773 vm_page_lock_queues();
3774 if(m->absent) {
3775 /* COPYOUT = FALSE case */
3776 /* check for error conditions which must */
3777 /* be passed back to the pages customer */
3778 if(error & UPL_ABORT_RESTART) {
3779 m->restart = TRUE;
3780 m->absent = FALSE;
3781 vm_object_absent_release(m->object);
3782 m->page_error = KERN_MEMORY_ERROR;
3783 m->error = TRUE;
3784 } else if(error & UPL_ABORT_UNAVAILABLE) {
3785 m->restart = FALSE;
3786 m->unusual = TRUE;
3787 m->clustered = FALSE;
3788 } else if(error & UPL_ABORT_ERROR) {
3789 m->restart = FALSE;
3790 m->absent = FALSE;
3791 vm_object_absent_release(m->object);
3792 m->page_error = KERN_MEMORY_ERROR;
3793 m->error = TRUE;
3794 } else if(error & UPL_ABORT_DUMP_PAGES) {
3795 m->clustered = TRUE;
3796 } else {
3797 m->clustered = TRUE;
3798 }
3799
3800 m->cleaning = FALSE;
3801 m->overwriting = FALSE;
3802 PAGE_WAKEUP_DONE(m);
3803 if(m->clustered) {
3804 vm_page_free(m);
3805 } else {
3806 vm_page_activate(m);
3807 }
3808 vm_page_unlock_queues();
3809 continue;
3810 }
3811 /*
3812 * Handle the trusted pager throttle.
3813 */
3814 if (m->laundry) {
55e303ae
A
3815 if (!shadow_internal)
3816 vm_page_burst_count--;
1c79356b
A
3817 vm_page_laundry_count--;
3818 m->laundry = FALSE;
3819 if (vm_page_laundry_count
3820 < vm_page_laundry_min) {
3821 vm_page_laundry_min = 0;
3822 thread_wakeup((event_t)
3823 &vm_page_laundry_count);
3824 }
3825 }
3826 if(m->pageout) {
3827 assert(m->busy);
3828 assert(m->wire_count == 1);
3829 m->pageout = FALSE;
3830 vm_page_unwire(m);
3831 }
0b4e3aa0 3832 m->dump_cleaning = FALSE;
1c79356b
A
3833 m->cleaning = FALSE;
3834 m->busy = FALSE;
3835 m->overwriting = FALSE;
3836#if MACH_PAGEMAP
3837 vm_external_state_clr(
3838 m->object->existence_map, m->offset);
3839#endif /* MACH_PAGEMAP */
3840 if(error & UPL_ABORT_DUMP_PAGES) {
3841 vm_page_free(m);
55e303ae 3842 pmap_page_protect(m->phys_page, VM_PROT_NONE);
1c79356b
A
3843 } else {
3844 PAGE_WAKEUP(m);
3845 }
3846 vm_page_unlock_queues();
3847 }
1c79356b 3848 }
55e303ae
A
3849 occupied = 1;
3850 if (upl->flags & UPL_DEVICE_MEMORY) {
3851 occupied = 0;
3852 } else if (upl->flags & UPL_LITE) {
3853 int pg_num;
3854 int i;
3855 pg_num = upl->size/PAGE_SIZE;
3856 pg_num = (pg_num + 31) >> 5;
3857 occupied = 0;
3858 for(i= 0; i<pg_num; i++) {
3859 if(lite_list[i] != 0) {
3860 occupied = 1;
3861 break;
3862 }
3863 }
3864 } else {
3865 if(queue_empty(&upl->map_object->memq)) {
3866 occupied = 0;
3867 }
3868 }
1c79356b 3869
55e303ae
A
3870 if(occupied == 0) {
3871 if(object == shadow_object)
3872 vm_object_paging_end(shadow_object);
1c79356b 3873 }
55e303ae
A
3874 vm_object_unlock(shadow_object);
3875
0b4e3aa0 3876 upl_unlock(upl);
1c79356b
A
3877 return KERN_SUCCESS;
3878}
3879
3880/* an option on commit should be wire */
3881kern_return_t
0b4e3aa0
A
3882upl_commit(
3883 upl_t upl,
3884 upl_page_info_t *page_list,
3885 mach_msg_type_number_t count)
1c79356b 3886{
0b4e3aa0
A
3887 if (upl == UPL_NULL)
3888 return KERN_INVALID_ARGUMENT;
3889
55e303ae
A
3890 if(upl->flags & (UPL_LITE | UPL_IO_WIRE)) {
3891 boolean_t empty;
3892 return upl_commit_range(upl, 0, upl->size, 0,
3893 page_list, count, &empty);
3894 }
3895
0b4e3aa0
A
3896 if (count == 0)
3897 page_list = NULL;
3898
3899 upl_lock(upl);
1c79356b
A
3900 if (upl->flags & UPL_DEVICE_MEMORY)
3901 page_list = NULL;
de355530 3902
55e303ae
A
3903 if ((upl->flags & UPL_CLEAR_DIRTY) ||
3904 (upl->flags & UPL_PAGE_SYNC_DONE) || page_list) {
1c79356b
A
3905 vm_object_t shadow_object = upl->map_object->shadow;
3906 vm_object_t object = upl->map_object;
3907 vm_object_offset_t target_offset;
3908 vm_size_t xfer_end;
3909 int entry;
3910
3911 vm_page_t t, m;
3912 upl_page_info_t *p;
3913
3914 vm_object_lock(shadow_object);
3915
3916 entry = 0;
3917 target_offset = object->shadow_offset;
3918 xfer_end = upl->size + object->shadow_offset;
3919
3920 while(target_offset < xfer_end) {
3921
3922 if ((t = vm_page_lookup(object,
3923 target_offset - object->shadow_offset))
3924 == NULL) {
3925 target_offset += PAGE_SIZE_64;
3926 entry++;
3927 continue;
3928 }
3929
3930 m = vm_page_lookup(shadow_object, target_offset);
3931 if(m != VM_PAGE_NULL) {
55e303ae
A
3932 if (upl->flags & UPL_CLEAR_DIRTY) {
3933 pmap_clear_modify(m->phys_page);
3934 m->dirty = FALSE;
3935 }
3936 /* It is a part of the semantic of */
3937 /* COPYOUT_FROM UPLs that a commit */
3938 /* implies cache sync between the */
3939 /* vm page and the backing store */
3940 /* this can be used to strip the */
3941 /* precious bit as well as clean */
3942 if (upl->flags & UPL_PAGE_SYNC_DONE)
3943 m->precious = FALSE;
3944
3945 if(page_list) {
3946 p = &(page_list[entry]);
3947 if(page_list[entry].phys_addr &&
1c79356b
A
3948 p->pageout && !m->pageout) {
3949 vm_page_lock_queues();
3950 m->busy = TRUE;
3951 m->pageout = TRUE;
3952 vm_page_wire(m);
3953 vm_page_unlock_queues();
55e303ae 3954 } else if (page_list[entry].phys_addr &&
0b4e3aa0
A
3955 !p->pageout && m->pageout &&
3956 !m->dump_cleaning) {
1c79356b
A
3957 vm_page_lock_queues();
3958 m->pageout = FALSE;
3959 m->absent = FALSE;
3960 m->overwriting = FALSE;
3961 vm_page_unwire(m);
3962 PAGE_WAKEUP_DONE(m);
3963 vm_page_unlock_queues();
55e303ae
A
3964 }
3965 page_list[entry].phys_addr = 0;
1c79356b 3966 }
1c79356b
A
3967 }
3968 target_offset += PAGE_SIZE_64;
3969 entry++;
3970 }
3971
3972 vm_object_unlock(shadow_object);
3973 }
55e303ae
A
3974 if (upl->flags & UPL_DEVICE_MEMORY) {
3975 vm_object_lock(upl->map_object->shadow);
3976 if(upl->map_object == upl->map_object->shadow)
3977 vm_object_paging_end(upl->map_object->shadow);
3978 vm_object_unlock(upl->map_object->shadow);
3979 }
0b4e3aa0 3980 upl_unlock(upl);
1c79356b
A
3981 return KERN_SUCCESS;
3982}
3983
55e303ae
A
3984
3985
3986kern_return_t
3987vm_object_iopl_request(
3988 vm_object_t object,
3989 vm_object_offset_t offset,
3990 vm_size_t size,
3991 upl_t *upl_ptr,
3992 upl_page_info_array_t user_page_list,
3993 unsigned int *page_list_count,
3994 int cntrl_flags)
3995{
3996 vm_page_t dst_page;
3997 vm_object_offset_t dst_offset = offset;
3998 vm_size_t xfer_size = size;
3999 upl_t upl = NULL;
4000 int entry;
4001 wpl_array_t lite_list;
4002 int page_field_size;
4003 int delayed_unlock = 0;
4004
4005 vm_page_t alias_page = NULL;
4006 kern_return_t ret;
4007 vm_prot_t prot;
4008
4009
4010 if(cntrl_flags & UPL_COPYOUT_FROM) {
4011 prot = VM_PROT_READ;
4012 } else {
4013 prot = VM_PROT_READ | VM_PROT_WRITE;
4014 }
4015
4016 if(((size/page_size) > MAX_UPL_TRANSFER) && !object->phys_contiguous) {
4017 size = MAX_UPL_TRANSFER * page_size;
4018 }
4019
4020 if(cntrl_flags & UPL_SET_INTERNAL)
4021 if(page_list_count != NULL)
4022 *page_list_count = MAX_UPL_TRANSFER;
4023 if(((cntrl_flags & UPL_SET_INTERNAL) && !(object->phys_contiguous)) &&
4024 ((page_list_count != NULL) && (*page_list_count != 0)
4025 && *page_list_count < (size/page_size)))
4026 return KERN_INVALID_ARGUMENT;
4027
4028 if((!object->internal) && (object->paging_offset != 0))
4029 panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
4030
4031 if(object->phys_contiguous) {
4032 /* No paging operations are possible against this memory */
4033 /* and so no need for map object, ever */
4034 cntrl_flags |= UPL_SET_LITE;
4035 }
4036
4037 if(upl_ptr) {
4038 if(cntrl_flags & UPL_SET_INTERNAL) {
4039 if(cntrl_flags & UPL_SET_LITE) {
4040 upl = upl_create(
4041 UPL_CREATE_INTERNAL | UPL_CREATE_LITE,
4042 size);
4043 user_page_list = (upl_page_info_t *)
4044 (((vm_offset_t)upl) + sizeof(struct upl));
4045 lite_list = (wpl_array_t)
4046 (((vm_offset_t)user_page_list) +
4047 ((size/PAGE_SIZE) *
4048 sizeof(upl_page_info_t)));
4049 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
4050 page_field_size =
4051 (page_field_size + 3) & 0xFFFFFFFC;
4052 bzero((char *)lite_list, page_field_size);
4053 upl->flags =
4054 UPL_LITE | UPL_INTERNAL | UPL_IO_WIRE;
4055 } else {
4056 upl = upl_create(UPL_CREATE_INTERNAL, size);
4057 user_page_list = (upl_page_info_t *)
4058 (((vm_offset_t)upl)
4059 + sizeof(struct upl));
4060 upl->flags = UPL_INTERNAL | UPL_IO_WIRE;
4061 }
4062 } else {
4063 if(cntrl_flags & UPL_SET_LITE) {
4064 upl = upl_create(UPL_CREATE_LITE, size);
4065 lite_list = (wpl_array_t)
4066 (((vm_offset_t)upl) + sizeof(struct upl));
4067 page_field_size = ((size/PAGE_SIZE) + 7) >> 3;
4068 page_field_size =
4069 (page_field_size + 3) & 0xFFFFFFFC;
4070 bzero((char *)lite_list, page_field_size);
4071 upl->flags = UPL_LITE | UPL_IO_WIRE;
4072 } else {
4073 upl = upl_create(UPL_CREATE_EXTERNAL, size);
4074 upl->flags = UPL_IO_WIRE;
4075 }
4076 }
4077
4078 if(object->phys_contiguous) {
4079 upl->map_object = object;
4080 /* don't need any shadow mappings for this one */
4081 /* since it is already I/O memory */
4082 upl->flags |= UPL_DEVICE_MEMORY;
4083
4084 vm_object_lock(object);
4085 vm_object_paging_begin(object);
4086 vm_object_unlock(object);
4087
4088 /* paging in progress also protects the paging_offset */
4089 upl->offset = offset + object->paging_offset;
4090 upl->size = size;
4091 *upl_ptr = upl;
4092 if(user_page_list) {
4093 user_page_list[0].phys_addr =
4094 (offset + object->shadow_offset)>>12;
4095 user_page_list[0].device = TRUE;
4096 }
4097
4098 if(page_list_count != NULL) {
4099 if (upl->flags & UPL_INTERNAL) {
4100 *page_list_count = 0;
4101 } else {
4102 *page_list_count = 1;
4103 }
4104 }
4105 return KERN_SUCCESS;
4106 }
4107 if(user_page_list)
4108 user_page_list[0].device = FALSE;
4109
4110 if(cntrl_flags & UPL_SET_LITE) {
4111 upl->map_object = object;
4112 } else {
4113 upl->map_object = vm_object_allocate(size);
4114 vm_object_lock(upl->map_object);
4115 upl->map_object->shadow = object;
4116 upl->map_object->pageout = TRUE;
4117 upl->map_object->can_persist = FALSE;
4118 upl->map_object->copy_strategy =
4119 MEMORY_OBJECT_COPY_NONE;
4120 upl->map_object->shadow_offset = offset;
4121 upl->map_object->wimg_bits = object->wimg_bits;
4122 vm_object_unlock(upl->map_object);
4123 }
4124 }
4125 vm_object_lock(object);
4126 vm_object_paging_begin(object);
4127
4128 if (!object->phys_contiguous) {
4129 /* Protect user space from future COW operations */
4130 object->true_share = TRUE;
4131 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC)
4132 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
4133 }
4134
4135 /* we can lock the upl offset now that paging_in_progress is set */
4136 if(upl_ptr) {
4137 upl->size = size;
4138 upl->offset = offset + object->paging_offset;
4139 *upl_ptr = upl;
4140#ifdef UBC_DEBUG
4141 queue_enter(&object->uplq, upl, upl_t, uplq);
4142#endif /* UBC_DEBUG */
4143 }
4144
4145 entry = 0;
4146 while (xfer_size) {
4147 if((alias_page == NULL) && !(cntrl_flags & UPL_SET_LITE)) {
4148 if (delayed_unlock) {
4149 delayed_unlock = 0;
4150 vm_page_unlock_queues();
4151 }
4152 vm_object_unlock(object);
4153 VM_PAGE_GRAB_FICTITIOUS(alias_page);
4154 vm_object_lock(object);
4155 }
4156 dst_page = vm_page_lookup(object, dst_offset);
4157
4158 if ((dst_page == VM_PAGE_NULL) || (dst_page->busy) ||
4159 (dst_page->unusual && (dst_page->error ||
4160 dst_page->restart || dst_page->absent ||
4161 dst_page->fictitious ||
4162 prot & dst_page->page_lock))) {
4163 vm_fault_return_t result;
4164 do {
4165 vm_page_t top_page;
4166 kern_return_t error_code;
4167 int interruptible;
4168
4169 vm_object_offset_t lo_offset = offset;
4170 vm_object_offset_t hi_offset = offset + size;
4171
4172
4173 if (delayed_unlock) {
4174 delayed_unlock = 0;
4175 vm_page_unlock_queues();
4176 }
4177
4178 if(cntrl_flags & UPL_SET_INTERRUPTIBLE) {
4179 interruptible = THREAD_ABORTSAFE;
4180 } else {
4181 interruptible = THREAD_UNINT;
4182 }
4183
4184 result = vm_fault_page(object, dst_offset,
4185 prot | VM_PROT_WRITE, FALSE,
4186 interruptible,
4187 lo_offset, hi_offset,
4188 VM_BEHAVIOR_SEQUENTIAL,
4189 &prot, &dst_page, &top_page,
4190 (int *)0,
4191 &error_code, FALSE, FALSE, NULL, 0);
4192
4193 switch(result) {
4194 case VM_FAULT_SUCCESS:
4195
4196 PAGE_WAKEUP_DONE(dst_page);
4197
4198 /*
4199 * Release paging references and
4200 * top-level placeholder page, if any.
4201 */
4202
4203 if(top_page != VM_PAGE_NULL) {
4204 vm_object_t local_object;
4205 local_object =
4206 top_page->object;
4207 if(top_page->object
4208 != dst_page->object) {
4209 vm_object_lock(
4210 local_object);
4211 VM_PAGE_FREE(top_page);
4212 vm_object_paging_end(
4213 local_object);
4214 vm_object_unlock(
4215 local_object);
4216 } else {
4217 VM_PAGE_FREE(top_page);
4218 vm_object_paging_end(
4219 local_object);
4220 }
4221 }
4222
4223 break;
4224
4225
4226 case VM_FAULT_RETRY:
4227 vm_object_lock(object);
4228 vm_object_paging_begin(object);
4229 break;
4230
4231 case VM_FAULT_FICTITIOUS_SHORTAGE:
4232 vm_page_more_fictitious();
4233 vm_object_lock(object);
4234 vm_object_paging_begin(object);
4235 break;
4236
4237 case VM_FAULT_MEMORY_SHORTAGE:
4238 if (vm_page_wait(interruptible)) {
4239 vm_object_lock(object);
4240 vm_object_paging_begin(object);
4241 break;
4242 }
4243 /* fall thru */
4244
4245 case VM_FAULT_INTERRUPTED:
4246 error_code = MACH_SEND_INTERRUPTED;
4247 case VM_FAULT_MEMORY_ERROR:
4248 ret = (error_code ? error_code:
4249 KERN_MEMORY_ERROR);
4250 vm_object_lock(object);
4251 for(; offset < dst_offset;
4252 offset += PAGE_SIZE) {
4253 dst_page = vm_page_lookup(
4254 object, offset);
4255 if(dst_page == VM_PAGE_NULL)
4256 panic("vm_object_iopl_request: Wired pages missing. \n");
4257 vm_page_lock_queues();
4258 vm_page_unwire(dst_page);
4259 vm_page_unlock_queues();
4260 VM_STAT(reactivations++);
4261 }
4262 vm_object_unlock(object);
4263 upl_destroy(upl);
4264 return ret;
4265 }
4266 } while ((result != VM_FAULT_SUCCESS)
4267 || (result == VM_FAULT_INTERRUPTED));
4268 }
4269 if (delayed_unlock == 0)
4270 vm_page_lock_queues();
4271 vm_page_wire(dst_page);
4272
4273 if (upl_ptr) {
4274 if (cntrl_flags & UPL_SET_LITE) {
4275 int pg_num;
4276 pg_num = (dst_offset-offset)/PAGE_SIZE;
4277 lite_list[pg_num>>5] |= 1 << (pg_num & 31);
4278 } else {
4279 /*
4280 * Convert the fictitious page to a
4281 * private shadow of the real page.
4282 */
4283 assert(alias_page->fictitious);
4284 alias_page->fictitious = FALSE;
4285 alias_page->private = TRUE;
4286 alias_page->pageout = TRUE;
4287 alias_page->phys_page = dst_page->phys_page;
4288 vm_page_wire(alias_page);
4289
4290 vm_page_insert(alias_page,
4291 upl->map_object, size - xfer_size);
4292 assert(!alias_page->wanted);
4293 alias_page->busy = FALSE;
4294 alias_page->absent = FALSE;
4295 }
4296
4297 /* expect the page to be used */
4298 dst_page->reference = TRUE;
4299
4300 if (!(cntrl_flags & UPL_COPYOUT_FROM))
4301 dst_page->dirty = TRUE;
4302 alias_page = NULL;
4303
4304 if (user_page_list) {
4305 user_page_list[entry].phys_addr
4306 = dst_page->phys_page;
4307 user_page_list[entry].dirty =
4308 dst_page->dirty;
4309 user_page_list[entry].pageout =
4310 dst_page->pageout;
4311 user_page_list[entry].absent =
4312 dst_page->absent;
4313 user_page_list[entry].precious =
4314 dst_page->precious;
4315 }
4316 }
4317 if (delayed_unlock++ > DELAYED_UNLOCK_LIMIT) {
4318 delayed_unlock = 0;
4319 vm_page_unlock_queues();
4320 }
4321 entry++;
4322 dst_offset += PAGE_SIZE_64;
4323 xfer_size -= PAGE_SIZE;
4324 }
4325 if (delayed_unlock)
4326 vm_page_unlock_queues();
4327
4328 if (upl->flags & UPL_INTERNAL) {
4329 if(page_list_count != NULL)
4330 *page_list_count = 0;
4331 } else if (*page_list_count > entry) {
4332 if(page_list_count != NULL)
4333 *page_list_count = entry;
4334 }
4335
4336 if (alias_page != NULL) {
4337 vm_page_lock_queues();
4338 vm_page_free(alias_page);
4339 vm_page_unlock_queues();
4340 }
4341
4342 vm_object_unlock(object);
4343 return KERN_SUCCESS;
4344}
4345
1c79356b
A
4346vm_size_t
4347upl_get_internal_pagelist_offset()
4348{
4349 return sizeof(struct upl);
4350}
4351
4352void
4353upl_set_dirty(
4354 upl_t upl)
4355{
4356 upl->flags |= UPL_CLEAR_DIRTY;
4357}
4358
4359void
4360upl_clear_dirty(
4361 upl_t upl)
4362{
4363 upl->flags &= ~UPL_CLEAR_DIRTY;
4364}
4365
4366
4367#ifdef MACH_BSD
1c79356b
A
4368
4369boolean_t upl_page_present(upl_page_info_t *upl, int index)
4370{
4371 return(UPL_PAGE_PRESENT(upl, index));
4372}
4373boolean_t upl_dirty_page(upl_page_info_t *upl, int index)
4374{
4375 return(UPL_DIRTY_PAGE(upl, index));
4376}
4377boolean_t upl_valid_page(upl_page_info_t *upl, int index)
4378{
4379 return(UPL_VALID_PAGE(upl, index));
4380}
4381vm_offset_t upl_phys_page(upl_page_info_t *upl, int index)
4382{
4383 return((vm_offset_t)UPL_PHYS_PAGE(upl, index));
4384}
4385
0b4e3aa0
A
4386void
4387vm_countdirtypages(void)
1c79356b
A
4388{
4389 vm_page_t m;
4390 int dpages;
4391 int pgopages;
4392 int precpages;
4393
4394
4395 dpages=0;
4396 pgopages=0;
4397 precpages=0;
4398
4399 vm_page_lock_queues();
4400 m = (vm_page_t) queue_first(&vm_page_queue_inactive);
4401 do {
4402 if (m ==(vm_page_t )0) break;
4403
4404 if(m->dirty) dpages++;
4405 if(m->pageout) pgopages++;
4406 if(m->precious) precpages++;
4407
4408 m = (vm_page_t) queue_next(&m->pageq);
4409 if (m ==(vm_page_t )0) break;
4410
4411 } while (!queue_end(&vm_page_queue_inactive,(queue_entry_t) m));
4412 vm_page_unlock_queues();
9bccf70c
A
4413
4414 vm_page_lock_queues();
4415 m = (vm_page_t) queue_first(&vm_page_queue_zf);
4416 do {
4417 if (m ==(vm_page_t )0) break;
4418
4419 if(m->dirty) dpages++;
4420 if(m->pageout) pgopages++;
4421 if(m->precious) precpages++;
4422
4423 m = (vm_page_t) queue_next(&m->pageq);
4424 if (m ==(vm_page_t )0) break;
4425
4426 } while (!queue_end(&vm_page_queue_zf,(queue_entry_t) m));
4427 vm_page_unlock_queues();
1c79356b
A
4428
4429 printf("IN Q: %d : %d : %d\n", dpages, pgopages, precpages);
4430
4431 dpages=0;
4432 pgopages=0;
4433 precpages=0;
4434
4435 vm_page_lock_queues();
4436 m = (vm_page_t) queue_first(&vm_page_queue_active);
4437
4438 do {
4439 if(m == (vm_page_t )0) break;
4440 if(m->dirty) dpages++;
4441 if(m->pageout) pgopages++;
4442 if(m->precious) precpages++;
4443
4444 m = (vm_page_t) queue_next(&m->pageq);
4445 if(m == (vm_page_t )0) break;
4446
4447 } while (!queue_end(&vm_page_queue_active,(queue_entry_t) m));
4448 vm_page_unlock_queues();
4449
4450 printf("AC Q: %d : %d : %d\n", dpages, pgopages, precpages);
4451
4452}
4453#endif /* MACH_BSD */
4454
4455#ifdef UBC_DEBUG
4456kern_return_t upl_ubc_alias_set(upl_t upl, unsigned int alias1, unsigned int alias2)
4457{
4458 upl->ubc_alias1 = alias1;
4459 upl->ubc_alias2 = alias2;
4460 return KERN_SUCCESS;
4461}
4462int upl_ubc_alias_get(upl_t upl, unsigned int * al, unsigned int * al2)
4463{
4464 if(al)
4465 *al = upl->ubc_alias1;
4466 if(al2)
4467 *al2 = upl->ubc_alias2;
4468 return KERN_SUCCESS;
4469}
4470#endif /* UBC_DEBUG */
4471
4472
4473
4474#if MACH_KDB
4475#include <ddb/db_output.h>
4476#include <ddb/db_print.h>
4477#include <vm/vm_print.h>
4478
4479#define printf kdbprintf
4480extern int db_indent;
4481void db_pageout(void);
4482
4483void
4484db_vm(void)
4485{
4486 extern int vm_page_gobble_count;
1c79356b
A
4487
4488 iprintf("VM Statistics:\n");
4489 db_indent += 2;
4490 iprintf("pages:\n");
4491 db_indent += 2;
4492 iprintf("activ %5d inact %5d free %5d",
4493 vm_page_active_count, vm_page_inactive_count,
4494 vm_page_free_count);
4495 printf(" wire %5d gobbl %5d\n",
4496 vm_page_wire_count, vm_page_gobble_count);
0b4e3aa0
A
4497 iprintf("laund %5d\n",
4498 vm_page_laundry_count);
1c79356b
A
4499 db_indent -= 2;
4500 iprintf("target:\n");
4501 db_indent += 2;
4502 iprintf("min %5d inact %5d free %5d",
4503 vm_page_free_min, vm_page_inactive_target,
4504 vm_page_free_target);
4505 printf(" resrv %5d\n", vm_page_free_reserved);
4506 db_indent -= 2;
4507
4508 iprintf("burst:\n");
4509 db_indent += 2;
4510 iprintf("max %5d min %5d wait %5d empty %5d\n",
4511 vm_pageout_burst_max, vm_pageout_burst_min,
4512 vm_pageout_burst_wait, vm_pageout_empty_wait);
4513 db_indent -= 2;
4514 iprintf("pause:\n");
4515 db_indent += 2;
4516 iprintf("count %5d max %5d\n",
4517 vm_pageout_pause_count, vm_pageout_pause_max);
4518#if MACH_COUNTERS
4519 iprintf("scan_continue called %8d\n", c_vm_pageout_scan_continue);
4520#endif /* MACH_COUNTERS */
4521 db_indent -= 2;
4522 db_pageout();
4523 db_indent -= 2;
4524}
4525
4526void
4527db_pageout(void)
4528{
1c79356b
A
4529#if MACH_COUNTERS
4530 extern int c_laundry_pages_freed;
4531#endif /* MACH_COUNTERS */
4532
4533 iprintf("Pageout Statistics:\n");
4534 db_indent += 2;
4535 iprintf("active %5d inactv %5d\n",
4536 vm_pageout_active, vm_pageout_inactive);
4537 iprintf("nolock %5d avoid %5d busy %5d absent %5d\n",
4538 vm_pageout_inactive_nolock, vm_pageout_inactive_avoid,
4539 vm_pageout_inactive_busy, vm_pageout_inactive_absent);
4540 iprintf("used %5d clean %5d dirty %5d\n",
4541 vm_pageout_inactive_used, vm_pageout_inactive_clean,
4542 vm_pageout_inactive_dirty);
1c79356b
A
4543#if MACH_COUNTERS
4544 iprintf("laundry_pages_freed %d\n", c_laundry_pages_freed);
4545#endif /* MACH_COUNTERS */
4546#if MACH_CLUSTER_STATS
4547 iprintf("Cluster Statistics:\n");
4548 db_indent += 2;
4549 iprintf("dirtied %5d cleaned %5d collisions %5d\n",
4550 vm_pageout_cluster_dirtied, vm_pageout_cluster_cleaned,
4551 vm_pageout_cluster_collisions);
4552 iprintf("clusters %5d conversions %5d\n",
4553 vm_pageout_cluster_clusters, vm_pageout_cluster_conversions);
4554 db_indent -= 2;
4555 iprintf("Target Statistics:\n");
4556 db_indent += 2;
4557 iprintf("collisions %5d page_dirtied %5d page_freed %5d\n",
4558 vm_pageout_target_collisions, vm_pageout_target_page_dirtied,
4559 vm_pageout_target_page_freed);
1c79356b
A
4560 db_indent -= 2;
4561#endif /* MACH_CLUSTER_STATS */
4562 db_indent -= 2;
4563}
4564
4565#if MACH_CLUSTER_STATS
4566unsigned long vm_pageout_cluster_dirtied = 0;
4567unsigned long vm_pageout_cluster_cleaned = 0;
4568unsigned long vm_pageout_cluster_collisions = 0;
4569unsigned long vm_pageout_cluster_clusters = 0;
4570unsigned long vm_pageout_cluster_conversions = 0;
4571unsigned long vm_pageout_target_collisions = 0;
4572unsigned long vm_pageout_target_page_dirtied = 0;
4573unsigned long vm_pageout_target_page_freed = 0;
1c79356b
A
4574#define CLUSTER_STAT(clause) clause
4575#else /* MACH_CLUSTER_STATS */
4576#define CLUSTER_STAT(clause)
4577#endif /* MACH_CLUSTER_STATS */
4578
4579#endif /* MACH_KDB */