]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/memory_object.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / osfmk / vm / memory_object.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
0a7de745 41 *
1c79356b
A
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58/*
59 * File: vm/memory_object.c
60 * Author: Michael Wayne Young
61 *
62 * External memory management interface control functions.
63 */
64
1c79356b
A
65/*
66 * Interface dependencies:
67 */
68
0a7de745 69#include <mach/std_types.h> /* For pointer_t */
1c79356b
A
70#include <mach/mach_types.h>
71
0b4e3aa0 72#include <mach/mig.h>
1c79356b
A
73#include <mach/kern_return.h>
74#include <mach/memory_object.h>
75#include <mach/memory_object_default.h>
76#include <mach/memory_object_control_server.h>
0b4e3aa0 77#include <mach/host_priv_server.h>
1c79356b
A
78#include <mach/boolean.h>
79#include <mach/vm_prot.h>
80#include <mach/message.h>
81
1c79356b
A
82/*
83 * Implementation dependencies:
84 */
0a7de745 85#include <string.h> /* For memcpy() */
1c79356b 86
0b4e3aa0 87#include <kern/host.h>
0a7de745 88#include <kern/thread.h> /* For current_thread() */
0b4e3aa0
A
89#include <kern/ipc_mig.h>
90#include <kern/misc_protos.h>
91
92#include <vm/vm_object.h>
93#include <vm/vm_fault.h>
1c79356b
A
94#include <vm/memory_object.h>
95#include <vm/vm_page.h>
96#include <vm/vm_pageout.h>
0a7de745
A
97#include <vm/pmap.h> /* For pmap_clear_modify */
98#include <vm/vm_kern.h> /* For kernel_map, vm_move */
99#include <vm/vm_map.h> /* For vm_map_pageable */
100#include <vm/vm_purgeable_internal.h> /* Needed by some vm_page.h macros */
6d2010ae 101#include <vm/vm_shared_region.h>
1c79356b 102
1c79356b 103#include <vm/vm_external.h>
1c79356b 104
91447636
A
105#include <vm/vm_protos.h>
106
0a7de745 107memory_object_default_t memory_manager_default = MEMORY_OBJECT_DEFAULT_NULL;
f427ee49 108LCK_MTX_EARLY_DECLARE(memory_manager_default_lock, &vm_object_lck_grp);
1c79356b 109
1c79356b
A
110
111/*
112 * Routine: memory_object_should_return_page
113 *
114 * Description:
115 * Determine whether the given page should be returned,
116 * based on the page's state and on the given return policy.
117 *
118 * We should return the page if one of the following is true:
119 *
120 * 1. Page is dirty and should_return is not RETURN_NONE.
121 * 2. Page is precious and should_return is RETURN_ALL.
122 * 3. Should_return is RETURN_ANYTHING.
123 *
d9a64523 124 * As a side effect, m->vmp_dirty will be made consistent
1c79356b
A
125 * with pmap_is_modified(m), if should_return is not
126 * MEMORY_OBJECT_RETURN_NONE.
127 */
128
0a7de745 129#define memory_object_should_return_page(m, should_return) \
1c79356b 130 (should_return != MEMORY_OBJECT_RETURN_NONE && \
d9a64523
A
131 (((m)->vmp_dirty || ((m)->vmp_dirty = pmap_is_modified(VM_PAGE_GET_PHYS_PAGE(m)))) || \
132 ((m)->vmp_precious && (should_return) == MEMORY_OBJECT_RETURN_ALL) || \
1c79356b
A
133 (should_return) == MEMORY_OBJECT_RETURN_ANYTHING))
134
0a7de745 135typedef int memory_object_lock_result_t;
1c79356b 136
0a7de745
A
137#define MEMORY_OBJECT_LOCK_RESULT_DONE 0
138#define MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK 1
139#define MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN 2
140#define MEMORY_OBJECT_LOCK_RESULT_MUST_FREE 3
1c79356b
A
141
142memory_object_lock_result_t memory_object_lock_page(
0a7de745
A
143 vm_page_t m,
144 memory_object_return_t should_return,
145 boolean_t should_flush,
146 vm_prot_t prot);
1c79356b
A
147
148/*
149 * Routine: memory_object_lock_page
150 *
151 * Description:
152 * Perform the appropriate lock operations on the
153 * given page. See the description of
154 * "memory_object_lock_request" for the meanings
155 * of the arguments.
156 *
157 * Returns an indication that the operation
158 * completed, blocked, or that the page must
159 * be cleaned.
160 */
161memory_object_lock_result_t
162memory_object_lock_page(
0a7de745
A
163 vm_page_t m,
164 memory_object_return_t should_return,
165 boolean_t should_flush,
166 vm_prot_t prot)
1c79356b 167{
0a7de745
A
168 if (m->vmp_busy || m->vmp_cleaning) {
169 return MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK;
170 }
b0d623f7 171
0a7de745 172 if (m->vmp_laundry) {
316670eb 173 vm_pageout_steal_laundry(m, FALSE);
0a7de745 174 }
6d2010ae 175
1c79356b
A
176 /*
177 * Don't worry about pages for which the kernel
178 * does not have any data.
179 */
d9a64523
A
180 if (m->vmp_absent || m->vmp_error || m->vmp_restart) {
181 if (m->vmp_error && should_flush && !VM_PAGE_WIRED(m)) {
6d2010ae
A
182 /*
183 * dump the page, pager wants us to
184 * clean it up and there is no
185 * relevant data to return
186 */
0a7de745 187 return MEMORY_OBJECT_LOCK_RESULT_MUST_FREE;
765c9de3 188 }
0a7de745 189 return MEMORY_OBJECT_LOCK_RESULT_DONE;
765c9de3 190 }
d9a64523 191 assert(!m->vmp_fictitious);
1c79356b 192
b0d623f7 193 if (VM_PAGE_WIRED(m)) {
6d2010ae
A
194 /*
195 * The page is wired... just clean or return the page if needed.
196 * Wired pages don't get flushed or disconnected from the pmap.
197 */
0a7de745
A
198 if (memory_object_should_return_page(m, should_return)) {
199 return MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN;
200 }
1c79356b 201
0a7de745
A
202 return MEMORY_OBJECT_LOCK_RESULT_DONE;
203 }
1c79356b 204
6d2010ae
A
205 if (should_flush) {
206 /*
0a7de745 207 * must do the pmap_disconnect before determining the
6d2010ae
A
208 * need to return the page... otherwise it's possible
209 * for the page to go from the clean to the dirty state
210 * after we've made our decision
211 */
39037602 212 if (pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m)) & VM_MEM_MODIFIED) {
316670eb
A
213 SET_PAGE_DIRTY(m, FALSE);
214 }
6d2010ae
A
215 } else {
216 /*
217 * If we are decreasing permission, do it now;
218 * let the fault handler take care of increases
219 * (pmap_page_protect may not increase protection).
220 */
0a7de745 221 if (prot != VM_PROT_NO_CHANGE) {
39037602 222 pmap_page_protect(VM_PAGE_GET_PHYS_PAGE(m), VM_PROT_ALL & ~prot);
0a7de745 223 }
1c79356b 224 }
1c79356b 225 /*
6d2010ae 226 * Handle returning dirty or precious pages
1c79356b 227 */
1c79356b 228 if (memory_object_should_return_page(m, should_return)) {
1c79356b 229 /*
6d2010ae
A
230 * we use to do a pmap_disconnect here in support
231 * of memory_object_lock_request, but that routine
232 * no longer requires this... in any event, in
233 * our world, it would turn into a big noop since
234 * we don't lock the page in any way and as soon
235 * as we drop the object lock, the page can be
236 * faulted back into an address space
237 *
238 * if (!should_flush)
39037602 239 * pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m));
1c79356b 240 */
0a7de745 241 return MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN;
1c79356b
A
242 }
243
244 /*
6d2010ae 245 * Handle flushing clean pages
1c79356b 246 */
0a7de745
A
247 if (should_flush) {
248 return MEMORY_OBJECT_LOCK_RESULT_MUST_FREE;
249 }
1c79356b 250
6d2010ae
A
251 /*
252 * we use to deactivate clean pages at this point,
253 * but we do not believe that an msync should change
254 * the 'age' of a page in the cache... here is the
255 * original comment and code concerning this...
256 *
257 * XXX Make clean but not flush a paging hint,
258 * and deactivate the pages. This is a hack
259 * because it overloads flush/clean with
260 * implementation-dependent meaning. This only
261 * happens to pages that are already clean.
262 *
263 * if (vm_page_deactivate_hint && (should_return != MEMORY_OBJECT_RETURN_NONE))
264 * return (MEMORY_OBJECT_LOCK_RESULT_MUST_DEACTIVATE);
265 */
1c79356b 266
0a7de745 267 return MEMORY_OBJECT_LOCK_RESULT_DONE;
1c79356b 268}
0b4e3aa0 269
6d2010ae 270
1c79356b 271
1c79356b
A
272/*
273 * Routine: memory_object_lock_request [user interface]
274 *
275 * Description:
276 * Control use of the data associated with the given
277 * memory object. For each page in the given range,
278 * perform the following operations, in order:
279 * 1) restrict access to the page (disallow
280 * forms specified by "prot");
281 * 2) return data to the manager (if "should_return"
282 * is RETURN_DIRTY and the page is dirty, or
0a7de745 283 * "should_return" is RETURN_ALL and the page
1c79356b
A
284 * is either dirty or precious); and,
285 * 3) flush the cached copy (if "should_flush"
286 * is asserted).
287 * The set of pages is defined by a starting offset
288 * ("offset") and size ("size"). Only pages with the
289 * same page alignment as the starting offset are
290 * considered.
291 *
292 * A single acknowledgement is sent (to the "reply_to"
293 * port) when these actions are complete. If successful,
294 * the naked send right for reply_to is consumed.
295 */
296
297kern_return_t
298memory_object_lock_request(
0a7de745
A
299 memory_object_control_t control,
300 memory_object_offset_t offset,
301 memory_object_size_t size,
302 memory_object_offset_t * resid_offset,
303 int * io_errno,
304 memory_object_return_t should_return,
305 int flags,
306 vm_prot_t prot)
1c79356b 307{
0a7de745 308 vm_object_t object;
1c79356b 309
0a7de745 310 /*
1c79356b
A
311 * Check for bogus arguments.
312 */
0b4e3aa0 313 object = memory_object_control_to_vm_object(control);
0a7de745
A
314 if (object == VM_OBJECT_NULL) {
315 return KERN_INVALID_ARGUMENT;
316 }
1c79356b 317
0a7de745
A
318 if ((prot & ~VM_PROT_ALL) != 0 && prot != VM_PROT_NO_CHANGE) {
319 return KERN_INVALID_ARGUMENT;
320 }
1c79356b 321
55e303ae 322 size = round_page_64(size);
1c79356b
A
323
324 /*
325 * Lock the object, and acquire a paging reference to
0b4e3aa0 326 * prevent the memory_object reference from being released.
1c79356b 327 */
1c79356b
A
328 vm_object_lock(object);
329 vm_object_paging_begin(object);
b0d623f7
A
330
331 if (flags & MEMORY_OBJECT_DATA_FLUSH_ALL) {
332 if ((should_return != MEMORY_OBJECT_RETURN_NONE) || offset || object->copy) {
333 flags &= ~MEMORY_OBJECT_DATA_FLUSH_ALL;
334 flags |= MEMORY_OBJECT_DATA_FLUSH;
335 }
336 }
1c79356b
A
337 offset -= object->paging_offset;
338
0a7de745 339 if (flags & MEMORY_OBJECT_DATA_FLUSH_ALL) {
b0d623f7 340 vm_object_reap_pages(object, REAP_DATA_FLUSH);
0a7de745 341 } else {
b0d623f7 342 (void)vm_object_update(object, offset, size, resid_offset,
0a7de745
A
343 io_errno, should_return, flags, prot);
344 }
1c79356b 345
1c79356b
A
346 vm_object_paging_end(object);
347 vm_object_unlock(object);
1c79356b 348
0a7de745 349 return KERN_SUCCESS;
1c79356b
A
350}
351
352/*
0b4e3aa0
A
353 * memory_object_release_name: [interface]
354 *
355 * Enforces name semantic on memory_object reference count decrement
356 * This routine should not be called unless the caller holds a name
357 * reference gained through the memory_object_named_create or the
358 * memory_object_rename call.
359 * If the TERMINATE_IDLE flag is set, the call will return if the
360 * reference count is not 1. i.e. idle with the only remaining reference
361 * being the name.
362 * If the decision is made to proceed the name field flag is set to
363 * false and the reference count is decremented. If the RESPECT_CACHE
0a7de745 364 * flag is set and the reference count has gone to zero, the
0b4e3aa0
A
365 * memory_object is checked to see if it is cacheable otherwise when
366 * the reference count is zero, it is simply terminated.
367 */
368
369kern_return_t
370memory_object_release_name(
0a7de745
A
371 memory_object_control_t control,
372 int flags)
0b4e3aa0 373{
0a7de745 374 vm_object_t object;
0b4e3aa0
A
375
376 object = memory_object_control_to_vm_object(control);
0a7de745
A
377 if (object == VM_OBJECT_NULL) {
378 return KERN_INVALID_ARGUMENT;
379 }
0b4e3aa0
A
380
381 return vm_object_release_name(object, flags);
382}
383
384
385
386/*
387 * Routine: memory_object_destroy [user interface]
388 * Purpose:
389 * Shut down a memory object, despite the
390 * presence of address map (or other) references
391 * to the vm_object.
392 */
393kern_return_t
394memory_object_destroy(
0a7de745
A
395 memory_object_control_t control,
396 kern_return_t reason)
0b4e3aa0 397{
0a7de745 398 vm_object_t object;
0b4e3aa0
A
399
400 object = memory_object_control_to_vm_object(control);
0a7de745
A
401 if (object == VM_OBJECT_NULL) {
402 return KERN_INVALID_ARGUMENT;
403 }
0b4e3aa0 404
0a7de745 405 return vm_object_destroy(object, reason);
0b4e3aa0
A
406}
407
408/*
409 * Routine: vm_object_sync
1c79356b
A
410 *
411 * Kernel internal function to synch out pages in a given
412 * range within an object to its memory manager. Much the
413 * same as memory_object_lock_request but page protection
414 * is not changed.
415 *
416 * If the should_flush and should_return flags are true pages
417 * are flushed, that is dirty & precious pages are written to
418 * the memory manager and then discarded. If should_return
419 * is false, only precious pages are returned to the memory
420 * manager.
421 *
422 * If should flush is false and should_return true, the memory
423 * manager's copy of the pages is updated. If should_return
424 * is also false, only the precious pages are updated. This
425 * last option is of limited utility.
426 *
427 * Returns:
428 * FALSE if no pages were returned to the pager
429 * TRUE otherwise.
430 */
431
432boolean_t
0b4e3aa0 433vm_object_sync(
0a7de745
A
434 vm_object_t object,
435 vm_object_offset_t offset,
436 vm_object_size_t size,
437 boolean_t should_flush,
438 boolean_t should_return,
439 boolean_t should_iosync)
1c79356b 440{
0a7de745 441 boolean_t rv;
91447636 442 int flags;
1c79356b 443
1c79356b
A
444 /*
445 * Lock the object, and acquire a paging reference to
446 * prevent the memory_object and control ports from
447 * being destroyed.
448 */
449 vm_object_lock(object);
450 vm_object_paging_begin(object);
451
39236c6e 452 if (should_flush) {
0a7de745 453 flags = MEMORY_OBJECT_DATA_FLUSH;
39236c6e
A
454 /*
455 * This flush is from an msync(), not a truncate(), so the
456 * contents of the file are not affected.
457 * MEMORY_OBECT_DATA_NO_CHANGE lets vm_object_update() know
458 * that the data is not changed and that there's no need to
459 * push the old contents to a copy object.
460 */
461 flags |= MEMORY_OBJECT_DATA_NO_CHANGE;
0a7de745
A
462 } else {
463 flags = 0;
464 }
91447636 465
0a7de745
A
466 if (should_iosync) {
467 flags |= MEMORY_OBJECT_IO_SYNC;
468 }
91447636
A
469
470 rv = vm_object_update(object, offset, (vm_object_size_t)size, NULL, NULL,
0a7de745
A
471 (should_return) ?
472 MEMORY_OBJECT_RETURN_ALL :
473 MEMORY_OBJECT_RETURN_NONE,
474 flags,
475 VM_PROT_NO_CHANGE);
1c79356b
A
476
477
478 vm_object_paging_end(object);
479 vm_object_unlock(object);
480 return rv;
481}
482
91447636
A
483
484
6d2010ae 485#define LIST_REQ_PAGEOUT_PAGES(object, data_cnt, po, ro, ioerr, iosync) \
0a7de745
A
486MACRO_BEGIN \
487 \
488 int upl_flags; \
489 memory_object_t pager; \
490 \
491 if ((pager = (object)->pager) != MEMORY_OBJECT_NULL) { \
492 vm_object_paging_begin(object); \
493 vm_object_unlock(object); \
494 \
495 if (iosync) \
496 upl_flags = UPL_MSYNC | UPL_IOSYNC; \
497 else \
498 upl_flags = UPL_MSYNC; \
499 \
500 (void) memory_object_data_return(pager, \
501 po, \
502 (memory_object_cluster_size_t)data_cnt, \
6d2010ae
A
503 ro, \
504 ioerr, \
0a7de745
A
505 FALSE, \
506 FALSE, \
507 upl_flags); \
508 \
509 vm_object_lock(object); \
510 vm_object_paging_end(object); \
511 } \
6d2010ae
A
512MACRO_END
513
39037602
A
514extern struct vnode *
515vnode_pager_lookup_vnode(memory_object_t);
91447636
A
516
517static int
518vm_object_update_extent(
0a7de745
A
519 vm_object_t object,
520 vm_object_offset_t offset,
521 vm_object_offset_t offset_end,
522 vm_object_offset_t *offset_resid,
523 int *io_errno,
524 boolean_t should_flush,
525 memory_object_return_t should_return,
526 boolean_t should_iosync,
527 vm_prot_t prot)
91447636 528{
0a7de745
A
529 vm_page_t m;
530 int retval = 0;
531 vm_object_offset_t paging_offset = 0;
532 vm_object_offset_t next_offset = offset;
533 memory_object_lock_result_t page_lock_result;
534 memory_object_cluster_size_t data_cnt = 0;
f427ee49
A
535 struct vm_page_delayed_work dw_array;
536 struct vm_page_delayed_work *dwp, *dwp_start;
537 bool dwp_finish_ctx = TRUE;
0a7de745
A
538 int dw_count;
539 int dw_limit;
540 int dirty_count;
541
f427ee49 542 dwp_start = dwp = NULL;
0a7de745 543 dw_count = 0;
6d2010ae 544 dw_limit = DELAYED_WORK_LIMIT(DEFAULT_DELAYED_WORK_LIMIT);
f427ee49
A
545 dwp_start = vm_page_delayed_work_get_ctx();
546 if (dwp_start == NULL) {
547 dwp_start = &dw_array;
548 dw_limit = 1;
549 dwp_finish_ctx = FALSE;
550 }
551 dwp = dwp_start;
552
4bd07ac2 553 dirty_count = 0;
91447636
A
554
555 for (;
0a7de745
A
556 offset < offset_end && object->resident_page_count;
557 offset += PAGE_SIZE_64) {
558 /*
b0d623f7 559 * Limit the number of pages to be cleaned at once to a contiguous
fe8ab488 560 * run, or at most MAX_UPL_TRANSFER_BYTES
91447636 561 */
b0d623f7 562 if (data_cnt) {
fe8ab488 563 if ((data_cnt >= MAX_UPL_TRANSFER_BYTES) || (next_offset != offset)) {
6d2010ae 564 if (dw_count) {
f427ee49
A
565 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, dwp_start, dw_count);
566 dwp = dwp_start;
6d2010ae
A
567 dw_count = 0;
568 }
569 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
0a7de745 570 paging_offset, offset_resid, io_errno, should_iosync);
b0d623f7
A
571 data_cnt = 0;
572 }
91447636 573 }
91447636 574 while ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
6d2010ae 575 dwp->dw_mask = 0;
0a7de745 576
6d2010ae
A
577 page_lock_result = memory_object_lock_page(m, should_return, should_flush, prot);
578
579 if (data_cnt && page_lock_result != MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN) {
580 /*
581 * End of a run of dirty/precious pages.
582 */
583 if (dw_count) {
f427ee49
A
584 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, dwp_start, dw_count);
585 dwp = dwp_start;
6d2010ae
A
586 dw_count = 0;
587 }
588 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
0a7de745 589 paging_offset, offset_resid, io_errno, should_iosync);
6d2010ae
A
590 /*
591 * LIST_REQ_PAGEOUT_PAGES will drop the object lock which will
592 * allow the state of page 'm' to change... we need to re-lookup
593 * the current offset
594 */
595 data_cnt = 0;
596 continue;
597 }
598
599 switch (page_lock_result) {
6d2010ae
A
600 case MEMORY_OBJECT_LOCK_RESULT_DONE:
601 break;
602
603 case MEMORY_OBJECT_LOCK_RESULT_MUST_FREE:
0a7de745 604 if (m->vmp_dirty == TRUE) {
4bd07ac2 605 dirty_count++;
0a7de745 606 }
6d2010ae
A
607 dwp->dw_mask |= DW_vm_page_free;
608 break;
609
610 case MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK:
611 PAGE_SLEEP(object, m, THREAD_UNINT);
612 continue;
613
614 case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:
0a7de745 615 if (data_cnt == 0) {
6d2010ae 616 paging_offset = offset;
0a7de745 617 }
6d2010ae
A
618
619 data_cnt += PAGE_SIZE;
620 next_offset = offset + PAGE_SIZE_64;
621
6d2010ae
A
622 /*
623 * wired pages shouldn't be flushed and
624 * since they aren't on any queue,
625 * no need to remove them
626 */
627 if (!VM_PAGE_WIRED(m)) {
6d2010ae
A
628 if (should_flush) {
629 /*
630 * add additional state for the flush
631 */
d9a64523 632 m->vmp_free_when_done = TRUE;
6d2010ae
A
633 }
634 /*
635 * we use to remove the page from the queues at this
636 * point, but we do not believe that an msync
637 * should cause the 'age' of a page to be changed
638 *
639 * else
640 * dwp->dw_mask |= DW_VM_PAGE_QUEUES_REMOVE;
641 */
642 }
643 retval = 1;
644 break;
645 }
646 if (dwp->dw_mask) {
647 VM_PAGE_ADD_DELAYED_WORK(dwp, m, dw_count);
648
649 if (dw_count >= dw_limit) {
f427ee49
A
650 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, dwp_start, dw_count);
651 dwp = dwp_start;
6d2010ae
A
652 dw_count = 0;
653 }
91447636
A
654 }
655 break;
656 }
657 }
0a7de745
A
658
659 if (object->pager) {
39037602 660 task_update_logical_writes(current_task(), (dirty_count * PAGE_SIZE), TASK_WRITE_INVALIDATED, vnode_pager_lookup_vnode(object->pager));
0a7de745 661 }
91447636
A
662 /*
663 * We have completed the scan for applicable pages.
664 * Clean any pages that have been saved.
665 */
0a7de745 666 if (dw_count) {
f427ee49 667 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, dwp_start, dw_count);
0a7de745 668 }
6d2010ae 669
91447636 670 if (data_cnt) {
0a7de745
A
671 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
672 paging_offset, offset_resid, io_errno, should_iosync);
91447636 673 }
f427ee49
A
674
675 if (dwp_start && dwp_finish_ctx) {
676 vm_page_delayed_work_finish_ctx(dwp_start);
677 dwp_start = dwp = NULL;
678 }
679
0a7de745 680 return retval;
91447636
A
681}
682
683
684
1c79356b 685/*
0b4e3aa0 686 * Routine: vm_object_update
1c79356b 687 * Description:
0b4e3aa0 688 * Work function for m_o_lock_request(), vm_o_sync().
1c79356b
A
689 *
690 * Called with object locked and paging ref taken.
691 */
692kern_return_t
0b4e3aa0 693vm_object_update(
0a7de745
A
694 vm_object_t object,
695 vm_object_offset_t offset,
696 vm_object_size_t size,
697 vm_object_offset_t *resid_offset,
698 int *io_errno,
699 memory_object_return_t should_return,
700 int flags,
701 vm_prot_t protection)
1c79356b 702{
0a7de745
A
703 vm_object_t copy_object = VM_OBJECT_NULL;
704 boolean_t data_returned = FALSE;
705 boolean_t update_cow;
706 boolean_t should_flush = (flags & MEMORY_OBJECT_DATA_FLUSH) ? TRUE : FALSE;
707 boolean_t should_iosync = (flags & MEMORY_OBJECT_IO_SYNC) ? TRUE : FALSE;
708 vm_fault_return_t result;
709 int num_of_extents;
710 int n;
711#define MAX_EXTENTS 8
712#define EXTENT_SIZE (1024 * 1024 * 256)
713#define RESIDENT_LIMIT (1024 * 32)
91447636 714 struct extent {
0a7de745
A
715 vm_object_offset_t e_base;
716 vm_object_offset_t e_min;
717 vm_object_offset_t e_max;
91447636 718 } extents[MAX_EXTENTS];
1c79356b
A
719
720 /*
721 * To avoid blocking while scanning for pages, save
722 * dirty pages to be cleaned all at once.
723 *
724 * XXXO A similar strategy could be used to limit the
725 * number of times that a scan must be restarted for
726 * other reasons. Those pages that would require blocking
727 * could be temporarily collected in another list, or
728 * their offsets could be recorded in a small array.
729 */
730
731 /*
732 * XXX NOTE: May want to consider converting this to a page list
733 * XXX vm_map_copy interface. Need to understand object
734 * XXX coalescing implications before doing so.
735 */
736
0a7de745
A
737 update_cow = ((flags & MEMORY_OBJECT_DATA_FLUSH)
738 && (!(flags & MEMORY_OBJECT_DATA_NO_CHANGE) &&
739 !(flags & MEMORY_OBJECT_DATA_PURGE)))
740 || (flags & MEMORY_OBJECT_COPY_SYNC);
741
2d21ac55 742 if (update_cow || (flags & (MEMORY_OBJECT_DATA_PURGE | MEMORY_OBJECT_DATA_SYNC))) {
0a7de745 743 int collisions = 0;
2d21ac55 744
0a7de745
A
745 while ((copy_object = object->copy) != VM_OBJECT_NULL) {
746 /*
2d21ac55
A
747 * need to do a try here since we're swimming upstream
748 * against the normal lock ordering... however, we need
749 * to hold the object stable until we gain control of the
750 * copy object so we have to be careful how we approach this
751 */
0a7de745
A
752 if (vm_object_lock_try(copy_object)) {
753 /*
754 * we 'won' the lock on the copy object...
755 * no need to hold the object lock any longer...
756 * take a real reference on the copy object because
757 * we're going to call vm_fault_page on it which may
758 * under certain conditions drop the lock and the paging
759 * reference we're about to take... the reference
760 * will keep the copy object from going away if that happens
761 */
762 vm_object_unlock(object);
763 vm_object_reference_locked(copy_object);
764 break;
2d21ac55
A
765 }
766 vm_object_unlock(object);
1c79356b 767
2d21ac55
A
768 collisions++;
769 mutex_pause(collisions);
770
771 vm_object_lock(object);
772 }
773 }
774 if ((copy_object != VM_OBJECT_NULL && update_cow) || (flags & MEMORY_OBJECT_DATA_SYNC)) {
f427ee49
A
775 vm_object_offset_t i;
776 vm_object_size_t copy_size;
777 vm_object_offset_t copy_offset;
0a7de745
A
778 vm_prot_t prot;
779 vm_page_t page;
780 vm_page_t top_page;
781 kern_return_t error = 0;
d9a64523 782 struct vm_object_fault_info fault_info = {};
2d21ac55
A
783
784 if (copy_object != VM_OBJECT_NULL) {
0a7de745 785 /*
2d21ac55
A
786 * translate offset with respect to shadow's offset
787 */
0a7de745 788 copy_offset = (offset >= copy_object->vo_shadow_offset) ?
f427ee49 789 (offset - copy_object->vo_shadow_offset) : 0;
2d21ac55 790
0a7de745
A
791 if (copy_offset > copy_object->vo_size) {
792 copy_offset = copy_object->vo_size;
793 }
2d21ac55
A
794
795 /*
796 * clip size with respect to shadow offset
797 */
6d2010ae 798 if (offset >= copy_object->vo_shadow_offset) {
0a7de745 799 copy_size = size;
6d2010ae 800 } else if (size >= copy_object->vo_shadow_offset - offset) {
f427ee49 801 copy_size = (size - (copy_object->vo_shadow_offset - offset));
2d21ac55 802 } else {
0a7de745 803 copy_size = 0;
2d21ac55 804 }
0a7de745 805
6d2010ae 806 if (copy_offset + copy_size > copy_object->vo_size) {
0a7de745
A
807 if (copy_object->vo_size >= copy_offset) {
808 copy_size = copy_object->vo_size - copy_offset;
2d21ac55 809 } else {
0a7de745 810 copy_size = 0;
2d21ac55
A
811 }
812 }
0a7de745 813 copy_size += copy_offset;
1c79356b
A
814 } else {
815 copy_object = object;
816
817 copy_size = offset + size;
818 copy_offset = offset;
819 }
2d21ac55
A
820 fault_info.interruptible = THREAD_UNINT;
821 fault_info.behavior = VM_BEHAVIOR_SEQUENTIAL;
2d21ac55
A
822 fault_info.lo_offset = copy_offset;
823 fault_info.hi_offset = copy_size;
b0d623f7 824 fault_info.stealth = TRUE;
d9a64523
A
825 assert(fault_info.cs_bypass == FALSE);
826 assert(fault_info.pmap_cs_associated == FALSE);
1c79356b
A
827
828 vm_object_paging_begin(copy_object);
2d21ac55
A
829
830 for (i = copy_offset; i < copy_size; i += PAGE_SIZE) {
0a7de745 831RETRY_COW_OF_LOCK_REQUEST:
b0d623f7
A
832 fault_info.cluster_size = (vm_size_t) (copy_size - i);
833 assert(fault_info.cluster_size == copy_size - i);
2d21ac55 834
0a7de745 835 prot = VM_PROT_WRITE | VM_PROT_READ;
39236c6e 836 page = VM_PAGE_NULL;
0a7de745
A
837 result = vm_fault_page(copy_object, i,
838 VM_PROT_WRITE | VM_PROT_READ,
839 FALSE,
840 FALSE, /* page not looked up */
841 &prot,
842 &page,
843 &top_page,
844 (int *)0,
845 &error,
846 FALSE,
847 FALSE, &fault_info);
b0d623f7
A
848
849 switch (result) {
1c79356b 850 case VM_FAULT_SUCCESS:
2d21ac55 851 if (top_page) {
1c79356b 852 vm_fault_cleanup(
39037602 853 VM_PAGE_OBJECT(page), top_page);
1c79356b
A
854 vm_object_lock(copy_object);
855 vm_object_paging_begin(copy_object);
1c79356b 856 }
0a7de745 857 if ((!VM_PAGE_NON_SPECULATIVE_PAGEABLE(page))) {
b0d623f7 858 vm_page_lockspin_queues();
0a7de745
A
859
860 if ((!VM_PAGE_NON_SPECULATIVE_PAGEABLE(page))) {
b0d623f7 861 vm_page_deactivate(page);
39037602 862 }
b0d623f7
A
863 vm_page_unlock_queues();
864 }
2d21ac55 865 PAGE_WAKEUP_DONE(page);
1c79356b
A
866 break;
867 case VM_FAULT_RETRY:
0a7de745 868 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
869 vm_object_lock(copy_object);
870 vm_object_paging_begin(copy_object);
871 goto RETRY_COW_OF_LOCK_REQUEST;
872 case VM_FAULT_INTERRUPTED:
0a7de745 873 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
874 vm_object_lock(copy_object);
875 vm_object_paging_begin(copy_object);
876 goto RETRY_COW_OF_LOCK_REQUEST;
877 case VM_FAULT_MEMORY_SHORTAGE:
878 VM_PAGE_WAIT();
0a7de745 879 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
880 vm_object_lock(copy_object);
881 vm_object_paging_begin(copy_object);
882 goto RETRY_COW_OF_LOCK_REQUEST;
b0d623f7
A
883 case VM_FAULT_SUCCESS_NO_VM_PAGE:
884 /* success but no VM page: fail */
885 vm_object_paging_end(copy_object);
886 vm_object_unlock(copy_object);
f427ee49 887 OS_FALLTHROUGH;
1c79356b 888 case VM_FAULT_MEMORY_ERROR:
0a7de745
A
889 if (object != copy_object) {
890 vm_object_deallocate(copy_object);
891 }
1c79356b
A
892 vm_object_lock(object);
893 goto BYPASS_COW_COPYIN;
b0d623f7
A
894 default:
895 panic("vm_object_update: unexpected error 0x%x"
0a7de745 896 " from vm_fault_page()\n", result);
1c79356b 897 }
1c79356b
A
898 }
899 vm_object_paging_end(copy_object);
2d21ac55
A
900 }
901 if ((flags & (MEMORY_OBJECT_DATA_SYNC | MEMORY_OBJECT_COPY_SYNC))) {
0a7de745 902 if (copy_object != VM_OBJECT_NULL && copy_object != object) {
1c79356b 903 vm_object_unlock(copy_object);
0a7de745 904 vm_object_deallocate(copy_object);
1c79356b
A
905 vm_object_lock(object);
906 }
2d21ac55 907 return KERN_SUCCESS;
1c79356b 908 }
2d21ac55 909 if (copy_object != VM_OBJECT_NULL && copy_object != object) {
0a7de745 910 if ((flags & MEMORY_OBJECT_DATA_PURGE)) {
39037602 911 vm_object_lock_assert_exclusive(copy_object);
0a7de745 912 copy_object->shadow_severed = TRUE;
2d21ac55
A
913 copy_object->shadowed = FALSE;
914 copy_object->shadow = NULL;
915 /*
916 * delete the ref the COW was holding on the target object
917 */
918 vm_object_deallocate(object);
919 }
920 vm_object_unlock(copy_object);
0a7de745 921 vm_object_deallocate(copy_object);
2d21ac55 922 vm_object_lock(object);
1c79356b
A
923 }
924BYPASS_COW_COPYIN:
925
91447636
A
926 /*
927 * when we have a really large range to check relative
928 * to the number of actual resident pages, we'd like
929 * to use the resident page list to drive our checks
930 * however, the object lock will get dropped while processing
931 * the page which means the resident queue can change which
932 * means we can't walk the queue as we process the pages
933 * we also want to do the processing in offset order to allow
0a7de745 934 * 'runs' of pages to be collected if we're being told to
91447636 935 * flush to disk... the resident page queue is NOT ordered.
0a7de745 936 *
91447636
A
937 * a temporary solution (until we figure out how to deal with
938 * large address spaces more generically) is to pre-flight
939 * the resident page queue (if it's small enough) and develop
940 * a collection of extents (that encompass actual resident pages)
941 * to visit. This will at least allow us to deal with some of the
942 * more pathological cases in a more efficient manner. The current
943 * worst case (a single resident page at the end of an extremely large
944 * range) can take minutes to complete for ranges in the terrabyte
945 * category... since this routine is called when truncating a file,
946 * and we currently support files up to 16 Tbytes in size, this
947 * is not a theoretical problem
948 */
1c79356b 949
0a7de745
A
950 if ((object->resident_page_count < RESIDENT_LIMIT) &&
951 (atop_64(size) > (unsigned)(object->resident_page_count / (8 * MAX_EXTENTS)))) {
952 vm_page_t next;
953 vm_object_offset_t start;
954 vm_object_offset_t end;
955 vm_object_size_t e_mask;
91447636 956 vm_page_t m;
1c79356b 957
91447636
A
958 start = offset;
959 end = offset + size;
960 num_of_extents = 0;
961 e_mask = ~((vm_object_size_t)(EXTENT_SIZE - 1));
1c79356b 962
39037602 963 m = (vm_page_t) vm_page_queue_first(&object->memq);
1c79356b 964
39037602 965 while (!vm_page_queue_end(&object->memq, (vm_page_queue_entry_t) m)) {
d9a64523 966 next = (vm_page_t) vm_page_queue_next(&m->vmp_listq);
1c79356b 967
d9a64523 968 if ((m->vmp_offset >= start) && (m->vmp_offset < end)) {
0a7de745 969 /*
91447636
A
970 * this is a page we're interested in
971 * try to fit it into a current extent
1c79356b 972 */
0a7de745
A
973 for (n = 0; n < num_of_extents; n++) {
974 if ((m->vmp_offset & e_mask) == extents[n].e_base) {
975 /*
91447636
A
976 * use (PAGE_SIZE - 1) to determine the
977 * max offset so that we don't wrap if
978 * we're at the last page of the space
979 */
0a7de745
A
980 if (m->vmp_offset < extents[n].e_min) {
981 extents[n].e_min = m->vmp_offset;
982 } else if ((m->vmp_offset + (PAGE_SIZE - 1)) > extents[n].e_max) {
983 extents[n].e_max = m->vmp_offset + (PAGE_SIZE - 1);
984 }
985 break;
91447636
A
986 }
987 }
988 if (n == num_of_extents) {
0a7de745 989 /*
91447636
A
990 * didn't find a current extent that can encompass
991 * this page
992 */
0a7de745
A
993 if (n < MAX_EXTENTS) {
994 /*
995 * if we still have room,
91447636
A
996 * create a new extent
997 */
0a7de745 998 extents[n].e_base = m->vmp_offset & e_mask;
d9a64523
A
999 extents[n].e_min = m->vmp_offset;
1000 extents[n].e_max = m->vmp_offset + (PAGE_SIZE - 1);
91447636
A
1001
1002 num_of_extents++;
1003 } else {
1004 /*
1005 * no room to create a new extent...
1006 * fall back to a single extent based
0a7de745 1007 * on the min and max page offsets
91447636
A
1008 * we find in the range we're interested in...
1009 * first, look through the extent list and
1010 * develop the overall min and max for the
1011 * pages we've looked at up to this point
0a7de745
A
1012 */
1013 for (n = 1; n < num_of_extents; n++) {
1014 if (extents[n].e_min < extents[0].e_min) {
1015 extents[0].e_min = extents[n].e_min;
1016 }
1017 if (extents[n].e_max > extents[0].e_max) {
1018 extents[0].e_max = extents[n].e_max;
1019 }
91447636
A
1020 }
1021 /*
1022 * now setup to run through the remaining pages
1023 * to determine the overall min and max
1024 * offset for the specified range
1025 */
1026 extents[0].e_base = 0;
1027 e_mask = 0;
1028 num_of_extents = 1;
1029
1030 /*
1031 * by continuing, we'll reprocess the
1032 * page that forced us to abandon trying
1033 * to develop multiple extents
1034 */
1035 continue;
1036 }
1037 }
1c79356b 1038 }
91447636 1039 m = next;
1c79356b 1040 }
91447636 1041 } else {
0a7de745 1042 extents[0].e_min = offset;
91447636 1043 extents[0].e_max = offset + (size - 1);
1c79356b 1044
91447636
A
1045 num_of_extents = 1;
1046 }
1047 for (n = 0; n < num_of_extents; n++) {
0a7de745
A
1048 if (vm_object_update_extent(object, extents[n].e_min, extents[n].e_max, resid_offset, io_errno,
1049 should_flush, should_return, should_iosync, protection)) {
1050 data_returned = TRUE;
1051 }
1c79356b 1052 }
0a7de745 1053 return data_returned;
1c79356b
A
1054}
1055
91447636 1056
0b4e3aa0
A
1057static kern_return_t
1058vm_object_set_attributes_common(
0a7de745
A
1059 vm_object_t object,
1060 boolean_t may_cache,
5ba3f43e 1061 memory_object_copy_strategy_t copy_strategy)
1c79356b 1062{
0a7de745 1063 boolean_t object_became_ready;
1c79356b 1064
0a7de745
A
1065 if (object == VM_OBJECT_NULL) {
1066 return KERN_INVALID_ARGUMENT;
1067 }
1c79356b
A
1068
1069 /*
1070 * Verify the attributes of importance
1071 */
1072
0a7de745
A
1073 switch (copy_strategy) {
1074 case MEMORY_OBJECT_COPY_NONE:
1075 case MEMORY_OBJECT_COPY_DELAY:
1076 break;
1077 default:
1078 return KERN_INVALID_ARGUMENT;
1c79356b
A
1079 }
1080
0a7de745 1081 if (may_cache) {
1c79356b 1082 may_cache = TRUE;
0a7de745 1083 }
1c79356b
A
1084
1085 vm_object_lock(object);
1086
1087 /*
1088 * Copy the attributes
1089 */
1090 assert(!object->internal);
1091 object_became_ready = !object->pager_ready;
1092 object->copy_strategy = copy_strategy;
1093 object->can_persist = may_cache;
1c79356b
A
1094
1095 /*
1096 * Wake up anyone waiting for the ready attribute
1097 * to become asserted.
1098 */
1099
1100 if (object_became_ready) {
1101 object->pager_ready = TRUE;
1102 vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY);
1103 }
1104
1105 vm_object_unlock(object);
1106
0a7de745 1107 return KERN_SUCCESS;
1c79356b
A
1108}
1109
5ba3f43e
A
1110
1111kern_return_t
1112memory_object_synchronize_completed(
0a7de745
A
1113 __unused memory_object_control_t control,
1114 __unused memory_object_offset_t offset,
1115 __unused memory_object_size_t length)
5ba3f43e 1116{
0a7de745
A
1117 panic("memory_object_synchronize_completed no longer supported\n");
1118 return KERN_FAILURE;
5ba3f43e
A
1119}
1120
1121
1c79356b
A
1122/*
1123 * Set the memory object attribute as provided.
1124 *
0a7de745 1125 * XXX This routine cannot be completed until the vm_msync, clean
1c79356b 1126 * in place, and cluster work is completed. See ifdef notyet
0b4e3aa0 1127 * below and note that vm_object_set_attributes_common()
1c79356b
A
1128 * may have to be expanded.
1129 */
1130kern_return_t
1131memory_object_change_attributes(
0a7de745
A
1132 memory_object_control_t control,
1133 memory_object_flavor_t flavor,
1134 memory_object_info_t attributes,
1135 mach_msg_type_number_t count)
1c79356b 1136{
0a7de745
A
1137 vm_object_t object;
1138 kern_return_t result = KERN_SUCCESS;
1139 boolean_t may_cache;
1140 boolean_t invalidate;
1141 memory_object_copy_strategy_t copy_strategy;
1c79356b 1142
0b4e3aa0 1143 object = memory_object_control_to_vm_object(control);
0a7de745
A
1144 if (object == VM_OBJECT_NULL) {
1145 return KERN_INVALID_ARGUMENT;
1146 }
1c79356b
A
1147
1148 vm_object_lock(object);
0b4e3aa0 1149
1c79356b
A
1150 may_cache = object->can_persist;
1151 copy_strategy = object->copy_strategy;
1c79356b
A
1152#if notyet
1153 invalidate = object->invalidate;
1154#endif
0a7de745 1155 vm_object_unlock(object);
1c79356b
A
1156
1157 switch (flavor) {
0a7de745
A
1158 case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1159 {
1160 old_memory_object_behave_info_t behave;
1c79356b 1161
0a7de745
A
1162 if (count != OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1163 result = KERN_INVALID_ARGUMENT;
1164 break;
1165 }
1c79356b 1166
0a7de745 1167 behave = (old_memory_object_behave_info_t) attributes;
1c79356b 1168
1c79356b
A
1169 invalidate = behave->invalidate;
1170 copy_strategy = behave->copy_strategy;
1171
1172 break;
0a7de745 1173 }
1c79356b 1174
0a7de745
A
1175 case MEMORY_OBJECT_BEHAVIOR_INFO:
1176 {
1177 memory_object_behave_info_t behave;
1c79356b 1178
0a7de745
A
1179 if (count != MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1180 result = KERN_INVALID_ARGUMENT;
1181 break;
1182 }
1c79356b 1183
0a7de745 1184 behave = (memory_object_behave_info_t) attributes;
1c79356b 1185
1c79356b
A
1186 invalidate = behave->invalidate;
1187 copy_strategy = behave->copy_strategy;
1c79356b 1188 break;
0a7de745 1189 }
1c79356b 1190
0a7de745
A
1191 case MEMORY_OBJECT_PERFORMANCE_INFO:
1192 {
1193 memory_object_perf_info_t perf;
1c79356b 1194
0a7de745
A
1195 if (count != MEMORY_OBJECT_PERF_INFO_COUNT) {
1196 result = KERN_INVALID_ARGUMENT;
1197 break;
1198 }
1c79356b 1199
0a7de745 1200 perf = (memory_object_perf_info_t) attributes;
1c79356b
A
1201
1202 may_cache = perf->may_cache;
1c79356b
A
1203
1204 break;
0a7de745 1205 }
1c79356b 1206
0a7de745
A
1207 case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1208 {
1209 old_memory_object_attr_info_t attr;
1c79356b 1210
0a7de745
A
1211 if (count != OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1212 result = KERN_INVALID_ARGUMENT;
1213 break;
1214 }
1c79356b
A
1215
1216 attr = (old_memory_object_attr_info_t) attributes;
1217
0a7de745
A
1218 may_cache = attr->may_cache;
1219 copy_strategy = attr->copy_strategy;
1c79356b
A
1220
1221 break;
0a7de745 1222 }
1c79356b 1223
0a7de745
A
1224 case MEMORY_OBJECT_ATTRIBUTE_INFO:
1225 {
1226 memory_object_attr_info_t attr;
1c79356b 1227
0a7de745
A
1228 if (count != MEMORY_OBJECT_ATTR_INFO_COUNT) {
1229 result = KERN_INVALID_ARGUMENT;
1230 break;
1231 }
1c79356b
A
1232
1233 attr = (memory_object_attr_info_t) attributes;
1234
1235 copy_strategy = attr->copy_strategy;
0a7de745 1236 may_cache = attr->may_cache_object;
1c79356b
A
1237
1238 break;
0a7de745 1239 }
1c79356b 1240
0a7de745 1241 default:
1c79356b
A
1242 result = KERN_INVALID_ARGUMENT;
1243 break;
1244 }
1245
0a7de745
A
1246 if (result != KERN_SUCCESS) {
1247 return result;
1248 }
1c79356b
A
1249
1250 if (copy_strategy == MEMORY_OBJECT_COPY_TEMPORARY) {
1251 copy_strategy = MEMORY_OBJECT_COPY_DELAY;
1c79356b
A
1252 }
1253
1254 /*
1c79356b
A
1255 * XXX may_cache may become a tri-valued variable to handle
1256 * XXX uncache if not in use.
1257 */
0a7de745
A
1258 return vm_object_set_attributes_common(object,
1259 may_cache,
1260 copy_strategy);
1c79356b
A
1261}
1262
1263kern_return_t
1264memory_object_get_attributes(
0a7de745
A
1265 memory_object_control_t control,
1266 memory_object_flavor_t flavor,
1267 memory_object_info_t attributes, /* pointer to OUT array */
1268 mach_msg_type_number_t *count) /* IN/OUT */
1c79356b 1269{
0a7de745
A
1270 kern_return_t ret = KERN_SUCCESS;
1271 vm_object_t object;
1c79356b 1272
0b4e3aa0 1273 object = memory_object_control_to_vm_object(control);
0a7de745
A
1274 if (object == VM_OBJECT_NULL) {
1275 return KERN_INVALID_ARGUMENT;
1276 }
1c79356b 1277
0a7de745 1278 vm_object_lock(object);
1c79356b
A
1279
1280 switch (flavor) {
0a7de745
A
1281 case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1282 {
1283 old_memory_object_behave_info_t behave;
1c79356b
A
1284
1285 if (*count < OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1286 ret = KERN_INVALID_ARGUMENT;
1287 break;
1288 }
1289
1290 behave = (old_memory_object_behave_info_t) attributes;
1291 behave->copy_strategy = object->copy_strategy;
5ba3f43e 1292 behave->temporary = FALSE;
0a7de745
A
1293#if notyet /* remove when vm_msync complies and clean in place fini */
1294 behave->invalidate = object->invalidate;
1c79356b
A
1295#else
1296 behave->invalidate = FALSE;
1297#endif
1298
1299 *count = OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1300 break;
0a7de745 1301 }
1c79356b 1302
0a7de745
A
1303 case MEMORY_OBJECT_BEHAVIOR_INFO:
1304 {
1305 memory_object_behave_info_t behave;
1c79356b
A
1306
1307 if (*count < MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
0a7de745
A
1308 ret = KERN_INVALID_ARGUMENT;
1309 break;
1310 }
1c79356b 1311
0a7de745
A
1312 behave = (memory_object_behave_info_t) attributes;
1313 behave->copy_strategy = object->copy_strategy;
5ba3f43e 1314 behave->temporary = FALSE;
0a7de745
A
1315#if notyet /* remove when vm_msync complies and clean in place fini */
1316 behave->invalidate = object->invalidate;
1c79356b
A
1317#else
1318 behave->invalidate = FALSE;
1319#endif
5ba3f43e 1320 behave->advisory_pageout = FALSE;
39236c6e 1321 behave->silent_overwrite = FALSE;
0a7de745 1322 *count = MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1c79356b 1323 break;
0a7de745 1324 }
1c79356b 1325
0a7de745
A
1326 case MEMORY_OBJECT_PERFORMANCE_INFO:
1327 {
1328 memory_object_perf_info_t perf;
1c79356b
A
1329
1330 if (*count < MEMORY_OBJECT_PERF_INFO_COUNT) {
1331 ret = KERN_INVALID_ARGUMENT;
1332 break;
1333 }
1334
1335 perf = (memory_object_perf_info_t) attributes;
2d21ac55 1336 perf->cluster_size = PAGE_SIZE;
1c79356b
A
1337 perf->may_cache = object->can_persist;
1338
1339 *count = MEMORY_OBJECT_PERF_INFO_COUNT;
1340 break;
0a7de745 1341 }
1c79356b 1342
0a7de745
A
1343 case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1344 {
1345 old_memory_object_attr_info_t attr;
1c79356b 1346
0a7de745
A
1347 if (*count < OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1348 ret = KERN_INVALID_ARGUMENT;
1349 break;
1350 }
1c79356b 1351
0a7de745
A
1352 attr = (old_memory_object_attr_info_t) attributes;
1353 attr->may_cache = object->can_persist;
1354 attr->copy_strategy = object->copy_strategy;
1c79356b 1355
0a7de745
A
1356 *count = OLD_MEMORY_OBJECT_ATTR_INFO_COUNT;
1357 break;
1358 }
1c79356b 1359
0a7de745
A
1360 case MEMORY_OBJECT_ATTRIBUTE_INFO:
1361 {
1362 memory_object_attr_info_t attr;
1c79356b 1363
0a7de745
A
1364 if (*count < MEMORY_OBJECT_ATTR_INFO_COUNT) {
1365 ret = KERN_INVALID_ARGUMENT;
1366 break;
1367 }
1c79356b 1368
0a7de745
A
1369 attr = (memory_object_attr_info_t) attributes;
1370 attr->copy_strategy = object->copy_strategy;
2d21ac55 1371 attr->cluster_size = PAGE_SIZE;
0a7de745 1372 attr->may_cache_object = object->can_persist;
5ba3f43e 1373 attr->temporary = FALSE;
1c79356b 1374
0a7de745
A
1375 *count = MEMORY_OBJECT_ATTR_INFO_COUNT;
1376 break;
1377 }
1c79356b 1378
0a7de745 1379 default:
1c79356b
A
1380 ret = KERN_INVALID_ARGUMENT;
1381 break;
1382 }
1383
0a7de745 1384 vm_object_unlock(object);
1c79356b 1385
0a7de745 1386 return ret;
1c79356b
A
1387}
1388
1c79356b 1389
55e303ae
A
1390kern_return_t
1391memory_object_iopl_request(
0a7de745
A
1392 ipc_port_t port,
1393 memory_object_offset_t offset,
1394 upl_size_t *upl_size,
1395 upl_t *upl_ptr,
1396 upl_page_info_array_t user_page_list,
1397 unsigned int *page_list_count,
1398 upl_control_flags_t *flags,
1399 vm_tag_t tag)
55e303ae 1400{
0a7de745
A
1401 vm_object_t object;
1402 kern_return_t ret;
1403 upl_control_flags_t caller_flags;
55e303ae
A
1404
1405 caller_flags = *flags;
1406
91447636
A
1407 if (caller_flags & ~UPL_VALID_FLAGS) {
1408 /*
1409 * For forward compatibility's sake,
1410 * reject any unknown flag.
1411 */
1412 return KERN_INVALID_VALUE;
1413 }
1414
55e303ae 1415 if (ip_kotype(port) == IKOT_NAMED_ENTRY) {
0a7de745 1416 vm_named_entry_t named_entry;
55e303ae 1417
ea3f0419 1418 named_entry = (vm_named_entry_t) ip_get_kobject(port);
55e303ae 1419 /* a few checks to make sure user is obeying rules */
0a7de745
A
1420 if (*upl_size == 0) {
1421 if (offset >= named_entry->size) {
1422 return KERN_INVALID_RIGHT;
1423 }
b0d623f7 1424 *upl_size = (upl_size_t)(named_entry->size - offset);
0a7de745 1425 if (*upl_size != named_entry->size - offset) {
b0d623f7 1426 return KERN_INVALID_ARGUMENT;
0a7de745 1427 }
55e303ae 1428 }
0a7de745
A
1429 if (caller_flags & UPL_COPYOUT_FROM) {
1430 if ((named_entry->protection & VM_PROT_READ)
1431 != VM_PROT_READ) {
1432 return KERN_INVALID_RIGHT;
55e303ae
A
1433 }
1434 } else {
0a7de745
A
1435 if ((named_entry->protection &
1436 (VM_PROT_READ | VM_PROT_WRITE))
1437 != (VM_PROT_READ | VM_PROT_WRITE)) {
1438 return KERN_INVALID_RIGHT;
55e303ae
A
1439 }
1440 }
0a7de745
A
1441 if (named_entry->size < (offset + *upl_size)) {
1442 return KERN_INVALID_ARGUMENT;
1443 }
55e303ae
A
1444
1445 /* the callers parameter offset is defined to be the */
1446 /* offset from beginning of named entry offset in object */
1447 offset = offset + named_entry->offset;
f427ee49 1448 offset += named_entry->data_offset;
55e303ae 1449
39236c6e 1450 if (named_entry->is_sub_map ||
0a7de745 1451 named_entry->is_copy) {
39236c6e 1452 return KERN_INVALID_ARGUMENT;
0a7de745 1453 }
f427ee49
A
1454 if (!named_entry->is_object) {
1455 return KERN_INVALID_ARGUMENT;
1456 }
0a7de745 1457
55e303ae
A
1458 named_entry_lock(named_entry);
1459
f427ee49
A
1460 object = vm_named_entry_to_vm_object(named_entry);
1461 assert(object != VM_OBJECT_NULL);
5ba3f43e
A
1462 vm_object_reference(object);
1463 named_entry_unlock(named_entry);
0c530ab8 1464 } else if (ip_kotype(port) == IKOT_MEM_OBJ_CONTROL) {
0a7de745 1465 memory_object_control_t control;
0c530ab8 1466 control = (memory_object_control_t) port;
0a7de745
A
1467 if (control == NULL) {
1468 return KERN_INVALID_ARGUMENT;
1469 }
55e303ae 1470 object = memory_object_control_to_vm_object(control);
0a7de745
A
1471 if (object == VM_OBJECT_NULL) {
1472 return KERN_INVALID_ARGUMENT;
1473 }
55e303ae 1474 vm_object_reference(object);
0c530ab8
A
1475 } else {
1476 return KERN_INVALID_ARGUMENT;
55e303ae 1477 }
0a7de745
A
1478 if (object == VM_OBJECT_NULL) {
1479 return KERN_INVALID_ARGUMENT;
1480 }
55e303ae
A
1481
1482 if (!object->private) {
55e303ae
A
1483 if (object->phys_contiguous) {
1484 *flags = UPL_PHYS_CONTIG;
1485 } else {
1486 *flags = 0;
1487 }
1488 } else {
1489 *flags = UPL_DEV_MEMORY | UPL_PHYS_CONTIG;
1490 }
1491
1492 ret = vm_object_iopl_request(object,
0a7de745
A
1493 offset,
1494 *upl_size,
1495 upl_ptr,
1496 user_page_list,
1497 page_list_count,
1498 caller_flags,
1499 tag);
55e303ae
A
1500 vm_object_deallocate(object);
1501 return ret;
1502}
1503
0a7de745 1504/*
0b4e3aa0
A
1505 * Routine: memory_object_upl_request [interface]
1506 * Purpose:
1507 * Cause the population of a portion of a vm_object.
1508 * Depending on the nature of the request, the pages
1509 * returned may be contain valid data or be uninitialized.
1510 *
1511 */
1c79356b 1512
0b4e3aa0
A
1513kern_return_t
1514memory_object_upl_request(
0a7de745
A
1515 memory_object_control_t control,
1516 memory_object_offset_t offset,
1517 upl_size_t size,
1518 upl_t *upl_ptr,
1519 upl_page_info_array_t user_page_list,
1520 unsigned int *page_list_count,
1521 int cntrl_flags,
1522 int tag)
0b4e3aa0 1523{
0a7de745 1524 vm_object_t object;
f427ee49
A
1525 vm_tag_t vmtag = (vm_tag_t)tag;
1526 assert(vmtag == tag);
0b4e3aa0
A
1527
1528 object = memory_object_control_to_vm_object(control);
0a7de745
A
1529 if (object == VM_OBJECT_NULL) {
1530 return KERN_TERMINATED;
1531 }
0b4e3aa0
A
1532
1533 return vm_object_upl_request(object,
0a7de745
A
1534 offset,
1535 size,
1536 upl_ptr,
1537 user_page_list,
1538 page_list_count,
1539 (upl_control_flags_t)(unsigned int) cntrl_flags,
f427ee49 1540 vmtag);
0b4e3aa0
A
1541}
1542
0a7de745 1543/*
0b4e3aa0
A
1544 * Routine: memory_object_super_upl_request [interface]
1545 * Purpose:
1546 * Cause the population of a portion of a vm_object
1547 * in much the same way as memory_object_upl_request.
1548 * Depending on the nature of the request, the pages
1549 * returned may be contain valid data or be uninitialized.
1550 * However, the region may be expanded up to the super
1551 * cluster size provided.
1c79356b 1552 */
0b4e3aa0 1553
1c79356b 1554kern_return_t
0b4e3aa0
A
1555memory_object_super_upl_request(
1556 memory_object_control_t control,
0a7de745
A
1557 memory_object_offset_t offset,
1558 upl_size_t size,
1559 upl_size_t super_cluster,
1560 upl_t *upl,
1561 upl_page_info_t *user_page_list,
1562 unsigned int *page_list_count,
1563 int cntrl_flags,
1564 int tag)
1c79356b 1565{
0a7de745 1566 vm_object_t object;
f427ee49
A
1567 vm_tag_t vmtag = (vm_tag_t)tag;
1568 assert(vmtag == tag);
0b4e3aa0
A
1569
1570 object = memory_object_control_to_vm_object(control);
0a7de745
A
1571 if (object == VM_OBJECT_NULL) {
1572 return KERN_INVALID_ARGUMENT;
1573 }
0b4e3aa0
A
1574
1575 return vm_object_super_upl_request(object,
0a7de745
A
1576 offset,
1577 size,
1578 super_cluster,
1579 upl,
1580 user_page_list,
1581 page_list_count,
1582 (upl_control_flags_t)(unsigned int) cntrl_flags,
f427ee49 1583 vmtag);
1c79356b
A
1584}
1585
2d21ac55 1586kern_return_t
d9a64523 1587memory_object_cluster_size(
0a7de745
A
1588 memory_object_control_t control,
1589 memory_object_offset_t *start,
1590 vm_size_t *length,
1591 uint32_t *io_streaming,
d9a64523 1592 memory_object_fault_info_t mo_fault_info)
2d21ac55 1593{
0a7de745
A
1594 vm_object_t object;
1595 vm_object_fault_info_t fault_info;
2d21ac55
A
1596
1597 object = memory_object_control_to_vm_object(control);
1598
0a7de745 1599 if (object == VM_OBJECT_NULL || object->paging_offset > *start) {
d9a64523 1600 return KERN_INVALID_ARGUMENT;
0a7de745 1601 }
2d21ac55
A
1602
1603 *start -= object->paging_offset;
1604
d9a64523
A
1605 fault_info = (vm_object_fault_info_t)(uintptr_t) mo_fault_info;
1606 vm_object_cluster_size(object,
0a7de745
A
1607 (vm_object_offset_t *)start,
1608 length,
1609 fault_info,
1610 io_streaming);
2d21ac55
A
1611
1612 *start += object->paging_offset;
1613
d9a64523 1614 return KERN_SUCCESS;
2d21ac55
A
1615}
1616
1617
1c79356b 1618/*
0b4e3aa0 1619 * Routine: host_default_memory_manager [interface]
1c79356b
A
1620 * Purpose:
1621 * set/get the default memory manager port and default cluster
1622 * size.
1623 *
1624 * If successful, consumes the supplied naked send right.
1625 */
1626kern_return_t
1627host_default_memory_manager(
0a7de745
A
1628 host_priv_t host_priv,
1629 memory_object_default_t *default_manager,
2d21ac55 1630 __unused memory_object_cluster_size_t cluster_size)
1c79356b 1631{
0b4e3aa0
A
1632 memory_object_default_t current_manager;
1633 memory_object_default_t new_manager;
1634 memory_object_default_t returned_manager;
2d21ac55 1635 kern_return_t result = KERN_SUCCESS;
1c79356b 1636
0a7de745
A
1637 if (host_priv == HOST_PRIV_NULL) {
1638 return KERN_INVALID_HOST;
1639 }
1c79356b
A
1640
1641 assert(host_priv == &realhost);
1642
1643 new_manager = *default_manager;
b0d623f7 1644 lck_mtx_lock(&memory_manager_default_lock);
1c79356b 1645 current_manager = memory_manager_default;
2d21ac55 1646 returned_manager = MEMORY_OBJECT_DEFAULT_NULL;
1c79356b 1647
0b4e3aa0 1648 if (new_manager == MEMORY_OBJECT_DEFAULT_NULL) {
1c79356b
A
1649 /*
1650 * Retrieve the current value.
1651 */
0b4e3aa0 1652 returned_manager = current_manager;
2d21ac55 1653 memory_object_default_reference(returned_manager);
1c79356b 1654 } else {
3e170ce0
A
1655 /*
1656 * Only allow the kernel to change the value.
1657 */
1658 extern task_t kernel_task;
1659 if (current_task() != kernel_task) {
1660 result = KERN_NO_ACCESS;
1661 goto out;
1662 }
2d21ac55
A
1663
1664 /*
1665 * If this is the first non-null manager, start
1666 * up the internal pager support.
1667 */
1668 if (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
1669 result = vm_pageout_internal_start();
0a7de745 1670 if (result != KERN_SUCCESS) {
2d21ac55 1671 goto out;
0a7de745 1672 }
2d21ac55
A
1673 }
1674
1c79356b
A
1675 /*
1676 * Retrieve the current value,
1677 * and replace it with the supplied value.
0b4e3aa0
A
1678 * We return the old reference to the caller
1679 * but we have to take a reference on the new
1680 * one.
1c79356b 1681 */
1c79356b
A
1682 returned_manager = current_manager;
1683 memory_manager_default = new_manager;
0b4e3aa0
A
1684 memory_object_default_reference(new_manager);
1685
1c79356b
A
1686 /*
1687 * In case anyone's been waiting for a memory
1688 * manager to be established, wake them up.
1689 */
1690
1691 thread_wakeup((event_t) &memory_manager_default);
b0d623f7
A
1692
1693 /*
1694 * Now that we have a default pager for anonymous memory,
1695 * reactivate all the throttled pages (i.e. dirty pages with
1696 * no pager).
1697 */
0a7de745 1698 if (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
b0d623f7
A
1699 vm_page_reactivate_all_throttled();
1700 }
1c79356b 1701 }
0a7de745 1702out:
b0d623f7 1703 lck_mtx_unlock(&memory_manager_default_lock);
1c79356b
A
1704
1705 *default_manager = returned_manager;
0a7de745 1706 return result;
1c79356b
A
1707}
1708
1709/*
1710 * Routine: memory_manager_default_reference
1711 * Purpose:
1712 * Returns a naked send right for the default
1713 * memory manager. The returned right is always
1714 * valid (not IP_NULL or IP_DEAD).
1715 */
1716
0b4e3aa0 1717__private_extern__ memory_object_default_t
2d21ac55 1718memory_manager_default_reference(void)
1c79356b 1719{
0b4e3aa0 1720 memory_object_default_t current_manager;
1c79356b 1721
b0d623f7 1722 lck_mtx_lock(&memory_manager_default_lock);
0b4e3aa0
A
1723 current_manager = memory_manager_default;
1724 while (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
9bccf70c
A
1725 wait_result_t res;
1726
b0d623f7 1727 res = lck_mtx_sleep(&memory_manager_default_lock,
0a7de745
A
1728 LCK_SLEEP_DEFAULT,
1729 (event_t) &memory_manager_default,
1730 THREAD_UNINT);
9bccf70c 1731 assert(res == THREAD_AWAKENED);
0b4e3aa0 1732 current_manager = memory_manager_default;
1c79356b 1733 }
0b4e3aa0 1734 memory_object_default_reference(current_manager);
b0d623f7 1735 lck_mtx_unlock(&memory_manager_default_lock);
1c79356b
A
1736
1737 return current_manager;
1738}
1739
1c79356b
A
1740/*
1741 * Routine: memory_manager_default_check
1742 *
1743 * Purpose:
1744 * Check whether a default memory manager has been set
1745 * up yet, or not. Returns KERN_SUCCESS if dmm exists,
1746 * and KERN_FAILURE if dmm does not exist.
1747 *
1748 * If there is no default memory manager, log an error,
1749 * but only the first time.
1750 *
1751 */
0b4e3aa0 1752__private_extern__ kern_return_t
1c79356b
A
1753memory_manager_default_check(void)
1754{
0b4e3aa0 1755 memory_object_default_t current;
1c79356b 1756
b0d623f7 1757 lck_mtx_lock(&memory_manager_default_lock);
1c79356b 1758 current = memory_manager_default;
0b4e3aa0 1759 if (current == MEMORY_OBJECT_DEFAULT_NULL) {
0a7de745
A
1760 static boolean_t logged; /* initialized to 0 */
1761 boolean_t complain = !logged;
1c79356b 1762 logged = TRUE;
b0d623f7 1763 lck_mtx_unlock(&memory_manager_default_lock);
0a7de745 1764 if (complain) {
1c79356b 1765 printf("Warning: No default memory manager\n");
0a7de745
A
1766 }
1767 return KERN_FAILURE;
1c79356b 1768 } else {
b0d623f7 1769 lck_mtx_unlock(&memory_manager_default_lock);
0a7de745 1770 return KERN_SUCCESS;
1c79356b
A
1771 }
1772}
1773
1c79356b
A
1774/* Allow manipulation of individual page state. This is actually part of */
1775/* the UPL regimen but takes place on the object rather than on a UPL */
1776
1777kern_return_t
1778memory_object_page_op(
0a7de745
A
1779 memory_object_control_t control,
1780 memory_object_offset_t offset,
1781 int ops,
1782 ppnum_t *phys_entry,
1783 int *flags)
1c79356b 1784{
0a7de745 1785 vm_object_t object;
0b4e3aa0
A
1786
1787 object = memory_object_control_to_vm_object(control);
0a7de745
A
1788 if (object == VM_OBJECT_NULL) {
1789 return KERN_INVALID_ARGUMENT;
1790 }
1c79356b 1791
0c530ab8 1792 return vm_object_page_op(object, offset, ops, phys_entry, flags);
1c79356b
A
1793}
1794
55e303ae 1795/*
0a7de745
A
1796 * memory_object_range_op offers performance enhancement over
1797 * memory_object_page_op for page_op functions which do not require page
1798 * level state to be returned from the call. Page_op was created to provide
1799 * a low-cost alternative to page manipulation via UPLs when only a single
1800 * page was involved. The range_op call establishes the ability in the _op
55e303ae
A
1801 * family of functions to work on multiple pages where the lack of page level
1802 * state handling allows the caller to avoid the overhead of the upl structures.
1803 */
1804
1805kern_return_t
1806memory_object_range_op(
0a7de745
A
1807 memory_object_control_t control,
1808 memory_object_offset_t offset_beg,
1809 memory_object_offset_t offset_end,
55e303ae
A
1810 int ops,
1811 int *range)
1812{
0a7de745 1813 vm_object_t object;
55e303ae
A
1814
1815 object = memory_object_control_to_vm_object(control);
0a7de745
A
1816 if (object == VM_OBJECT_NULL) {
1817 return KERN_INVALID_ARGUMENT;
1818 }
55e303ae 1819
0c530ab8 1820 return vm_object_range_op(object,
0a7de745
A
1821 offset_beg,
1822 offset_end,
1823 ops,
1824 (uint32_t *) range);
55e303ae
A
1825}
1826
91447636 1827
6d2010ae
A
1828void
1829memory_object_mark_used(
0a7de745 1830 memory_object_control_t control)
6d2010ae 1831{
0a7de745 1832 vm_object_t object;
6d2010ae 1833
0a7de745 1834 if (control == NULL) {
6d2010ae 1835 return;
0a7de745 1836 }
6d2010ae
A
1837
1838 object = memory_object_control_to_vm_object(control);
1839
0a7de745 1840 if (object != VM_OBJECT_NULL) {
6d2010ae 1841 vm_object_cache_remove(object);
0a7de745 1842 }
6d2010ae
A
1843}
1844
1845
1846void
1847memory_object_mark_unused(
0a7de745
A
1848 memory_object_control_t control,
1849 __unused boolean_t rage)
6d2010ae 1850{
0a7de745 1851 vm_object_t object;
6d2010ae 1852
0a7de745 1853 if (control == NULL) {
6d2010ae 1854 return;
0a7de745 1855 }
6d2010ae
A
1856
1857 object = memory_object_control_to_vm_object(control);
1858
0a7de745 1859 if (object != VM_OBJECT_NULL) {
6d2010ae 1860 vm_object_cache_add(object);
0a7de745 1861 }
6d2010ae
A
1862}
1863
fe8ab488
A
1864void
1865memory_object_mark_io_tracking(
1866 memory_object_control_t control)
1867{
1868 vm_object_t object;
1869
0a7de745 1870 if (control == NULL) {
fe8ab488 1871 return;
0a7de745 1872 }
fe8ab488
A
1873 object = memory_object_control_to_vm_object(control);
1874
1875 if (object != VM_OBJECT_NULL) {
1876 vm_object_lock(object);
1877 object->io_tracking = TRUE;
1878 vm_object_unlock(object);
1879 }
1880}
6d2010ae 1881
cb323159
A
1882void
1883memory_object_mark_trusted(
1884 memory_object_control_t control)
1885{
1886 vm_object_t object;
1887
1888 if (control == NULL) {
1889 return;
1890 }
1891 object = memory_object_control_to_vm_object(control);
1892
1893 if (object != VM_OBJECT_NULL) {
1894 vm_object_lock(object);
1895 object->pager_trusted = TRUE;
1896 vm_object_unlock(object);
1897 }
1898}
1899
39037602
A
1900#if CONFIG_SECLUDED_MEMORY
1901void
1902memory_object_mark_eligible_for_secluded(
1903 memory_object_control_t control,
0a7de745 1904 boolean_t eligible_for_secluded)
39037602
A
1905{
1906 vm_object_t object;
1907
0a7de745 1908 if (control == NULL) {
39037602 1909 return;
0a7de745 1910 }
39037602
A
1911 object = memory_object_control_to_vm_object(control);
1912
1913 if (object == VM_OBJECT_NULL) {
1914 return;
1915 }
1916
1917 vm_object_lock(object);
1918 if (eligible_for_secluded &&
1919 secluded_for_filecache && /* global boot-arg */
1920 !object->eligible_for_secluded) {
1921 object->eligible_for_secluded = TRUE;
1922 vm_page_secluded.eligible_for_secluded += object->resident_page_count;
1923 } else if (!eligible_for_secluded &&
0a7de745 1924 object->eligible_for_secluded) {
39037602
A
1925 object->eligible_for_secluded = FALSE;
1926 vm_page_secluded.eligible_for_secluded -= object->resident_page_count;
1927 if (object->resident_page_count) {
1928 /* XXX FBDP TODO: flush pages from secluded queue? */
1929 // printf("FBDP TODO: flush %d pages from %p from secluded queue\n", object->resident_page_count, object);
1930 }
1931 }
1932 vm_object_unlock(object);
1933}
1934#endif /* CONFIG_SECLUDED_MEMORY */
1935
91447636
A
1936kern_return_t
1937memory_object_pages_resident(
0a7de745
A
1938 memory_object_control_t control,
1939 boolean_t * has_pages_resident)
91447636 1940{
0a7de745 1941 vm_object_t object;
91447636
A
1942
1943 *has_pages_resident = FALSE;
1944
1945 object = memory_object_control_to_vm_object(control);
0a7de745
A
1946 if (object == VM_OBJECT_NULL) {
1947 return KERN_INVALID_ARGUMENT;
1948 }
91447636 1949
0a7de745 1950 if (object->resident_page_count) {
91447636 1951 *has_pages_resident = TRUE;
0a7de745
A
1952 }
1953
1954 return KERN_SUCCESS;
91447636
A
1955}
1956
2d21ac55
A
1957kern_return_t
1958memory_object_signed(
0a7de745
A
1959 memory_object_control_t control,
1960 boolean_t is_signed)
2d21ac55 1961{
0a7de745 1962 vm_object_t object;
2d21ac55
A
1963
1964 object = memory_object_control_to_vm_object(control);
0a7de745 1965 if (object == VM_OBJECT_NULL) {
2d21ac55 1966 return KERN_INVALID_ARGUMENT;
0a7de745 1967 }
2d21ac55
A
1968
1969 vm_object_lock(object);
1970 object->code_signed = is_signed;
1971 vm_object_unlock(object);
1972
1973 return KERN_SUCCESS;
1974}
91447636 1975
39236c6e
A
1976boolean_t
1977memory_object_is_signed(
0a7de745 1978 memory_object_control_t control)
39236c6e 1979{
0a7de745
A
1980 boolean_t is_signed;
1981 vm_object_t object;
39236c6e
A
1982
1983 object = memory_object_control_to_vm_object(control);
0a7de745 1984 if (object == VM_OBJECT_NULL) {
39236c6e 1985 return FALSE;
0a7de745 1986 }
39236c6e
A
1987
1988 vm_object_lock_shared(object);
1989 is_signed = object->code_signed;
1990 vm_object_unlock(object);
1991
1992 return is_signed;
1993}
1994
6d2010ae 1995boolean_t
d9a64523 1996memory_object_is_shared_cache(
0a7de745 1997 memory_object_control_t control)
6d2010ae 1998{
0a7de745 1999 vm_object_t object = VM_OBJECT_NULL;
6d2010ae
A
2000
2001 object = memory_object_control_to_vm_object(control);
0a7de745 2002 if (object == VM_OBJECT_NULL) {
6d2010ae 2003 return FALSE;
0a7de745 2004 }
6d2010ae 2005
d9a64523 2006 return object->object_is_shared_cache;
6d2010ae
A
2007}
2008
f427ee49
A
2009static ZONE_DECLARE(mem_obj_control_zone, "mem_obj_control",
2010 sizeof(struct memory_object_control), ZC_NOENCRYPT);
0b4e3aa0
A
2011
2012__private_extern__ memory_object_control_t
2013memory_object_control_allocate(
0a7de745
A
2014 vm_object_t object)
2015{
0b4e3aa0
A
2016 memory_object_control_t control;
2017
2018 control = (memory_object_control_t)zalloc(mem_obj_control_zone);
0c530ab8
A
2019 if (control != MEMORY_OBJECT_CONTROL_NULL) {
2020 control->moc_object = object;
2021 control->moc_ikot = IKOT_MEM_OBJ_CONTROL; /* fake ip_kotype */
2022 }
0a7de745 2023 return control;
0b4e3aa0
A
2024}
2025
2026__private_extern__ void
2027memory_object_control_collapse(
0a7de745
A
2028 memory_object_control_t control,
2029 vm_object_t object)
2030{
0c530ab8 2031 assert((control->moc_object != VM_OBJECT_NULL) &&
0a7de745 2032 (control->moc_object != object));
0c530ab8 2033 control->moc_object = object;
0b4e3aa0
A
2034}
2035
2036__private_extern__ vm_object_t
2037memory_object_control_to_vm_object(
0a7de745 2038 memory_object_control_t control)
0b4e3aa0 2039{
0c530ab8 2040 if (control == MEMORY_OBJECT_CONTROL_NULL ||
0a7de745 2041 control->moc_ikot != IKOT_MEM_OBJ_CONTROL) {
0b4e3aa0 2042 return VM_OBJECT_NULL;
0a7de745 2043 }
0b4e3aa0 2044
0a7de745 2045 return control->moc_object;
0b4e3aa0
A
2046}
2047
5ba3f43e
A
2048__private_extern__ vm_object_t
2049memory_object_to_vm_object(
2050 memory_object_t mem_obj)
2051{
2052 memory_object_control_t mo_control;
2053
2054 if (mem_obj == MEMORY_OBJECT_NULL) {
2055 return VM_OBJECT_NULL;
2056 }
2057 mo_control = mem_obj->mo_control;
2058 if (mo_control == NULL) {
2059 return VM_OBJECT_NULL;
2060 }
2061 return memory_object_control_to_vm_object(mo_control);
2062}
2063
0b4e3aa0
A
2064memory_object_control_t
2065convert_port_to_mo_control(
0a7de745 2066 __unused mach_port_t port)
0b4e3aa0
A
2067{
2068 return MEMORY_OBJECT_CONTROL_NULL;
2069}
2070
2071
2072mach_port_t
2073convert_mo_control_to_port(
0a7de745 2074 __unused memory_object_control_t control)
0b4e3aa0
A
2075{
2076 return MACH_PORT_NULL;
2077}
2078
2079void
2080memory_object_control_reference(
0a7de745 2081 __unused memory_object_control_t control)
0b4e3aa0
A
2082{
2083 return;
2084}
2085
2086/*
2087 * We only every issue one of these references, so kill it
2088 * when that gets released (should switch the real reference
2089 * counting in true port-less EMMI).
2090 */
2091void
2092memory_object_control_deallocate(
0a7de745 2093 memory_object_control_t control)
0b4e3aa0 2094{
91447636 2095 zfree(mem_obj_control_zone, control);
0b4e3aa0
A
2096}
2097
2098void
2099memory_object_control_disable(
0a7de745 2100 memory_object_control_t control)
0b4e3aa0 2101{
0c530ab8
A
2102 assert(control->moc_object != VM_OBJECT_NULL);
2103 control->moc_object = VM_OBJECT_NULL;
0b4e3aa0
A
2104}
2105
2106void
2107memory_object_default_reference(
2108 memory_object_default_t dmm)
2109{
2110 ipc_port_make_send(dmm);
2111}
2112
2113void
2114memory_object_default_deallocate(
2115 memory_object_default_t dmm)
2116{
2117 ipc_port_release_send(dmm);
2118}
2119
2120memory_object_t
2121convert_port_to_memory_object(
0a7de745 2122 __unused mach_port_t port)
0b4e3aa0 2123{
0a7de745 2124 return MEMORY_OBJECT_NULL;
0b4e3aa0
A
2125}
2126
2127
2128mach_port_t
2129convert_memory_object_to_port(
0a7de745 2130 __unused memory_object_t object)
0b4e3aa0 2131{
0a7de745 2132 return MACH_PORT_NULL;
0b4e3aa0
A
2133}
2134
0b4e3aa0
A
2135
2136/* Routine memory_object_reference */
0a7de745
A
2137void
2138memory_object_reference(
0b4e3aa0
A
2139 memory_object_t memory_object)
2140{
0c530ab8
A
2141 (memory_object->mo_pager_ops->memory_object_reference)(
2142 memory_object);
0b4e3aa0
A
2143}
2144
2145/* Routine memory_object_deallocate */
0a7de745
A
2146void
2147memory_object_deallocate(
0b4e3aa0
A
2148 memory_object_t memory_object)
2149{
0c530ab8 2150 (memory_object->mo_pager_ops->memory_object_deallocate)(
0a7de745 2151 memory_object);
0b4e3aa0
A
2152}
2153
2154
2155/* Routine memory_object_init */
0a7de745
A
2156kern_return_t
2157memory_object_init
0b4e3aa0
A
2158(
2159 memory_object_t memory_object,
2160 memory_object_control_t memory_control,
91447636 2161 memory_object_cluster_size_t memory_object_page_size
0b4e3aa0
A
2162)
2163{
0c530ab8
A
2164 return (memory_object->mo_pager_ops->memory_object_init)(
2165 memory_object,
2166 memory_control,
2167 memory_object_page_size);
0b4e3aa0
A
2168}
2169
2170/* Routine memory_object_terminate */
0a7de745
A
2171kern_return_t
2172memory_object_terminate
0b4e3aa0
A
2173(
2174 memory_object_t memory_object
2175)
2176{
0c530ab8
A
2177 return (memory_object->mo_pager_ops->memory_object_terminate)(
2178 memory_object);
0b4e3aa0
A
2179}
2180
2181/* Routine memory_object_data_request */
0a7de745
A
2182kern_return_t
2183memory_object_data_request
0b4e3aa0
A
2184(
2185 memory_object_t memory_object,
2186 memory_object_offset_t offset,
91447636 2187 memory_object_cluster_size_t length,
2d21ac55
A
2188 vm_prot_t desired_access,
2189 memory_object_fault_info_t fault_info
0b4e3aa0
A
2190)
2191{
0c530ab8
A
2192 return (memory_object->mo_pager_ops->memory_object_data_request)(
2193 memory_object,
0a7de745 2194 offset,
0c530ab8 2195 length,
2d21ac55
A
2196 desired_access,
2197 fault_info);
0b4e3aa0
A
2198}
2199
2200/* Routine memory_object_data_return */
0a7de745
A
2201kern_return_t
2202memory_object_data_return
0b4e3aa0
A
2203(
2204 memory_object_t memory_object,
2205 memory_object_offset_t offset,
b0d623f7 2206 memory_object_cluster_size_t size,
91447636 2207 memory_object_offset_t *resid_offset,
0a7de745 2208 int *io_error,
0b4e3aa0 2209 boolean_t dirty,
91447636 2210 boolean_t kernel_copy,
0a7de745 2211 int upl_flags
0b4e3aa0
A
2212)
2213{
0c530ab8
A
2214 return (memory_object->mo_pager_ops->memory_object_data_return)(
2215 memory_object,
2216 offset,
2217 size,
2218 resid_offset,
2219 io_error,
2220 dirty,
2221 kernel_copy,
2222 upl_flags);
0b4e3aa0
A
2223}
2224
2225/* Routine memory_object_data_initialize */
0a7de745
A
2226kern_return_t
2227memory_object_data_initialize
0b4e3aa0
A
2228(
2229 memory_object_t memory_object,
2230 memory_object_offset_t offset,
b0d623f7 2231 memory_object_cluster_size_t size
0b4e3aa0
A
2232)
2233{
0c530ab8
A
2234 return (memory_object->mo_pager_ops->memory_object_data_initialize)(
2235 memory_object,
2236 offset,
2237 size);
0b4e3aa0
A
2238}
2239
2240/* Routine memory_object_data_unlock */
0a7de745
A
2241kern_return_t
2242memory_object_data_unlock
0b4e3aa0
A
2243(
2244 memory_object_t memory_object,
2245 memory_object_offset_t offset,
b0d623f7 2246 memory_object_size_t size,
0b4e3aa0
A
2247 vm_prot_t desired_access
2248)
2249{
0c530ab8
A
2250 return (memory_object->mo_pager_ops->memory_object_data_unlock)(
2251 memory_object,
2252 offset,
2253 size,
2254 desired_access);
0b4e3aa0
A
2255}
2256
2257/* Routine memory_object_synchronize */
0a7de745
A
2258kern_return_t
2259memory_object_synchronize
0b4e3aa0
A
2260(
2261 memory_object_t memory_object,
2262 memory_object_offset_t offset,
b0d623f7 2263 memory_object_size_t size,
0b4e3aa0
A
2264 vm_sync_t sync_flags
2265)
2266{
0a7de745 2267 panic("memory_object_syncrhonize no longer supported\n");
5ba3f43e 2268
0c530ab8
A
2269 return (memory_object->mo_pager_ops->memory_object_synchronize)(
2270 memory_object,
2271 offset,
2272 size,
2273 sync_flags);
0b4e3aa0
A
2274}
2275
593a1d5f
A
2276
2277/*
2278 * memory_object_map() is called by VM (in vm_map_enter() and its variants)
2279 * each time a "named" VM object gets mapped directly or indirectly
2280 * (copy-on-write mapping). A "named" VM object has an extra reference held
0a7de745 2281 * by the pager to keep it alive until the pager decides that the
593a1d5f
A
2282 * memory object (and its VM object) can be reclaimed.
2283 * VM calls memory_object_last_unmap() (in vm_object_deallocate()) when all
2284 * the mappings of that memory object have been removed.
2285 *
2286 * For a given VM object, calls to memory_object_map() and memory_object_unmap()
2287 * are serialized (through object->mapping_in_progress), to ensure that the
2288 * pager gets a consistent view of the mapping status of the memory object.
2289 *
2290 * This allows the pager to keep track of how many times a memory object
2291 * has been mapped and with which protections, to decide when it can be
2292 * reclaimed.
2293 */
2294
2295/* Routine memory_object_map */
0a7de745
A
2296kern_return_t
2297memory_object_map
593a1d5f
A
2298(
2299 memory_object_t memory_object,
2300 vm_prot_t prot
2301)
2302{
2303 return (memory_object->mo_pager_ops->memory_object_map)(
2304 memory_object,
2305 prot);
2306}
2307
2308/* Routine memory_object_last_unmap */
0a7de745
A
2309kern_return_t
2310memory_object_last_unmap
0b4e3aa0
A
2311(
2312 memory_object_t memory_object
2313)
2314{
593a1d5f 2315 return (memory_object->mo_pager_ops->memory_object_last_unmap)(
0c530ab8 2316 memory_object);
0b4e3aa0
A
2317}
2318
6d2010ae 2319/* Routine memory_object_data_reclaim */
0a7de745
A
2320kern_return_t
2321memory_object_data_reclaim
6d2010ae
A
2322(
2323 memory_object_t memory_object,
0a7de745 2324 boolean_t reclaim_backing_store
6d2010ae
A
2325)
2326{
0a7de745 2327 if (memory_object->mo_pager_ops->memory_object_data_reclaim == NULL) {
6d2010ae 2328 return KERN_NOT_SUPPORTED;
0a7de745 2329 }
6d2010ae
A
2330 return (memory_object->mo_pager_ops->memory_object_data_reclaim)(
2331 memory_object,
2332 reclaim_backing_store);
2333}
2334
a991bd8d
A
2335boolean_t
2336memory_object_backing_object
2337(
2338 memory_object_t memory_object,
2339 memory_object_offset_t offset,
2340 vm_object_t *backing_object,
2341 vm_object_offset_t *backing_offset)
2342{
2343 if (memory_object->mo_pager_ops->memory_object_backing_object == NULL) {
2344 return FALSE;
2345 }
2346 return (memory_object->mo_pager_ops->memory_object_backing_object)(
2347 memory_object,
2348 offset,
2349 backing_object,
2350 backing_offset);
2351}
2352
91447636
A
2353upl_t
2354convert_port_to_upl(
0a7de745 2355 ipc_port_t port)
91447636
A
2356{
2357 upl_t upl;
2358
2359 ip_lock(port);
2360 if (!ip_active(port) || (ip_kotype(port) != IKOT_UPL)) {
0a7de745
A
2361 ip_unlock(port);
2362 return (upl_t)NULL;
91447636 2363 }
ea3f0419 2364 upl = (upl_t) ip_get_kobject(port);
91447636
A
2365 ip_unlock(port);
2366 upl_lock(upl);
0a7de745 2367 upl->ref_count += 1;
91447636
A
2368 upl_unlock(upl);
2369 return upl;
2370}
2371
2372mach_port_t
2373convert_upl_to_port(
0a7de745 2374 __unused upl_t upl)
91447636
A
2375{
2376 return MACH_PORT_NULL;
2377}
2378
2379__private_extern__ void
2380upl_no_senders(
0a7de745
A
2381 __unused ipc_port_t port,
2382 __unused mach_port_mscount_t mscount)
91447636
A
2383{
2384 return;
2385}