|
|
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> ! 70: #endif NORMA_VM ! 71: #include <mach_pagemap.h> ! 72: #if MACH_PAGEMAP ! 73: #include <vm/vm_external.h> ! 74: #endif MACH_PAGEMAP ! 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: } ! 105: #endif !NORMA_VM ! 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; ! 385: #endif MACH_PAGEMAP ! 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 ! 394: if ((offset == 0) && (size > VM_EXTERNAL_LARGE_SIZE) && ! 395: (object->existence_info == VM_EXTERNAL_NULL)) { ! 396: existence_info = vm_external_create(VM_EXTERNAL_SMALL_SIZE); ! 397: } ! 398: #endif MACH_PAGEMAP ! 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: } ! 410: #endif MACH_PAGEMAP ! 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 )) ! 503: * ! 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: /* ! 901: * Old version of memory_object_lock_request. ! 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: } ! 927: #endif !NORMA_VM ! 928: ! 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: } ! 1055: #endif !NORMA_VM ! 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.