|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: vm/memory_object.c
54: * Author: Michael Wayne Young
55: *
56: * External memory management interface control functions.
57: */
58:
59: #ifdef MACH_BSD
60: /* THIS code should be removed when the component merge is completed */
61: extern int vnode_pager_workaround;
62: #endif
63:
64: #include <advisory_pageout.h>
65:
66: /*
67: * Interface dependencies:
68: */
69:
70: #include <mach/std_types.h> /* For pointer_t */
71: #include <mach/mach_types.h>
72:
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>
77: #include <mach/mach_host_server.h>
78: #include <mach/boolean.h>
79: #include <mach/vm_prot.h>
80: #include <mach/message.h>
81:
82: #include <vm/vm_object.h>
83: #include <vm/vm_fault.h>
84: /*
85: * Implementation dependencies:
86: */
87: #include <string.h> /* For memcpy() */
88:
89: #include <vm/memory_object.h>
90: #include <vm/vm_page.h>
91: #include <vm/vm_pageout.h>
92: #include <vm/pmap.h> /* For pmap_clear_modify */
93: #include <kern/xpr.h>
94: #include <kern/thread.h> /* For current_thread() */
95: #include <kern/host.h>
96: #include <vm/vm_kern.h> /* For kernel_map, vm_move */
97: #include <vm/vm_map.h> /* For vm_map_pageable */
98: #include <ipc/ipc_port.h>
99: #include <ipc/ipc_space.h>
100:
101:
102:
103: #include <kern/misc_protos.h>
104:
105: #if MACH_PAGEMAP
106: #include <vm/vm_external.h>
107: #endif /* MACH_PAGEMAP */
108:
109: ipc_port_t memory_manager_default = IP_NULL;
110: vm_size_t memory_manager_default_cluster = 0;
111: decl_mutex_data(,memory_manager_default_lock)
112:
113: /*
114: * Forward ref to file-local function:
115: */
116: boolean_t
117: memory_object_update(vm_object_t,
118: vm_offset_t, vm_size_t, memory_object_return_t, boolean_t, vm_prot_t);
119:
120: /*
121: * Important note:
122: * All of the external (user interface) routines gain a reference
123: * to the object (first argument) as part of the automatic
124: * argument conversion. Explicit deallocation is necessary.
125: */
126:
127: kern_return_t
128: memory_object_data_supply(
129: register
130: vm_object_t object,
131: register
132: vm_offset_t offset,
133: vm_offset_t data,
134: mach_msg_type_number_t data_cnt,
135: vm_prot_t lock_value,
136: boolean_t precious,
137: ipc_port_t reply_to,
138: mach_msg_type_name_t reply_to_type)
139: {
140: vm_map_copy_t data_copy = (vm_map_copy_t)data;
141: kern_return_t result = KERN_SUCCESS;
142: vm_offset_t error_offset = 0;
143: register
144: vm_page_t m;
145: register
146: vm_page_t data_m;
147: vm_size_t original_length;
148: vm_offset_t original_offset;
149: vm_page_t *page_list;
150: boolean_t was_absent;
151: vm_map_copy_t orig_copy = data_copy;
152: boolean_t was_clustered;
153:
154:
155: XPR(XPR_MEMORY_OBJECT,
156: "m_o_data_supply, object 0x%X, offset 0x%X data_cnt 0x%X\n",
157: (integer_t)object, offset, data_cnt, 0, 0);
158:
159: /*
160: * Look for bogus arguments
161: */
162:
163: if (object == VM_OBJECT_NULL) {
164: return(KERN_INVALID_ARGUMENT);
165: }
166:
167: if (lock_value & ~VM_PROT_ALL) {
168: vm_object_deallocate(object);
169: return(KERN_INVALID_ARGUMENT);
170: }
171:
172: if (! page_aligned(data_cnt)) {
173: vm_object_deallocate(object);
174: return(KERN_INVALID_ARGUMENT);
175: }
176:
177: /*
178: * Adjust the offset from the memory object to the offset
179: * within the vm_object.
180: */
181:
182: original_length = data_cnt;
183: original_offset = offset;
184:
185: assert(data_copy->type == VM_MAP_COPY_PAGE_LIST);
186: page_list = &data_copy->cpy_page_list[0];
187:
188: vm_object_lock(object);
189: vm_object_paging_begin(object);
190: offset -= object->paging_offset;
191:
192: /*
193: * Loop over copy stealing pages for pagein.
194: */
195:
196: for (; data_cnt > 0 ; data_cnt -= PAGE_SIZE, offset += PAGE_SIZE) {
197:
198: assert(data_copy != VM_MAP_COPY_NULL);
199: assert(data_copy->type == VM_MAP_COPY_PAGE_LIST);
200: assert(data_copy->cpy_npages > 0);
201: data_m = *page_list;
202:
203: assert( !(data_m == VM_PAGE_NULL || data_m->tabled ||
204: data_m->error || data_m->absent || data_m->fictitious ||
205: data_m->restart));
206:
207: /*
208: * Look up target page and check its state.
209: */
210:
211: retry_lookup:
212: m = vm_page_lookup(object,offset);
213: was_clustered = FALSE;
214: if (m == VM_PAGE_NULL) {
215: was_absent = FALSE;
216: }
217: else {
218: if (m->absent) {
219:
220: /*
221: * Page was requested. Free the busy
222: * page waiting for it. Insertion
223: * of new page happens below.
224: */
225: m->list_req_pending = FALSE;
226: if (m->clustered) {
227: was_clustered = TRUE;
228: m->clustered = FALSE;
229: }
230: if (m->busy) {
231: VM_PAGE_FREE(m);
232: }
233: was_absent = TRUE;
234: }
235: else {
236:
237: /*
238: * Have to wait for page that is busy and
239: * not absent. This is probably going to
240: * be an error, but go back and check.
241: */
242: if (m->busy) {
243: PAGE_ASSERT_WAIT(m, THREAD_UNINT);
244: vm_object_unlock(object);
245: thread_block((void (*)(void))0);
246: vm_object_lock(object);
247: goto retry_lookup;
248: }
249:
250: /*
251: * Page already present; error.
252: * This is an error if data is precious.
253: */
254: result = KERN_MEMORY_PRESENT;
255: error_offset = offset + object->paging_offset;
256:
257: break;
258: }
259: }
260:
261: /*
262: * Ok to pagein page. Target object now has no page
263: * at offset. Set the page parameters, then drop
264: * in new page and set up pageout state. Object is
265: * still locked here.
266: *
267: * Must clear busy bit in page before inserting it.
268: * Ok to skip wakeup logic because nobody else
269: * can possibly know about this page.
270: */
271:
272: data_m->lock_supplied = TRUE;
273: data_m->busy = FALSE;
274: data_m->dirty = FALSE;
275: pmap_clear_modify(data_m->phys_addr);
276:
277: data_m->page_lock = lock_value;
278: if (lock_value != VM_PROT_NONE)
279: data_m->unusual = TRUE;
280: else
281: data_m->unusual = FALSE;
282:
283: data_m->unlock_request = VM_PROT_NONE;
284: data_m->precious = precious;
285:
286: data_m->clustered = was_clustered;
287:
288: vm_page_insert(data_m, object, offset);
289:
290: vm_page_lock_queues();
291: if (was_absent)
292: vm_page_activate(data_m);
293: else
294: vm_page_deactivate(data_m);
295: vm_page_unlock_queues();
296:
297: /*
298: * Null out this page list entry, and advance to next
299: * page.
300: */
301:
302: *page_list++ = VM_PAGE_NULL;
303:
304: if (--(data_copy->cpy_npages) == 0 &&
305: vm_map_copy_has_cont(data_copy)) {
306: vm_map_copy_t new_copy;
307:
308: vm_object_unlock(object);
309: vm_map_copy_invoke_cont(data_copy, &new_copy, &result);
310: vm_object_lock(object);
311:
312: if (result == KERN_SUCCESS) {
313:
314: /*
315: * Consume on success requires that
316: * we keep the original vm_map_copy
317: * around in case something fails.
318: * Free the old copy if it's not the original
319: */
320: if (data_copy != orig_copy) {
321: vm_map_copy_discard(data_copy);
322: }
323:
324: if ((data_copy = new_copy) != VM_MAP_COPY_NULL)
325: page_list = &data_copy->cpy_page_list[0];
326: }
327: else {
328: error_offset = offset + object->paging_offset +
329: PAGE_SIZE;
330: break;
331: }
332: }
333: }
334:
335: vm_object_paging_end(object);
336:
337: /*
338: * If there is a continuation that has not been invoked,
339: * there must have been an error. Abort the continuation.
340: */
341:
342: if (data_copy != VM_MAP_COPY_NULL && vm_map_copy_has_cont(data_copy)) {
343: vm_object_unlock(object);
344: vm_map_copy_abort_cont(data_copy);
345: vm_object_lock(object);
346: }
347:
348: /*
349: * If the pager wants a reply, send it one.
350: */
351:
352: if (IP_VALID(reply_to)) {
353: vm_object_unlock(object);
354: memory_object_supply_completed(
355: reply_to, reply_to_type,
356: object->pager_request,
357: original_offset,
358: original_length,
359: result,
360: error_offset);
361: }
362: else
363: vm_object_unlock(object);
364:
365: vm_object_deallocate(object);
366:
367: /*
368: * Consume on success: The final data copy must be
369: * discarded if it is not the original. The original
370: * gets discarded only if this routine succeeds.
371: */
372: if (data_copy != VM_MAP_COPY_NULL &&
373: data_copy != orig_copy)
374: vm_map_copy_discard(data_copy);
375: if (result == KERN_SUCCESS)
376: vm_map_copy_discard(orig_copy);
377:
378: return(result);
379: }
380:
381: kern_return_t
382: memory_object_data_error(
383: vm_object_t object,
384: vm_offset_t offset,
385: vm_size_t size,
386: kern_return_t error_value)
387: {
388: XPR(XPR_MEMORY_OBJECT,
389: "m_o_data_error, object 0x%X, offset 0x%X size 0x%X\n",
390: (integer_t)object, offset, size, 0, 0);
391:
392: if (object == VM_OBJECT_NULL)
393: return(KERN_INVALID_ARGUMENT);
394:
395: if (size != round_page(size)) {
396: vm_object_deallocate(object);
397: return(KERN_INVALID_ARGUMENT);
398: }
399:
400: vm_object_lock(object);
401: offset -= object->paging_offset;
402:
403: while (size != 0) {
404: register vm_page_t m;
405:
406: m = vm_page_lookup(object, offset);
407: if ((m != VM_PAGE_NULL) && m->busy && m->absent) {
408: if (error_value == KERN_MEMORY_DATA_MOVED) {
409: m->restart = TRUE;
410: } else {
411: if (error_value > KERN_RETURN_MAX) {
412: m->page_error = error_value;
413: } else {
414: m->page_error = KERN_MEMORY_ERROR;
415: }
416: m->error = TRUE;
417: }
418:
419: /*
420: * m->unusual was true because page was absent.
421: * It remains true because page is either error
422: * or restart.
423: */
424: m->absent = FALSE;
425: vm_object_absent_release(object);
426:
427: PAGE_WAKEUP_DONE(m);
428:
429: /*
430: * If this page was not requested (clustered is set),
431: * then throw it away since there is no one to which
432: * an error can be reported.
433: */
434: vm_page_lock_queues();
435: if (m->clustered)
436: vm_page_free(m);
437: else
438: vm_page_activate(m);
439: vm_page_unlock_queues();
440: }
441:
442: size -= PAGE_SIZE;
443: offset += PAGE_SIZE;
444: }
445: vm_object_unlock(object);
446:
447: vm_object_deallocate(object);
448: return(KERN_SUCCESS);
449: }
450:
451: kern_return_t
452: memory_object_data_unavailable(
453: vm_object_t object,
454: vm_offset_t offset,
455: vm_size_t size)
456: {
457: XPR(XPR_MEMORY_OBJECT,
458: "m_o_data_unavailable, object 0x%X, offset 0x%X size 0x%X\n",
459: (integer_t)object, offset, size, 0, 0);
460:
461: if (object == VM_OBJECT_NULL)
462: return(KERN_INVALID_ARGUMENT);
463:
464: if (size != round_page(size)) {
465: vm_object_deallocate(object);
466: return(KERN_INVALID_ARGUMENT);
467: }
468:
469: vm_object_lock(object);
470: offset -= object->paging_offset;
471:
472: while (size != 0) {
473: register vm_page_t m;
474:
475: /*
476: * We're looking for pages that are both busy and
477: * absent (waiting to be filled), converting them
478: * to just absent.
479: *
480: * Pages that are just busy can be ignored entirely.
481: */
482:
483: m = vm_page_lookup(object, offset);
484: if (m == VM_PAGE_NULL) {
485: if (object->absent_count < vm_object_absent_max)
486: m = vm_page_grab_fictitious();
487: if (m != VM_PAGE_NULL) {
488: m->absent = TRUE;
489: m->unusual = TRUE;
490: m->clustered = FALSE;
491: object->absent_count++;
492: vm_page_lock_queues();
493: vm_page_insert(m, object, offset);
494: vm_page_activate(m);
495: vm_page_unlock_queues();
496: PAGE_WAKEUP_DONE(m);
497: }
498: } else if (m->busy && m->absent) {
499: /* only consider real pageins in clustering stats */
500: m->clustered = FALSE;
501:
502: PAGE_WAKEUP_DONE(m);
503:
504: vm_page_lock_queues();
505: vm_page_activate(m);
506: vm_page_unlock_queues();
507: }
508: size -= PAGE_SIZE;
509: offset += PAGE_SIZE;
510: }
511:
512: vm_object_unlock(object);
513:
514: vm_object_deallocate(object);
515: return(KERN_SUCCESS);
516: }
517:
518: /*
519: * Routine: memory_object_should_return_page
520: *
521: * Description:
522: * Determine whether the given page should be returned,
523: * based on the page's state and on the given return policy.
524: *
525: * We should return the page if one of the following is true:
526: *
527: * 1. Page is dirty and should_return is not RETURN_NONE.
528: * 2. Page is precious and should_return is RETURN_ALL.
529: * 3. Should_return is RETURN_ANYTHING.
530: *
531: * As a side effect, m->dirty will be made consistent
532: * with pmap_is_modified(m), if should_return is not
533: * MEMORY_OBJECT_RETURN_NONE.
534: */
535:
536: #define memory_object_should_return_page(m, should_return) \
537: (should_return != MEMORY_OBJECT_RETURN_NONE && \
538: (((m)->dirty || ((m)->dirty = pmap_is_modified((m)->phys_addr))) || \
539: ((m)->precious && (should_return) == MEMORY_OBJECT_RETURN_ALL) || \
540: (should_return) == MEMORY_OBJECT_RETURN_ANYTHING))
541:
542: typedef int memory_object_lock_result_t;
543:
544: #define MEMORY_OBJECT_LOCK_RESULT_DONE 0
545: #define MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK 1
546: #define MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN 2
547: #define MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN 3
548:
549: memory_object_lock_result_t memory_object_lock_page(
550: vm_page_t m,
551: memory_object_return_t should_return,
552: boolean_t should_flush,
553: vm_prot_t prot);
554:
555: /*
556: * Routine: memory_object_lock_page
557: *
558: * Description:
559: * Perform the appropriate lock operations on the
560: * given page. See the description of
561: * "memory_object_lock_request" for the meanings
562: * of the arguments.
563: *
564: * Returns an indication that the operation
565: * completed, blocked, or that the page must
566: * be cleaned.
567: */
568: memory_object_lock_result_t
569: memory_object_lock_page(
570: vm_page_t m,
571: memory_object_return_t should_return,
572: boolean_t should_flush,
573: vm_prot_t prot)
574: {
575: XPR(XPR_MEMORY_OBJECT,
576: "m_o_lock_page, page 0x%X rtn %d flush %d prot %d\n",
577: (integer_t)m, should_return, should_flush, prot, 0);
578:
579: /*
580: * Don't worry about pages for which the kernel
581: * does not have any data.
582: */
583:
584: if (m->absent || m->error || m->restart)
585: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
586:
587: /*
588: * If we cannot change access to the page,
589: * either because a mapping is in progress
590: * (busy page) or because a mapping has been
591: * wired, then give up.
592: */
593:
594: if (m->busy)
595: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK);
596:
597: assert(!m->fictitious);
598:
599: if (m->wire_count != 0) {
600: /*
601: * If no change would take place
602: * anyway, return successfully.
603: *
604: * No change means:
605: * Not flushing AND
606: * No change to page lock [2 checks] AND
607: * Should not return page
608: *
609: * XXX This doesn't handle sending a copy of a wired
610: * XXX page to the pager, but that will require some
611: * XXX significant surgery.
612: */
613: if (!should_flush &&
614: (m->page_lock == prot || prot == VM_PROT_NO_CHANGE) &&
615: ! memory_object_should_return_page(m, should_return)) {
616:
617: /*
618: * Restart page unlock requests,
619: * even though no change took place.
620: * [Memory managers may be expecting
621: * to see new requests.]
622: */
623: m->unlock_request = VM_PROT_NONE;
624: PAGE_WAKEUP(m);
625:
626: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
627: }
628:
629: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK);
630: }
631:
632: /*
633: * If the page is to be flushed, allow
634: * that to be done as part of the protection.
635: */
636:
637: if (should_flush)
638: prot = VM_PROT_ALL;
639:
640: /*
641: * Set the page lock.
642: *
643: * If we are decreasing permission, do it now;
644: * let the fault handler take care of increases
645: * (pmap_page_protect may not increase protection).
646: */
647:
648: if (prot != VM_PROT_NO_CHANGE) {
649: if ((m->page_lock ^ prot) & prot) {
650: pmap_page_protect(m->phys_addr, VM_PROT_ALL & ~prot);
651: }
652: m->page_lock = prot;
653: m->lock_supplied = TRUE;
654: if (prot != VM_PROT_NONE)
655: m->unusual = TRUE;
656: else
657: m->unusual = FALSE;
658:
659: /*
660: * Restart any past unlock requests, even if no
661: * change resulted. If the manager explicitly
662: * requested no protection change, then it is assumed
663: * to be remembering past requests.
664: */
665:
666: m->unlock_request = VM_PROT_NONE;
667: PAGE_WAKEUP(m);
668: }
669:
670: /*
671: * Handle page returning.
672: */
673:
674: if (memory_object_should_return_page(m, should_return)) {
675:
676: /*
677: * If we weren't planning
678: * to flush the page anyway,
679: * we may need to remove the
680: * page from the pageout
681: * system and from physical
682: * maps now.
683: */
684:
685: vm_page_lock_queues();
686: VM_PAGE_QUEUES_REMOVE(m);
687: vm_page_unlock_queues();
688:
689: if (!should_flush)
690: pmap_page_protect(m->phys_addr, VM_PROT_NONE);
691:
692: if (m->dirty)
693: return(MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN);
694: else
695: return(MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN);
696: }
697:
698: /*
699: * Handle flushing
700: */
701:
702: if (should_flush) {
703: VM_PAGE_FREE(m);
704: } else {
705: extern boolean_t vm_page_deactivate_hint;
706:
707: /*
708: * XXX Make clean but not flush a paging hint,
709: * and deactivate the pages. This is a hack
710: * because it overloads flush/clean with
711: * implementation-dependent meaning. This only
712: * happens to pages that are already clean.
713: */
714:
715: if (vm_page_deactivate_hint &&
716: (should_return != MEMORY_OBJECT_RETURN_NONE)) {
717: vm_page_lock_queues();
718: vm_page_deactivate(m);
719: vm_page_unlock_queues();
720: }
721: }
722:
723: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
724: }
725: #define LIST_REQ_PAGEOUT_PAGES(object, new_object, new_offset, action, po) \
726: MACRO_BEGIN \
727: \
728: register int i; \
729: register vm_page_t hp; \
730: \
731: vm_object_unlock(object); \
732: \
733: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) == \
734: ((rpc_subsystem_t) &vnode_pager_workaround)) { \
735: (void) vnode_pager_data_return(object->pager, \
736: object->pager_request, \
737: po, \
738: POINTER_T(0), \
739: new_offset, \
740: (action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
741: !should_flush); \
742: } else { \
743: (void) memory_object_data_return(object->pager, \
744: object->pager_request, \
745: po, \
746: POINTER_T(0), \
747: new_offset, \
748: (action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
749: !should_flush); \
750: } \
751: \
752: vm_object_lock(object); \
753: \
754: new_object = VM_OBJECT_NULL; \
755: MACRO_END
756:
757: #ifdef MACH_BSD
758: #define PAGEOUT_PAGES(object, new_object, new_offset, action, po) \
759: MACRO_BEGIN \
760: \
761: vm_map_copy_t copy; \
762: register int i; \
763: register vm_page_t hp; \
764: \
765: vm_object_unlock(object); \
766: \
767: (void) vm_map_copyin_object(new_object, 0, new_offset, ©); \
768: \
769: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) == \
770: ((rpc_subsystem_t) &vnode_pager_workaround)) { \
771: (void) vnode_pager_data_return(object->pager, \
772: object->pager_request, \
773: po, \
774: POINTER_T(copy), \
775: new_offset, \
776: (action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
777: !should_flush); \
778: } else { \
779: (void) memory_object_data_return(object->pager, \
780: object->pager_request, \
781: po, \
782: POINTER_T(copy), \
783: new_offset, \
784: (action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
785: !should_flush); \
786: } \
787: \
788: vm_object_lock(object); \
789: \
790: for (i = 0; i < atop(new_offset); i++) { \
791: hp = holding_pages[i]; \
792: if (hp != VM_PAGE_NULL) { \
793: vm_object_paging_end(object); \
794: VM_PAGE_FREE(hp); \
795: } \
796: } \
797: \
798: new_object = VM_OBJECT_NULL; \
799: MACRO_END
800: #else
801: #define PAGEOUT_PAGES(object, new_object, new_offset, action, po) \
802: MACRO_BEGIN \
803: \
804: vm_map_copy_t copy; \
805: register int i; \
806: register vm_page_t hp; \
807: \
808: vm_object_unlock(object); \
809: \
810: (void) vm_map_copyin_object(new_object, 0, new_offset, ©); \
811: \
812: (void) memory_object_data_return( \
813: object->pager, \
814: object->pager_request, \
815: po, \
816: POINTER_T(copy), \
817: new_offset, \
818: (action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
819: !should_flush); \
820: \
821: vm_object_lock(object); \
822: \
823: for (i = 0; i < atop(new_offset); i++) { \
824: hp = holding_pages[i]; \
825: if (hp != VM_PAGE_NULL) { \
826: vm_object_paging_end(object); \
827: VM_PAGE_FREE(hp); \
828: } \
829: } \
830: \
831: new_object = VM_OBJECT_NULL; \
832: MACRO_END
833: #endif
834:
835: /*
836: * Routine: memory_object_lock_request [user interface]
837: *
838: * Description:
839: * Control use of the data associated with the given
840: * memory object. For each page in the given range,
841: * perform the following operations, in order:
842: * 1) restrict access to the page (disallow
843: * forms specified by "prot");
844: * 2) return data to the manager (if "should_return"
845: * is RETURN_DIRTY and the page is dirty, or
846: * "should_return" is RETURN_ALL and the page
847: * is either dirty or precious); and,
848: * 3) flush the cached copy (if "should_flush"
849: * is asserted).
850: * The set of pages is defined by a starting offset
851: * ("offset") and size ("size"). Only pages with the
852: * same page alignment as the starting offset are
853: * considered.
854: *
855: * A single acknowledgement is sent (to the "reply_to"
856: * port) when these actions are complete. If successful,
857: * the naked send right for reply_to is consumed.
858: */
859:
860: kern_return_t
861: memory_object_lock_request(
862: register vm_object_t object,
863: register vm_offset_t offset,
864: register vm_size_t size,
865: memory_object_return_t should_return,
866: boolean_t should_flush,
867: vm_prot_t prot,
868: ipc_port_t reply_to,
869: mach_msg_type_name_t reply_to_type)
870: {
871: vm_offset_t original_offset = offset;
872:
873: XPR(XPR_MEMORY_OBJECT,
874: "m_o_lock_request, obj 0x%X off 0x%X size 0x%X flags %X prot %X\n",
875: (integer_t)object, offset, size,
876: (((should_return&1)<<1)|should_flush), prot);
877:
878: /*
879: * Check for bogus arguments.
880: */
881: if (object == VM_OBJECT_NULL)
882: return (KERN_INVALID_ARGUMENT);
883:
884: if ((prot & ~VM_PROT_ALL) != 0 && prot != VM_PROT_NO_CHANGE) {
885: vm_object_deallocate(object);
886: return (KERN_INVALID_ARGUMENT);
887: }
888:
889: size = round_page(size);
890:
891: /*
892: * Lock the object, and acquire a paging reference to
893: * prevent the memory_object and control ports from
894: * being destroyed.
895: */
896:
897: vm_object_lock(object);
898: vm_object_paging_begin(object);
899: offset -= object->paging_offset;
900:
901: (void)memory_object_update(object,
902: offset, size, should_return, should_flush, prot);
903:
904: if (IP_VALID(reply_to)) {
905: vm_object_unlock(object);
906:
907: /* consumes our naked send-once/send right for reply_to */
908: (void) memory_object_lock_completed(reply_to, reply_to_type,
909: object->pager_request, original_offset, size);
910:
911: vm_object_lock(object);
912: }
913:
914: vm_object_paging_end(object);
915: vm_object_unlock(object);
916: vm_object_deallocate(object);
917:
918: return (KERN_SUCCESS);
919: }
920:
921: /*
922: * Routine: memory_object_sync
923: *
924: * Kernel internal function to synch out pages in a given
925: * range within an object to its memory manager. Much the
926: * same as memory_object_lock_request but page protection
927: * is not changed.
928: *
929: * If the should_flush and should_return flags are true pages
930: * are flushed, that is dirty & precious pages are written to
931: * the memory manager and then discarded. If should_return
932: * is false, only precious pages are returned to the memory
933: * manager.
934: *
935: * If should flush is false and should_return true, the memory
936: * manager's copy of the pages is updated. If should_return
937: * is also false, only the precious pages are updated. This
938: * last option is of limited utility.
939: *
940: * Returns:
941: * FALSE if no pages were returned to the pager
942: * TRUE otherwise.
943: */
944:
945: boolean_t
946: memory_object_sync(
947: vm_object_t object,
948: vm_offset_t offset,
949: vm_size_t size,
950: boolean_t should_flush,
951: boolean_t should_return)
952: {
953: boolean_t rv;
954:
955: XPR(XPR_MEMORY_OBJECT,
956: "m_o_sync, object 0x%X, offset 0x%X size 0x%x flush %d rtn %d\n",
957: (integer_t)object, offset, size, should_flush, should_return);
958:
959: /*
960: * Lock the object, and acquire a paging reference to
961: * prevent the memory_object and control ports from
962: * being destroyed.
963: */
964: vm_object_lock(object);
965: vm_object_paging_begin(object);
966:
967: rv = memory_object_update(object, offset, size,
968: (should_return) ?
969: MEMORY_OBJECT_RETURN_ALL :
970: MEMORY_OBJECT_RETURN_NONE,
971: should_flush,
972: VM_PROT_NO_CHANGE);
973:
974:
975: vm_object_paging_end(object);
976: vm_object_unlock(object);
977: return rv;
978: }
979:
980: /*
981: * Routine: memory_object_update
982: * Description:
983: * Work function for m_o_lock_request(), m_o_sync().
984: *
985: * Called with object locked and paging ref taken.
986: */
987: kern_return_t
988: memory_object_update(
989: register vm_object_t object,
990: register vm_offset_t offset,
991: register vm_size_t size,
992: memory_object_return_t should_return,
993: boolean_t should_flush,
994: vm_prot_t prot)
995: {
996: register vm_page_t m;
997: vm_page_t holding_page;
998: vm_size_t original_size = size;
999: vm_offset_t paging_offset = 0;
1000: vm_object_t new_object = VM_OBJECT_NULL;
1001: vm_object_t copy_object;
1002: vm_offset_t new_offset = 0;
1003: vm_offset_t last_offset = offset;
1004: memory_object_lock_result_t page_lock_result;
1005: memory_object_lock_result_t pageout_action;
1006: vm_page_t holding_pages[DATA_WRITE_MAX];
1007: boolean_t data_returned = FALSE;
1008: #ifndef NOT_LIST_REQ
1009: boolean_t pending_pageout = FALSE;
1010: #endif
1011:
1012: /*
1013: * To avoid blocking while scanning for pages, save
1014: * dirty pages to be cleaned all at once.
1015: *
1016: * XXXO A similar strategy could be used to limit the
1017: * number of times that a scan must be restarted for
1018: * other reasons. Those pages that would require blocking
1019: * could be temporarily collected in another list, or
1020: * their offsets could be recorded in a small array.
1021: */
1022:
1023: /*
1024: * XXX NOTE: May want to consider converting this to a page list
1025: * XXX vm_map_copy interface. Need to understand object
1026: * XXX coalescing implications before doing so.
1027: */
1028:
1029:
1030: if(((copy_object = object->copy) != NULL) && should_flush) {
1031: vm_size_t i;
1032: vm_size_t copy_size;
1033: vm_offset_t copy_offset;
1034: vm_prot_t prot;
1035: vm_page_t page;
1036: vm_page_t top_page;
1037: kern_return_t error = 0;
1038:
1039:
1040:
1041: /* translate offset with respect to shadow's offset */
1042: copy_offset = (offset >= copy_object->shadow_offset)?
1043: offset - copy_object->shadow_offset :
1044: (vm_offset_t)0;
1045: if(copy_offset > copy_object->size)
1046: copy_offset = copy_object->size;
1047:
1048: /* clip size with respect to shadow offset */
1049: copy_size = (offset >= copy_object->shadow_offset) ?
1050: size : size - (copy_object->shadow_offset - offset);
1051:
1052: if(copy_size <= 0) {
1053: copy_size = 0;
1054: } else {
1055: copy_size = ((copy_offset + copy_size)
1056: <= copy_object->size) ?
1057: copy_size : copy_object->size - copy_offset;
1058: }
1059: /* check for a copy_offset which is beyond the end of */
1060: /* the copy_object */
1061: if(copy_size < 0)
1062: copy_size = 0;
1063:
1064: vm_object_unlock(object);
1065: vm_object_lock(copy_object);
1066: vm_object_paging_begin(copy_object);
1067: for (i=copy_offset; i<copy_size; i+=PAGE_SIZE) {
1068: RETRY_COW_OF_LOCK_REQUEST:
1069: prot = VM_PROT_WRITE|VM_PROT_READ;
1070: switch (vm_fault_page(copy_object, i,
1071: VM_PROT_WRITE|VM_PROT_READ,
1072: FALSE,
1073: THREAD_UNINT,
1074: copy_offset,
1075: copy_offset+copy_size,
1076: VM_BEHAVIOR_SEQUENTIAL,
1077: &prot,
1078: &page,
1079: &top_page,
1080: (int *)0,
1081: &error,
1082: FALSE,
1083: FALSE)) {
1084:
1085: case VM_FAULT_SUCCESS:
1086: if(top_page) {
1087: vm_fault_cleanup(
1088: page->object, top_page);
1089: PAGE_WAKEUP_DONE(page);
1090: vm_page_lock_queues();
1091: if (!page->active && !page->inactive)
1092: vm_page_activate(page);
1093: vm_page_unlock_queues();
1094: vm_object_lock(copy_object);
1095: vm_object_paging_begin(copy_object);
1096: } else {
1097: PAGE_WAKEUP_DONE(page);
1098: vm_page_lock_queues();
1099: if (!page->active && !page->inactive)
1100: vm_page_activate(page);
1101: vm_page_unlock_queues();
1102: }
1103: break;
1104: case VM_FAULT_RETRY:
1105: prot = VM_PROT_WRITE|VM_PROT_READ;
1106: vm_object_lock(copy_object);
1107: vm_object_paging_begin(copy_object);
1108: goto RETRY_COW_OF_LOCK_REQUEST;
1109: case VM_FAULT_INTERRUPTED:
1110: prot = VM_PROT_WRITE|VM_PROT_READ;
1111: vm_object_lock(copy_object);
1112: vm_object_paging_begin(copy_object);
1113: goto RETRY_COW_OF_LOCK_REQUEST;
1114: case VM_FAULT_MEMORY_SHORTAGE:
1115: VM_PAGE_WAIT();
1116: prot = VM_PROT_WRITE|VM_PROT_READ;
1117: vm_object_lock(copy_object);
1118: vm_object_paging_begin(copy_object);
1119: goto RETRY_COW_OF_LOCK_REQUEST;
1120: case VM_FAULT_FICTITIOUS_SHORTAGE:
1121: vm_page_more_fictitious();
1122: prot = VM_PROT_WRITE|VM_PROT_READ;
1123: vm_object_lock(copy_object);
1124: vm_object_paging_begin(copy_object);
1125: goto RETRY_COW_OF_LOCK_REQUEST;
1126: case VM_FAULT_MEMORY_ERROR:
1127: vm_object_lock(object);
1128: goto BYPASS_COW_COPYIN;
1129: }
1130:
1131:
1132: }
1133: vm_object_paging_end(copy_object);
1134: vm_object_unlock(copy_object);
1135: vm_object_lock(object);
1136: }
1137: BYPASS_COW_COPYIN:
1138:
1139: for (;
1140: size != 0;
1141: size -= PAGE_SIZE, offset += PAGE_SIZE)
1142: {
1143: /*
1144: * Limit the number of pages to be cleaned at once.
1145: */
1146: #ifdef NOT_LIST_REQ
1147: if (new_object != VM_OBJECT_NULL &&
1148: new_offset >= PAGE_SIZE * DATA_WRITE_MAX)
1149: {
1150: PAGEOUT_PAGES(object, new_object, new_offset, pageout_action,
1151: paging_offset);
1152: }
1153: #else
1154: /*
1155: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) !=
1156: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1157: if (new_object != VM_OBJECT_NULL &&
1158: new_offset >= PAGE_SIZE * DATA_WRITE_MAX)
1159: {
1160: PAGEOUT_PAGES(object, new_object, new_offset, pageout_action,
1161: paging_offset);
1162: }
1163: } else {
1164: */
1165: if (pending_pageout &&
1166: new_offset >= PAGE_SIZE * DATA_WRITE_MAX)
1167: {
1168: LIST_REQ_PAGEOUT_PAGES(object, new_object,
1169: new_offset,
1170: pageout_action, paging_offset);
1171: pending_pageout = FALSE;
1172: }
1173: /*
1174: }
1175: */
1176: #endif
1177:
1178: while ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
1179: page_lock_result = memory_object_lock_page(m, should_return,
1180: should_flush, prot);
1181:
1182: XPR(XPR_MEMORY_OBJECT,
1183: "m_o_update: lock_page, obj 0x%X offset 0x%X result %d\n",
1184: (integer_t)object, offset, page_lock_result, 0, 0);
1185:
1186: switch (page_lock_result)
1187: {
1188: case MEMORY_OBJECT_LOCK_RESULT_DONE:
1189: /*
1190: * End of a cluster of dirty pages.
1191: */
1192: #ifdef NOT_LIST_REQ
1193: if (new_object != VM_OBJECT_NULL) {
1194: PAGEOUT_PAGES(object, new_object, new_offset,
1195: pageout_action, paging_offset);
1196: continue;
1197: }
1198: #else
1199: /*
1200: if(((rpc_subsystem_t) pager_mux_hash_lookup(object->pager)) !=
1201: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1202: if (new_object != VM_OBJECT_NULL) {
1203: PAGEOUT_PAGES(object, new_object, new_offset,
1204: pageout_action, paging_offset);
1205: continue;
1206: }
1207: } else {
1208: */
1209: if(pending_pageout) {
1210: LIST_REQ_PAGEOUT_PAGES(object, new_object,
1211: new_offset, pageout_action,
1212: paging_offset);
1213: pending_pageout = FALSE;
1214: continue;
1215: }
1216: /*
1217: }
1218: */
1219: #endif
1220: break;
1221:
1222: case MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK:
1223: /*
1224: * Since it is necessary to block,
1225: * clean any dirty pages now.
1226: */
1227: #ifdef NOT_LIST_REQ
1228: if (new_object != VM_OBJECT_NULL) {
1229: PAGEOUT_PAGES(object, new_object, new_offset,
1230: pageout_action, paging_offset);
1231: continue;
1232: }
1233: #else
1234: /*
1235: if(((rpc_subsystem_t) pager_mux_hash_lookup(object->pager)) !=
1236: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1237: if (new_object != VM_OBJECT_NULL) {
1238: PAGEOUT_PAGES(object, new_object, new_offset,
1239: pageout_action, paging_offset);
1240: continue;
1241: }
1242: } else {
1243: */
1244: if(pending_pageout) {
1245: LIST_REQ_PAGEOUT_PAGES(object, new_object,
1246: new_offset, pageout_action,
1247: paging_offset);
1248: pending_pageout = FALSE;
1249: continue;
1250: }
1251: /*
1252: }
1253: */
1254: #endif
1255:
1256: PAGE_ASSERT_WAIT(m, THREAD_UNINT);
1257: vm_object_unlock(object);
1258: thread_block((void (*)(void))0);
1259: vm_object_lock(object);
1260: continue;
1261:
1262: case MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN:
1263: case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:
1264: /*
1265: * The clean and return cases are similar.
1266: *
1267: */
1268:
1269: /*
1270: * if this would form a discontiguous block,
1271: * clean the old pages and start anew.
1272: *
1273: * NOTE: The first time through here, new_object
1274: * is null, hiding the fact that pageout_action
1275: * is not initialized.
1276: */
1277: #ifdef NOT_LIST_REQ
1278: /*
1279: * Mark the page busy since we unlock the
1280: * object below.
1281: */
1282: m->busy = TRUE;
1283: if (new_object != VM_OBJECT_NULL &&
1284: (last_offset != offset ||
1285: pageout_action != page_lock_result)) {
1286: PAGEOUT_PAGES(object, new_object, new_offset,
1287: pageout_action, paging_offset);
1288: }
1289: vm_object_unlock(object);
1290:
1291: /*
1292: * If we have not already allocated an object
1293: * for a range of pages to be written, do so
1294: * now.
1295: */
1296: if (new_object == VM_OBJECT_NULL) {
1297: if (should_flush) {
1298: /* use clean-in-place if possible */
1299: new_object = vm_pageout_object_allocate(
1300: m,
1301: original_size,
1302: m->offset);
1303: } else {
1304: /* do not use clean-in-place */
1305: new_object =
1306: vm_object_allocate(original_size);
1307: }
1308: new_offset = 0;
1309: paging_offset = m->offset +
1310: object->paging_offset;
1311: pageout_action = page_lock_result;
1312: }
1313:
1314: if (should_flush) {
1315: /*
1316: * Move or shadow the dirty page into the
1317: * new object.
1318: * This applies to either trusted or
1319: * untrusted pagers.
1320: * Get a paging ref to donate to
1321: * vm_pageout_setup().
1322: */
1323: vm_object_lock(object);
1324: vm_object_paging_begin(object);
1325: vm_object_unlock(object);
1326: holding_page = vm_pageout_setup(m,
1327: new_object,
1328: new_offset);
1329: } else {
1330: /*
1331: * Clean but do not flush, always
1332: * copying the page. Allowing clean-in-place
1333: * is potentially confusing to pagers and XMM
1334: * that ask for clean pages, since the page
1335: * could become dirty before the pager
1336: * looks at it.
1337: */
1338: vm_page_t new_m;
1339:
1340: while ((new_m=vm_page_grab()) == VM_PAGE_NULL) {
1341: VM_PAGE_WAIT();
1342: }
1343: assert(new_m != VM_PAGE_NULL);
1344:
1345: vm_object_lock(m->object);
1346: m->busy = FALSE;
1347: vm_page_lock_queues();
1348: vm_pageclean_copy(m, new_m, new_object,
1349: new_offset);
1350: vm_page_unlock_queues();
1351: vm_object_unlock(m->object);
1352: holding_page = VM_PAGE_NULL;
1353: }
1354: /*
1355: * Save the holding page if there is one.
1356: */
1357: holding_pages[atop(new_offset)] = holding_page;
1358: #else
1359: #if 0
1360: if(((rpc_subsystem_t) pager_mux_hash_lookup(object->pager)) !=
1361: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1362: /*
1363: * Mark the page busy since we unlock the
1364: * object below.
1365: */
1366: m->busy = TRUE;
1367: if (new_object != VM_OBJECT_NULL &&
1368: (last_offset != offset ||
1369: pageout_action != page_lock_result)) {
1370: PAGEOUT_PAGES(object, new_object, new_offset,
1371: pageout_action, paging_offset);
1372: }
1373: vm_object_unlock(object);
1374:
1375: /*
1376: * If we have not already allocated an object
1377: * for a range of pages to be written, do so
1378: * now.
1379: */
1380: if (new_object == VM_OBJECT_NULL) {
1381: if (should_flush) {
1382: /* use clean-in-place if possible */
1383: new_object = vm_pageout_object_allocate(
1384: m,
1385: original_size,
1386: m->offset);
1387: } else {
1388: /* do not use clean-in-place */
1389: new_object =
1390: vm_object_allocate(original_size);
1391: }
1392: new_offset = 0;
1393: paging_offset = m->offset +
1394: object->paging_offset;
1395: pageout_action = page_lock_result;
1396: }
1397:
1398: if (should_flush) {
1399: /*
1400: * Move or shadow the dirty page into the
1401: * new object.
1402: * This applies to either trusted or
1403: * untrusted pagers.
1404: * Get a paging ref to donate to
1405: * vm_pageout_setup().
1406: */
1407: vm_object_lock(object);
1408: vm_object_paging_begin(object);
1409: vm_object_unlock(object);
1410: holding_page = vm_pageout_setup(m,
1411: new_object,
1412: new_offset);
1413: } else {
1414: /*
1415: * Clean but do not flush, always
1416: * copying the page. Allowing clean-in-place
1417: * is potentially confusing to pagers and XMM
1418: * that ask for clean pages, since the page
1419: * could become dirty before the pager
1420: * looks at it.
1421: */
1422: vm_page_t new_m;
1423:
1424: while ((new_m=vm_page_grab()) == VM_PAGE_NULL) {
1425: VM_PAGE_WAIT();
1426: }
1427: assert(new_m != VM_PAGE_NULL);
1428:
1429: vm_object_lock(m->object);
1430: m->busy = FALSE;
1431: vm_page_lock_queues();
1432: vm_pageclean_copy(m, new_m, new_object,
1433: new_offset);
1434: vm_page_unlock_queues();
1435: vm_object_unlock(m->object);
1436: holding_page = VM_PAGE_NULL;
1437: }
1438: /*
1439: * Save the holding page if there is one.
1440: */
1441: holding_pages[atop(new_offset)] = holding_page;
1442: } else {
1443: #endif
1444: if (pending_pageout &&
1445: (last_offset != offset ||
1446: pageout_action != page_lock_result)) {
1447: LIST_REQ_PAGEOUT_PAGES(object, new_object,
1448: new_offset, pageout_action,
1449: paging_offset);
1450: pending_pageout = FALSE;
1451: }
1452: holding_page = VM_PAGE_NULL;
1453: if(!pending_pageout) {
1454: pending_pageout = TRUE;
1455: pageout_action = page_lock_result;
1456: paging_offset = offset;
1457: }
1458: m->list_req_pending = TRUE;
1459: m->cleaning = TRUE;
1460: if (should_flush) {
1461: m->busy = TRUE;
1462: m->pageout = TRUE;
1463: }
1464: vm_object_unlock(object);
1465: /*
1466: }
1467: */
1468:
1469: #endif
1470:
1471: new_offset += PAGE_SIZE;
1472: last_offset = offset + PAGE_SIZE;
1473: data_returned = TRUE;
1474:
1475: vm_object_lock(object);
1476: break;
1477: }
1478: break;
1479: }
1480: }
1481:
1482: /*
1483: * We have completed the scan for applicable pages.
1484: * Clean any pages that have been saved.
1485: */
1486: #ifdef NOT_LIST_REQ
1487: if (new_object != VM_OBJECT_NULL) {
1488: PAGEOUT_PAGES(object, new_object, new_offset, pageout_action,
1489: paging_offset);
1490: }
1491: #else
1492: /*
1493: if(((rpc_subsystem_t) pager_mux_hash_lookup(object->pager)) !=
1494: ((rpc_subsystem_t) &vnode_pager_workaround)) {
1495: if (new_object != VM_OBJECT_NULL) {
1496: PAGEOUT_PAGES(object, new_object, new_offset, pageout_action,
1497: paging_offset);
1498: }
1499: } else {
1500: */
1501: if (pending_pageout) {
1502: LIST_REQ_PAGEOUT_PAGES(object, new_object,
1503: new_offset, pageout_action, paging_offset);
1504: }
1505: /*
1506: }
1507: */
1508: #endif
1509: return (data_returned);
1510: }
1511:
1512: /*
1513: * Routine: memory_object_synchronize_completed [user interface]
1514: *
1515: * Tell kernel that previously synchronized data
1516: * (memory_object_synchronize) has been queue or placed on the
1517: * backing storage.
1518: *
1519: * Note: there may be multiple synchronize requests for a given
1520: * memory object outstanding but they will not overlap.
1521: */
1522:
1523: kern_return_t
1524: memory_object_synchronize_completed(
1525: vm_object_t object,
1526: vm_offset_t offset,
1527: vm_offset_t length)
1528: {
1529: msync_req_t msr;
1530:
1531: XPR(XPR_MEMORY_OBJECT,
1532: "m_o_sync_completed, object 0x%X, offset 0x%X length 0x%X\n",
1533: (integer_t)object, offset, length, 0, 0);
1534:
1535: /*
1536: * Look for bogus arguments
1537: */
1538:
1539: if (object == VM_OBJECT_NULL) {
1540: return KERN_INVALID_ARGUMENT;
1541: }
1542:
1543: vm_object_lock(object);
1544:
1545: /*
1546: * search for sync request structure
1547: */
1548: queue_iterate(&object->msr_q, msr, msync_req_t, msr_q) {
1549: if (msr->offset == offset && msr->length == length) {
1550: queue_remove(&object->msr_q, msr, msync_req_t, msr_q);
1551: break;
1552: }
1553: }/* queue_iterate */
1554:
1555: if (queue_end(&object->msr_q, (queue_entry_t)msr)) {
1556: vm_object_unlock(object);
1557: vm_object_deallocate(object);
1558: return KERN_INVALID_ARGUMENT;
1559: }
1560:
1561: msr_lock(msr);
1562: vm_object_unlock(object);
1563: msr->flag = VM_MSYNC_DONE;
1564: msr_unlock(msr);
1565: thread_wakeup((event_t) msr);
1566: vm_object_deallocate(object);
1567:
1568: return KERN_SUCCESS;
1569: }/* memory_object_synchronize_completed */
1570:
1571: kern_return_t
1572: memory_object_set_attributes_common(
1573: vm_object_t object,
1574: boolean_t may_cache,
1575: memory_object_copy_strategy_t copy_strategy,
1576: boolean_t temporary,
1577: vm_size_t cluster_size,
1578: boolean_t silent_overwrite,
1579: boolean_t advisory_pageout)
1580: {
1581: boolean_t object_became_ready;
1582:
1583: XPR(XPR_MEMORY_OBJECT,
1584: "m_o_set_attr_com, object 0x%X flg %x strat %d\n",
1585: (integer_t)object, (may_cache&1)|((temporary&1)<1), copy_strategy, 0, 0);
1586:
1587: if (object == VM_OBJECT_NULL)
1588: return(KERN_INVALID_ARGUMENT);
1589:
1590: /*
1591: * Verify the attributes of importance
1592: */
1593:
1594: switch(copy_strategy) {
1595: case MEMORY_OBJECT_COPY_NONE:
1596: case MEMORY_OBJECT_COPY_DELAY:
1597: break;
1598: default:
1599: vm_object_deallocate(object);
1600: return(KERN_INVALID_ARGUMENT);
1601: }
1602:
1603: #if !ADVISORY_PAGEOUT
1604: if (silent_overwrite || advisory_pageout) {
1605: vm_object_deallocate(object);
1606: return(KERN_INVALID_ARGUMENT);
1607: }
1608: #endif /* !ADVISORY_PAGEOUT */
1609: if (may_cache)
1610: may_cache = TRUE;
1611: if (temporary)
1612: temporary = TRUE;
1613: if (cluster_size != 0) {
1614: int pages_per_cluster;
1615: pages_per_cluster = atop(cluster_size);
1616: /*
1617: * Cluster size must be integral multiple of page size,
1618: * and be a power of 2 number of pages.
1619: */
1620: if ((cluster_size & (PAGE_SIZE-1)) ||
1621: ((pages_per_cluster-1) & pages_per_cluster)) {
1622: vm_object_deallocate(object);
1623: return KERN_INVALID_ARGUMENT;
1624: }
1625: }
1626:
1627: vm_object_lock(object);
1628:
1629: /*
1630: * Copy the attributes
1631: */
1632: assert(!object->internal);
1633: object_became_ready = !object->pager_ready;
1634: object->copy_strategy = copy_strategy;
1635: object->can_persist = may_cache;
1636: object->temporary = temporary;
1637: object->silent_overwrite = silent_overwrite;
1638: object->advisory_pageout = advisory_pageout;
1639: if (cluster_size == 0)
1640: cluster_size = PAGE_SIZE;
1641: object->cluster_size = cluster_size;
1642:
1643: assert(cluster_size >= PAGE_SIZE &&
1644: cluster_size % PAGE_SIZE == 0);
1645:
1646: /*
1647: * Wake up anyone waiting for the ready attribute
1648: * to become asserted.
1649: */
1650:
1651: if (object_became_ready) {
1652: object->pager_ready = TRUE;
1653: vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY);
1654: }
1655:
1656: vm_object_unlock(object);
1657:
1658: vm_object_deallocate(object);
1659:
1660: return(KERN_SUCCESS);
1661: }
1662:
1663: /*
1664: * Set the memory object attribute as provided.
1665: *
1666: * XXX This routine cannot be completed until the vm_msync, clean
1667: * in place, and cluster work is completed. See ifdef notyet
1668: * below and note that memory_object_set_attributes_common()
1669: * may have to be expanded.
1670: */
1671: kern_return_t
1672: memory_object_change_attributes(
1673: vm_object_t object,
1674: memory_object_flavor_t flavor,
1675: memory_object_info_t attributes,
1676: mach_msg_type_number_t count,
1677: ipc_port_t reply_to,
1678: mach_msg_type_name_t reply_to_type)
1679: {
1680: kern_return_t result = KERN_SUCCESS;
1681: boolean_t temporary;
1682: boolean_t may_cache;
1683: boolean_t invalidate;
1684: vm_size_t cluster_size;
1685: memory_object_copy_strategy_t copy_strategy;
1686: boolean_t silent_overwrite;
1687: boolean_t advisory_pageout;
1688:
1689: if (object == VM_OBJECT_NULL)
1690: return(KERN_INVALID_ARGUMENT);
1691:
1692: vm_object_lock(object);
1693: temporary = object->temporary;
1694: may_cache = object->can_persist;
1695: copy_strategy = object->copy_strategy;
1696: silent_overwrite = object->silent_overwrite;
1697: advisory_pageout = object->advisory_pageout;
1698: #if notyet
1699: invalidate = object->invalidate;
1700: #endif
1701: cluster_size = object->cluster_size;
1702: vm_object_unlock(object);
1703:
1704: switch (flavor) {
1705: case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1706: {
1707: old_memory_object_behave_info_t behave;
1708:
1709: if (count != OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1710: result = KERN_INVALID_ARGUMENT;
1711: break;
1712: }
1713:
1714: behave = (old_memory_object_behave_info_t) attributes;
1715:
1716: temporary = behave->temporary;
1717: invalidate = behave->invalidate;
1718: copy_strategy = behave->copy_strategy;
1719:
1720: break;
1721: }
1722:
1723: case MEMORY_OBJECT_BEHAVIOR_INFO:
1724: {
1725: memory_object_behave_info_t behave;
1726:
1727: if (count != MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1728: result = KERN_INVALID_ARGUMENT;
1729: break;
1730: }
1731:
1732: behave = (memory_object_behave_info_t) attributes;
1733:
1734: temporary = behave->temporary;
1735: invalidate = behave->invalidate;
1736: copy_strategy = behave->copy_strategy;
1737: silent_overwrite = behave->silent_overwrite;
1738: advisory_pageout = behave->advisory_pageout;
1739: break;
1740: }
1741:
1742: case MEMORY_OBJECT_PERFORMANCE_INFO:
1743: {
1744: memory_object_perf_info_t perf;
1745:
1746: if (count != MEMORY_OBJECT_PERF_INFO_COUNT) {
1747: result = KERN_INVALID_ARGUMENT;
1748: break;
1749: }
1750:
1751: perf = (memory_object_perf_info_t) attributes;
1752:
1753: may_cache = perf->may_cache;
1754: cluster_size = round_page(perf->cluster_size);
1755:
1756: break;
1757: }
1758:
1759: case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1760: {
1761: old_memory_object_attr_info_t attr;
1762:
1763: if (count != OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1764: result = KERN_INVALID_ARGUMENT;
1765: break;
1766: }
1767:
1768: attr = (old_memory_object_attr_info_t) attributes;
1769:
1770: may_cache = attr->may_cache;
1771: copy_strategy = attr->copy_strategy;
1772: cluster_size = page_size;
1773:
1774: break;
1775: }
1776:
1777: case MEMORY_OBJECT_ATTRIBUTE_INFO:
1778: {
1779: memory_object_attr_info_t attr;
1780:
1781: if (count != MEMORY_OBJECT_ATTR_INFO_COUNT) {
1782: result = KERN_INVALID_ARGUMENT;
1783: break;
1784: }
1785:
1786: attr = (memory_object_attr_info_t) attributes;
1787:
1788: copy_strategy = attr->copy_strategy;
1789: may_cache = attr->may_cache_object;
1790: cluster_size = attr->cluster_size;
1791: temporary = attr->temporary;
1792:
1793: break;
1794: }
1795:
1796: default:
1797: result = KERN_INVALID_ARGUMENT;
1798: break;
1799: }
1800:
1801: if (result != KERN_SUCCESS) {
1802: vm_object_deallocate(object);
1803: return(result);
1804: }
1805:
1806: if (copy_strategy == MEMORY_OBJECT_COPY_TEMPORARY) {
1807: copy_strategy = MEMORY_OBJECT_COPY_DELAY;
1808: temporary = TRUE;
1809: } else {
1810: temporary = FALSE;
1811: }
1812:
1813: /*
1814: * Do the work and throw away our object reference. It
1815: * is important that the object reference be deallocated
1816: * BEFORE sending the reply. The whole point of the reply
1817: * is that it shows up after the terminate message that
1818: * may be generated by setting the object uncacheable.
1819: *
1820: * XXX may_cache may become a tri-valued variable to handle
1821: * XXX uncache if not in use.
1822: */
1823: result = memory_object_set_attributes_common(object,
1824: may_cache,
1825: copy_strategy,
1826: temporary,
1827: cluster_size,
1828: silent_overwrite,
1829: advisory_pageout);
1830:
1831: if (IP_VALID(reply_to)) {
1832: /* consumes our naked send-once/send right for reply_to */
1833: (void) memory_object_change_completed(reply_to, reply_to_type,
1834: object->alive ?
1835: object->pager_request : PAGER_REQUEST_NULL,
1836: flavor);
1837: }
1838:
1839: return(result);
1840: }
1841:
1842: kern_return_t
1843: memory_object_get_attributes(
1844: vm_object_t object,
1845: memory_object_flavor_t flavor,
1846: memory_object_info_t attributes, /* pointer to OUT array */
1847: mach_msg_type_number_t *count) /* IN/OUT */
1848: {
1849: kern_return_t ret = KERN_SUCCESS;
1850:
1851: if (object == VM_OBJECT_NULL)
1852: return(KERN_INVALID_ARGUMENT);
1853:
1854: vm_object_lock(object);
1855:
1856: switch (flavor) {
1857: case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1858: {
1859: old_memory_object_behave_info_t behave;
1860:
1861: if (*count < OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1862: ret = KERN_INVALID_ARGUMENT;
1863: break;
1864: }
1865:
1866: behave = (old_memory_object_behave_info_t) attributes;
1867: behave->copy_strategy = object->copy_strategy;
1868: behave->temporary = object->temporary;
1869: #if notyet /* remove when vm_msync complies and clean in place fini */
1870: behave->invalidate = object->invalidate;
1871: #else
1872: behave->invalidate = FALSE;
1873: #endif
1874:
1875: *count = OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1876: break;
1877: }
1878:
1879: case MEMORY_OBJECT_BEHAVIOR_INFO:
1880: {
1881: memory_object_behave_info_t behave;
1882:
1883: if (*count < MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1884: ret = KERN_INVALID_ARGUMENT;
1885: break;
1886: }
1887:
1888: behave = (memory_object_behave_info_t) attributes;
1889: behave->copy_strategy = object->copy_strategy;
1890: behave->temporary = object->temporary;
1891: #if notyet /* remove when vm_msync complies and clean in place fini */
1892: behave->invalidate = object->invalidate;
1893: #else
1894: behave->invalidate = FALSE;
1895: #endif
1896: behave->advisory_pageout = object->advisory_pageout;
1897: behave->silent_overwrite = object->silent_overwrite;
1898: *count = MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1899: break;
1900: }
1901:
1902: case MEMORY_OBJECT_PERFORMANCE_INFO:
1903: {
1904: memory_object_perf_info_t perf;
1905:
1906: if (*count < MEMORY_OBJECT_PERF_INFO_COUNT) {
1907: ret = KERN_INVALID_ARGUMENT;
1908: break;
1909: }
1910:
1911: perf = (memory_object_perf_info_t) attributes;
1912: perf->cluster_size = object->cluster_size;
1913: perf->may_cache = object->can_persist;
1914:
1915: *count = MEMORY_OBJECT_PERF_INFO_COUNT;
1916: break;
1917: }
1918:
1919: case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1920: {
1921: old_memory_object_attr_info_t attr;
1922:
1923: if (*count < OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1924: ret = KERN_INVALID_ARGUMENT;
1925: break;
1926: }
1927:
1928: attr = (old_memory_object_attr_info_t) attributes;
1929: attr->may_cache = object->can_persist;
1930: attr->copy_strategy = object->copy_strategy;
1931:
1932: *count = OLD_MEMORY_OBJECT_ATTR_INFO_COUNT;
1933: break;
1934: }
1935:
1936: case MEMORY_OBJECT_ATTRIBUTE_INFO:
1937: {
1938: memory_object_attr_info_t attr;
1939:
1940: if (*count < MEMORY_OBJECT_ATTR_INFO_COUNT) {
1941: ret = KERN_INVALID_ARGUMENT;
1942: break;
1943: }
1944:
1945: attr = (memory_object_attr_info_t) attributes;
1946: attr->copy_strategy = object->copy_strategy;
1947: attr->cluster_size = object->cluster_size;
1948: attr->may_cache_object = object->can_persist;
1949: attr->temporary = object->temporary;
1950:
1951: *count = MEMORY_OBJECT_ATTR_INFO_COUNT;
1952: break;
1953: }
1954:
1955: default:
1956: ret = KERN_INVALID_ARGUMENT;
1957: break;
1958: }
1959:
1960: vm_object_unlock(object);
1961:
1962: vm_object_deallocate(object);
1963:
1964: return(ret);
1965: }
1966:
1967: int vm_stat_discard_cleared_reply = 0;
1968: int vm_stat_discard_cleared_unset = 0;
1969: int vm_stat_discard_cleared_too_late = 0;
1970:
1971: #if ADVISORY_PAGEOUT
1972: kern_return_t
1973: memory_object_discard_reply(
1974: vm_object_t object,
1975: vm_offset_t requested_offset,
1976: vm_size_t requested_size,
1977: vm_offset_t discard_offset,
1978: vm_size_t discard_size,
1979: memory_object_return_t should_return,
1980: ipc_port_t reply_to,
1981: mach_msg_type_name_t reply_to_type)
1982: {
1983: vm_offset_t original_offset = discard_offset;
1984: vm_size_t original_size = discard_size;
1985:
1986: XPR(XPR_MEMORY_OBJECT,
1987: "m_o_discard_reply, obj 0x%X req_off 0x%X req_size 0x%X "
1988: "discard_off 0x%X discard_size 0x%X\n",
1989: (integer_t) object, requested_offset, requested_size,
1990: discard_offset, discard_size);
1991:
1992: /*
1993: * Check for bogus arguments.
1994: */
1995: if (object == VM_OBJECT_NULL)
1996: return KERN_INVALID_ARGUMENT;
1997:
1998: requested_size = round_page(requested_size);
1999: discard_size = round_page(discard_size);
2000:
2001: /*
2002: * Lock the object, and acquire a paging reference to
2003: * prevent the memory_object and control ports from
2004: * being destroyed.
2005: */
2006:
2007: vm_object_lock(object);
2008: vm_object_paging_begin(object);
2009: discard_offset -= object->paging_offset;
2010: requested_offset -= object->paging_offset;
2011:
2012: if (discard_size != 0) {
2013: (void) memory_object_update(object,
2014: discard_offset, discard_size,
2015: should_return, TRUE, VM_PROT_ALL);
2016: }
2017:
2018: if (original_offset != requested_offset ||
2019: discard_size != requested_size) {
2020: /*
2021: * We're not discarding the requested pages, so reset
2022: * the "discard_request" flag on the requested pages.
2023: * But don't rehabilitate more pages than we discard.
2024: */
2025: while (requested_size != 0) {
2026: vm_page_t m;
2027:
2028: m = vm_page_lookup(object, requested_offset);
2029: if (m != VM_PAGE_NULL) {
2030: if (discard_size != 0) {
2031: if (m->discard_request) {
2032: m->discard_request = FALSE;
2033: vm_stat_discard_cleared_reply++;
2034: } else {
2035: vm_stat_discard_cleared_unset++;
2036: }
2037: }
2038: } else {
2039: vm_stat_discard_cleared_too_late++;
2040: }
2041:
2042: requested_offset += PAGE_SIZE;
2043: requested_size -= PAGE_SIZE;
2044: discard_size -= PAGE_SIZE;
2045: }
2046: }
2047:
2048: if (IP_VALID(reply_to)) {
2049: vm_object_unlock(object);
2050:
2051: /* consumes our naked send-once/send right for reply_to */
2052: (void) memory_object_lock_completed(reply_to, reply_to_type,
2053: object->pager_request,
2054: original_offset,
2055: original_size);
2056:
2057: vm_object_lock(object);
2058: }
2059:
2060: vm_object_paging_end(object);
2061: vm_object_unlock(object);
2062: vm_object_deallocate(object);
2063:
2064: return KERN_SUCCESS;
2065: }
2066: #endif /* ADVISORY_PAGEOUT */
2067:
2068: /*
2069: * vm_set_default_memory_manager():
2070: * [Obsolete]
2071: */
2072: kern_return_t
2073: vm_set_default_memory_manager(
2074: host_t host,
2075: ipc_port_t *default_manager)
2076: {
2077: return(host_default_memory_manager(host, default_manager, 4*PAGE_SIZE));
2078: }
2079:
2080: /*
2081: * Routine: host_default_memory_manager
2082: * Purpose:
2083: * set/get the default memory manager port and default cluster
2084: * size.
2085: *
2086: * If successful, consumes the supplied naked send right.
2087: */
2088: kern_return_t
2089: host_default_memory_manager(
2090: host_t host,
2091: ipc_port_t *default_manager,
2092: vm_size_t cluster_size)
2093: {
2094: ipc_port_t current_manager;
2095: ipc_port_t new_manager;
2096: ipc_port_t returned_manager;
2097:
2098: if (host == HOST_NULL)
2099: return(KERN_INVALID_HOST);
2100:
2101: new_manager = *default_manager;
2102: mutex_lock(&memory_manager_default_lock);
2103: current_manager = memory_manager_default;
2104:
2105: if (new_manager == IP_NULL) {
2106: /*
2107: * Retrieve the current value.
2108: */
2109:
2110: returned_manager = ipc_port_copy_send(current_manager);
2111: } else {
2112: /*
2113: * Retrieve the current value,
2114: * and replace it with the supplied value.
2115: * We consume the supplied naked send right.
2116: */
2117:
2118: returned_manager = current_manager;
2119: memory_manager_default = new_manager;
2120: if (cluster_size % PAGE_SIZE != 0) {
2121: #if 0
2122: mutex_unlock(&memory_manager_default_lock);
2123: return KERN_INVALID_ARGUMENT;
2124: #else
2125: cluster_size = round_page(cluster_size);
2126: #endif
2127: }
2128: memory_manager_default_cluster = cluster_size;
2129:
2130: /*
2131: * In case anyone's been waiting for a memory
2132: * manager to be established, wake them up.
2133: */
2134:
2135: thread_wakeup((event_t) &memory_manager_default);
2136: }
2137:
2138: mutex_unlock(&memory_manager_default_lock);
2139:
2140: *default_manager = returned_manager;
2141: return(KERN_SUCCESS);
2142: }
2143:
2144: /*
2145: * Routine: memory_manager_default_reference
2146: * Purpose:
2147: * Returns a naked send right for the default
2148: * memory manager. The returned right is always
2149: * valid (not IP_NULL or IP_DEAD).
2150: */
2151:
2152: ipc_port_t
2153: memory_manager_default_reference(
2154: vm_size_t *cluster_size)
2155: {
2156: ipc_port_t current_manager;
2157:
2158: mutex_lock(&memory_manager_default_lock);
2159:
2160: while (current_manager = ipc_port_copy_send(memory_manager_default),
2161: !IP_VALID(current_manager)) {
2162: thread_sleep_mutex((event_t) &memory_manager_default,
2163: &memory_manager_default_lock, THREAD_UNINT);
2164: mutex_lock(&memory_manager_default_lock);
2165: }
2166: *cluster_size = memory_manager_default_cluster;
2167:
2168: mutex_unlock(&memory_manager_default_lock);
2169:
2170: return current_manager;
2171: }
2172:
2173: /*
2174: * Routine: memory_manager_default_port
2175: * Purpose:
2176: * Returns true if the receiver for the port
2177: * is the default memory manager.
2178: *
2179: * This is a hack to let ds_read_done
2180: * know when it should keep memory wired.
2181: */
2182:
2183: boolean_t
2184: memory_manager_default_port(
2185: ipc_port_t port)
2186: {
2187: ipc_port_t current;
2188: boolean_t result;
2189:
2190: mutex_lock(&memory_manager_default_lock);
2191: current = memory_manager_default;
2192: if (IP_VALID(current)) {
2193: /*
2194: * There is no point in bothering to lock
2195: * both ports, which would be painful to do.
2196: * If the receive rights are moving around,
2197: * we might be inaccurate.
2198: */
2199:
2200: result = port->ip_receiver == current->ip_receiver;
2201: } else
2202: result = FALSE;
2203: mutex_unlock(&memory_manager_default_lock);
2204:
2205: return result;
2206: }
2207:
2208: /*
2209: * Routine: memory_manager_default_check
2210: *
2211: * Purpose:
2212: * Check whether a default memory manager has been set
2213: * up yet, or not. Returns KERN_SUCCESS if dmm exists,
2214: * and KERN_FAILURE if dmm does not exist.
2215: *
2216: * If there is no default memory manager, log an error,
2217: * but only the first time.
2218: *
2219: */
2220: kern_return_t
2221: memory_manager_default_check(void)
2222: {
2223: ipc_port_t current;
2224:
2225: mutex_lock(&memory_manager_default_lock);
2226: current = memory_manager_default;
2227: if (!IP_VALID(current)) {
2228: static boolean_t logged; /* initialized to 0 */
2229: boolean_t complain = !logged;
2230: logged = TRUE;
2231: mutex_unlock(&memory_manager_default_lock);
2232: if (complain)
2233: printf("Warning: No default memory manager\n");
2234: return(KERN_FAILURE);
2235: } else {
2236: mutex_unlock(&memory_manager_default_lock);
2237: return(KERN_SUCCESS);
2238: }
2239: }
2240:
2241: void
2242: memory_manager_default_init(void)
2243: {
2244: memory_manager_default = IP_NULL;
2245: mutex_init(&memory_manager_default_lock, ETAP_VM_MEMMAN);
2246: }
2247:
2248:
2249: void
2250: memory_object_kill_pages(
2251: vm_object_t object,
2252: vm_offset_t offset,
2253: vm_size_t size)
2254: {
2255: register vm_page_t m;
2256:
2257: /*
2258: * entered with object lock held, acquire a paging reference to
2259: * prevent the memory_object and control ports from
2260: * being destroyed.
2261: */
2262: vm_object_paging_begin(object);
2263:
2264: for (;
2265: size != 0;
2266: size -= PAGE_SIZE, offset += PAGE_SIZE)
2267: {
2268: if ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
2269: if (memory_object_lock_page(m, MEMORY_OBJECT_RETURN_NONE, TRUE, VM_PROT_NO_CHANGE) ==
2270: MEMORY_OBJECT_LOCK_RESULT_DONE)
2271: vm_external_state_clr(object->existence_map, offset);
2272: }
2273: }
2274: vm_object_paging_end(object);
2275: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.