|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1992,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: * File: vm/memory_object.c
52: * Author: Michael Wayne Young
53: *
54: * External memory management interface control functions.
55: */
56:
57: /*
58: * Interface dependencies:
59: */
60:
61: #include <mach/std_types.h> /* For pointer_t */
62: #include <mach/mach_types.h>
63:
64: #include <mach/kern_return.h>
65: #include <vm/vm_object.h>
66: #include <mach/memory_object.h>
67: #include <mach/memory_object_user.h>
68: #include <mach/memory_object_default.h>
69: #include <mach/boolean.h>
70: #include <mach/vm_prot.h>
71: #include <mach/message.h>
72:
73: /*
74: * Implementation dependencies:
75: */
76: #include <vm/memory_object.h>
77: #include <vm/vm_page.h>
78: #include <vm/vm_pageout.h>
79: #include <vm/pmap.h> /* For copy_to_phys, pmap_clear_modify */
80: #include <kern/thread.h> /* For current_thread() */
81: #include <kern/host.h>
82: #include <vm/vm_kern.h> /* For kernel_map, vm_move */
83: #include <vm/vm_map.h> /* For vm_map_pageable */
84: #include <ipc/ipc_port.h>
85:
86: #include <norma_vm.h>
87: #include <norma_ipc.h>
88: #if NORMA_VM
89: #include <norma/xmm_server_rename.h>
90: #endif NORMA_VM
91: #include <mach_pagemap.h>
92: #if MACH_PAGEMAP
93: #include <vm/vm_external.h>
94: #endif MACH_PAGEMAP
95:
96: typedef int memory_object_lock_result_t; /* moved from below */
97:
98:
99: ipc_port_t memory_manager_default = IP_NULL;
100: decl_simple_lock_data(,memory_manager_default_lock)
101:
102: /*
103: * Important note:
104: * All of these routines gain a reference to the
105: * object (first argument) as part of the automatic
106: * argument conversion. Explicit deallocation is necessary.
107: */
108:
109: #if !NORMA_VM
110: /*
111: * If successful, destroys the map copy object.
112: */
113: kern_return_t memory_object_data_provided(object, offset, data, data_cnt,
114: lock_value)
115: vm_object_t object;
116: vm_offset_t offset;
117: pointer_t data;
118: unsigned int data_cnt;
119: vm_prot_t lock_value;
120: {
121: return memory_object_data_supply(object, offset, (vm_map_copy_t) data,
122: data_cnt, lock_value, FALSE, IP_NULL,
123: 0);
124: }
125: #endif !NORMA_VM
126:
127:
128: kern_return_t memory_object_data_supply(object, offset, data_copy, data_cnt,
129: lock_value, precious, reply_to, reply_to_type)
130: register
131: vm_object_t object;
132: register
133: vm_offset_t offset;
134: vm_map_copy_t data_copy;
135: unsigned int data_cnt;
136: vm_prot_t lock_value;
137: boolean_t precious;
138: ipc_port_t reply_to;
139: mach_msg_type_name_t reply_to_type;
140: {
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:
153: /*
154: * Look for bogus arguments
155: */
156:
157: if (object == VM_OBJECT_NULL) {
158: return(KERN_INVALID_ARGUMENT);
159: }
160:
161: if (lock_value & ~VM_PROT_ALL) {
162: vm_object_deallocate(object);
163: return(KERN_INVALID_ARGUMENT);
164: }
165:
166: if ((data_cnt % PAGE_SIZE) != 0) {
167: vm_object_deallocate(object);
168: return(KERN_INVALID_ARGUMENT);
169: }
170:
171: /*
172: * Adjust the offset from the memory object to the offset
173: * within the vm_object.
174: */
175:
176: original_length = data_cnt;
177: original_offset = offset;
178:
179: assert(data_copy->type == VM_MAP_COPY_PAGE_LIST);
180: page_list = &data_copy->cpy_page_list[0];
181:
182: vm_object_lock(object);
183: vm_object_paging_begin(object);
184: offset -= object->paging_offset;
185:
186: /*
187: * Loop over copy stealing pages for pagein.
188: */
189:
190: for (; data_cnt > 0 ; data_cnt -= PAGE_SIZE, offset += PAGE_SIZE) {
191:
192: assert(data_copy->cpy_npages > 0);
193: data_m = *page_list;
194:
195: if (data_m == VM_PAGE_NULL || data_m->tabled ||
196: data_m->error || data_m->absent || data_m->fictitious) {
197:
198: panic("Data_supply: bad page");
199: }
200:
201: /*
202: * Look up target page and check its state.
203: */
204:
205: retry_lookup:
206: m = vm_page_lookup(object,offset);
207: if (m == VM_PAGE_NULL) {
208: was_absent = FALSE;
209: }
210: else {
211: if (m->absent && m->busy) {
212:
213: /*
214: * Page was requested. Free the busy
215: * page waiting for it. Insertion
216: * of new page happens below.
217: */
218:
219: VM_PAGE_FREE(m);
220: was_absent = TRUE;
221: }
222: else {
223:
224: /*
225: * Have to wait for page that is busy and
226: * not absent. This is probably going to
227: * be an error, but go back and check.
228: */
229: if (m->busy) {
230: PAGE_ASSERT_WAIT(m, FALSE);
231: vm_object_unlock(object);
232: thread_block((void (*)()) 0);
233: vm_object_lock(object);
234: goto retry_lookup;
235: }
236:
237: /*
238: * Page already present; error.
239: * This is an error if data is precious.
240: */
241: result = KERN_MEMORY_PRESENT;
242: error_offset = offset + object->paging_offset;
243:
244: break;
245: }
246: }
247:
248: /*
249: * Ok to pagein page. Target object now has no page
250: * at offset. Set the page parameters, then drop
251: * in new page and set up pageout state. Object is
252: * still locked here.
253: *
254: * Must clear busy bit in page before inserting it.
255: * Ok to skip wakeup logic because nobody else
256: * can possibly know about this page.
257: */
258:
259: data_m->busy = FALSE;
260: data_m->dirty = FALSE;
261: pmap_clear_modify(data_m->phys_addr);
262:
263: data_m->page_lock = lock_value;
264: data_m->unlock_request = VM_PROT_NONE;
265: data_m->precious = precious;
266:
267: vm_page_lock_queues();
268: vm_page_insert(data_m, object, offset);
269:
270: if (was_absent)
271: vm_page_activate(data_m);
272: else
273: vm_page_deactivate(data_m);
274:
275: vm_page_unlock_queues();
276:
277: /*
278: * Null out this page list entry, and advance to next
279: * page.
280: */
281:
282: *page_list++ = VM_PAGE_NULL;
283:
284: if (--(data_copy->cpy_npages) == 0 &&
285: vm_map_copy_has_cont(data_copy)) {
286: vm_map_copy_t new_copy;
287:
288: vm_object_unlock(object);
289:
290: vm_map_copy_invoke_cont(data_copy, &new_copy, &result);
291:
292: if (result == KERN_SUCCESS) {
293:
294: /*
295: * Consume on success requires that
296: * we keep the original vm_map_copy
297: * around in case something fails.
298: * Free the old copy if it's not the original
299: */
300: if (data_copy != orig_copy) {
301: vm_map_copy_discard(data_copy);
302: }
303:
304: if ((data_copy = new_copy) != VM_MAP_COPY_NULL)
305: page_list = &data_copy->cpy_page_list[0];
306:
307: vm_object_lock(object);
308: }
309: else {
310: vm_object_lock(object);
311: error_offset = offset + object->paging_offset +
312: PAGE_SIZE;
313: break;
314: }
315: }
316: }
317:
318: /*
319: * Send reply if one was requested.
320: */
321: vm_object_paging_end(object);
322: vm_object_unlock(object);
323:
324: if (vm_map_copy_has_cont(data_copy))
325: vm_map_copy_abort_cont(data_copy);
326:
327: if (IP_VALID(reply_to)) {
328: memory_object_supply_completed(
329: reply_to, reply_to_type,
330: object->pager_request,
331: original_offset,
332: original_length,
333: result,
334: error_offset);
335: }
336:
337: vm_object_deallocate(object);
338:
339: /*
340: * Consume on success: The final data copy must be
341: * be discarded if it is not the original. The original
342: * gets discarded only if this routine succeeds.
343: */
344: if (data_copy != orig_copy)
345: vm_map_copy_discard(data_copy);
346: if (result == KERN_SUCCESS)
347: vm_map_copy_discard(orig_copy);
348:
349:
350: return(result);
351: }
352:
353: kern_return_t memory_object_data_error(object, offset, size, error_value)
354: vm_object_t object;
355: vm_offset_t offset;
356: vm_size_t size;
357: kern_return_t error_value;
358: {
359: if (object == VM_OBJECT_NULL)
360: return(KERN_INVALID_ARGUMENT);
361:
362: if (size != round_page(size))
363: return(KERN_INVALID_ARGUMENT);
364:
365: #ifdef lint
366: /* Error value is ignored at this time */
367: error_value++;
368: #endif
369:
370: vm_object_lock(object);
371: offset -= object->paging_offset;
372:
373: while (size != 0) {
374: register vm_page_t m;
375:
376: m = vm_page_lookup(object, offset);
377: if ((m != VM_PAGE_NULL) && m->busy && m->absent) {
378: m->error = TRUE;
379: m->absent = FALSE;
380: vm_object_absent_release(object);
381:
382: PAGE_WAKEUP_DONE(m);
383:
384: vm_page_lock_queues();
385: vm_page_activate(m);
386: vm_page_unlock_queues();
387: }
388:
389: size -= PAGE_SIZE;
390: offset += PAGE_SIZE;
391: }
392: vm_object_unlock(object);
393:
394: vm_object_deallocate(object);
395: return(KERN_SUCCESS);
396: }
397:
398: kern_return_t memory_object_data_unavailable(object, offset, size)
399: vm_object_t object;
400: vm_offset_t offset;
401: vm_size_t size;
402: {
403: #if MACH_PAGEMAP
404: vm_external_t existence_info = VM_EXTERNAL_NULL;
405: #endif MACH_PAGEMAP
406:
407: if (object == VM_OBJECT_NULL)
408: return(KERN_INVALID_ARGUMENT);
409:
410: if (size != round_page(size))
411: return(KERN_INVALID_ARGUMENT);
412:
413: #if MACH_PAGEMAP
414: if ((offset == 0) && (size > VM_EXTERNAL_LARGE_SIZE) &&
415: (object->existence_info == VM_EXTERNAL_NULL)) {
416: existence_info = vm_external_create(VM_EXTERNAL_SMALL_SIZE);
417: }
418: #endif MACH_PAGEMAP
419:
420: vm_object_lock(object);
421: #if MACH_PAGEMAP
422: if (existence_info != VM_EXTERNAL_NULL) {
423: object->existence_info = existence_info;
424: }
425: if ((offset == 0) && (size > VM_EXTERNAL_LARGE_SIZE)) {
426: vm_object_unlock(object);
427: vm_object_deallocate(object);
428: return(KERN_SUCCESS);
429: }
430: #endif MACH_PAGEMAP
431: offset -= object->paging_offset;
432:
433: while (size != 0) {
434: register vm_page_t m;
435:
436: /*
437: * We're looking for pages that are both busy and
438: * absent (waiting to be filled), converting them
439: * to just absent.
440: *
441: * Pages that are just busy can be ignored entirely.
442: */
443:
444: m = vm_page_lookup(object, offset);
445: if ((m != VM_PAGE_NULL) && m->busy && m->absent) {
446: PAGE_WAKEUP_DONE(m);
447:
448: vm_page_lock_queues();
449: vm_page_activate(m);
450: vm_page_unlock_queues();
451: }
452: size -= PAGE_SIZE;
453: offset += PAGE_SIZE;
454: }
455:
456: vm_object_unlock(object);
457:
458: vm_object_deallocate(object);
459: return(KERN_SUCCESS);
460: }
461:
462: /*
463: * Routine: memory_object_lock_page
464: *
465: * Description:
466: * Perform the appropriate lock operations on the
467: * given page. See the description of
468: * "memory_object_lock_request" for the meanings
469: * of the arguments.
470: *
471: * Returns an indication that the operation
472: * completed, blocked, or that the page must
473: * be cleaned.
474: */
475:
476: #define MEMORY_OBJECT_LOCK_RESULT_DONE 0
477: #define MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK 1
478: #define MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN 2
479: #define MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN 3
480:
481: memory_object_lock_result_t memory_object_lock_page(m, should_return,
482: should_flush, prot)
483: vm_page_t m;
484: memory_object_return_t should_return;
485: boolean_t should_flush;
486: vm_prot_t prot;
487: {
488: /*
489: * Don't worry about pages for which the kernel
490: * does not have any data.
491: */
492:
493: if (m->absent)
494: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
495:
496: /*
497: * If we cannot change access to the page,
498: * either because a mapping is in progress
499: * (busy page) or because a mapping has been
500: * wired, then give up.
501: */
502:
503: if (m->busy)
504: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK);
505:
506: assert(!m->fictitious);
507:
508: if (m->wire_count != 0) {
509: /*
510: * If no change would take place
511: * anyway, return successfully.
512: *
513: * No change means:
514: * Not flushing AND
515: * No change to page lock [2 checks] AND
516: * Don't need to send page to manager
517: *
518: * Don't need to send page to manager means:
519: * No clean or return request OR (
520: * Page is not dirty [2 checks] AND (
521: * Page is not precious OR
522: * No request to return precious pages ))
523: *
524: * Now isn't that straightforward and obvious ?? ;-)
525: *
526: * XXX This doesn't handle sending a copy of a wired
527: * XXX page to the pager, but that will require some
528: * XXX significant surgery.
529: */
530:
531: if (!should_flush &&
532: ((m->page_lock == prot) || (prot == VM_PROT_NO_CHANGE)) &&
533: ((should_return == MEMORY_OBJECT_RETURN_NONE) ||
534: (!m->dirty && !pmap_is_modified(m->phys_addr) &&
535: (!m->precious ||
536: should_return != MEMORY_OBJECT_RETURN_ALL)))) {
537: /*
538: * Restart page unlock requests,
539: * even though no change took place.
540: * [Memory managers may be expecting
541: * to see new requests.]
542: */
543: m->unlock_request = VM_PROT_NONE;
544: PAGE_WAKEUP(m);
545:
546: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
547: }
548:
549: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK);
550: }
551:
552: /*
553: * If the page is to be flushed, allow
554: * that to be done as part of the protection.
555: */
556:
557: if (should_flush)
558: prot = VM_PROT_ALL;
559:
560: /*
561: * Set the page lock.
562: *
563: * If we are decreasing permission, do it now;
564: * let the fault handler take care of increases
565: * (pmap_page_protect may not increase protection).
566: */
567:
568: if (prot != VM_PROT_NO_CHANGE) {
569: if ((m->page_lock ^ prot) & prot) {
570: pmap_page_protect(m->phys_addr, VM_PROT_ALL & ~prot);
571: }
572: m->page_lock = prot;
573:
574: /*
575: * Restart any past unlock requests, even if no
576: * change resulted. If the manager explicitly
577: * requested no protection change, then it is assumed
578: * to be remembering past requests.
579: */
580:
581: m->unlock_request = VM_PROT_NONE;
582: PAGE_WAKEUP(m);
583: }
584:
585: /*
586: * Handle cleaning.
587: */
588:
589: if (should_return != MEMORY_OBJECT_RETURN_NONE) {
590: /*
591: * Check whether the page is dirty. If
592: * write permission has not been removed,
593: * this may have unpredictable results.
594: */
595:
596: if (!m->dirty)
597: m->dirty = pmap_is_modified(m->phys_addr);
598:
599: if (m->dirty || (m->precious &&
600: should_return == MEMORY_OBJECT_RETURN_ALL)) {
601: /*
602: * If we weren't planning
603: * to flush the page anyway,
604: * we may need to remove the
605: * page from the pageout
606: * system and from physical
607: * maps now.
608: */
609:
610: vm_page_lock_queues();
611: VM_PAGE_QUEUES_REMOVE(m);
612: vm_page_unlock_queues();
613:
614: if (!should_flush)
615: pmap_page_protect(m->phys_addr,
616: VM_PROT_NONE);
617:
618: /*
619: * Cleaning a page will cause
620: * it to be flushed.
621: */
622:
623: if (m->dirty)
624: return(MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN);
625: else
626: return(MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN);
627: }
628: }
629:
630: /*
631: * Handle flushing
632: */
633:
634: if (should_flush) {
635: VM_PAGE_FREE(m);
636: } else {
637: extern boolean_t vm_page_deactivate_hint;
638:
639: /*
640: * XXX Make clean but not flush a paging hint,
641: * and deactivate the pages. This is a hack
642: * because it overloads flush/clean with
643: * implementation-dependent meaning. This only
644: * happens to pages that are already clean.
645: */
646:
647: if (vm_page_deactivate_hint &&
648: (should_return != MEMORY_OBJECT_RETURN_NONE)) {
649: vm_page_lock_queues();
650: vm_page_deactivate(m);
651: vm_page_unlock_queues();
652: }
653: }
654:
655: return(MEMORY_OBJECT_LOCK_RESULT_DONE);
656: }
657:
658: /*
659: * Routine: memory_object_lock_request [user interface]
660: *
661: * Description:
662: * Control use of the data associated with the given
663: * memory object. For each page in the given range,
664: * perform the following operations, in order:
665: * 1) restrict access to the page (disallow
666: * forms specified by "prot");
667: * 2) return data to the manager (if "should_return"
668: * is RETURN_DIRTY and the page is dirty, or
669: * "should_return" is RETURN_ALL and the page
670: * is either dirty or precious); and,
671: * 3) flush the cached copy (if "should_flush"
672: * is asserted).
673: * The set of pages is defined by a starting offset
674: * ("offset") and size ("size"). Only pages with the
675: * same page alignment as the starting offset are
676: * considered.
677: *
678: * A single acknowledgement is sent (to the "reply_to"
679: * port) when these actions are complete. If successful,
680: * the naked send right for reply_to is consumed.
681: */
682:
683: kern_return_t
684: memory_object_lock_request(object, offset, size,
685: should_return, should_flush, prot,
686: reply_to, reply_to_type)
687: register vm_object_t object;
688: register vm_offset_t offset;
689: register vm_size_t size;
690: memory_object_return_t should_return;
691: boolean_t should_flush;
692: vm_prot_t prot;
693: ipc_port_t reply_to;
694: mach_msg_type_name_t reply_to_type;
695: {
696: register vm_page_t m;
697: vm_offset_t original_offset = offset;
698: vm_size_t original_size = size;
699: vm_offset_t paging_offset = 0;
700: vm_object_t new_object = VM_OBJECT_NULL;
701: vm_offset_t new_offset = 0;
702: vm_offset_t last_offset = offset;
703: int page_lock_result;
704: int pageout_action = 0; /* '=0' to quiet lint */
705:
706: #define DATA_WRITE_MAX 32
707: vm_page_t holding_pages[DATA_WRITE_MAX];
708:
709: /*
710: * Check for bogus arguments.
711: */
712: if (object == VM_OBJECT_NULL ||
713: ((prot & ~VM_PROT_ALL) != 0 && prot != VM_PROT_NO_CHANGE))
714: return (KERN_INVALID_ARGUMENT);
715:
716: size = round_page(size);
717:
718: /*
719: * Lock the object, and acquire a paging reference to
720: * prevent the memory_object and control ports from
721: * being destroyed.
722: */
723:
724: vm_object_lock(object);
725: vm_object_paging_begin(object);
726: offset -= object->paging_offset;
727:
728: /*
729: * To avoid blocking while scanning for pages, save
730: * dirty pages to be cleaned all at once.
731: *
732: * XXXO A similar strategy could be used to limit the
733: * number of times that a scan must be restarted for
734: * other reasons. Those pages that would require blocking
735: * could be temporarily collected in another list, or
736: * their offsets could be recorded in a small array.
737: */
738:
739: /*
740: * XXX NOTE: May want to consider converting this to a page list
741: * XXX vm_map_copy interface. Need to understand object
742: * XXX coalescing implications before doing so.
743: */
744:
745: #define PAGEOUT_PAGES \
746: MACRO_BEGIN \
747: vm_map_copy_t copy; \
748: register int i; \
749: register vm_page_t hp; \
750: \
751: vm_object_unlock(object); \
752: \
753: (void) vm_map_copyin_object(new_object, 0, new_offset, ©); \
754: \
755: if (object->use_old_pageout) { \
756: assert(pageout_action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN); \
757: (void) memory_object_data_write( \
758: object->pager, \
759: object->pager_request, \
760: paging_offset, \
761: (pointer_t) copy, \
762: new_offset); \
763: } \
764: else { \
765: (void) memory_object_data_return( \
766: object->pager, \
767: object->pager_request, \
768: paging_offset, \
769: (pointer_t) copy, \
770: new_offset, \
771: (pageout_action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \
772: !should_flush); \
773: } \
774: \
775: vm_object_lock(object); \
776: \
777: for (i = 0; i < atop(new_offset); i++) { \
778: hp = holding_pages[i]; \
779: if (hp != VM_PAGE_NULL) \
780: VM_PAGE_FREE(hp); \
781: } \
782: \
783: new_object = VM_OBJECT_NULL; \
784: MACRO_END
785:
786: for (;
787: size != 0;
788: size -= PAGE_SIZE, offset += PAGE_SIZE)
789: {
790: /*
791: * Limit the number of pages to be cleaned at once.
792: */
793: if (new_object != VM_OBJECT_NULL &&
794: new_offset >= PAGE_SIZE * DATA_WRITE_MAX)
795: {
796: PAGEOUT_PAGES;
797: }
798:
799: while ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
800: switch ((page_lock_result = memory_object_lock_page(m,
801: should_return,
802: should_flush,
803: prot)))
804: {
805: case MEMORY_OBJECT_LOCK_RESULT_DONE:
806: /*
807: * End of a cluster of dirty pages.
808: */
809: if (new_object != VM_OBJECT_NULL) {
810: PAGEOUT_PAGES;
811: continue;
812: }
813: break;
814:
815: case MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK:
816: /*
817: * Since it is necessary to block,
818: * clean any dirty pages now.
819: */
820: if (new_object != VM_OBJECT_NULL) {
821: PAGEOUT_PAGES;
822: continue;
823: }
824:
825: PAGE_ASSERT_WAIT(m, FALSE);
826: vm_object_unlock(object);
827: thread_block((void (*)()) 0);
828: vm_object_lock(object);
829: continue;
830:
831: case MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN:
832: case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:
833: /*
834: * The clean and return cases are similar.
835: *
836: * Mark the page busy since we unlock the
837: * object below.
838: */
839: m->busy = TRUE;
840:
841: /*
842: * if this would form a discontiguous block,
843: * clean the old pages and start anew.
844: *
845: * NOTE: The first time through here, new_object
846: * is null, hiding the fact that pageout_action
847: * is not initialized.
848: */
849: if (new_object != VM_OBJECT_NULL &&
850: (last_offset != offset ||
851: pageout_action != page_lock_result)) {
852: PAGEOUT_PAGES;
853: }
854:
855: vm_object_unlock(object);
856:
857: /*
858: * If we have not already allocated an object
859: * for a range of pages to be written, do so
860: * now.
861: */
862: if (new_object == VM_OBJECT_NULL) {
863: new_object = vm_object_allocate(original_size);
864: new_offset = 0;
865: paging_offset = m->offset +
866: object->paging_offset;
867: pageout_action = page_lock_result;
868: }
869:
870: /*
871: * Move or copy the dirty page into the
872: * new object.
873: */
874: m = vm_pageout_setup(m,
875: m->offset + object->paging_offset,
876: new_object,
877: new_offset,
878: should_flush);
879:
880: /*
881: * Save the holding page if there is one.
882: */
883: holding_pages[atop(new_offset)] = m;
884: new_offset += PAGE_SIZE;
885: last_offset = offset + PAGE_SIZE;
886:
887: vm_object_lock(object);
888: break;
889: }
890: break;
891: }
892: }
893:
894: /*
895: * We have completed the scan for applicable pages.
896: * Clean any pages that have been saved.
897: */
898: if (new_object != VM_OBJECT_NULL) {
899: PAGEOUT_PAGES;
900: }
901:
902: if (IP_VALID(reply_to)) {
903: vm_object_unlock(object);
904:
905: /* consumes our naked send-once/send right for reply_to */
906: (void) memory_object_lock_completed(reply_to, reply_to_type,
907: object->pager_request, original_offset, original_size);
908:
909: vm_object_lock(object);
910: }
911:
912: vm_object_paging_end(object);
913: vm_object_unlock(object);
914: vm_object_deallocate(object);
915:
916: return (KERN_SUCCESS);
917: }
918:
919: #if !NORMA_VM
920: /*
921: * Old version of memory_object_lock_request.
922: */
923: kern_return_t
924: xxx_memory_object_lock_request(object, offset, size,
925: should_clean, should_flush, prot,
926: reply_to, reply_to_type)
927: register vm_object_t object;
928: register vm_offset_t offset;
929: register vm_size_t size;
930: boolean_t should_clean;
931: boolean_t should_flush;
932: vm_prot_t prot;
933: ipc_port_t reply_to;
934: mach_msg_type_name_t reply_to_type;
935: {
936: register int should_return;
937:
938: if (should_clean)
939: should_return = MEMORY_OBJECT_RETURN_DIRTY;
940: else
941: should_return = MEMORY_OBJECT_RETURN_NONE;
942:
943: return(memory_object_lock_request(object,offset,size,
944: should_return, should_flush, prot,
945: reply_to, reply_to_type));
946: }
947: #endif !NORMA_VM
948:
949: kern_return_t
950: memory_object_set_attributes_common(object, object_ready, may_cache,
951: copy_strategy, use_old_pageout)
952: vm_object_t object;
953: boolean_t object_ready;
954: boolean_t may_cache;
955: memory_object_copy_strategy_t copy_strategy;
956: boolean_t use_old_pageout;
957: {
958: if (object == VM_OBJECT_NULL)
959: return(KERN_INVALID_ARGUMENT);
960:
961: /*
962: * Verify the attributes of importance
963: */
964:
965: switch(copy_strategy) {
966: case MEMORY_OBJECT_COPY_NONE:
967: case MEMORY_OBJECT_COPY_CALL:
968: case MEMORY_OBJECT_COPY_DELAY:
969: case MEMORY_OBJECT_COPY_TEMPORARY:
970: break;
971: default:
972: vm_object_deallocate(object);
973: return(KERN_INVALID_ARGUMENT);
974: }
975:
976: if (object_ready)
977: object_ready = TRUE;
978: if (may_cache)
979: may_cache = TRUE;
980:
981: vm_object_lock(object);
982:
983: /*
984: * Wake up anyone waiting for the ready attribute
985: * to become asserted.
986: */
987:
988: if (object_ready && !object->pager_ready) {
989: object->use_old_pageout = use_old_pageout;
990: vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY);
991: }
992:
993: /*
994: * Copy the attributes
995: */
996:
997: object->can_persist = may_cache;
998: object->pager_ready = object_ready;
999: if (copy_strategy == MEMORY_OBJECT_COPY_TEMPORARY) {
1000: object->temporary = TRUE;
1001: } else {
1002: object->copy_strategy = copy_strategy;
1003: }
1004:
1005: vm_object_unlock(object);
1006:
1007: vm_object_deallocate(object);
1008:
1009: return(KERN_SUCCESS);
1010: }
1011:
1012: #if !NORMA_VM
1013:
1014: /*
1015: * XXX rpd claims that reply_to could be obviated in favor of a client
1016: * XXX stub that made change_attributes an RPC. Need investigation.
1017: */
1018:
1019: kern_return_t memory_object_change_attributes(object, may_cache,
1020: copy_strategy, reply_to, reply_to_type)
1021: vm_object_t object;
1022: boolean_t may_cache;
1023: memory_object_copy_strategy_t copy_strategy;
1024: ipc_port_t reply_to;
1025: mach_msg_type_name_t reply_to_type;
1026: {
1027: kern_return_t result;
1028:
1029: /*
1030: * Do the work and throw away our object reference. It
1031: * is important that the object reference be deallocated
1032: * BEFORE sending the reply. The whole point of the reply
1033: * is that it shows up after the terminate message that
1034: * may be generated by setting the object uncacheable.
1035: *
1036: * XXX may_cache may become a tri-valued variable to handle
1037: * XXX uncache if not in use.
1038: */
1039: result = memory_object_set_attributes_common(object, TRUE,
1040: may_cache, copy_strategy,
1041: FALSE);
1042:
1043: if (IP_VALID(reply_to)) {
1044:
1045: /* consumes our naked send-once/send right for reply_to */
1046: (void) memory_object_change_completed(reply_to, reply_to_type,
1047: may_cache, copy_strategy);
1048:
1049: }
1050:
1051: return(result);
1052: }
1053:
1054: kern_return_t
1055: memory_object_set_attributes(object, object_ready, may_cache, copy_strategy)
1056: vm_object_t object;
1057: boolean_t object_ready;
1058: boolean_t may_cache;
1059: memory_object_copy_strategy_t copy_strategy;
1060: {
1061: return memory_object_set_attributes_common(object, object_ready,
1062: may_cache, copy_strategy,
1063: TRUE);
1064: }
1065:
1066: kern_return_t memory_object_ready(object, may_cache, copy_strategy)
1067: vm_object_t object;
1068: boolean_t may_cache;
1069: memory_object_copy_strategy_t copy_strategy;
1070: {
1071: return memory_object_set_attributes_common(object, TRUE,
1072: may_cache, copy_strategy,
1073: FALSE);
1074: }
1075: #endif !NORMA_VM
1076:
1077: kern_return_t memory_object_get_attributes(object, object_ready,
1078: may_cache, copy_strategy)
1079: vm_object_t object;
1080: boolean_t *object_ready;
1081: boolean_t *may_cache;
1082: memory_object_copy_strategy_t *copy_strategy;
1083: {
1084: if (object == VM_OBJECT_NULL)
1085: return(KERN_INVALID_ARGUMENT);
1086:
1087: vm_object_lock(object);
1088: *may_cache = object->can_persist;
1089: *object_ready = object->pager_ready;
1090: *copy_strategy = object->copy_strategy;
1091: vm_object_unlock(object);
1092:
1093: vm_object_deallocate(object);
1094:
1095: return(KERN_SUCCESS);
1096: }
1097:
1098: /*
1099: * If successful, consumes the supplied naked send right.
1100: */
1101: kern_return_t vm_set_default_memory_manager(host, default_manager)
1102: host_t host;
1103: ipc_port_t *default_manager;
1104: {
1105: ipc_port_t current_manager;
1106: ipc_port_t new_manager;
1107: ipc_port_t returned_manager;
1108:
1109: if (host == HOST_NULL)
1110: return(KERN_INVALID_HOST);
1111:
1112: new_manager = *default_manager;
1113: simple_lock(&memory_manager_default_lock);
1114: current_manager = memory_manager_default;
1115:
1116: if (new_manager == IP_NULL) {
1117: /*
1118: * Retrieve the current value.
1119: */
1120:
1121: returned_manager = ipc_port_copy_send(current_manager);
1122: } else {
1123: /*
1124: * Retrieve the current value,
1125: * and replace it with the supplied value.
1126: * We consume the supplied naked send right.
1127: */
1128:
1129: returned_manager = current_manager;
1130: memory_manager_default = new_manager;
1131:
1132: /*
1133: * In case anyone's been waiting for a memory
1134: * manager to be established, wake them up.
1135: */
1136:
1137: thread_wakeup((event_t) &memory_manager_default);
1138: }
1139:
1140: simple_unlock(&memory_manager_default_lock);
1141:
1142: *default_manager = returned_manager;
1143: return(KERN_SUCCESS);
1144: }
1145:
1146: /*
1147: * Routine: memory_manager_default_reference
1148: * Purpose:
1149: * Returns a naked send right for the default
1150: * memory manager. The returned right is always
1151: * valid (not IP_NULL or IP_DEAD).
1152: */
1153:
1154: ipc_port_t memory_manager_default_reference()
1155: {
1156: ipc_port_t current_manager;
1157:
1158: simple_lock(&memory_manager_default_lock);
1159:
1160: while (current_manager = ipc_port_copy_send(memory_manager_default),
1161: !IP_VALID(current_manager)) {
1162: thread_sleep((event_t) &memory_manager_default,
1163: simple_lock_addr(memory_manager_default_lock),
1164: FALSE);
1165: simple_lock(&memory_manager_default_lock);
1166: }
1167:
1168: simple_unlock(&memory_manager_default_lock);
1169:
1170: return current_manager;
1171: }
1172:
1173: /*
1174: * Routine: memory_manager_default_port
1175: * Purpose:
1176: * Returns true if the receiver for the port
1177: * is the default memory manager.
1178: *
1179: * This is a hack to let ds_read_done
1180: * know when it should keep memory wired.
1181: */
1182:
1183: boolean_t memory_manager_default_port(port)
1184: ipc_port_t port;
1185: {
1186: ipc_port_t current;
1187: boolean_t result;
1188:
1189: simple_lock(&memory_manager_default_lock);
1190: current = memory_manager_default;
1191: if (IP_VALID(current)) {
1192: /*
1193: * There is no point in bothering to lock
1194: * both ports, which would be painful to do.
1195: * If the receive rights are moving around,
1196: * we might be inaccurate.
1197: */
1198:
1199: result = port->ip_receiver == current->ip_receiver;
1200: } else
1201: result = FALSE;
1202: simple_unlock(&memory_manager_default_lock);
1203:
1204: return result;
1205: }
1206:
1207: void memory_manager_default_init()
1208: {
1209: memory_manager_default = IP_NULL;
1210: simple_lock_init(&memory_manager_default_lock);
1211: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.