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