Annotation of Gnu-Mach/vm/memory_object.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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