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