Annotation of kernel/vm/memory_object.c, revision 1.1.1.1

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, &copy);  \
                    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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.