Annotation of XNU/osfmk/default_pager/dp_backing_store.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989 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: /*
                     52:  *     Default Pager.
                     53:  *             Paging File Management.
                     54:  */
                     55: 
                     56: #include <mach/memory_object_server.h>
                     57: #include "default_pager_internal.h"
                     58: #include <default_pager/default_pager_alerts.h>
                     59: #include <ipc/ipc_port.h>
                     60: #include <ipc/ipc_space.h>
                     61: #include <kern/queue.h>
                     62: #include <kern/counters.h>
                     63: #include <kern/sched_prim.h>
                     64: #include <vm/vm_kern.h> 
                     65: #include <vm/vm_pageout.h>
                     66: /* CDY CDY */
                     67: #include <vm/vm_map.h>
                     68: 
                     69: /* MAXPHYS derived from bsd/bsd/ppc/param.h, we need a */
                     70: /* universal originating in the kernel, or a formal means of exporting */
                     71: /* from the bsd component */
                     72: 
                     73: #define MAXPHYS  (64 * 1024)
                     74: int physical_transfer_cluster_count = 0;
                     75: 
                     76: #define VM_SUPER_CLUSTER       0x10000
                     77: 
                     78: /*
                     79:  * 0 means no shift to pages, so == 1 page/cluster. 1 would mean
                     80:  * 2 pages/cluster, 2 means 4 pages/cluster, and so on.
                     81:  */
                     82: #define VSTRUCT_DEF_CLSHIFT    2
                     83: int vstruct_def_clshift = VSTRUCT_DEF_CLSHIFT;
                     84: int default_pager_clsize = 0;
                     85: 
                     86: /* statistics */
                     87: unsigned int clustered_writes[MAX_CLUSTER_SIZE+1];
                     88: unsigned int clustered_reads[MAX_CLUSTER_SIZE+1];
                     89: 
                     90: /*
                     91:  * Globals used for asynchronous paging operations:
                     92:  *     vs_async_list:  head of list of to-be-completed I/O ops
                     93:  *     async_num_queued: number of pages completed, but not yet
                     94:  *             processed by async thread.
                     95:  *     async_requests_out: number of pages of requests not completed.
                     96:  */
                     97: 
                     98: #if 0
                     99: struct vs_async *vs_async_list;
                    100: int    async_num_queued;
                    101: int    async_requests_out;
                    102: #endif
                    103: 
                    104: 
                    105: #define VS_ASYNC_REUSE 1
                    106: struct vs_async *vs_async_free_list;
                    107: 
                    108: mutex_t default_pager_async_lock;      /* Protects globals above */
                    109: 
                    110: 
                    111: int vs_alloc_async_failed = 0;                 /* statistics */
                    112: int vs_alloc_async_count = 0;                  /* statistics */
                    113: struct vs_async *vs_alloc_async(void);         /* forward */
                    114: void vs_free_async(struct vs_async *vsa);      /* forward */
                    115: 
                    116: 
                    117: #define VS_ALLOC_ASYNC()       vs_alloc_async()
                    118: #define VS_FREE_ASYNC(vsa)     vs_free_async(vsa)
                    119: 
                    120: #define VS_ASYNC_LOCK()                mutex_lock(&default_pager_async_lock)
                    121: #define VS_ASYNC_UNLOCK()      mutex_unlock(&default_pager_async_lock)
                    122: #define VS_ASYNC_LOCK_INIT()   mutex_init(&default_pager_async_lock,  \
                    123:                                                ETAP_IO_DEV_PAGEH)
                    124: #define VS_ASYNC_LOCK_ADDR()   (&default_pager_async_lock)
                    125: /*
                    126:  *  Paging Space Hysteresis triggers and the target notification port
                    127:  *
                    128:  */ 
                    129: 
                    130: unsigned int   minimum_pages_remaining = 0;
                    131: unsigned int   maximum_pages_free = 0;
                    132: ipc_port_t     min_pages_trigger_port = NULL;
                    133: ipc_port_t     max_pages_trigger_port = NULL;
                    134: 
                    135: boolean_t      bs_low = FALSE;
                    136:  
                    137: 
                    138: 
                    139: /*
                    140:  * Object sizes are rounded up to the next power of 2,
                    141:  * unless they are bigger than a given maximum size.
                    142:  */
                    143: vm_size_t      max_doubled_size = 4 * 1024 * 1024;     /* 4 meg */
                    144: 
                    145: /*
                    146:  * List of all backing store and segments.
                    147:  */
                    148: struct backing_store_list_head backing_store_list;
                    149: paging_segment_t       paging_segments[MAX_NUM_PAGING_SEGMENTS];
                    150: mutex_t                        paging_segments_lock;
                    151: int                    paging_segment_max = 0;
                    152: int                    paging_segment_count = 0;
                    153: int ps_select_array[BS_MAXPRI+1] = { -1,-1,-1,-1,-1 };
                    154: 
                    155: 
                    156: /*
                    157:  * Total pages free in system
                    158:  * This differs from clusters committed/avail which is a measure of the
                    159:  * over commitment of paging segments to backing store.  An idea which is
                    160:  * likely to be deprecated.
                    161:  */
                    162: unsigned  int  dp_pages_free = 0;
                    163: unsigned  int  cluster_transfer_minimum = 100;
                    164: 
                    165: kern_return_t ps_write_file(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int); /* forward */
                    166: 
                    167: default_pager_thread_t *
                    168: get_read_buffer()
                    169: {
                    170:        int     i;
                    171: 
                    172:        DPT_LOCK(dpt_lock);
                    173:        while(TRUE) {
                    174:                for (i=0; i<default_pager_internal_count; i++) {
                    175:                        if(dpt_array[i]->checked_out == FALSE) {
                    176:                          dpt_array[i]->checked_out = TRUE;
                    177:                          DPT_UNLOCK(dpt_lock);
                    178:                          return  dpt_array[i];
                    179:                        }
                    180:                }
                    181:                assert_wait(&dpt_array, THREAD_UNINT);
                    182:                DPT_UNLOCK(dpt_lock);
                    183:                thread_block((void(*)(void))0);
                    184:        }
                    185: }
                    186: 
                    187: void
                    188: bs_initialize(void)
                    189: {
                    190:        int i;
                    191: 
                    192:        /*
                    193:         * List of all backing store.
                    194:         */
                    195:        BSL_LOCK_INIT();
                    196:        queue_init(&backing_store_list.bsl_queue);
                    197:        PSL_LOCK_INIT();
                    198: 
                    199:        VS_ASYNC_LOCK_INIT();
                    200: #if    VS_ASYNC_REUSE
                    201:        vs_async_free_list = NULL;
                    202: #endif /* VS_ASYNC_REUSE */
                    203: 
                    204:        for (i = 0; i < MAX_CLUSTER_SIZE+1; i++) {
                    205:                clustered_writes[i] = 0;
                    206:                clustered_reads[i] = 0;
                    207:        }
                    208: 
                    209: }
                    210: 
                    211: /*
                    212:  * When things do not quite workout...
                    213:  */
                    214: void bs_no_paging_space(boolean_t);    /* forward */
                    215: 
                    216: void
                    217: bs_no_paging_space(
                    218:        boolean_t out_of_memory)
                    219: {
                    220:        static char     here[] = "bs_no_paging_space";
                    221: 
                    222:        if (out_of_memory)
                    223:                dprintf(("*** OUT OF MEMORY ***\n"));
                    224:        panic("bs_no_paging_space: NOT ENOUGH PAGING SPACE");
                    225: }
                    226: 
                    227: void bs_more_space(int);       /* forward */
                    228: void bs_commit(int);           /* forward */
                    229: 
                    230: boolean_t      user_warned = FALSE;
                    231: unsigned int   clusters_committed = 0;
                    232: unsigned int   clusters_available = 0;
                    233: unsigned int   clusters_committed_peak = 0;
                    234: 
                    235: void
                    236: bs_more_space(
                    237:        int     nclusters)
                    238: {
                    239:        BSL_LOCK();
                    240:        /*
                    241:         * Account for new paging space.
                    242:         */
                    243:        clusters_available += nclusters;
                    244: 
                    245:        if (clusters_available >= clusters_committed) {
                    246:                if (verbose && user_warned) {
                    247:                        printf("%s%s - %d excess clusters now.\n",
                    248:                               my_name,
                    249:                               "paging space is OK now",
                    250:                               clusters_available - clusters_committed);
                    251:                        user_warned = FALSE;
                    252:                        clusters_committed_peak = 0;
                    253:                }
                    254:        } else {
                    255:                if (verbose && user_warned) {
                    256:                        printf("%s%s - still short of %d clusters.\n",
                    257:                               my_name,
                    258:                               "WARNING: paging space over-committed",
                    259:                               clusters_committed - clusters_available);
                    260:                        clusters_committed_peak -= nclusters;
                    261:                }
                    262:        }
                    263:        BSL_UNLOCK();
                    264: 
                    265:        return;
                    266: }
                    267: 
                    268: void
                    269: bs_commit(
                    270:        int     nclusters)
                    271: {
                    272:        BSL_LOCK();
                    273:        clusters_committed += nclusters;
                    274:        if (clusters_committed > clusters_available) {
                    275:                if (verbose && !user_warned) {
                    276:                        user_warned = TRUE;
                    277:                        printf("%s%s - short of %d clusters.\n",
                    278:                               my_name,
                    279:                               "WARNING: paging space over-committed",
                    280:                               clusters_committed - clusters_available);
                    281:                }
                    282:                if (clusters_committed > clusters_committed_peak) {
                    283:                        clusters_committed_peak = clusters_committed;
                    284:                }
                    285:        } else {
                    286:                if (verbose && user_warned) {
                    287:                        printf("%s%s - was short of up to %d clusters.\n",
                    288:                               my_name,
                    289:                               "paging space is OK now",
                    290:                               clusters_committed_peak - clusters_available);
                    291:                        user_warned = FALSE;
                    292:                        clusters_committed_peak = 0;
                    293:                }
                    294:        }
                    295:        BSL_UNLOCK();
                    296: 
                    297:        return;
                    298: }
                    299: 
                    300: int default_pager_info_verbose = 1;
                    301: 
                    302: void
                    303: bs_global_info(
                    304:        vm_size_t       *totalp,
                    305:        vm_size_t       *freep)
                    306: {
                    307:        vm_size_t               pages_total, pages_free;
                    308:        paging_segment_t        ps;
                    309:        int                     i;
                    310:        static char             here[] = "bs_global_info";
                    311: 
                    312:        PSL_LOCK();
                    313:        pages_total = pages_free = 0;
                    314:        for (i = 0; i <= paging_segment_max; i++) {
                    315:                ps = paging_segments[i];
                    316:                if (ps == PAGING_SEGMENT_NULL) 
                    317:                        continue;
                    318: 
                    319:                /*
                    320:                 * no need to lock: by the time this data
                    321:                 * gets back to any remote requestor it
                    322:                 * will be obsolete anyways
                    323:                 */
                    324:                pages_total += ps->ps_pgnum;
                    325:                pages_free += ps->ps_clcount << ps->ps_clshift;
                    326:                DEBUG(DEBUG_BS_INTERNAL,
                    327:                      ("segment #%d: %d total, %d free\n",
                    328:                       i, ps->ps_pgnum, ps->ps_clcount << ps->ps_clshift));
                    329:        }
                    330:        *totalp = pages_total;
                    331:        *freep = pages_free;
                    332:        if (verbose && user_warned && default_pager_info_verbose) {
                    333:                if (clusters_available < clusters_committed) {
                    334:                        printf("%s %d clusters committed, %d available.\n",
                    335:                               my_name,
                    336:                               clusters_committed,
                    337:                               clusters_available);
                    338:                }
                    339:        }
                    340:        PSL_UNLOCK();
                    341: }
                    342: 
                    343: backing_store_t backing_store_alloc(void);     /* forward */
                    344: 
                    345: backing_store_t
                    346: backing_store_alloc(void)
                    347: {
                    348:        backing_store_t bs;
                    349:        static char     here[] = "backing_store_alloc";
                    350: 
                    351:        bs = (backing_store_t) kalloc(sizeof (struct backing_store));
                    352:        if (bs == BACKING_STORE_NULL)
                    353:                panic("backing_store_alloc: no memory");
                    354: 
                    355:        BS_LOCK_INIT(bs);
                    356:        bs->bs_port = MACH_PORT_NULL;
                    357:        bs->bs_priority = 0;
                    358:        bs->bs_clsize = 0;
                    359:        bs->bs_pages_total = 0;
                    360:        bs->bs_pages_in = 0;
                    361:        bs->bs_pages_in_fail = 0;
                    362:        bs->bs_pages_out = 0;
                    363:        bs->bs_pages_out_fail = 0;
                    364: 
                    365:        return bs;
                    366: }
                    367: 
                    368: backing_store_t backing_store_lookup(MACH_PORT_FACE);  /* forward */
                    369: 
                    370: /* Even in both the component space and external versions of this pager, */
                    371: /* backing_store_lookup will be called from tasks in the application space */
                    372: backing_store_t
                    373: backing_store_lookup(
                    374:        MACH_PORT_FACE port)
                    375: {
                    376:        backing_store_t bs;
                    377: 
                    378: /*
                    379:        port is currently backed with a vs structure in the alias field
                    380:        we could create an ISBS alias and a port_is_bs call but frankly
                    381:        I see no reason for the test, the bs->port == port check below
                    382:        will work properly on junk entries.
                    383: 
                    384:        if ((port == MACH_PORT_NULL) || port_is_vs(port))
                    385: */
                    386:        if ((port == MACH_PORT_NULL))
                    387:                return BACKING_STORE_NULL;
                    388: 
                    389:        BSL_LOCK();
                    390:        queue_iterate(&backing_store_list.bsl_queue, bs, backing_store_t,
                    391:                      bs_links) {
                    392:                BS_LOCK(bs);
                    393:                if (bs->bs_port == port) {
                    394:                        BSL_UNLOCK();
                    395:                        /* Success, return it locked. */
                    396:                        return bs;
                    397:                }
                    398:                BS_UNLOCK(bs);
                    399:        }
                    400:        BSL_UNLOCK();
                    401:        return BACKING_STORE_NULL;
                    402: }
                    403: 
                    404: void backing_store_add(backing_store_t);       /* forward */
                    405: 
                    406: void
                    407: backing_store_add(
                    408:        backing_store_t bs)
                    409: {
                    410:        MACH_PORT_FACE          port = bs->bs_port;
                    411:        MACH_PORT_FACE          pset = default_pager_default_set;
                    412:        kern_return_t           kr = KERN_SUCCESS;
                    413:        static char             here[] = "backing_store_add";
                    414: 
                    415:        if (kr != KERN_SUCCESS)
                    416:                panic("backing_store_add: add to set");
                    417: 
                    418: }
                    419: 
                    420: /*
                    421:  * Set up default page shift, but only if not already
                    422:  * set and argument is within range.
                    423:  */
                    424: boolean_t
                    425: bs_set_default_clsize(unsigned int npages)
                    426: {
                    427:        switch(npages){
                    428:            case 1:
                    429:            case 2:
                    430:            case 4:
                    431:            case 8:
                    432:                if (default_pager_clsize == 0)  /* if not yet set */
                    433:                        vstruct_def_clshift = local_log2(npages);
                    434:                return(TRUE);
                    435:        }
                    436:        return(FALSE);
                    437: }
                    438: 
                    439: int bs_get_global_clsize(int clsize);  /* forward */
                    440: 
                    441: int
                    442: bs_get_global_clsize(
                    443:        int     clsize)
                    444: {
                    445:        int                     i;
                    446:        MACH_PORT_FACE          DMM;
                    447:        kern_return_t           kr;
                    448:        static char             here[] = "bs_get_global_clsize";
                    449: 
                    450:        /*
                    451:         * Only allow setting of cluster size once. If called
                    452:         * with no cluster size (default), we use the compiled-in default
                    453:         * for the duration. The same cluster size is used for all
                    454:         * paging segments.
                    455:         */
                    456:        if (default_pager_clsize == 0) {
                    457:                if (norma_mk) {
                    458:                        /*
                    459:                         * On NORMA, don't use clustered paging because
                    460:                         * XMM can't handle it.
                    461:                         */
                    462:                        vstruct_def_clshift = 0;
                    463:                }
                    464:                /*
                    465:                 * Keep cluster size in bit shift because it's quicker
                    466:                 * arithmetic, and easier to keep at a power of 2.
                    467:                 */
                    468:                if (clsize != NO_CLSIZE) {
                    469:                        for (i = 0; (1 << i) < clsize; i++);
                    470:                        if (i > MAX_CLUSTER_SHIFT)
                    471:                                i = MAX_CLUSTER_SHIFT;
                    472:                        vstruct_def_clshift = i;
                    473:                }
                    474:                default_pager_clsize = (1 << vstruct_def_clshift);
                    475: 
                    476:                /*
                    477:                 * Let the user know the new (and definitive) cluster size.
                    478:                 */
                    479:                if (verbose)
                    480:                        printf("%scluster size = %d page%s\n",
                    481:                                my_name, default_pager_clsize,
                    482:                                (default_pager_clsize == 1) ? "" : "s");
                    483:                /*
                    484:                 * Let the kernel know too, in case it hasn't used the
                    485:                 * default value provided in main() yet.
                    486:                 */
                    487:                DMM = default_pager_default_port;
                    488:                clsize = default_pager_clsize * vm_page_size;   /* in bytes */
                    489:                kr = host_default_memory_manager(default_pager_host_port,
                    490:                                                 &DMM,
                    491:                                                 clsize);
                    492:                if (kr != KERN_SUCCESS) {
                    493:                   panic("bs_get_global_cl_size:host_default_memory_manager");
                    494:                }
                    495:                if (DMM != default_pager_default_port) {
                    496:                  panic("bs_get_global_cl_size:there is another default pager");
                    497:                }
                    498:        }
                    499:        ASSERT(default_pager_clsize > 0 &&
                    500:               (default_pager_clsize & (default_pager_clsize - 1)) == 0);
                    501: 
                    502:        return default_pager_clsize;
                    503: }
                    504: 
                    505: kern_return_t
                    506: default_pager_backing_store_create(
                    507:        MACH_PORT_FACE  pager,
                    508:        int             priority,
                    509:        int             clsize,         /* in bytes */
                    510:        MACH_PORT_FACE  *backing_store)
                    511: {
                    512:        backing_store_t bs;
                    513:        MACH_PORT_FACE  port;
                    514:        kern_return_t   kr;
                    515:        struct vstruct_alias *alias_struct;
                    516:        static char here[] = "default_pager_backing_store_create";
                    517: 
                    518:        if (pager != default_pager_default_port)
                    519:                return KERN_INVALID_ARGUMENT;
                    520: 
                    521:        bs = backing_store_alloc();
                    522:        port = ipc_port_alloc_kernel();
                    523:        ipc_port_make_send(port);
                    524:        assert (port != IP_NULL);
                    525: 
                    526:        DEBUG(DEBUG_BS_EXTERNAL,
                    527:              ("priority=%d clsize=%d bs_port=0x%x\n",
                    528:               priority, clsize, (int) backing_store));
                    529: 
                    530:        alias_struct = (struct vstruct_alias *) 
                    531:                                kalloc(sizeof (struct vstruct_alias));
                    532:        if(alias_struct != NULL) {
                    533:                alias_struct->vs = (struct vstruct *)bs;
                    534:                alias_struct->name = ISVS;
                    535:                port->alias = (int) alias_struct;
                    536:        }
                    537:        else {
                    538:                ipc_port_dealloc_kernel((MACH_PORT_FACE)(port));
                    539:                kfree((vm_offset_t)bs, sizeof (struct backing_store));
                    540:                return KERN_RESOURCE_SHORTAGE;
                    541:        }
                    542: 
                    543:        bs->bs_port = port;
                    544:        if (priority == DEFAULT_PAGER_BACKING_STORE_MAXPRI)
                    545:                priority = BS_MAXPRI;
                    546:        else if (priority == BS_NOPRI)
                    547:                priority = BS_MAXPRI;
                    548:        else
                    549:                priority = BS_MINPRI;
                    550:        bs->bs_priority = priority;
                    551: 
                    552:        bs->bs_clsize = bs_get_global_clsize(atop(clsize));
                    553: 
                    554:        BSL_LOCK();
                    555:        queue_enter(&backing_store_list.bsl_queue, bs, backing_store_t,
                    556:                    bs_links);
                    557:        BSL_UNLOCK();
                    558: 
                    559:        backing_store_add(bs);
                    560: 
                    561:        *backing_store = port;
                    562:        return KERN_SUCCESS;
                    563: }
                    564: 
                    565: kern_return_t
                    566: default_pager_backing_store_info(
                    567:        MACH_PORT_FACE          backing_store,
                    568:        backing_store_flavor_t  flavour,
                    569:        backing_store_info_t    info,
                    570:        mach_msg_type_number_t  *size)
                    571: {
                    572:        backing_store_t                 bs;
                    573:        backing_store_basic_info_t      basic;
                    574:        int                             i;
                    575:        paging_segment_t                ps;
                    576: 
                    577:        if (flavour != BACKING_STORE_BASIC_INFO ||
                    578:            *size < BACKING_STORE_BASIC_INFO_COUNT)
                    579:                return KERN_INVALID_ARGUMENT;
                    580: 
                    581:        basic = (backing_store_basic_info_t)info;
                    582:        *size = BACKING_STORE_BASIC_INFO_COUNT;
                    583: 
                    584:        VSTATS_LOCK(&global_stats.gs_lock);
                    585:        basic->pageout_calls    = global_stats.gs_pageout_calls;
                    586:        basic->pagein_calls     = global_stats.gs_pagein_calls;
                    587:        basic->pages_in         = global_stats.gs_pages_in;
                    588:        basic->pages_out        = global_stats.gs_pages_out;
                    589:        basic->pages_unavail    = global_stats.gs_pages_unavail;
                    590:        basic->pages_init       = global_stats.gs_pages_init;
                    591:        basic->pages_init_writes= global_stats.gs_pages_init_writes;
                    592:        VSTATS_UNLOCK(&global_stats.gs_lock);
                    593: 
                    594:        if ((bs = backing_store_lookup(backing_store)) == BACKING_STORE_NULL)
                    595:                return KERN_INVALID_ARGUMENT;
                    596: 
                    597:        basic->bs_pages_total   = bs->bs_pages_total;
                    598:        PSL_LOCK();
                    599:        bs->bs_pages_free = 0;
                    600:        for (i = 0; i <= paging_segment_max; i++) {
                    601:                ps = paging_segments[i];
                    602:                if (ps != PAGING_SEGMENT_NULL && ps->ps_bs == bs) {
                    603:                        PS_LOCK(ps);
                    604:                        bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
                    605:                        PS_UNLOCK(ps);
                    606:                }
                    607:        }
                    608:        PSL_UNLOCK();
                    609:        basic->bs_pages_free    = bs->bs_pages_free;
                    610:        basic->bs_pages_in      = bs->bs_pages_in;
                    611:        basic->bs_pages_in_fail = bs->bs_pages_in_fail;
                    612:        basic->bs_pages_out     = bs->bs_pages_out;
                    613:        basic->bs_pages_out_fail= bs->bs_pages_out_fail;
                    614: 
                    615:        basic->bs_priority      = bs->bs_priority;
                    616:        basic->bs_clsize        = ptoa(bs->bs_clsize);  /* in bytes */
                    617: 
                    618:        BS_UNLOCK(bs);
                    619: 
                    620:        return KERN_SUCCESS;
                    621: }
                    622: 
                    623: int ps_delete(paging_segment_t);       /* forward */
                    624: 
                    625: int
                    626: ps_delete(
                    627:        paging_segment_t ps)
                    628: {
                    629:        vstruct_t       vs;
                    630:        kern_return_t   error = KERN_SUCCESS;
                    631:        int             vs_count;
                    632:        
                    633:        VSL_LOCK();             /* get the lock on the list of vs's      */
                    634: 
                    635:        /* The lock relationship and sequence is farily complicated      */
                    636:        /* this code looks at a live list, locking and unlocking the list */
                    637:        /* as it traverses it.  It depends on the locking behavior of    */
                    638:        /* default_pager_no_senders.  no_senders always locks the vstruct */
                    639:        /* targeted for removal before locking the vstruct list.  However */
                    640:        /* it will remove that member of the list without locking its    */
                    641:        /* neighbors.  We can be sure when we hold a lock on a vstruct   */
                    642:        /* it cannot be removed from the list but we must hold the list  */
                    643:        /* lock to be sure that its pointers to its neighbors are valid. */
                    644:        /* Also, we can hold off destruction of a vstruct when the list  */
                    645:        /* lock and the vs locks are not being held by bumping the       */
                    646:        /* vs_async_pending count.      */
                    647: 
                    648:        /* we will choose instead to hold a send right */
                    649:        vs_count = vstruct_list.vsl_count;
                    650:        vs = (vstruct_t) queue_first((queue_entry_t)&(vstruct_list.vsl_queue));
                    651:        if(vs == (vstruct_t)&vstruct_list)  {
                    652:                VSL_UNLOCK();
                    653:                return KERN_SUCCESS;
                    654:        }
                    655:        VS_LOCK(vs);
                    656:        vs_async_wait(vs);  /* wait for any pending async writes */
                    657:        if ((vs_count != 0) && (vs != NULL))
                    658:                vs->vs_async_pending += 1;  /* hold parties calling  */
                    659:                                            /* vs_async_wait */
                    660:        VS_UNLOCK(vs);
                    661:        VSL_UNLOCK();
                    662:        while((vs_count != 0) && (vs != NULL)) {
                    663:                /* We take the count of AMO's before beginning the         */
                    664:                /* transfer of of the target segment.                      */
                    665:                /* We are guaranteed that the target segment cannot get    */
                    666:                /* more users.  We also know that queue entries are        */
                    667:                /* made at the back of the list.  If some of the entries   */
                    668:                /* we would check disappear while we are traversing the    */
                    669:                /* list then we will either check new entries which        */
                    670:                /* do not have any backing store in the target segment     */
                    671:                /* or re-check old entries.  This might not be optimal     */
                    672:                /* but it will always be correct. The alternative is to    */
                    673:                /* take a snapshot of the list.                            */
                    674:                vstruct_t       next_vs;
                    675:                
                    676:                if(dp_pages_free < cluster_transfer_minimum)
                    677:                        error = KERN_FAILURE;
                    678:                else {
                    679:                        vm_object_t     transfer_object;
                    680:                        upl_t           page_list;
                    681: 
                    682:                        transfer_object = vm_object_allocate(VM_SUPER_CLUSTER);
                    683:                        error = vm_fault_list_request(transfer_object, 
                    684:                                        0, VM_SUPER_CLUSTER, &page_list, NULL, 
                    685:                                        0, UPL_NO_SYNC | UPL_CLEAN_IN_PLACE);
                    686:                        if(error == KERN_SUCCESS)
                    687:                                error = ps_vstruct_transfer_from_segment(
                    688:                                                        vs, ps, page_list);
                    689:                        upl_commit(page_list, NULL);
                    690:                        vm_object_deallocate(transfer_object);
                    691:                }
                    692:                if(error) {
                    693:                        VS_LOCK(vs);
                    694:                        vs->vs_async_pending -= 1;  /* release vs_async_wait */
                    695:                        if (vs->vs_async_pending == 0) {
                    696:                                VS_UNLOCK(vs);
                    697:                                thread_wakeup(&vs->vs_waiting_async);
                    698:                        } else {
                    699:                                VS_UNLOCK(vs);
                    700:                        }
                    701:                        return KERN_FAILURE;
                    702:                }
                    703: 
                    704:                VSL_LOCK(); 
                    705:                next_vs = (vstruct_t) queue_next(&(vs->vs_links));
                    706:                if((next_vs != (vstruct_t)&vstruct_list) && 
                    707:                                (vs != next_vs) && (vs_count != 1)) {
                    708:                        VS_LOCK(next_vs);
                    709:                        next_vs->vs_async_pending += 1; /* hold parties  */
                    710:                                                /* calling vs_async_wait */
                    711:                        VS_UNLOCK(next_vs);
                    712:                }
                    713:                VSL_UNLOCK();
                    714:                VS_LOCK(vs);
                    715:                vs->vs_async_pending -= 1; 
                    716:                if (vs->vs_async_pending == 0) {
                    717:                        VS_UNLOCK(vs);
                    718:                        thread_wakeup(&vs->vs_waiting_async);
                    719:                } else {
                    720:                        VS_UNLOCK(vs);
                    721:                }
                    722:                if((vs == next_vs) || (next_vs == (vstruct_t)&vstruct_list))
                    723:                        vs = NULL;
                    724:                else
                    725:                        vs = next_vs;
                    726:                vs_count--;
                    727:        }
                    728:        return KERN_SUCCESS;
                    729: }
                    730: 
                    731: 
                    732: kern_return_t
                    733: default_pager_backing_store_delete(
                    734:        MACH_PORT_FACE backing_store)
                    735: {
                    736:        backing_store_t         bs;
                    737:        int                     i;
                    738:        paging_segment_t        ps;
                    739:        int                     error;
                    740:        int                     interim_pages_removed = 0;
                    741:        kern_return_t           kr;
                    742:        static char here[] = "default_pager_backing_store_delete";
                    743: 
                    744:        if ((bs = backing_store_lookup(backing_store)) == BACKING_STORE_NULL)
                    745:                return KERN_INVALID_ARGUMENT;
                    746: 
                    747: #if 0
                    748:        /* not implemented */
                    749:        BS_UNLOCK(bs);
                    750:        return KERN_FAILURE;
                    751: #endif
                    752: 
                    753:     restart:
                    754:        PSL_LOCK();
                    755:        error = KERN_SUCCESS;
                    756:        for (i = 0; i <= paging_segment_max; i++) {
                    757:                ps = paging_segments[i];
                    758:                if (ps != PAGING_SEGMENT_NULL &&
                    759:                    ps->ps_bs == bs &&
                    760:                    ! ps->ps_going_away) {
                    761:                        PS_LOCK(ps);
                    762:                        /* disable access to this segment */
                    763:                        ps->ps_going_away = TRUE;
                    764:                        PS_UNLOCK(ps);
                    765:                        /*
                    766:                         * The "ps" segment is "off-line" now,
                    767:                         * we can try and delete it...
                    768:                         */
                    769:                        if(dp_pages_free < (cluster_transfer_minimum
                    770:                                 + (ps->ps_clcount << ps->ps_clshift))) {
                    771:                                error = KERN_FAILURE;
                    772:                                PSL_UNLOCK();
                    773:                        }
                    774:                        else {
                    775:                                dp_pages_free -= 
                    776:                                        ps->ps_clcount << ps->ps_clshift;
                    777:                                interim_pages_removed +=
                    778:                                        ps->ps_clcount << ps->ps_clshift;
                    779:                                PSL_UNLOCK();
                    780:                                error = ps_delete(ps);
                    781:                        }
                    782:                        if (error != KERN_SUCCESS) {
                    783:                                /*
                    784:                                 * We couldn't delete the segment,
                    785:                                 * probably because there's not enough
                    786:                                 * virtual memory left.
                    787:                                 * Re-enable all the segments.
                    788:                                 */
                    789:                                PSL_LOCK();
                    790:                                break;
                    791:                        }
                    792:                        goto restart;
                    793:                }
                    794:        }
                    795: 
                    796:        if (error != KERN_SUCCESS) {
                    797:                for (i = 0; i <= paging_segment_max; i++) {
                    798:                        ps = paging_segments[i];
                    799:                        if (ps != PAGING_SEGMENT_NULL &&
                    800:                            ps->ps_bs == bs &&
                    801:                            ps->ps_going_away) {
                    802:                                PS_LOCK(ps);
                    803:                                /* re-enable access to this segment */
                    804:                                ps->ps_going_away = FALSE;
                    805:                                PS_UNLOCK(ps);
                    806:                        }
                    807:                }
                    808:                dp_pages_free += interim_pages_removed;
                    809:                PSL_UNLOCK();
                    810:                BS_UNLOCK(bs);
                    811:                return error;
                    812:        }
                    813: 
                    814:        for (i = 0; i <= paging_segment_max; i++) {
                    815:                ps = paging_segments[i];
                    816:                if (ps != PAGING_SEGMENT_NULL &&
                    817:                    ps->ps_bs == bs) { 
                    818:                        if(ps->ps_going_away) {
                    819:                                paging_segments[i] = PAGING_SEGMENT_NULL;
                    820:                                paging_segment_count--;
                    821:                                PS_LOCK(ps);
                    822:                                kfree((vm_offset_t)ps->ps_bmap, 
                    823:                                                RMAPSIZE(ps->ps_ncls));
                    824:                                kfree((vm_offset_t)ps, sizeof *ps);
                    825:                        }
                    826:                }
                    827:        }
                    828: 
                    829:        /* Scan the entire ps array separately to make certain we find the */
                    830:        /* proper paging_segment_max                                       */
                    831:        for (i = 0; i < MAX_NUM_PAGING_SEGMENTS; i++) {
                    832:                if(paging_segments[i] != PAGING_SEGMENT_NULL)
                    833:                   paging_segment_max = i;
                    834:        }
                    835: 
                    836:        PSL_UNLOCK();
                    837: 
                    838:        /*
                    839:         * All the segments have been deleted.
                    840:         * We can remove the backing store.
                    841:         */
                    842: 
                    843:        /*
                    844:         * Disable lookups of this backing store.
                    845:         */
                    846:        if((void *)bs->bs_port->alias != NULL)
                    847:                kfree((vm_offset_t) bs->bs_port->alias, 
                    848:                                sizeof (struct vstruct_alias));
                    849:        pager_mux_hash_delete((ipc_port_t) (bs->bs_port));
                    850:        ipc_port_dealloc_kernel((ipc_port_t) (bs->bs_port));
                    851:        bs->bs_port = MACH_PORT_NULL;
                    852:        BS_UNLOCK(bs);
                    853: 
                    854:        /*
                    855:         * Remove backing store from backing_store list.
                    856:         */
                    857:        BSL_LOCK();
                    858:        queue_remove(&backing_store_list.bsl_queue, bs, backing_store_t,
                    859:                     bs_links);
                    860:        BSL_UNLOCK();
                    861: 
                    862:        /*
                    863:         * Free the backing store structure.
                    864:         */
                    865:        kfree((vm_offset_t)bs, sizeof *bs);
                    866: 
                    867:        return KERN_SUCCESS;
                    868: }
                    869: 
                    870: int    ps_enter(paging_segment_t);     /* forward */
                    871: 
                    872: int
                    873: ps_enter(
                    874:        paging_segment_t ps)
                    875: {
                    876:        int i;
                    877: 
                    878:        PSL_LOCK();
                    879: 
                    880:        for (i = 0; i < MAX_NUM_PAGING_SEGMENTS; i++) {
                    881:                if (paging_segments[i] == PAGING_SEGMENT_NULL)
                    882:                        break;
                    883:        }
                    884: 
                    885:        if (i < MAX_NUM_PAGING_SEGMENTS) {
                    886:                paging_segments[i] = ps;
                    887:                if (i > paging_segment_max)
                    888:                        paging_segment_max = i;
                    889:                paging_segment_count++;
                    890:                if ((ps_select_array[ps->ps_bs->bs_priority] == BS_NOPRI) ||
                    891:                        (ps_select_array[ps->ps_bs->bs_priority] == BS_FULLPRI))
                    892:                        ps_select_array[ps->ps_bs->bs_priority] = 0;
                    893:                i = 0;
                    894:        } else {
                    895:                PSL_UNLOCK();
                    896:                return KERN_RESOURCE_SHORTAGE;
                    897:        }
                    898: 
                    899:        PSL_UNLOCK();
                    900:        return i;
                    901: }
                    902: 
                    903: #ifdef DEVICE_PAGING
                    904: kern_return_t
                    905: default_pager_add_segment(
                    906:        MACH_PORT_FACE  backing_store,
                    907:        MACH_PORT_FACE  device,
                    908:        recnum_t        offset,
                    909:        recnum_t        count,
                    910:        int             record_size)
                    911: {
                    912:        backing_store_t         bs;
                    913:        paging_segment_t        ps;
                    914:        int                     i;
                    915:        int                     error;
                    916:        static char here[] = "default_pager_add_segment"; 
                    917: 
                    918:        if ((bs = backing_store_lookup(backing_store))
                    919:            == BACKING_STORE_NULL)
                    920:                return KERN_INVALID_ARGUMENT;
                    921: 
                    922:        PSL_LOCK();
                    923:        for (i = 0; i <= paging_segment_max; i++) {
                    924:                ps = paging_segments[i];
                    925:                if (ps == PAGING_SEGMENT_NULL)
                    926:                        continue;
                    927: 
                    928:                /*
                    929:                 * Check for overlap on same device.
                    930:                 */
                    931:                if (!(ps->ps_device != device
                    932:                      || offset >= ps->ps_offset + ps->ps_recnum
                    933:                      || offset + count <= ps->ps_offset)) {
                    934:                        PSL_UNLOCK();
                    935:                        BS_UNLOCK(bs);
                    936:                        return KERN_INVALID_ARGUMENT;
                    937:                }
                    938:        }
                    939:        PSL_UNLOCK();
                    940: 
                    941:        /*
                    942:         * Set up the paging segment
                    943:         */
                    944:        ps = (paging_segment_t) kalloc(sizeof (struct paging_segment));
                    945:        if (ps == PAGING_SEGMENT_NULL) {
                    946:                BS_UNLOCK(bs);
                    947:                return KERN_RESOURCE_SHORTAGE;
                    948:        }
                    949: 
                    950:        ps->ps_segtype = PS_PARTITION;
                    951:        ps->ps_device = device;
                    952:        ps->ps_offset = offset;
                    953:        ps->ps_record_shift = local_log2(vm_page_size / record_size);
                    954:        ps->ps_recnum = count;
                    955:        ps->ps_pgnum = count >> ps->ps_record_shift;
                    956: 
                    957:        ps->ps_pgcount = ps->ps_pgnum;
                    958:        ps->ps_clshift = local_log2(bs->bs_clsize);
                    959:        ps->ps_clcount = ps->ps_ncls = ps->ps_pgcount >> ps->ps_clshift;
                    960:        ps->ps_hint = 0;
                    961: 
                    962:        PS_LOCK_INIT(ps);
                    963:        ps->ps_bmap = (unsigned char *) kalloc(RMAPSIZE(ps->ps_ncls));
                    964:        if (!ps->ps_bmap) {
                    965:                kfree((vm_offset_t)ps, sizeof *ps);
                    966:                BS_UNLOCK(bs);
                    967:                return KERN_RESOURCE_SHORTAGE;
                    968:        }
                    969:        for (i = 0; i < ps->ps_ncls; i++) {
                    970:                clrbit(ps->ps_bmap, i);
                    971:        }
                    972: 
                    973:        ps->ps_going_away = FALSE;
                    974:        ps->ps_bs = bs;
                    975: 
                    976:        if ((error = ps_enter(ps)) != 0) {
                    977:                kfree((vm_offset_t)ps->ps_bmap, RMAPSIZE(ps->ps_ncls));
                    978:                kfree((vm_offset_t)ps, sizeof *ps);
                    979:                BS_UNLOCK(bs);
                    980:                return KERN_RESOURCE_SHORTAGE;
                    981:        }
                    982: 
                    983:        bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
                    984:        bs->bs_pages_total += ps->ps_clcount << ps->ps_clshift;
                    985:        BS_UNLOCK(bs);
                    986: 
                    987:        PSL_LOCK();
                    988:        dp_pages_free += ps->ps_pgcount;
                    989:        PSL_UNLOCK();
                    990: 
                    991:        bs_more_space(ps->ps_clcount);
                    992: 
                    993:        DEBUG(DEBUG_BS_INTERNAL,
                    994:              ("device=0x%x,offset=0x%x,count=0x%x,record_size=0x%x,shift=%d,total_size=0x%x\n",
                    995:               device, offset, count, record_size,
                    996:               ps->ps_record_shift, ps->ps_pgnum));
                    997: 
                    998:        return KERN_SUCCESS;
                    999: }
                   1000: 
                   1001: boolean_t
                   1002: bs_add_device(
                   1003:        char            *dev_name,
                   1004:        MACH_PORT_FACE  master)
                   1005: {
                   1006:        security_token_t        null_security_token = {
                   1007:                { 0, 0 }
                   1008:        };
                   1009:        MACH_PORT_FACE  device;
                   1010:        int             info[DEV_GET_SIZE_COUNT];
                   1011:        mach_msg_type_number_t info_count;
                   1012:        MACH_PORT_FACE  bs = MACH_PORT_NULL;
                   1013:        unsigned int    rec_size;
                   1014:        recnum_t        count;
                   1015:        int             clsize;
                   1016:        MACH_PORT_FACE  reply_port;
                   1017: 
                   1018:        if (ds_device_open_sync(master, MACH_PORT_NULL, D_READ | D_WRITE,
                   1019:                        null_security_token, dev_name, &device))
                   1020:                return FALSE;
                   1021: 
                   1022:        info_count = DEV_GET_SIZE_COUNT;
                   1023:        if (!ds_device_get_status(device, DEV_GET_SIZE, info, &info_count)) {
                   1024:                rec_size = info[DEV_GET_SIZE_RECORD_SIZE];
                   1025:                count = info[DEV_GET_SIZE_DEVICE_SIZE] /  rec_size;
                   1026:                clsize = bs_get_global_clsize(0);
                   1027:                if (!default_pager_backing_store_create(
                   1028:                                        default_pager_default_port,
                   1029:                                        DEFAULT_PAGER_BACKING_STORE_MAXPRI,
                   1030:                                        (clsize * vm_page_size),
                   1031:                                        &bs)) {
                   1032:                        if (!default_pager_add_segment(bs, device,
                   1033:                                                       0, count, rec_size)) {
                   1034:                                return TRUE;
                   1035:                        }
                   1036:                        ipc_port_release_receive(bs);
                   1037:                }
                   1038:        }
                   1039: 
                   1040:        ipc_port_release_send(device);
                   1041:        return FALSE;
                   1042: }
                   1043: #endif /* DEVICE_PAGING */
                   1044: 
                   1045: #if    VS_ASYNC_REUSE
                   1046: 
                   1047: struct vs_async *
                   1048: vs_alloc_async(void)
                   1049: {
                   1050:        struct vs_async *vsa;
                   1051:        MACH_PORT_FACE  reply_port;
                   1052:        kern_return_t   kr;
                   1053: 
                   1054:        VS_ASYNC_LOCK();
                   1055:        if (vs_async_free_list == NULL) {
                   1056:                VS_ASYNC_UNLOCK();
                   1057:                vsa = (struct vs_async *) kalloc(sizeof (struct vs_async));
                   1058:                if (vsa != NULL) {
                   1059:                        /*
                   1060:                         * Try allocating a reply port named after the
                   1061:                         * address of the vs_async structure.
                   1062:                         */
                   1063:                        struct vstruct_alias    *alias_struct;
                   1064: 
                   1065:                        reply_port = ipc_port_alloc_kernel();
                   1066:                        alias_struct = (struct vstruct_alias *) 
                   1067:                                kalloc(sizeof (struct vstruct_alias));
                   1068:                        if(alias_struct != NULL) {
                   1069:                                alias_struct->vs = (struct vstruct *)vsa;
                   1070:                                alias_struct->name = ISVS;
                   1071:                                reply_port->alias = (int) alias_struct;
                   1072:                                vsa->reply_port = reply_port;
                   1073:                                vs_alloc_async_count++;
                   1074:                        }
                   1075:                        else {
                   1076:                                vs_alloc_async_failed++;
                   1077:                                ipc_port_dealloc_kernel((MACH_PORT_FACE) 
                   1078:                                                                (reply_port));
                   1079:                                kfree((vm_offset_t)vsa, 
                   1080:                                                sizeof (struct vs_async));
                   1081:                                vsa = NULL;
                   1082:                        }
                   1083:                }
                   1084:        } else {
                   1085:                vsa = vs_async_free_list;
                   1086:                vs_async_free_list = vs_async_free_list->vsa_next;
                   1087:                VS_ASYNC_UNLOCK();
                   1088:        }
                   1089: 
                   1090:        return vsa;
                   1091: }
                   1092: 
                   1093: void
                   1094: vs_free_async(
                   1095:        struct vs_async *vsa)
                   1096: {
                   1097:        VS_ASYNC_LOCK();
                   1098:        vsa->vsa_next = vs_async_free_list;
                   1099:        vs_async_free_list = vsa;
                   1100:        VS_ASYNC_UNLOCK();
                   1101: }
                   1102: 
                   1103: #else  /* VS_ASYNC_REUSE */
                   1104: 
                   1105: struct vs_async *
                   1106: vs_alloc_async(void)
                   1107: {
                   1108:        struct vs_async *vsa;
                   1109:        MACH_PORT_FACE  reply_port;
                   1110:        kern_return_t   kr;
                   1111: 
                   1112:        vsa = (struct vs_async *) kalloc(sizeof (struct vs_async));
                   1113:        if (vsa != NULL) {
                   1114:                /*
                   1115:                 * Try allocating a reply port named after the
                   1116:                 * address of the vs_async structure.
                   1117:                 */
                   1118:                        reply_port = ipc_port_alloc_kernel();
                   1119:                        alias_struct = (vstruct_alias *) 
                   1120:                                kalloc(sizeof (struct vstruct_alias));
                   1121:                        if(alias_struct != NULL) {
                   1122:                                alias_struct->vs = reply_port;
                   1123:                                alias_struct->name = ISVS;
                   1124:                                reply_port->alias = (int) vsa;
                   1125:                                vsa->reply_port = reply_port;
                   1126:                                vs_alloc_async_count++;
                   1127:                        }
                   1128:                        else {
                   1129:                                vs_alloc_async_failed++;
                   1130:                                ipc_port_dealloc_kernel((MACH_PORT_FACE) 
                   1131:                                                                (reply_port));
                   1132:                                kfree((vm_offset_t) vsa, 
                   1133:                                                sizeof (struct vs_async));
                   1134:                                vsa = NULL;
                   1135:                        }
                   1136:        }
                   1137: 
                   1138:        return vsa;
                   1139: }
                   1140: 
                   1141: void
                   1142: vs_free_async(
                   1143:        struct vs_async *vsa)
                   1144: {
                   1145:        static char     here[] = "vs_free_async";
                   1146:        MACH_PORT_FACE  reply_port;
                   1147:        kern_return_t   kr;
                   1148: 
                   1149:        reply_port = vsa->reply_port;
                   1150:        kfree((vm_offset_t) reply_port->alias, sizeof (struct vstuct_alias));
                   1151:        kfree((vm_offset_t) vsa, sizeof (struct vs_async));
                   1152:        pager_mux_hash_delete(reply_port);
                   1153:        ipc_port_dealloc_kernel((MACH_PORT_FACE) (reply_port));
                   1154: #if 0
                   1155:        VS_ASYNC_LOCK();
                   1156:        vs_alloc_async_count--;
                   1157:        VS_ASYNC_UNLOCK();
                   1158: #endif
                   1159: }
                   1160: 
                   1161: #endif /* VS_ASYNC_REUSE */
                   1162: 
                   1163: vstruct_t
                   1164: ps_vstruct_create(
                   1165:        vm_size_t size)
                   1166: {
                   1167:        vstruct_t       vs;
                   1168:        int             i;
                   1169:        static char here[] = "ps_vstruct_create";
                   1170: 
                   1171:        vs = (vstruct_t) kalloc(sizeof (struct vstruct));
                   1172:        if (vs == VSTRUCT_NULL) {
                   1173:                return VSTRUCT_NULL;
                   1174:        }
                   1175: 
                   1176:        VS_LOCK_INIT(vs);
                   1177: 
                   1178:        /*
                   1179:         * The following fields will be provided later.
                   1180:         */
                   1181:        vs->vs_mem_obj_port = MACH_PORT_NULL;
                   1182:        vs->vs_seqno = 0;
                   1183:        vs->vs_control_port = MACH_PORT_NULL;
                   1184:        vs->vs_control_refs = 0;
                   1185:        vs->vs_object_name = MACH_PORT_NULL;
                   1186:        vs->vs_name_refs = 0;
                   1187: 
                   1188: #ifdef MACH_KERNEL
                   1189:        vs->vs_waiting_seqno = FALSE;
                   1190:        vs->vs_waiting_read = FALSE;
                   1191:        vs->vs_waiting_write = FALSE;
                   1192:        vs->vs_waiting_refs = FALSE;
                   1193:        vs->vs_waiting_async = FALSE;
                   1194: #else
                   1195:        mutex_init(&vs->vs_waiting_seqno, ETAP_DPAGE_VSSEQNO);
                   1196:        mutex_init(&vs->vs_waiting_read, ETAP_DPAGE_VSREAD);
                   1197:        mutex_init(&vs->vs_waiting_write, ETAP_DPAGE_VSWRITE);
                   1198:        mutex_init(&vs->vs_waiting_refs, ETAP_DPAGE_VSREFS);
                   1199:        mutex_init(&vs->vs_waiting_async, ETAP_DPAGE_VSASYNC);
                   1200: #endif
                   1201: 
                   1202:        vs->vs_readers = 0;
                   1203:        vs->vs_writers = 0;
                   1204: 
                   1205:        vs->vs_errors = 0;
                   1206: 
                   1207:        vs->vs_clshift = local_log2(bs_get_global_clsize(0));
                   1208:        vs->vs_size = ((atop(round_page(size)) - 1) >> vs->vs_clshift) + 1;
                   1209:        vs->vs_async_pending = 0;
                   1210: 
                   1211:        /*
                   1212:         * Allocate the pmap, either CLMAP_SIZE or INDIRECT_CLMAP_SIZE
                   1213:         * depending on the size of the memory object.
                   1214:         */
                   1215:        if (INDIRECT_CLMAP(vs->vs_size)) {
                   1216:                vs->vs_imap = (struct vs_map **)
                   1217:                        kalloc(INDIRECT_CLMAP_SIZE(vs->vs_size));
                   1218:                vs->vs_indirect = TRUE;
                   1219:        } else {
                   1220:                vs->vs_dmap = (struct vs_map *)
                   1221:                        kalloc(CLMAP_SIZE(vs->vs_size));
                   1222:                vs->vs_indirect = FALSE;
                   1223:        }
                   1224:        vs->vs_xfer_pending = FALSE;
                   1225:        DEBUG(DEBUG_VS_INTERNAL,
                   1226:              ("map=0x%x, indirect=%d\n", (int) vs->vs_dmap, vs->vs_indirect));
                   1227: 
                   1228:        /*
                   1229:         * Check to see that we got the space.
                   1230:         */
                   1231:        if (!vs->vs_dmap) {
                   1232:                kfree((vm_offset_t)vs, sizeof *vs);
                   1233:                return VSTRUCT_NULL;
                   1234:        }
                   1235: 
                   1236:        /*
                   1237:         * Zero the indirect pointers, or clear the direct pointers.
                   1238:         */
                   1239:        if (vs->vs_indirect)
                   1240:                memset(vs->vs_imap, 0,
                   1241:                       INDIRECT_CLMAP_SIZE(vs->vs_size));
                   1242:        else
                   1243:                for (i = 0; i < vs->vs_size; i++) 
                   1244:                        VSM_CLR(vs->vs_dmap[i]);
                   1245: 
                   1246:        VS_MAP_LOCK_INIT(vs);
                   1247: 
                   1248:        bs_commit(vs->vs_size);
                   1249: 
                   1250:        return vs;
                   1251: }
                   1252: 
                   1253: paging_segment_t ps_select_segment(int, int *);        /* forward */
                   1254: 
                   1255: paging_segment_t
                   1256: ps_select_segment(
                   1257:        int     shift,
                   1258:        int     *psindex)
                   1259: {
                   1260:        paging_segment_t        ps;
                   1261:        int                     i;
                   1262:        int                     j;
                   1263:        static char here[] = "ps_select_segment";
                   1264: 
                   1265:        /*
                   1266:         * Optimize case where there's only one segment.
                   1267:         * paging_segment_max will index the one and only segment.
                   1268:         */
                   1269: 
                   1270:        PSL_LOCK();
                   1271:        if (paging_segment_count == 1) {
                   1272:                paging_segment_t lps;   /* used to avoid extra PS_UNLOCK */
                   1273: 
                   1274:                ps = paging_segments[paging_segment_max];
                   1275:                *psindex = paging_segment_max;
                   1276:                PS_LOCK(ps);
                   1277:                if (ps->ps_going_away) {
                   1278:                        /* this segment is being turned off */
                   1279:                        lps = PAGING_SEGMENT_NULL;
                   1280:                } else {
                   1281:                        ASSERT(ps->ps_clshift >= shift);
                   1282:                        if (ps->ps_clcount) {
                   1283:                                ps->ps_clcount--;
                   1284:                                dp_pages_free -=  1 << ps->ps_clshift;
                   1285:                                if(min_pages_trigger_port && 
                   1286:                                  (dp_pages_free < minimum_pages_remaining)) {
                   1287:                                        default_pager_space_alert(
                   1288:                                                min_pages_trigger_port,
                   1289:                                                HI_WAT_ALERT);
                   1290:                                        min_pages_trigger_port = NULL;
                   1291:                                        bs_low = TRUE;
                   1292:                                }
                   1293:                                lps = ps;
                   1294:                        } else
                   1295:                                lps = PAGING_SEGMENT_NULL;
                   1296:                }
                   1297:                PS_UNLOCK(ps);
                   1298:                PSL_UNLOCK();
                   1299:                return lps;
                   1300:        }
                   1301: 
                   1302:        if (paging_segment_count == 0) {
                   1303:                PSL_UNLOCK();
                   1304:                return PAGING_SEGMENT_NULL;
                   1305:        }
                   1306: 
                   1307:        for (i = BS_MAXPRI;
                   1308:             i >= BS_MINPRI; i--) {
                   1309:                int start_index;
                   1310: 
                   1311:                if ((ps_select_array[i] == BS_NOPRI) ||
                   1312:                                (ps_select_array[i] == BS_FULLPRI))
                   1313:                        continue;
                   1314:                start_index = ps_select_array[i];
                   1315: 
                   1316:                if(!(paging_segments[start_index])) {
                   1317:                        j = start_index+1;
                   1318:                        physical_transfer_cluster_count = 0;
                   1319:                }
                   1320:                else if ((physical_transfer_cluster_count+1) == (MAXPHYS >> 
                   1321:                                (((paging_segments[start_index])->ps_clshift)
                   1322:                                + page_shift))) {
                   1323:                        physical_transfer_cluster_count = 0;
                   1324:                        j = start_index + 1;
                   1325:                } else {
                   1326:                        physical_transfer_cluster_count+=1;
                   1327:                        j = start_index;
                   1328:                        if(start_index == 0)
                   1329:                                start_index = paging_segment_max; 
                   1330:                        else
                   1331:                                start_index = start_index - 1;
                   1332:                }
                   1333: 
                   1334:                while (1) {
                   1335:                        if (j > paging_segment_max)
                   1336:                                j = 0;
                   1337:                        if ((ps = paging_segments[j]) &&
                   1338:                            (ps->ps_bs->bs_priority == i)) {
                   1339:                                /*
                   1340:                                 * Force the ps cluster size to be
                   1341:                                 * >= that of the vstruct.
                   1342:                                 */
                   1343:                                PS_LOCK(ps);
                   1344:                                if (ps->ps_going_away) {
                   1345:                                        /* this segment is being turned off */
                   1346:                                } else if ((ps->ps_clcount) &&
                   1347:                                           (ps->ps_clshift >= shift)) {
                   1348:                                        ps->ps_clcount--;
                   1349:                                        dp_pages_free -=  1 << ps->ps_clshift;
                   1350:                                        if(min_pages_trigger_port && 
                   1351:                                                (dp_pages_free < 
                   1352:                                                minimum_pages_remaining)) {
                   1353:                                                default_pager_space_alert(
                   1354:                                                        min_pages_trigger_port,
                   1355:                                                        HI_WAT_ALERT);
                   1356:                                                min_pages_trigger_port = NULL;
                   1357:                                        }
                   1358:                                        PS_UNLOCK(ps);
                   1359:                                        /*
                   1360:                                         * found one, quit looking.
                   1361:                                         */
                   1362:                                        ps_select_array[i] = j;
                   1363:                                        PSL_UNLOCK();
                   1364:                                        *psindex = j;
                   1365:                                        return ps;
                   1366:                                }
                   1367:                                PS_UNLOCK(ps);
                   1368:                        }
                   1369:                        if (j == start_index) {
                   1370:                                /*
                   1371:                                 * none at this priority -- mark it full
                   1372:                                 */
                   1373:                                ps_select_array[i] = BS_FULLPRI;
                   1374:                                break;
                   1375:                        }
                   1376:                        j++;
                   1377:                }
                   1378:        }
                   1379:        PSL_UNLOCK();
                   1380:        return PAGING_SEGMENT_NULL;
                   1381: }
                   1382: 
                   1383: vm_offset_t ps_allocate_cluster(vstruct_t, int *, paging_segment_t); /*forward*/
                   1384: 
                   1385: vm_offset_t
                   1386: ps_allocate_cluster(
                   1387:        vstruct_t               vs,
                   1388:        int                     *psindex,
                   1389:        paging_segment_t        use_ps)
                   1390: {
                   1391:        int                     byte_num;
                   1392:        int                     bit_num = 0;
                   1393:        paging_segment_t        ps;
                   1394:        vm_offset_t             cluster;
                   1395:        static char here[] = "ps_allocate_cluster";
                   1396: 
                   1397:        /*
                   1398:         * Find best paging segment.
                   1399:         * ps_select_segment will decrement cluster count on ps.
                   1400:         * Must pass cluster shift to find the most appropriate segment.
                   1401:         */
                   1402:        /* NOTE:  The addition of paging segment delete capability threatened
                   1403:         * to seriously complicate the treatment of paging segments in this
                   1404:         * module and the ones that call it (notably ps_clmap), because of the
                   1405:         * difficulty in assuring that the paging segment would continue to
                   1406:         * exist between being unlocked and locked.   This was
                   1407:         * avoided because all calls to this module are based in either
                   1408:         * dp_memory_object calls which rely on the vs lock, or by
                   1409:         * the transfer function which is part of the segment delete path.
                   1410:         * The transfer function which is part of paging segment delete is 
                   1411:         * protected from multiple callers by the backing store lock.  
                   1412:         * The paging segment delete function treats mappings to a paging 
                   1413:         * segment on a vstruct by vstruct basis, locking the vstruct targeted 
                   1414:         * while data is transferred to the remaining segments.  This is in
                   1415:         * line with the view that incomplete or in-transition mappings between
                   1416:         * data, a vstruct, and backing store are protected by the vs lock. 
                   1417:         * This and the ordering of the paging segment "going_away" bit setting
                   1418:         * protects us.
                   1419:         */
                   1420:        if (use_ps != PAGING_SEGMENT_NULL) {
                   1421:                ps = use_ps;
                   1422:                PSL_LOCK();
                   1423:                PS_LOCK(ps);
                   1424:                ps->ps_clcount--;
                   1425:                dp_pages_free -=  1 << ps->ps_clshift;
                   1426:                PSL_UNLOCK();
                   1427:                if(min_pages_trigger_port && 
                   1428:                                (dp_pages_free < minimum_pages_remaining)) {
                   1429:                        default_pager_space_alert(
                   1430:                                min_pages_trigger_port,
                   1431:                                HI_WAT_ALERT);
                   1432:                        min_pages_trigger_port = NULL;
                   1433:                }
                   1434:                PS_UNLOCK(ps);
                   1435:        } else if ((ps = ps_select_segment(vs->vs_clshift, psindex)) ==
                   1436:                   PAGING_SEGMENT_NULL) {
                   1437: #if 0
                   1438:                bs_no_paging_space(TRUE);
                   1439: #endif
                   1440: #if 0
                   1441:                if (verbose)
                   1442: #endif
                   1443:                        dprintf(("no space in available paging segments; "
                   1444:                                 "swapon suggested\n"));
                   1445:                return (vm_offset_t) -1;
                   1446:        }
                   1447:        ASSERT(ps->ps_clcount != 0);
                   1448: 
                   1449:        /*
                   1450:         * Look for an available cluster.  At the end of the loop,
                   1451:         * byte_num is the byte offset and bit_num is the bit offset of the
                   1452:         * first zero bit in the paging segment bitmap.
                   1453:         */
                   1454:        PS_LOCK(ps);
                   1455:        byte_num = ps->ps_hint;
                   1456:        for (; byte_num < howmany(ps->ps_ncls, NBBY); byte_num++) {
                   1457:                if (*(ps->ps_bmap + byte_num) != BYTEMASK) {
                   1458:                        for (bit_num = 0; bit_num < NBBY; bit_num++) {
                   1459:                                if (isclr((ps->ps_bmap + byte_num), bit_num))
                   1460:                                        break;
                   1461:                        }
                   1462:                        ASSERT(bit_num != NBBY);
                   1463:                        break;
                   1464:                }
                   1465:        }
                   1466:        ps->ps_hint = byte_num;
                   1467:        cluster = (byte_num*NBBY) + bit_num;
                   1468: 
                   1469:        /* Space was reserved, so this must be true */
                   1470:        ASSERT(cluster < ps->ps_ncls);
                   1471: 
                   1472:        setbit(ps->ps_bmap, cluster);
                   1473:        PS_UNLOCK(ps);
                   1474: 
                   1475:        return cluster;
                   1476: }
                   1477: 
                   1478: void ps_deallocate_cluster(paging_segment_t, vm_offset_t);     /* forward */
                   1479: 
                   1480: void
                   1481: ps_deallocate_cluster(
                   1482:        paging_segment_t        ps,
                   1483:        vm_offset_t             cluster)
                   1484: {
                   1485: 
                   1486:        if (cluster >= (vm_offset_t) ps->ps_ncls)
                   1487:                panic("ps_deallocate_cluster: Invalid cluster number");
                   1488: 
                   1489:        /*
                   1490:         * Lock the paging segment, clear the cluster's bitmap and increment the
                   1491:         * number of free cluster.
                   1492:         */
                   1493:        PSL_LOCK();
                   1494:        PS_LOCK(ps);
                   1495:        clrbit(ps->ps_bmap, cluster);
                   1496:        ++ps->ps_clcount;
                   1497:        dp_pages_free +=  1 << ps->ps_clshift;
                   1498:        PSL_UNLOCK();
                   1499:        if(max_pages_trigger_port && (dp_pages_free > maximum_pages_free)) {
                   1500:                default_pager_space_alert(max_pages_trigger_port, LO_WAT_ALERT);
                   1501:                max_pages_trigger_port = NULL;
                   1502:        }
                   1503: 
                   1504:        /*
                   1505:         * Move the hint down to the freed cluster if it is
                   1506:         * less than the current hint.
                   1507:         */
                   1508:        if ((cluster/NBBY) < ps->ps_hint) {
                   1509:                ps->ps_hint = (cluster/NBBY);
                   1510:        }
                   1511: 
                   1512:        PS_UNLOCK(ps);
                   1513: 
                   1514:        /*
                   1515:         * If we're freeing space on a full priority, reset the array.
                   1516:         */
                   1517:        PSL_LOCK();
                   1518:        if (ps_select_array[ps->ps_bs->bs_priority] == BS_FULLPRI)
                   1519:                ps_select_array[ps->ps_bs->bs_priority] = 0;
                   1520:        PSL_UNLOCK();
                   1521: 
                   1522:        return;
                   1523: }
                   1524: 
                   1525: void ps_dealloc_vsmap(struct vs_map *, vm_size_t);     /* forward */
                   1526: 
                   1527: void
                   1528: ps_dealloc_vsmap(
                   1529:        struct vs_map   *vsmap,
                   1530:        vm_size_t       size)
                   1531: {
                   1532:        int i;
                   1533:        for (i = 0; i < size; i++)
                   1534:                if (!VSM_ISCLR(vsmap[i]) && !VSM_ISERR(vsmap[i]))
                   1535:                        ps_deallocate_cluster(VSM_PS(vsmap[i]),
                   1536:                                              VSM_CLOFF(vsmap[i]));
                   1537: }
                   1538: 
                   1539: void
                   1540: ps_vstruct_dealloc(
                   1541:        vstruct_t vs)
                   1542: {
                   1543:        int     i;
                   1544:        static char here[] = "ps_vstruct_dealloc";
                   1545: 
                   1546:        VS_MAP_LOCK(vs);
                   1547: 
                   1548:        /*
                   1549:         * If this is an indirect structure, then we walk through the valid
                   1550:         * (non-zero) indirect pointers and deallocate the clusters
                   1551:         * associated with each used map entry (via ps_dealloc_vsmap).
                   1552:         * When all of the clusters in an indirect block have been
                   1553:         * freed, we deallocate the block.  When all of the indirect
                   1554:         * blocks have been deallocated we deallocate the memory
                   1555:         * holding the indirect pointers.
                   1556:         */
                   1557:        if (vs->vs_indirect) {
                   1558:                for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
                   1559:                        if (vs->vs_imap[i] != NULL) {
                   1560:                                ps_dealloc_vsmap(vs->vs_imap[i], CLMAP_ENTRIES);
                   1561:                                kfree((vm_offset_t)vs->vs_imap[i], 
                   1562:                                                        CLMAP_THRESHOLD);
                   1563:                        }
                   1564:                }
                   1565:                kfree((vm_offset_t)vs->vs_imap, 
                   1566:                                        INDIRECT_CLMAP_SIZE(vs->vs_size));
                   1567:        } else {
                   1568:                /*
                   1569:                 * Direct map.  Free used clusters, then memory.
                   1570:                 */
                   1571:                ps_dealloc_vsmap(vs->vs_dmap, vs->vs_size);
                   1572:                kfree((vm_offset_t)vs->vs_dmap, CLMAP_SIZE(vs->vs_size));
                   1573:        }
                   1574:        VS_MAP_UNLOCK(vs);
                   1575: 
                   1576:        bs_commit(- vs->vs_size);
                   1577: 
                   1578:        ip_lock(vs_to_port(vs));
                   1579:        (vs_to_port(vs))->ip_destination = 0;
                   1580:        (vs_to_port(vs))->ip_receiver_name = MACH_PORT_NULL;
                   1581:        imq_lock(&vs_to_port(vs)->ip_messages);
                   1582:        (vs_to_port(vs))->ip_mscount = 0;
                   1583:        (vs_to_port(vs))->ip_messages.imq_seqno = 0;
                   1584:        imq_unlock(&vs_to_port(vs)->ip_messages);
                   1585:        ip_unlock(vs_to_port(vs));
                   1586:        pager_mux_hash_delete((ipc_port_t) vs_to_port(vs));
                   1587:        ipc_port_release_receive(vs_to_port(vs));
                   1588:        /*
                   1589:         * Do this *after* deallocating the port name
                   1590:         */
                   1591:        kfree((vm_offset_t)vs, sizeof *vs);
                   1592: }
                   1593: 
                   1594: int ps_map_extend(vstruct_t, int);     /* forward */
                   1595: 
                   1596: int ps_map_extend(
                   1597:        vstruct_t       vs,
                   1598:        int             new_size)
                   1599: {
                   1600:        struct vs_map   **new_imap;
                   1601:        struct vs_map   *new_dmap = NULL;
                   1602:        int             newdsize;
                   1603:        int             i;
                   1604:        void            *old_map = NULL;
                   1605:        int             old_map_size = 0;
                   1606: 
                   1607:        if (vs->vs_size >= new_size) {
                   1608:                /*
                   1609:                 * Someone has already done the work.
                   1610:                 */
                   1611:                return 0;
                   1612:        }
                   1613: 
                   1614:        /*
                   1615:         * If the new size extends into the indirect range, then we have one
                   1616:         * of two cases: we are going from indirect to indirect, or we are
                   1617:         * going from direct to indirect.  If we are going from indirect to
                   1618:         * indirect, then it is possible that the new size will fit in the old
                   1619:         * indirect map.  If this is the case, then just reset the size of the
                   1620:         * vstruct map and we are done.  If the new size will not
                   1621:         * fit into the old indirect map, then we have to allocate a new
                   1622:         * indirect map and copy the old map pointers into this new map.
                   1623:         *
                   1624:         * If we are going from direct to indirect, then we have to allocate a
                   1625:         * new indirect map and copy the old direct pages into the first
                   1626:         * indirect page of the new map.
                   1627:         * NOTE: allocating memory here is dangerous, as we're in the
                   1628:         * pageout path.
                   1629:         */
                   1630:        if (INDIRECT_CLMAP(new_size)) {
                   1631:                int new_map_size = INDIRECT_CLMAP_SIZE(new_size);
                   1632: 
                   1633:                /*
                   1634:                 * Get a new indirect map and zero it.
                   1635:                 */
                   1636:                old_map_size = INDIRECT_CLMAP_SIZE(vs->vs_size);
                   1637:                if (vs->vs_indirect &&
                   1638:                    (new_map_size == old_map_size)) {
                   1639:                        bs_commit(new_size - vs->vs_size);
                   1640:                        vs->vs_size = new_size;
                   1641:                        return 0;
                   1642:                }
                   1643: 
                   1644:                new_imap = (struct vs_map **)kalloc(new_map_size);
                   1645:                if (new_imap == NULL) {
                   1646:                        return -1;
                   1647:                }
                   1648:                memset(new_imap, 0, new_map_size);
                   1649: 
                   1650:                if (vs->vs_indirect) {
                   1651:                        /* Copy old entries into new map */
                   1652:                        memcpy(new_imap, vs->vs_imap, old_map_size);
                   1653:                        /* Arrange to free the old map */
                   1654:                        old_map = (void *) vs->vs_imap;
                   1655:                        newdsize = 0;
                   1656:                } else {        /* Old map was a direct map */
                   1657:                        /* Allocate an indirect page */
                   1658:                        if ((new_imap[0] = (struct vs_map *)
                   1659:                             kalloc(CLMAP_THRESHOLD)) == NULL) {
                   1660:                                kfree((vm_offset_t)new_imap, new_map_size);
                   1661:                                return -1;
                   1662:                        }
                   1663:                        new_dmap = new_imap[0];
                   1664:                        newdsize = CLMAP_ENTRIES;
                   1665:                }
                   1666:        } else {
                   1667:                new_imap = NULL;
                   1668:                newdsize = new_size;
                   1669:                /*
                   1670:                 * If the new map is a direct map, then the old map must
                   1671:                 * also have been a direct map.  All we have to do is
                   1672:                 * to allocate a new direct map, copy the old entries
                   1673:                 * into it and free the old map.
                   1674:                 */
                   1675:                if ((new_dmap = (struct vs_map *)
                   1676:                     kalloc(CLMAP_SIZE(new_size))) == NULL) {
                   1677:                        return -1;
                   1678:                }
                   1679:        }
                   1680:        if (newdsize) {
                   1681: 
                   1682:                /* Free the old map */
                   1683:                old_map = (void *) vs->vs_dmap;
                   1684:                old_map_size = CLMAP_SIZE(vs->vs_size);
                   1685: 
                   1686:                /* Copy info from the old map into the new map */
                   1687:                memcpy(new_dmap, vs->vs_dmap, old_map_size);
                   1688: 
                   1689:                /* Initialize the rest of the new map */
                   1690:                for (i = vs->vs_size; i < newdsize; i++)
                   1691:                        VSM_CLR(new_dmap[i]);
                   1692:        }
                   1693:        if (new_imap) {
                   1694:                vs->vs_imap = new_imap;
                   1695:                vs->vs_indirect = TRUE;
                   1696:        } else
                   1697:                vs->vs_dmap = new_dmap;
                   1698:        bs_commit(new_size - vs->vs_size);
                   1699:        vs->vs_size = new_size;
                   1700:        if (old_map)
                   1701:                kfree((vm_offset_t)old_map, old_map_size);
                   1702:        return 0;
                   1703: }
                   1704: 
                   1705: vm_offset_t
                   1706: ps_clmap(
                   1707:        vstruct_t       vs,
                   1708:        vm_offset_t     offset,
                   1709:        struct clmap    *clmap,
                   1710:        int             flag,
                   1711:        vm_size_t       size,
                   1712:        int             error)
                   1713: {
                   1714:        vm_offset_t     cluster;        /* The cluster of offset.       */
                   1715:        vm_offset_t     newcl;          /* The new cluster allocated.   */
                   1716:        vm_offset_t     newoff;
                   1717:        int             i;
                   1718:        struct vs_map   *vsmap;
                   1719:        static char here[] = "ps_clmap";
                   1720: 
                   1721:        VS_MAP_LOCK(vs);
                   1722: 
                   1723:        ASSERT(vs->vs_dmap);
                   1724:        cluster = atop(offset) >> vs->vs_clshift;
                   1725: 
                   1726:        /*
                   1727:         * Initialize cluster error value
                   1728:         */
                   1729:        clmap->cl_error = 0;
                   1730: 
                   1731:        /*
                   1732:         * If the object has grown, extend the page map.
                   1733:         */
                   1734:        if (cluster >= vs->vs_size) {
                   1735:                if (flag == CL_FIND) {
                   1736:                        /* Do not allocate if just doing a lookup */
                   1737:                        VS_MAP_UNLOCK(vs);
                   1738:                        return (vm_offset_t) -1;
                   1739:                }
                   1740:                if (ps_map_extend(vs, cluster + 1)) {
                   1741:                        VS_MAP_UNLOCK(vs);
                   1742:                        return (vm_offset_t) -1;
                   1743:                }
                   1744:        }
                   1745: 
                   1746:        /*
                   1747:         * Look for the desired cluster.  If the map is indirect, then we
                   1748:         * have a two level lookup.  First find the indirect block, then
                   1749:         * find the actual cluster.  If the indirect block has not yet
                   1750:         * been allocated, then do so.  If the cluster has not yet been
                   1751:         * allocated, then do so.
                   1752:         *
                   1753:         * If any of the allocations fail, then return an error.
                   1754:         * Don't allocate if just doing a lookup.
                   1755:         */
                   1756:        if (vs->vs_indirect) {
                   1757:                long    ind_block = cluster/CLMAP_ENTRIES;
                   1758: 
                   1759:                /* Is the indirect block allocated? */
                   1760:                vsmap = vs->vs_imap[ind_block];
                   1761:                if (vsmap == NULL) {
                   1762:                        if (flag == CL_FIND) {
                   1763:                                VS_MAP_UNLOCK(vs);
                   1764:                                return (vm_offset_t) -1;
                   1765:                        }
                   1766: 
                   1767:                        /* Allocate the indirect block */
                   1768:                        vsmap = (struct vs_map *) kalloc(CLMAP_THRESHOLD);
                   1769:                        if (vsmap == NULL) {
                   1770:                                VS_MAP_UNLOCK(vs);
                   1771:                                return (vm_offset_t) -1;
                   1772:                        }
                   1773:                        /* Initialize the cluster offsets */
                   1774:                        for (i = 0; i < CLMAP_ENTRIES; i++)
                   1775:                                VSM_CLR(vsmap[i]);
                   1776:                        vs->vs_imap[ind_block] = vsmap;
                   1777:                }
                   1778:        } else
                   1779:                vsmap = vs->vs_dmap;
                   1780: 
                   1781:        ASSERT(vsmap);
                   1782:        vsmap += cluster%CLMAP_ENTRIES;
                   1783: 
                   1784:        /*
                   1785:         * At this point, vsmap points to the struct vs_map desired.
                   1786:         *
                   1787:         * Look in the map for the cluster, if there was an error on a
                   1788:         * previous write, flag it and return.  If it is not yet
                   1789:         * allocated, then allocate it, if we're writing; if we're
                   1790:         * doing a lookup and the cluster's not allocated, return error.
                   1791:         */
                   1792:        if (VSM_ISERR(*vsmap)) {
                   1793:                clmap->cl_error = VSM_GETERR(*vsmap);
                   1794:                VS_MAP_UNLOCK(vs);
                   1795:                return (vm_offset_t) -1;
                   1796:        } else if (VSM_ISCLR(*vsmap)) {
                   1797:                int psindex;
                   1798: 
                   1799:                if (flag == CL_FIND) {
                   1800:                        /*
                   1801:                         * If there's an error and the entry is clear, then
                   1802:                         * we've run out of swap space.  Record the error
                   1803:                         * here and return.
                   1804:                         */
                   1805:                        if (error) {
                   1806:                                VSM_SETERR(*vsmap, error);
                   1807:                        }
                   1808:                        VS_MAP_UNLOCK(vs);
                   1809:                        return (vm_offset_t) -1;
                   1810:                } else {
                   1811:                        /*
                   1812:                         * Attempt to allocate a cluster from the paging segment
                   1813:                         */
                   1814:                        newcl = ps_allocate_cluster(vs, &psindex,
                   1815:                                                    PAGING_SEGMENT_NULL);
                   1816:                        if (newcl == -1) {
                   1817:                                VS_MAP_UNLOCK(vs);
                   1818:                                return (vm_offset_t) -1;
                   1819:                        }
                   1820:                        VSM_CLR(*vsmap);
                   1821:                        VSM_SETCLOFF(*vsmap, newcl);
                   1822:                        VSM_SETPS(*vsmap, psindex);
                   1823:                }
                   1824:        } else
                   1825:                newcl = VSM_CLOFF(*vsmap);
                   1826: 
                   1827:        /*
                   1828:         * Fill in pertinent fields of the clmap
                   1829:         */
                   1830:        clmap->cl_ps = VSM_PS(*vsmap);
                   1831:        clmap->cl_numpages = VSCLSIZE(vs);
                   1832:        clmap->cl_bmap.clb_map = (unsigned int) VSM_BMAP(*vsmap);
                   1833: 
                   1834:        /*
                   1835:         * Byte offset in paging segment is byte offset to cluster plus
                   1836:         * byte offset within cluster.  It looks ugly, but should be
                   1837:         * relatively quick.
                   1838:         */
                   1839:        ASSERT(trunc_page(offset) == offset);
                   1840:        newcl = ptoa(newcl) << vs->vs_clshift;
                   1841:        newoff = offset & ((1<<(vm_page_shift + vs->vs_clshift)) - 1);
                   1842:        if (flag == CL_ALLOC) {
                   1843:                /*
                   1844:                 * set bits in the allocation bitmap according to which
                   1845:                 * pages were requested.  size is in bytes.
                   1846:                 */
                   1847:                i = atop(newoff);
                   1848:                while ((size > 0) && (i < VSCLSIZE(vs))) {
                   1849:                        VSM_SETALLOC(*vsmap, i);
                   1850:                        i++;
                   1851:                        size -= vm_page_size;
                   1852:                }
                   1853:        }
                   1854:        clmap->cl_alloc.clb_map = (unsigned int) VSM_ALLOC(*vsmap);
                   1855:        if (newoff) {
                   1856:                /*
                   1857:                 * Offset is not cluster aligned, so number of pages
                   1858:                 * and bitmaps must be adjusted
                   1859:                 */
                   1860:                clmap->cl_numpages -= atop(newoff);
                   1861:                CLMAP_SHIFT(clmap, vs);
                   1862:                CLMAP_SHIFTALLOC(clmap, vs);
                   1863:        }
                   1864: 
                   1865:        /*
                   1866:         *
                   1867:         * The setting of valid bits and handling of write errors
                   1868:         * must be done here, while we hold the lock on the map.
                   1869:         * It logically should be done in ps_vs_write_complete().
                   1870:         * The size and error information has been passed from
                   1871:         * ps_vs_write_complete().  If the size parameter is non-zero,
                   1872:         * then there is work to be done.  If error is also non-zero,
                   1873:         * then the error number is recorded in the cluster and the
                   1874:         * entire cluster is in error.
                   1875:         */
                   1876:        if (size && flag == CL_FIND) {
                   1877:                vm_offset_t off = (vm_offset_t) 0;
                   1878: 
                   1879:                if (!error) {
                   1880:                        for (i = VSCLSIZE(vs) - clmap->cl_numpages; size > 0;
                   1881:                             i++) {
                   1882:                                VSM_SETPG(*vsmap, i);
                   1883:                                size -= vm_page_size;
                   1884:                        }
                   1885:                        ASSERT(i <= VSCLSIZE(vs));
                   1886:                } else {
                   1887:                        BS_STAT(clmap->cl_ps->ps_bs,
                   1888:                                clmap->cl_ps->ps_bs->bs_pages_out_fail +=
                   1889:                                        atop(size));
                   1890:                        off = VSM_CLOFF(*vsmap);
                   1891:                        VSM_SETERR(*vsmap, error);
                   1892:                }
                   1893:                /*
                   1894:                 * Deallocate cluster if error, and no valid pages
                   1895:                 * already present.
                   1896:                 */
                   1897:                if (off != (vm_offset_t) 0)
                   1898:                        ps_deallocate_cluster(clmap->cl_ps, off);
                   1899:                VS_MAP_UNLOCK(vs);
                   1900:                return (vm_offset_t) 0;
                   1901:        } else
                   1902:                VS_MAP_UNLOCK(vs);
                   1903: 
                   1904:        DEBUG(DEBUG_VS_INTERNAL,
                   1905:              ("returning 0x%X,vs=0x%X,vsmap=0x%X,flag=%d\n",
                   1906:               newcl+newoff, (int) vs, (int) vsmap, flag));
                   1907:        DEBUG(DEBUG_VS_INTERNAL,
                   1908:              ("        clmap->cl_ps=0x%X,cl_numpages=%d,clbmap=0x%x,cl_alloc=%x\n",
                   1909:               (int) clmap->cl_ps, clmap->cl_numpages,
                   1910:               (int) clmap->cl_bmap.clb_map, (int) clmap->cl_alloc.clb_map));
                   1911: 
                   1912:        return (newcl + newoff);
                   1913: }
                   1914: 
                   1915: void ps_clunmap(vstruct_t, vm_offset_t, vm_size_t);    /* forward */
                   1916: 
                   1917: void
                   1918: ps_clunmap(
                   1919:        vstruct_t       vs,
                   1920:        vm_offset_t     offset,
                   1921:        vm_size_t       length)
                   1922: {
                   1923:        vm_offset_t             cluster; /* The cluster number of offset */
                   1924:        struct vs_map           *vsmap;
                   1925:        static char here[] = "ps_clunmap";
                   1926: 
                   1927:        VS_MAP_LOCK(vs);
                   1928: 
                   1929:        /*
                   1930:         * Loop through all clusters in this range, freeing paging segment
                   1931:         * clusters and map entries as encountered.
                   1932:         */
                   1933:        while (length > 0) {
                   1934:                vm_offset_t     newoff;
                   1935:                int             i;
                   1936: 
                   1937:                cluster = atop(offset) >> vs->vs_clshift;
                   1938:                if (vs->vs_indirect)    /* indirect map */
                   1939:                        vsmap = vs->vs_imap[cluster/CLMAP_ENTRIES];
                   1940:                else
                   1941:                        vsmap = vs->vs_dmap;
                   1942:                if (vsmap == NULL) {
                   1943:                        VS_MAP_UNLOCK(vs);
                   1944:                        return;
                   1945:                }
                   1946:                vsmap += cluster%CLMAP_ENTRIES;
                   1947:                if (VSM_ISCLR(*vsmap)) {
                   1948:                        length -= vm_page_size;
                   1949:                        offset += vm_page_size;
                   1950:                        continue;
                   1951:                }
                   1952:                /*
                   1953:                 * We've got a valid mapping.  Clear it and deallocate
                   1954:                 * paging segment cluster pages.
                   1955:                 * Optimize for entire cluster cleraing.
                   1956:                 */
                   1957:                if (newoff = (offset&((1<<(vm_page_shift+vs->vs_clshift))-1))) {
                   1958:                        /*
                   1959:                         * Not cluster aligned.
                   1960:                         */
                   1961:                        ASSERT(trunc_page(newoff) == newoff);
                   1962:                        i = atop(newoff);
                   1963:                } else
                   1964:                        i = 0;
                   1965:                while ((i < VSCLSIZE(vs)) && (length > 0)) {
                   1966:                        VSM_CLRPG(*vsmap, i);
                   1967:                        VSM_CLRALLOC(*vsmap, i);
                   1968:                        length -= vm_page_size;
                   1969:                        offset += vm_page_size;
                   1970:                        i++;
                   1971:                }
                   1972: 
                   1973:                /*
                   1974:                 * If map entry is empty, clear and deallocate cluster.
                   1975:                 */
                   1976:                if (!VSM_ALLOC(*vsmap)) {
                   1977:                        ps_deallocate_cluster(VSM_PS(*vsmap),
                   1978:                                              VSM_CLOFF(*vsmap));
                   1979:                        VSM_CLR(*vsmap);
                   1980:                }
                   1981:        }
                   1982: 
                   1983:        VS_MAP_UNLOCK(vs);
                   1984: }
                   1985: 
                   1986: void ps_vs_write_complete(vstruct_t, vm_offset_t, vm_size_t, int); /* forward */
                   1987: 
                   1988: void
                   1989: ps_vs_write_complete(
                   1990:        vstruct_t       vs,
                   1991:        vm_offset_t     offset,
                   1992:        vm_size_t       size,
                   1993:        int             error)
                   1994: {
                   1995:        struct clmap    clmap;
                   1996: 
                   1997:        /*
                   1998:         * Get the struct vsmap for this cluster.
                   1999:         * Use READ, even though it was written, because the
                   2000:         * cluster MUST be present, unless there was an error
                   2001:         * in the original ps_clmap (e.g. no space), in which
                   2002:         * case, nothing happens.
                   2003:         *
                   2004:         * Must pass enough information to ps_clmap to allow it
                   2005:         * to set the vs_map structure bitmap under lock.
                   2006:         */
                   2007:        (void) ps_clmap(vs, offset, &clmap, CL_FIND, size, error);
                   2008: }
                   2009: 
                   2010: void vs_cl_write_complete(vstruct_t, paging_segment_t, vm_offset_t, vm_offset_t, vm_size_t, boolean_t, int);   /* forward */
                   2011: 
                   2012: void
                   2013: vs_cl_write_complete(
                   2014:        vstruct_t               vs,
                   2015:        paging_segment_t        ps,
                   2016:        vm_offset_t             offset,
                   2017:        vm_offset_t             addr,
                   2018:        vm_size_t               size,
                   2019:        boolean_t               async,
                   2020:        int                     error)
                   2021: {
                   2022:        static char here[] = "vs_cl_write_complete";
                   2023:        kern_return_t   kr;
                   2024: 
                   2025:        if (error) {
                   2026:                /*
                   2027:                 * For internal objects, the error is recorded on a
                   2028:                 * per-cluster basis by ps_clmap() which is called
                   2029:                 * by ps_vs_write_complete() below.
                   2030:                 */
                   2031:                dprintf(("write failed error = 0x%x\n", error));
                   2032:                /* add upl_abort code here */
                   2033:        } else
                   2034:                GSTAT(global_stats.gs_pages_out += atop(size));
                   2035:        /*
                   2036:         * Notify the vstruct mapping code, so it can do its accounting.
                   2037:         */
                   2038:        ps_vs_write_complete(vs, offset, size, error);
                   2039: 
                   2040:        if (async) {
                   2041:                VS_LOCK(vs);
                   2042:                ASSERT(vs->vs_async_pending > 0);
                   2043:                vs->vs_async_pending -= size;
                   2044:                if (vs->vs_async_pending == 0) {
                   2045:                        VS_UNLOCK(vs);
                   2046:                        /* mutex_unlock(&vs->vs_waiting_async); */
                   2047:                        thread_wakeup(&vs->vs_waiting_async);
                   2048:                } else {
                   2049:                        VS_UNLOCK(vs);
                   2050:                }
                   2051:        }
                   2052: }
                   2053: 
                   2054: #ifdef DEVICE_PAGING
                   2055: kern_return_t device_write_reply(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
                   2056: 
                   2057: kern_return_t
                   2058: device_write_reply(
                   2059:        MACH_PORT_FACE  reply_port,
                   2060:        kern_return_t   device_code,
                   2061:        io_buf_len_t    bytes_written)
                   2062: {
                   2063:        struct vs_async *vsa;
                   2064:        static char here[] = "device_write_reply";
                   2065: 
                   2066:        vsa = (struct vs_async *)
                   2067:                ((struct vstruct_alias *)(reply_port->alias))->vs;
                   2068: 
                   2069:        if (device_code == KERN_SUCCESS && bytes_written != vsa->vsa_size) {
                   2070:                device_code = KERN_FAILURE;
                   2071:        }
                   2072: 
                   2073:        vsa->vsa_error = device_code;
                   2074: 
                   2075: 
                   2076:        ASSERT(vsa->vsa_vs != VSTRUCT_NULL);
                   2077:        if(vsa->vsa_flags & VSA_TRANSFER) {
                   2078:                /* revisit when async disk segments redone */
                   2079:                if(vsa->vsa_error) {
                   2080:                   /* need to consider error condition.  re-write data or */
                   2081:                   /* throw it away here. */
                   2082:                   vm_offset_t  ioaddr;
                   2083:                   if(vm_map_copyout(kernel_map, &ioaddr,
                   2084:                                 (vm_map_copy_t)vsa->vsa_addr) != KERN_SUCCESS)
                   2085:                   panic("vs_cluster_write: unable to copy source list\n");
                   2086:                   vm_deallocate(kernel_map, ioaddr, vsa->vsa_size);
                   2087:                }
                   2088:                ps_vs_write_complete(vsa->vsa_vs, vsa->vsa_offset, 
                   2089:                                                vsa->vsa_size, vsa->vsa_error);
                   2090:        } else {
                   2091:                vs_cl_write_complete(vsa->vsa_vs, vsa->vsa_ps, vsa->vsa_offset,
                   2092:                             vsa->vsa_addr, vsa->vsa_size, TRUE,
                   2093:                             vsa->vsa_error);
                   2094:        }
                   2095:        VS_FREE_ASYNC(vsa);
                   2096: 
                   2097:        return KERN_SUCCESS;
                   2098: }
                   2099: 
                   2100: kern_return_t device_write_reply_inband(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
                   2101: kern_return_t
                   2102: device_write_reply_inband(
                   2103:        MACH_PORT_FACE          reply_port,
                   2104:        kern_return_t           return_code,
                   2105:        io_buf_len_t            bytes_written)
                   2106: {
                   2107:        panic("device_write_reply_inband: illegal");
                   2108:        return KERN_SUCCESS;
                   2109: }
                   2110: 
                   2111: kern_return_t device_read_reply(MACH_PORT_FACE, kern_return_t, io_buf_ptr_t, mach_msg_type_number_t);
                   2112: kern_return_t
                   2113: device_read_reply(
                   2114:        MACH_PORT_FACE          reply_port,
                   2115:        kern_return_t           return_code,
                   2116:        io_buf_ptr_t            data,
                   2117:        mach_msg_type_number_t  dataCnt)
                   2118: {
                   2119:        struct vs_async *vsa;
                   2120:        vsa = (struct vs_async *)
                   2121:                ((struct vstruct_alias *)(reply_port->alias))->vs;
                   2122:        vsa->vsa_addr = (vm_offset_t)data;
                   2123:        vsa->vsa_size = (vm_size_t)dataCnt;
                   2124:        vsa->vsa_error = return_code;
                   2125:        thread_wakeup(&vsa->vsa_lock);
                   2126:        return KERN_SUCCESS;
                   2127: }
                   2128: 
                   2129: kern_return_t device_read_reply_inband(MACH_PORT_FACE, kern_return_t, io_buf_ptr_inband_t, mach_msg_type_number_t);
                   2130: kern_return_t
                   2131: device_read_reply_inband(
                   2132:        MACH_PORT_FACE          reply_port,
                   2133:        kern_return_t           return_code,
                   2134:        io_buf_ptr_inband_t     data,
                   2135:        mach_msg_type_number_t  dataCnt)
                   2136: {
                   2137:        panic("device_read_reply_inband: illegal");
                   2138:        return KERN_SUCCESS;
                   2139: }
                   2140: 
                   2141: kern_return_t device_read_reply_overwrite(MACH_PORT_FACE, kern_return_t, io_buf_len_t);
                   2142: kern_return_t
                   2143: device_read_reply_overwrite(
                   2144:        MACH_PORT_FACE          reply_port,
                   2145:        kern_return_t           return_code,
                   2146:        io_buf_len_t            bytes_read)
                   2147: {
                   2148:        panic("device_read_reply_overwrite: illegal\n");
                   2149:        return KERN_SUCCESS;
                   2150: }
                   2151: 
                   2152: kern_return_t device_open_reply(MACH_PORT_FACE, kern_return_t, MACH_PORT_FACE);
                   2153: kern_return_t
                   2154: device_open_reply(
                   2155:        MACH_PORT_FACE          reply_port,
                   2156:        kern_return_t           return_code,
                   2157:        MACH_PORT_FACE          device_port)
                   2158: {
                   2159:        panic("device_open_reply: illegal\n");
                   2160:        return KERN_SUCCESS;
                   2161: }
                   2162: 
                   2163: kern_return_t ps_read_device(paging_segment_t, vm_offset_t, vm_offset_t *, unsigned int, unsigned int *);      /* forward */
                   2164: 
                   2165: kern_return_t
                   2166: ps_read_device(
                   2167:        paging_segment_t        ps,
                   2168:        vm_offset_t             offset,
                   2169:        vm_offset_t             *bufferp,
                   2170:        unsigned int            size,
                   2171:        unsigned int            *residualp)
                   2172: {
                   2173:        kern_return_t   kr;
                   2174:        recnum_t        dev_offset;
                   2175:        unsigned int    bytes_wanted;
                   2176:        unsigned int    bytes_read;
                   2177:        unsigned int    total_read;
                   2178:        vm_offset_t     dev_buffer;
                   2179:        vm_offset_t     buf_ptr;
                   2180:        unsigned int    records_read;
                   2181:        static char     here[] = "ps_read_device";
                   2182:        struct vs_async *vsa;   
                   2183:        mutex_t vs_waiting_read_reply;
                   2184: 
                   2185:        device_t        device;
                   2186:        vm_map_copy_t   device_data = NULL;
                   2187:        default_pager_thread_t *dpt = NULL;
                   2188: 
                   2189:        device = dev_port_lookup(ps->ps_device);
                   2190:        clustered_reads[atop(size)]++;
                   2191: 
                   2192:        dev_offset = (ps->ps_offset +
                   2193:                      (offset >> (vm_page_shift - ps->ps_record_shift)));
                   2194:        bytes_wanted = size;
                   2195:        total_read = 0;
                   2196:        *bufferp = (vm_offset_t)NULL;
                   2197:        
                   2198:        do {
                   2199:                vsa = VS_ALLOC_ASYNC();
                   2200:                if (vsa) {
                   2201:                        vsa->vsa_vs = NULL;
                   2202:                        vsa->vsa_addr = 0;
                   2203:                        vsa->vsa_offset = 0;
                   2204:                        vsa->vsa_size = 0;
                   2205:                        vsa->vsa_ps = NULL;
                   2206:                }
                   2207:                mutex_init(&vsa->vsa_lock, ETAP_DPAGE_VSSEQNO);
                   2208:                ip_lock(vsa->reply_port);
                   2209:                vsa->reply_port->ip_sorights++;
                   2210:                ip_reference(vsa->reply_port);
                   2211:                ip_unlock(vsa->reply_port);
                   2212:                kr = ds_device_read_common(device,
                   2213:                                 vsa->reply_port,
                   2214:                                 (mach_msg_type_name_t) 
                   2215:                                        MACH_MSG_TYPE_MOVE_SEND_ONCE,
                   2216:                                 (dev_mode_t) 0,
                   2217:                                 dev_offset,
                   2218:                                 bytes_wanted,
                   2219:                                 (IO_READ | IO_CALL),
                   2220:                                 (io_buf_ptr_t *) &dev_buffer,
                   2221:                                 (mach_msg_type_number_t *) &bytes_read);
                   2222:                if(kr == MIG_NO_REPLY) { 
                   2223:                        assert_wait(&vsa->vsa_lock, THREAD_UNINT);
                   2224:                        thread_block((void(*)(void))0);
                   2225: 
                   2226:                        dev_buffer = vsa->vsa_addr;
                   2227:                        bytes_read = (unsigned int)vsa->vsa_size;
                   2228:                        kr = vsa->vsa_error;
                   2229:                } 
                   2230:                VS_FREE_ASYNC(vsa);
                   2231:                if (kr != KERN_SUCCESS || bytes_read == 0) {
                   2232:                        break;
                   2233:                }
                   2234:                total_read += bytes_read;
                   2235: 
                   2236:                /*
                   2237:                 * If we got the entire range, use the returned dev_buffer.
                   2238:                 */
                   2239:                if (bytes_read == size) {
                   2240:                        *bufferp = (vm_offset_t)dev_buffer;
                   2241:                        break;
                   2242:                }
                   2243: 
                   2244: #if 1
                   2245:                dprintf(("read only %d bytes out of %d\n",
                   2246:                         bytes_read, bytes_wanted));
                   2247: #endif
                   2248:                if(dpt == NULL) {
                   2249:                        dpt = get_read_buffer();
                   2250:                        buf_ptr = dpt->dpt_buffer;
                   2251:                        *bufferp = (vm_offset_t)buf_ptr;
                   2252:                }
                   2253:                /*
                   2254:                 * Otherwise, copy the data into the provided buffer (*bufferp)
                   2255:                 * and append the rest of the range as it comes in.
                   2256:                 */
                   2257:                memcpy((void *) buf_ptr, (void *) dev_buffer, bytes_read);
                   2258:                buf_ptr += bytes_read;
                   2259:                bytes_wanted -= bytes_read;
                   2260:                records_read = (bytes_read >>
                   2261:                                (vm_page_shift - ps->ps_record_shift));
                   2262:                dev_offset += records_read;
                   2263:                DEBUG(DEBUG_VS_INTERNAL,
                   2264:                      ("calling vm_deallocate(addr=0x%X,size=0x%X)\n",
                   2265:                       dev_buffer, bytes_read));
                   2266:                if (vm_deallocate(kernel_map, dev_buffer, bytes_read)
                   2267:                    != KERN_SUCCESS)
                   2268:                        Panic("dealloc buf");
                   2269:        } while (bytes_wanted);
                   2270: 
                   2271:        *residualp = size - total_read;
                   2272:        if((dev_buffer != *bufferp) && (total_read != 0)) {
                   2273:                vm_offset_t temp_buffer;
                   2274:                vm_allocate(kernel_map, &temp_buffer, total_read, TRUE);
                   2275:                memcpy((void *) temp_buffer, (void *) *bufferp, total_read);
                   2276:                if(vm_map_copyin_page_list(kernel_map, temp_buffer, total_read, 
                   2277:                        VM_MAP_COPYIN_OPT_SRC_DESTROY | 
                   2278:                        VM_MAP_COPYIN_OPT_STEAL_PAGES | 
                   2279:                        VM_MAP_COPYIN_OPT_PMAP_ENTER,
                   2280:                        (vm_map_copy_t *)&device_data, FALSE))
                   2281:                                panic("ps_read_device: cannot copyin locally provided buffer\n");
                   2282:        }
                   2283:        else if((kr == KERN_SUCCESS) && (total_read != 0) && (dev_buffer != 0)){
                   2284:                if(vm_map_copyin_page_list(kernel_map, dev_buffer, bytes_read, 
                   2285:                        VM_MAP_COPYIN_OPT_SRC_DESTROY | 
                   2286:                        VM_MAP_COPYIN_OPT_STEAL_PAGES | 
                   2287:                        VM_MAP_COPYIN_OPT_PMAP_ENTER,
                   2288:                        (vm_map_copy_t *)&device_data, FALSE))
                   2289:                                panic("ps_read_device: cannot copyin backing store provided buffer\n");
                   2290:        }
                   2291:        else {
                   2292:                device_data = NULL;
                   2293:        }
                   2294:        *bufferp = (vm_offset_t)device_data;
                   2295: 
                   2296:        if(dpt != NULL) {
                   2297:                /* Free the receive buffer */
                   2298:                dpt->checked_out = 0;   
                   2299:                thread_wakeup(&dpt_array);
                   2300:        }
                   2301:        return KERN_SUCCESS;
                   2302: }
                   2303: 
                   2304: kern_return_t ps_write_device(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int, struct vs_async *);    /* forward */
                   2305: 
                   2306: kern_return_t
                   2307: ps_write_device(
                   2308:        paging_segment_t        ps,
                   2309:        vm_offset_t             offset,
                   2310:        vm_offset_t             addr,
                   2311:        unsigned int            size,
                   2312:        struct vs_async         *vsa)
                   2313: {
                   2314:        recnum_t        dev_offset;
                   2315:        io_buf_len_t    bytes_to_write, bytes_written;
                   2316:        recnum_t        records_written;
                   2317:        kern_return_t   kr;
                   2318:        MACH_PORT_FACE  reply_port;
                   2319:        static char here[] = "ps_write_device";
                   2320: 
                   2321: 
                   2322: 
                   2323:        clustered_writes[atop(size)]++;
                   2324: 
                   2325:        dev_offset = (ps->ps_offset +
                   2326:                      (offset >> (vm_page_shift - ps->ps_record_shift)));
                   2327:        bytes_to_write = size;
                   2328: 
                   2329:        if (vsa) {
                   2330:                /*
                   2331:                 * Asynchronous write.
                   2332:                 */
                   2333:                reply_port = vsa->reply_port;
                   2334:                ip_lock(reply_port);
                   2335:                reply_port->ip_sorights++;
                   2336:                ip_reference(reply_port);
                   2337:                ip_unlock(reply_port);
                   2338:                {
                   2339:                device_t        device;
                   2340:                device = dev_port_lookup(ps->ps_device);
                   2341: 
                   2342:                vsa->vsa_addr = addr;
                   2343:                kr=ds_device_write_common(device,
                   2344:                        reply_port,
                   2345:                        (mach_msg_type_name_t) MACH_MSG_TYPE_MOVE_SEND_ONCE,
                   2346:                        (dev_mode_t) 0,
                   2347:                        dev_offset,
                   2348:                        (io_buf_ptr_t)  addr,
                   2349:                        size, 
                   2350:                        (IO_WRITE | IO_CALL),
                   2351:                        &bytes_written);
                   2352:                }
                   2353:                if ((kr != KERN_SUCCESS) && (kr != MIG_NO_REPLY)) {
                   2354:                        if (verbose) 
                   2355:                                dprintf(("%s0x%x, addr=0x%x,"
                   2356:                                         "size=0x%x,offset=0x%x\n",
                   2357:                                         "device_write_request returned ",
                   2358:                                         kr, addr, size, offset));
                   2359:                        BS_STAT(ps->ps_bs,
                   2360:                                ps->ps_bs->bs_pages_out_fail += atop(size));
                   2361:                        /* do the completion notification to free resources */
                   2362:                        device_write_reply(reply_port, kr, 0);
                   2363:                        return PAGER_ERROR;
                   2364:                }
                   2365:        } else do {
                   2366:                /*
                   2367:                 * Synchronous write.
                   2368:                 */
                   2369:                {
                   2370:                device_t        device;
                   2371:                device = dev_port_lookup(ps->ps_device);
                   2372:                kr=ds_device_write_common(device,
                   2373:                        IP_NULL, 0,
                   2374:                        (dev_mode_t) 0,
                   2375:                        dev_offset,
                   2376:                        (io_buf_ptr_t)  addr,
                   2377:                        size, 
                   2378:                        (IO_WRITE | IO_SYNC | IO_KERNEL_BUF),
                   2379:                        &bytes_written);
                   2380:                }
                   2381:                if (kr != KERN_SUCCESS) {
                   2382:                        dprintf(("%s0x%x, addr=0x%x,size=0x%x,offset=0x%x\n",
                   2383:                                 "device_write returned ",
                   2384:                                 kr, addr, size, offset));
                   2385:                        BS_STAT(ps->ps_bs,
                   2386:                                ps->ps_bs->bs_pages_out_fail += atop(size));
                   2387:                        return PAGER_ERROR;
                   2388:                }
                   2389:                if (bytes_written & ((vm_page_size >> ps->ps_record_shift) - 1))
                   2390:                        Panic("fragmented write");
                   2391:                records_written = (bytes_written >>
                   2392:                                   (vm_page_shift - ps->ps_record_shift));
                   2393:                dev_offset += records_written;
                   2394: #if 1
                   2395:                if (bytes_written != bytes_to_write) {
                   2396:                        dprintf(("wrote only %d bytes out of %d\n",
                   2397:                                 bytes_written, bytes_to_write));
                   2398:                }
                   2399: #endif
                   2400:                bytes_to_write -= bytes_written;
                   2401:                addr += bytes_written;
                   2402:        } while (bytes_to_write > 0);
                   2403: 
                   2404:        return PAGER_SUCCESS;
                   2405: }
                   2406: 
                   2407: 
                   2408: #else /* !DEVICE_PAGING */
                   2409: 
                   2410: kern_return_t
                   2411: ps_read_device(
                   2412:        paging_segment_t        ps,
                   2413:        vm_offset_t             offset,
                   2414:        vm_offset_t             *bufferp,
                   2415:        unsigned int            size,
                   2416:        unsigned int            *residualp)
                   2417: {
                   2418:   panic("ps_read_device not supported");
                   2419: }
                   2420: 
                   2421: ps_write_device(
                   2422:        paging_segment_t        ps,
                   2423:        vm_offset_t             offset,
                   2424:        vm_offset_t             addr,
                   2425:        unsigned int            size,
                   2426:        struct vs_async         *vsa)
                   2427: {
                   2428:   panic("ps_write_device not supported");
                   2429: }
                   2430: 
                   2431: #endif /* DEVICE_PAGING */
                   2432: void pvs_object_data_provided(vstruct_t, upl_t, vm_offset_t, vm_size_t);       /* forward */
                   2433: 
                   2434: void
                   2435: pvs_object_data_provided(
                   2436:        vstruct_t       vs,
                   2437:        upl_t           page_list,
                   2438:        vm_offset_t     offset,
                   2439:        vm_size_t       size)
                   2440: {
                   2441:        static char here[] = "pvs_object_data_provided";
                   2442: 
                   2443:        DEBUG(DEBUG_VS_INTERNAL,
                   2444:              ("buffer=0x%x,offset=0x%x,size=0x%x\n",
                   2445:               page_list, offset, size));
                   2446: 
                   2447:        ASSERT(size > 0);
                   2448:        GSTAT(global_stats.gs_pages_in += atop(size));
                   2449: 
                   2450: 
                   2451: #if    USE_PRECIOUS
                   2452:        ps_clunmap(vs, offset, size);
                   2453: #endif /* USE_PRECIOUS */
                   2454: 
                   2455:        if(size < (page_list->size)) {
                   2456:                upl_commit_range(page_list, 0, size, FALSE, NULL);
                   2457:        } else {
                   2458:                upl_commit(page_list, NULL);
                   2459:        }
                   2460: }
                   2461: 
                   2462: kern_return_t
                   2463: pvs_cluster_read(
                   2464:        vstruct_t       vs,
                   2465:        vm_offset_t     offset,
                   2466:        vm_size_t       cnt)
                   2467: {
                   2468:        vm_offset_t             actual_offset;
                   2469:        vm_offset_t             buffer;
                   2470:        paging_segment_t        ps;
                   2471:        struct clmap            clmap;
                   2472:        upl_t                   page_list;
                   2473:        kern_return_t           error = KERN_SUCCESS;
                   2474:        int                     size, size_wanted, i;
                   2475:        unsigned int            residual;
                   2476:        unsigned int            request_flags;
                   2477:        int                     unavail_size;
                   2478:        default_pager_thread_t  *dpt;
                   2479:        boolean_t               dealloc;
                   2480:        static char here[] = "pvs_cluster_read";
                   2481: 
                   2482:        /*
                   2483:         * This loop will be executed once per cluster referenced.
                   2484:         * Typically this means once, since it's unlikely that the
                   2485:         * VM system will ask for anything spanning cluster boundaries.
                   2486:         *
                   2487:         * If there are holes in a cluster (in a paging segment), we stop
                   2488:         * reading at the hole, inform the VM of any data read, inform
                   2489:         * the VM of an unavailable range, then loop again, hoping to
                   2490:         * find valid pages later in the cluster.  This continues until
                   2491:         * the entire range has been examined, and read, if present.
                   2492:         */
                   2493: #if    USE_PRECIOUS
                   2494:        request_flags = UPL_NO_SYNC |  UPL_CLEAN_IN_PLACE | UPL_PRECIOUS;
                   2495: #else
                   2496:        request_flags = UPL_NO_SYNC |  UPL_CLEAN_IN_PLACE;
                   2497: #endif
                   2498:        while (cnt && (error == KERN_SUCCESS)) {
                   2499:                actual_offset = ps_clmap(vs, offset, &clmap, CL_FIND, 0, 0);
                   2500: 
                   2501:                if (actual_offset == (vm_offset_t) -1) {
                   2502: 
                   2503:                        /*
                   2504:                         * Either a failure due to an error on a previous
                   2505:                         * write or a zero fill on demand page.  In either case,
                   2506:                         * optimize to do one reply for all pages up to next
                   2507:                         * cluster boundary.
                   2508:                         */
                   2509:                        unsigned int local_size, clmask, clsize;
                   2510: 
                   2511:                        clmask = (vm_page_size << vs->vs_clshift) - 1;
                   2512:                        clsize = vm_page_size << vs->vs_clshift;
                   2513:                        clmask = clsize - 1;
                   2514:                        local_size = clsize - (offset & clmask);
                   2515:                        ASSERT(local_size);
                   2516:                        local_size = MIN(local_size, cnt);
                   2517: 
                   2518:                        upl_system_list_request((vm_object_t)
                   2519:                                        vs->vs_control_port->ip_kobject,
                   2520:                                        offset, local_size, local_size, 
                   2521:                                        &page_list, NULL, 0, request_flags);
                   2522:                        if (clmap.cl_error) {
                   2523:                                upl_abort(page_list, UPL_ABORT_ERROR);
                   2524:                        } else {
                   2525:                                upl_abort(page_list, UPL_ABORT_UNAVAILABLE);
                   2526:                        }
                   2527: 
                   2528:                        cnt -= local_size;
                   2529:                        offset += local_size;
                   2530:                        continue;
                   2531:                }
                   2532: 
                   2533:                /*
                   2534:                 * Count up contiguous available or unavailable
                   2535:                 * pages.
                   2536:                 */
                   2537:                ps = CLMAP_PS(clmap);
                   2538:                ASSERT(ps);
                   2539:                size = 0;
                   2540:                unavail_size = 0;
                   2541:                for (i = 0;
                   2542:                     (size < cnt) && (unavail_size < cnt) &&
                   2543:                     (i < CLMAP_NPGS(clmap)); i++) {
                   2544:                        if (CLMAP_ISSET(clmap, i)) {
                   2545:                                if (unavail_size != 0)
                   2546:                                        break;
                   2547:                                size += vm_page_size;
                   2548:                                BS_STAT(ps->ps_bs,
                   2549:                                        ps->ps_bs->bs_pages_in++);
                   2550:                        } else {
                   2551:                                if (size != 0)
                   2552:                                        break;
                   2553:                                unavail_size += vm_page_size;
                   2554:                        }
                   2555:                }
                   2556:                /*
                   2557:                 * Let VM system know about holes in clusters.
                   2558:                 */
                   2559:                if (size == 0) {
                   2560:                        ASSERT(unavail_size);
                   2561:                        GSTAT(global_stats.gs_pages_unavail +=
                   2562:                              atop(unavail_size));
                   2563:                        upl_system_list_request((vm_object_t)
                   2564:                                        vs->vs_control_port->ip_kobject,
                   2565:                                        offset, unavail_size, 
                   2566:                                        unavail_size, &page_list, NULL, 0,
                   2567:                                        request_flags);
                   2568:                        upl_abort(page_list, UPL_ABORT_UNAVAILABLE);
                   2569:                        cnt -= unavail_size;
                   2570:                        offset += unavail_size;
                   2571:                        continue;
                   2572:                }
                   2573: 
                   2574:                upl_system_list_request((vm_object_t)
                   2575:                                        vs->vs_control_port->ip_kobject,
                   2576:                                        offset, size, size, &page_list, 
                   2577:                                        NULL, 0, request_flags);
                   2578:                if(ps->ps_segtype == PS_PARTITION) {
                   2579: /*
                   2580:                        error = ps_read_device(ps, actual_offset, page_list,
                   2581:                                       size, &residual);
                   2582: */
                   2583:                } else {
                   2584:                        vm_offset_t ioaddr;
                   2585: 
                   2586:                        upl_map(kernel_map, page_list, &ioaddr);
                   2587:                        error = ps_read_file(ps, actual_offset, ioaddr, 
                   2588:                                        size, &residual);
                   2589:                        upl_un_map(kernel_map, page_list);
                   2590:                }
                   2591: 
                   2592:                /*
                   2593:                 * Adjust counts and send response to VM.  Optimize for the
                   2594:                 * common case, i.e. no error and/or partial data.
                   2595:                 * If there was an error, then we need to error the entire
                   2596:                 * range, even if some data was successfully read.
                   2597:                 * If there was a partial read we may supply some
                   2598:                 * data and may error some as well.  In all cases the
                   2599:                 * VM must receive some notification for every page in the
                   2600:                 * range.
                   2601:                 */
                   2602:                if ((error == KERN_SUCCESS) && (residual == 0)) {
                   2603:                        /*
                   2604:                         * Got everything we asked for, supply the data to
                   2605:                         * the VM.  Note that as a side effect of supplying
                   2606:                         * the data, the buffer holding the supplied data is
                   2607:                         * deallocated from the pager's address space.
                   2608:                         */
                   2609:                        pvs_object_data_provided(vs, page_list, offset, size);
                   2610:                } else {
                   2611:                        size_wanted = size;
                   2612:                        if (error == KERN_SUCCESS) {
                   2613:                                if (residual == size) {
                   2614:                                        /*
                   2615:                                         * If a read operation returns no error
                   2616:                                         * and no data moved, we turn it into
                   2617:                                         * an error, assuming we're reading at
                   2618:                                         * or beyong EOF.
                   2619:                                         * Fall through and error the entire
                   2620:                                         * range.
                   2621:                                         */
                   2622:                                        error = KERN_FAILURE;
                   2623:                                } else {
                   2624:                                        /*
                   2625:                                         * Otherwise, we have partial read. If
                   2626:                                         * the part read is a integral number
                   2627:                                         * of pages supply it. Otherwise round
                   2628:                                         * it up to a page boundary, zero fill
                   2629:                                         * the unread part, and supply it.
                   2630:                                         * Fall through and error the remainder
                   2631:                                         * of the range, if any.
                   2632:                                         */
                   2633:                                        int fill, lsize;
                   2634: 
                   2635:                                        fill = residual & ~vm_page_size;
                   2636:                                        lsize = (size - residual) + fill;
                   2637:                                        pvs_object_data_provided(vs, page_list,
                   2638:                                                        offset, lsize);
                   2639:                                        cnt -= lsize;
                   2640:                                        offset += lsize;
                   2641:                                        if (size -= lsize) {
                   2642:                                                error = KERN_FAILURE;
                   2643:                                        }
                   2644:                                }
                   2645:                        }
                   2646: 
                   2647:                        /*
                   2648:                         * If there was an error in any part of the range, tell
                   2649:                         * the VM.  Deallocate the remainder of the buffer.
                   2650:                         * Note that error is explicitly checked again since
                   2651:                         * it can be modified above.
                   2652:                         */
                   2653:                        if (error != KERN_SUCCESS) {
                   2654:                                BS_STAT(ps->ps_bs,
                   2655:                                        ps->ps_bs->bs_pages_in_fail +=
                   2656:                                        atop(size));
                   2657:                                upl_abort(page_list, UPL_ABORT_RESTART);
                   2658:                        }
                   2659:                }
                   2660:                cnt -= size;
                   2661:                offset += size;
                   2662: 
                   2663:        } /* END while (cnt && (error == 0)) */
                   2664:        return error;
                   2665: }
                   2666: 
                   2667: int vs_do_async_write = 1;
                   2668: 
                   2669: kern_return_t
                   2670: vs_cluster_write(
                   2671:        vstruct_t       vs,
                   2672:        vm_offset_t     offset,
                   2673:        vm_offset_t     addr,
                   2674:        vm_size_t       cnt,
                   2675:        boolean_t       dp_internal)
                   2676: {
                   2677:        vm_offset_t     actual_offset;  /* Offset within paging segment */
                   2678:        vm_offset_t     size;
                   2679:        vm_offset_t     transfer_size;
                   2680:        vm_offset_t     subx_size;
                   2681:        int             error = 0;
                   2682:        struct clmap    clmap;
                   2683:        paging_segment_t ps;
                   2684:        struct vs_async *vsa;
                   2685:        vm_map_copy_t   copy;
                   2686:        static char here[] = "vs_cluster_write";
                   2687: 
                   2688:        
                   2689:        upl_t           upl;
                   2690: 
                   2691:        vm_offset_t     mapped_data;
                   2692:        vm_offset_t     mobj_base_addr;
                   2693:        vm_offset_t     mobj_target_addr;
                   2694:        int             mobj_size;
                   2695:        vm_offset_t     vs_map_error_addr = 0;
                   2696:        int             page_index;
                   2697:        int             list_size;
                   2698:        int             cl_size;
                   2699: 
                   2700:        upl_page_info_t page_list[20];
                   2701:        upl_page_info_t *pl;
                   2702: 
                   2703:        
                   2704:        ps = PAGING_SEGMENT_NULL;
                   2705:        if(!dp_internal) {
                   2706:                int     request_flags;
                   2707:                int     super_size;
                   2708: 
                   2709:                cl_size = (1 << vs->vs_clshift) * vm_page_size;
                   2710:                if(bs_low) {
                   2711:                        super_size = cl_size;
                   2712:                        request_flags = UPL_NOBLOCK |
                   2713:                                UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM | 
                   2714:                                UPL_NO_SYNC;
                   2715:                } else {
                   2716:                        super_size = VM_SUPER_CLUSTER;
                   2717:                        request_flags = UPL_NOBLOCK | UPL_CLEAN_IN_PLACE |
                   2718:                                UPL_RET_ONLY_DIRTY | UPL_COPYOUT_FROM | 
                   2719:                                UPL_NO_SYNC;
                   2720:                }
                   2721: 
                   2722: 
                   2723:                pl = page_list;
                   2724:                upl_system_list_request((vm_object_t)
                   2725:                                vs->vs_control_port->ip_kobject,
                   2726:                                offset, cnt, super_size, 
                   2727:                                &upl, &pl, 
                   2728:                                20, request_flags);
                   2729: 
                   2730:                mobj_base_addr = upl->offset;
                   2731:                list_size = upl->size;
                   2732: 
                   2733:                upl_map(kernel_map, upl, &mapped_data);
                   2734:        
                   2735:                /* Now parcel up the 64k transfer, do at most cluster size */
                   2736:                /*  at a time. */
                   2737:                page_index = 0;
                   2738:                mobj_target_addr = mobj_base_addr;
                   2739:                for(transfer_size = list_size; transfer_size != 0;) {
                   2740:                        actual_offset = ps_clmap(vs, mobj_target_addr, 
                   2741:                                &clmap, CL_ALLOC, 
                   2742:                                transfer_size < cl_size ? 
                   2743:                                        transfer_size : cl_size, 0);
                   2744:                        if(actual_offset == (vm_offset_t) -1) {
                   2745:                                vs_map_error_addr = mobj_target_addr;
                   2746:                                error = 1;
                   2747:                                break;
                   2748:                        }
                   2749:                        cnt = MIN(transfer_size, 
                   2750:                                CLMAP_NPGS(clmap) * vm_page_size);
                   2751:                        ps = CLMAP_PS(clmap);
                   2752:                        while(cnt > 0) {
                   2753:                           /* attempt to send entire cluster */
                   2754:                           subx_size = 0;
                   2755:                           while(cnt > 0) {
                   2756:                              /* do the biggest contiguous transfer of dirty */
                   2757:                              /* pages */
                   2758:                              if(UPL_DIRTY_PAGE(page_list, page_index) ||
                   2759:                                ((bs_low) &&
                   2760:                                UPL_PRECIOUS_PAGE(page_list, page_index))) {
                   2761:                                 page_index++;
                   2762:                                 subx_size += vm_page_size;
                   2763:                                 cnt -= vm_page_size;
                   2764:                              } else {
                   2765:                                 if(subx_size == 0) {
                   2766:                                        actual_offset += vm_page_size;
                   2767:                                        mobj_target_addr += vm_page_size;
                   2768:                                        mapped_data += vm_page_size;
                   2769:                                        transfer_size -= vm_page_size;
                   2770:                                        page_index++;
                   2771:                                        cnt -= vm_page_size;
                   2772:                                 } else {
                   2773:                                        break;
                   2774:                                 }
                   2775:                              }
                   2776:                           }
                   2777:                           if(subx_size) {
                   2778:                                error = ps_write_file(ps, actual_offset,
                   2779:                                                        mapped_data, subx_size);
                   2780:                                if(error) {
                   2781:                                        vs_map_error_addr = mobj_target_addr;
                   2782:                                }
                   2783:                                ps_vs_write_complete(vs, mobj_target_addr, 
                   2784:                                                        subx_size, error);
                   2785:                           }
                   2786:                           if(error)
                   2787:                                break;
                   2788:                           actual_offset += subx_size;
                   2789:                           mobj_target_addr += subx_size;
                   2790:                           mapped_data += subx_size;
                   2791:                           transfer_size -= subx_size;
                   2792:                           subx_size = 0;
                   2793:                        }
                   2794:                        if(error)
                   2795:                                break;
                   2796:                }
                   2797:                upl_un_map(kernel_map, upl);
                   2798:                if(error) {
                   2799:                        if(vs_map_error_addr > mobj_base_addr) {
                   2800:                                upl_commit_range(upl, 0, 
                   2801:                                        vs_map_error_addr - mobj_base_addr,
                   2802:                                        FALSE, page_list);
                   2803:                        }
                   2804:                        upl_abort(upl, 0);
                   2805:                } else {
                   2806:                        upl_commit(upl, page_list);
                   2807:                }
                   2808:        } else {
                   2809:                assert(cnt  <= (vm_page_size << vs->vs_clshift));
                   2810:                mapped_data = addr;
                   2811:                list_size = cnt;
                   2812: 
                   2813:                page_index = 0;
                   2814:                /* The caller provides a mapped_data which is derived  */
                   2815:                /* from a temporary object.  The targeted pages are    */
                   2816:                /* guaranteed to be set at offset 0 in the mapped_data */
                   2817:                /* The actual offset however must still be derived     */
                   2818:                /* from the offset in the vs in question               */
                   2819:                mobj_base_addr = offset;
                   2820:                mobj_target_addr = mobj_base_addr;
                   2821:                for(transfer_size = list_size; transfer_size != 0;) {
                   2822:                        actual_offset = ps_clmap(vs, mobj_target_addr, 
                   2823:                                &clmap, CL_ALLOC, 
                   2824:                                transfer_size < cl_size ? 
                   2825:                                        transfer_size : cl_size, 0);
                   2826:                        if(actual_offset == (vm_offset_t) -1) {
                   2827:                                error = KERN_FAILURE;
                   2828:                                break;
                   2829:                        }
                   2830:                        cnt = MIN(transfer_size, 
                   2831:                                CLMAP_NPGS(clmap) * vm_page_size);
                   2832:                        ps = CLMAP_PS(clmap);
                   2833:                        /* Assume that the caller has given us contiguous */
                   2834:                        /* pages */
                   2835:                        if(cnt) {
                   2836:                                error = ps_write_file(ps, actual_offset,
                   2837:                                                        mapped_data, cnt);
                   2838:                                ps_vs_write_complete(vs, mobj_target_addr, 
                   2839:                                                                cnt, error);
                   2840:                           }
                   2841:                        actual_offset += cnt;
                   2842:                        mobj_target_addr += cnt;
                   2843:                        mapped_data += cnt;
                   2844:                        transfer_size -= cnt;
                   2845:                        cnt = 0;
                   2846: 
                   2847:                        if(error)
                   2848:                                break;
                   2849:                }
                   2850:        }
                   2851:        if(error)
                   2852:                return KERN_FAILURE;
                   2853:        else
                   2854:                return KERN_SUCCESS;
                   2855: }
                   2856: 
                   2857: vm_size_t
                   2858: ps_vstruct_allocated_size(
                   2859:        vstruct_t       vs)
                   2860: {
                   2861:        int             num_pages;
                   2862:        struct vs_map   *vsmap;
                   2863:        int             i, j, k;
                   2864: 
                   2865:        num_pages = 0;
                   2866:        if (vs->vs_indirect) {
                   2867:                /* loop on indirect maps */
                   2868:                for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
                   2869:                        vsmap = vs->vs_imap[i];
                   2870:                        if (vsmap == NULL)
                   2871:                                continue;
                   2872:                        /* loop on clusters in this indirect map */
                   2873:                        for (j = 0; j < CLMAP_ENTRIES; j++) {
                   2874:                                if (VSM_ISCLR(vsmap[j]) ||
                   2875:                                    VSM_ISERR(vsmap[j]))
                   2876:                                        continue;
                   2877:                                /* loop on pages in this cluster */
                   2878:                                for (k = 0; k < VSCLSIZE(vs); k++) {
                   2879:                                        if ((VSM_BMAP(vsmap[j])) & (1 << k))
                   2880:                                                num_pages++;
                   2881:                                }
                   2882:                        }
                   2883:                }
                   2884:        } else {
                   2885:                vsmap = vs->vs_dmap;
                   2886:                if (vsmap == NULL)
                   2887:                        return 0;
                   2888:                /* loop on clusters in the direct map */
                   2889:                for (j = 0; j < CLMAP_ENTRIES; j++) {
                   2890:                        if (VSM_ISCLR(vsmap[j]) ||
                   2891:                            VSM_ISERR(vsmap[j])) 
                   2892:                                continue;
                   2893:                        /* loop on pages in this cluster */
                   2894:                        for (k = 0; k < VSCLSIZE(vs); k++) {
                   2895:                                if ((VSM_BMAP(vsmap[j])) & (1 << k))
                   2896:                                        num_pages++;
                   2897:                        }
                   2898:                }
                   2899:        }
                   2900: 
                   2901:        return ptoa(num_pages);
                   2902: }
                   2903: 
                   2904: size_t
                   2905: ps_vstruct_allocated_pages(
                   2906:        vstruct_t               vs,
                   2907:        default_pager_page_t    *pages,
                   2908:        size_t                  pages_size)
                   2909: {
                   2910:        int             num_pages;
                   2911:        struct vs_map   *vsmap;
                   2912:        vm_offset_t     offset;
                   2913:        int             i, j, k;
                   2914: 
                   2915:        num_pages = 0;
                   2916:        offset = 0;
                   2917:        if (vs->vs_indirect) {
                   2918:                /* loop on indirect maps */
                   2919:                for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
                   2920:                        vsmap = vs->vs_imap[i];
                   2921:                        if (vsmap == NULL) {
                   2922:                                offset += (vm_page_size * CLMAP_ENTRIES *
                   2923:                                           VSCLSIZE(vs));
                   2924:                                continue;
                   2925:                        }
                   2926:                        /* loop on clusters in this indirect map */
                   2927:                        for (j = 0; j < CLMAP_ENTRIES; j++) {
                   2928:                                if (VSM_ISCLR(vsmap[j]) ||
                   2929:                                    VSM_ISERR(vsmap[j])) {
                   2930:                                        offset += vm_page_size * VSCLSIZE(vs);
                   2931:                                        continue;
                   2932:                                }
                   2933:                                /* loop on pages in this cluster */
                   2934:                                for (k = 0; k < VSCLSIZE(vs); k++) {
                   2935:                                        if ((VSM_BMAP(vsmap[j])) & (1 << k)) {
                   2936:                                                num_pages++;
                   2937:                                                if (num_pages < pages_size)
                   2938:                                                        pages++->dpp_offset =
                   2939:                                                                offset;
                   2940:                                        }
                   2941:                                        offset += vm_page_size;
                   2942:                                }
                   2943:                        }
                   2944:                }
                   2945:        } else {
                   2946:                vsmap = vs->vs_dmap;
                   2947:                if (vsmap == NULL)
                   2948:                        return 0;
                   2949:                /* loop on clusters in the direct map */
                   2950:                for (j = 0; j < CLMAP_ENTRIES; j++) {
                   2951:                        if (VSM_ISCLR(vsmap[j]) ||
                   2952:                            VSM_ISERR(vsmap[j])) {
                   2953:                                offset += vm_page_size * VSCLSIZE(vs);
                   2954:                                continue;
                   2955:                        }
                   2956:                        /* loop on pages in this cluster */
                   2957:                        for (k = 0; k < VSCLSIZE(vs); k++) {
                   2958:                                if ((VSM_BMAP(vsmap[j])) & (1 << k)) {
                   2959:                                        num_pages++;
                   2960:                                        if (num_pages < pages_size)
                   2961:                                                pages++->dpp_offset = offset;
                   2962:                                }
                   2963:                                offset += vm_page_size;
                   2964:                        }
                   2965:                }
                   2966:        }
                   2967: 
                   2968:        return num_pages;
                   2969: }
                   2970: 
                   2971: 
                   2972: kern_return_t
                   2973: ps_vstruct_transfer_from_segment(
                   2974:        vstruct_t        vs,
                   2975:        paging_segment_t segment,
                   2976:        upl_t            page_list)
                   2977: {
                   2978:        struct vs_map   *vsmap;
                   2979:        struct vs_map   old_vsmap;
                   2980:        struct vs_map   new_vsmap;
                   2981:        int             i, j, k;
                   2982: 
                   2983:        VS_LOCK(vs);    /* block all work on this vstruct */
                   2984:                        /* can't allow the normal multiple write */
                   2985:                        /* semantic because writes may conflict */
                   2986:        vs->vs_xfer_pending = TRUE;
                   2987:        vs_wait_for_sync_writers(vs);
                   2988:        vs_start_write(vs);
                   2989:        vs_wait_for_readers(vs);
                   2990:        /* we will unlock the vs to allow other writes while transferring */
                   2991:        /* and will be guaranteed of the persistance of the vs struct     */
                   2992:        /* because the caller of  ps_vstruct_transfer_from_segment bumped */
                   2993:        /* vs_async_pending */
                   2994:        /* OK we now have guaranteed no other parties are accessing this */
                   2995:        /* vs.  Now that we are also supporting simple lock versions of  */
                   2996:        /* vs_lock we cannot hold onto VS_LOCK as we may block below.    */
                   2997:        /* our purpose in holding it before was the multiple write case */
                   2998:        /* we now use the boolean xfer_pending to do that.  We can use  */
                   2999:        /* a boolean instead of a count because we have guaranteed single */
                   3000:        /* file access to this code in its caller */
                   3001:        VS_UNLOCK(vs);
                   3002: vs_changed:
                   3003:        if (vs->vs_indirect) {
                   3004:                int     vsmap_size;
                   3005:                int     clmap_off;
                   3006:                /* loop on indirect maps */
                   3007:                for (i = 0; i < INDIRECT_CLMAP_ENTRIES(vs->vs_size); i++) {
                   3008:                        vsmap = vs->vs_imap[i];
                   3009:                        if (vsmap == NULL)
                   3010:                                continue;
                   3011:                        /* loop on clusters in this indirect map */
                   3012:                        clmap_off = (vm_page_size * CLMAP_ENTRIES *
                   3013:                                           VSCLSIZE(vs) * i);
                   3014:                        if(i+1 == INDIRECT_CLMAP_ENTRIES(vs->vs_size))
                   3015:                                vsmap_size = vs->vs_size - (CLMAP_ENTRIES * i);
                   3016:                        else
                   3017:                                vsmap_size = CLMAP_ENTRIES;
                   3018:                        for (j = 0; j < vsmap_size; j++) {
                   3019:                                if (VSM_ISCLR(vsmap[j]) ||
                   3020:                                    VSM_ISERR(vsmap[j]) ||
                   3021:                                    (VSM_PS(vsmap[j]) != segment))
                   3022:                                        continue;
                   3023:                                if(vs_cluster_transfer(vs, 
                   3024:                                        (vm_page_size * (j << vs->vs_clshift))
                   3025:                                        + clmap_off, 
                   3026:                                        vm_page_size << vs->vs_clshift,
                   3027:                                        page_list)
                   3028:                                                != KERN_SUCCESS) {
                   3029:                                   VS_LOCK(vs);
                   3030:                                   vs->vs_xfer_pending = FALSE;
                   3031:                                   VS_UNLOCK(vs);
                   3032:                                   vs_finish_write(vs);
                   3033:                                   return KERN_FAILURE;
                   3034:                                }
                   3035:                                /* allow other readers/writers during transfer*/
                   3036:                                VS_LOCK(vs);
                   3037:                                vs->vs_xfer_pending = FALSE;
                   3038:                                VS_UNLOCK(vs);
                   3039:                                vs_finish_write(vs);
                   3040:                                VS_LOCK(vs);
                   3041:                                vs->vs_xfer_pending = TRUE;
                   3042:                                VS_UNLOCK(vs);
                   3043:                                vs_wait_for_sync_writers(vs);
                   3044:                                vs_start_write(vs);
                   3045:                                vs_wait_for_readers(vs);
                   3046:                                if (!(vs->vs_indirect)) {
                   3047:                                        goto vs_changed;
                   3048:                                }
                   3049:                        }
                   3050:                }
                   3051:        } else {
                   3052:                vsmap = vs->vs_dmap;
                   3053:                if (vsmap == NULL) {
                   3054:                        VS_LOCK(vs);
                   3055:                        vs->vs_xfer_pending = FALSE;
                   3056:                        VS_UNLOCK(vs);
                   3057:                        vs_finish_write(vs);
                   3058:                        return KERN_SUCCESS;
                   3059:                }
                   3060:                /* loop on clusters in the direct map */
                   3061:                for (j = 0; j < vs->vs_size; j++) {
                   3062:                        if (VSM_ISCLR(vsmap[j]) ||
                   3063:                            VSM_ISERR(vsmap[j]) ||
                   3064:                            (VSM_PS(vsmap[j]) != segment))
                   3065:                                continue;
                   3066:                        if(vs_cluster_transfer(vs, 
                   3067:                                vm_page_size * (j << vs->vs_clshift), 
                   3068:                                vm_page_size << vs->vs_clshift,
                   3069:                                page_list) != KERN_SUCCESS) {
                   3070:                           VS_LOCK(vs);
                   3071:                           vs->vs_xfer_pending = FALSE;
                   3072:                           VS_UNLOCK(vs);
                   3073:                           vs_finish_write(vs);
                   3074:                           return KERN_FAILURE;
                   3075:                        }
                   3076:                        /* allow other readers/writers during transfer*/
                   3077:                        VS_LOCK(vs);
                   3078:                        vs->vs_xfer_pending = FALSE;
                   3079:                        VS_UNLOCK(vs);
                   3080:                        vs_finish_write(vs);
                   3081:                        VS_LOCK(vs);
                   3082:                        vs->vs_xfer_pending = TRUE;
                   3083:                        VS_UNLOCK(vs);
                   3084:                        vs_wait_for_sync_writers(vs);
                   3085:                        vs_start_write(vs);
                   3086:                        vs_wait_for_readers(vs);
                   3087:                        if (vs->vs_indirect) {
                   3088:                                goto vs_changed;
                   3089:                        }
                   3090:                }
                   3091:        }
                   3092: 
                   3093:        VS_LOCK(vs);
                   3094:        vs->vs_xfer_pending = FALSE;
                   3095:        VS_UNLOCK(vs);
                   3096:        vs_finish_write(vs);
                   3097:        return KERN_SUCCESS;
                   3098: }
                   3099: 
                   3100: 
                   3101: 
                   3102: vs_map_t
                   3103: vs_get_map_entry(
                   3104:        vstruct_t       vs, 
                   3105:        vm_offset_t     offset)
                   3106: {
                   3107:        struct vs_map   *vsmap;
                   3108:        vm_offset_t     cluster;
                   3109: 
                   3110:        cluster = atop(offset) >> vs->vs_clshift;
                   3111:        if (vs->vs_indirect) {
                   3112:                long    ind_block = cluster/CLMAP_ENTRIES;
                   3113: 
                   3114:                /* Is the indirect block allocated? */
                   3115:                vsmap = vs->vs_imap[ind_block];
                   3116:                if(vsmap == (vs_map_t) NULL)
                   3117:                        return vsmap;
                   3118:        } else
                   3119:                vsmap = vs->vs_dmap;
                   3120:        vsmap += cluster%CLMAP_ENTRIES;
                   3121:        return vsmap;
                   3122: }
                   3123: 
                   3124: 
                   3125: 
                   3126: 
                   3127: 
                   3128: 
                   3129: 
                   3130: kern_return_t
                   3131: vs_cluster_transfer(
                   3132:        vstruct_t       vs,
                   3133:        vm_offset_t     offset,
                   3134:        vm_size_t       cnt,
                   3135:        upl_t           page_list)
                   3136: {
                   3137:        vm_offset_t             actual_offset;
                   3138:        paging_segment_t        ps;
                   3139:        struct clmap            clmap;
                   3140:        kern_return_t           error = KERN_SUCCESS;
                   3141:        int                     size, size_wanted, i;
                   3142:        unsigned int            residual;
                   3143:        int                     unavail_size;
                   3144:        default_pager_thread_t  *dpt;
                   3145:        boolean_t               dealloc;
                   3146:        struct  vs_map          *vsmap_ptr;
                   3147:        struct  vs_map          read_vsmap;
                   3148:        struct  vs_map          original_read_vsmap;
                   3149:        struct  vs_map          write_vsmap;
                   3150: 
                   3151:        vm_offset_t     ioaddr;
                   3152: 
                   3153:        static char here[] = "vs_cluster_transfer";
                   3154: 
                   3155:        /* vs_cluster_transfer reads in the pages of a cluster and
                   3156:         * then writes these pages back to new backing store.  The
                   3157:         * segment the pages are being read from is assumed to have
                   3158:         * been taken off-line and is no longer considered for new
                   3159:         * space requests.
                   3160:          */
                   3161: 
                   3162:        /*
                   3163:         * This loop will be executed once per cluster referenced.
                   3164:         * Typically this means once, since it's unlikely that the
                   3165:         * VM system will ask for anything spanning cluster boundaries.
                   3166:         *
                   3167:         * If there are holes in a cluster (in a paging segment), we stop
                   3168:         * reading at the hole, then loop again, hoping to
                   3169:         * find valid pages later in the cluster.  This continues until
                   3170:         * the entire range has been examined, and read, if present.  The
                   3171:         * pages are written as they are read.  If a failure occurs after
                   3172:         * some pages are written the unmap call at the bottom of the loop
                   3173:         * recovers the backing store and the old backing store remains
                   3174:         * in effect.
                   3175:         */
                   3176: 
                   3177:        upl_map(kernel_map, page_list, &ioaddr);
                   3178: 
                   3179:        VSM_CLR(write_vsmap);
                   3180:        VSM_CLR(original_read_vsmap);
                   3181:        while (cnt && (error == KERN_SUCCESS)) {
                   3182:                vsmap_ptr = vs_get_map_entry(vs, offset);
                   3183:                actual_offset = ps_clmap(vs, offset, &clmap, CL_FIND, 0, 0);
                   3184: 
                   3185:                if (actual_offset == (vm_offset_t) -1) {
                   3186: 
                   3187:                        /*
                   3188:                         * Nothing left to write in this cluster at least
                   3189:                         * set write cluster information for any previous
                   3190:                         * write, clear for next cluster, if there is one
                   3191:                         */
                   3192:                        unsigned int local_size, clmask, clsize;
                   3193: 
                   3194:                        clsize = vm_page_size << vs->vs_clshift;
                   3195:                        clmask = clsize - 1;
                   3196:                        local_size = clsize - (offset & clmask);
                   3197:                        ASSERT(local_size);
                   3198:                        local_size = MIN(local_size, cnt);
                   3199: 
                   3200:                        /* This cluster has no data in it beyond what may */
                   3201:                        /* have been found on a previous iteration through */
                   3202:                        /* the loop "write_vsmap" */
                   3203:                        *vsmap_ptr = write_vsmap;
                   3204:                        VSM_CLR(write_vsmap);
                   3205:                        VSM_CLR(original_read_vsmap);
                   3206: 
                   3207:                        cnt -= local_size;
                   3208:                        offset += local_size;
                   3209:                        continue;
                   3210:                }
                   3211: 
                   3212:                /*
                   3213:                 * Count up contiguous available or unavailable
                   3214:                 * pages.
                   3215:                 */
                   3216:                ps = CLMAP_PS(clmap);
                   3217:                ASSERT(ps);
                   3218:                size = 0;
                   3219:                unavail_size = 0;
                   3220:                for (i = 0;
                   3221:                     (size < cnt) && (unavail_size < cnt) &&
                   3222:                     (i < CLMAP_NPGS(clmap)); i++) {
                   3223:                        if (CLMAP_ISSET(clmap, i)) {
                   3224:                                if (unavail_size != 0)
                   3225:                                        break;
                   3226:                                size += vm_page_size;
                   3227:                                BS_STAT(ps->ps_bs,
                   3228:                                        ps->ps_bs->bs_pages_in++);
                   3229:                        } else {
                   3230:                                if (size != 0)
                   3231:                                        break;
                   3232:                                unavail_size += vm_page_size;
                   3233:                        }
                   3234:                }
                   3235: 
                   3236:                if (size == 0) {
                   3237:                        ASSERT(unavail_size);
                   3238:                        cnt -= unavail_size;
                   3239:                        offset += unavail_size;
                   3240:                        if((offset & ((vm_page_size << vs->vs_clshift) - 1)) 
                   3241:                                == 0) {
                   3242:                                /* There is no more to transfer in this
                   3243:                                   cluster
                   3244:                                */
                   3245:                                *vsmap_ptr = write_vsmap;
                   3246:                                VSM_CLR(write_vsmap);
                   3247:                                VSM_CLR(original_read_vsmap);
                   3248:                        } 
                   3249:                        continue;
                   3250:                }
                   3251: 
                   3252:                if(VSM_ISCLR(original_read_vsmap))
                   3253:                        original_read_vsmap = *vsmap_ptr;
                   3254: 
                   3255:                if(ps->ps_segtype == PS_PARTITION) {
                   3256: /*
                   3257:                        error = ps_read_device(ps, actual_offset, &buffer,
                   3258:                                       size, &residual);
                   3259: */
                   3260:                } else {
                   3261:                        error = ps_read_file(ps, actual_offset, ioaddr, 
                   3262:                                        size, &residual);
                   3263:                }
                   3264: 
                   3265:                read_vsmap = *vsmap_ptr;
                   3266: 
                   3267: 
                   3268:                /*
                   3269:                 * Adjust counts and put data in new BS.  Optimize for the
                   3270:                 * common case, i.e. no error and/or partial data.
                   3271:                 * If there was an error, then we need to error the entire
                   3272:                 * range, even if some data was successfully read.
                   3273:                 * 
                   3274:                 */
                   3275:                if ((error == KERN_SUCCESS) && (residual == 0)) {
                   3276:                        /*
                   3277:                         * Got everything we asked for, supply the data to
                   3278:                         * the new BS.  Note that as a side effect of supplying
                   3279:                         * the data, the buffer holding the supplied data is
                   3280:                         * deallocated from the pager's address space unless
                   3281:                         * the write is unsuccessful.
                   3282:                         */
                   3283: 
                   3284:                        /* note buffer will be cleaned up in all cases by */
                   3285:                        /* internal_cluster_write or if an error on write */
                   3286:                        /* the vm_map_copy_page_discard call              */
                   3287:                        *vsmap_ptr = write_vsmap;
                   3288:                        if(vs_cluster_write(vs, offset, 
                   3289:                                        ioaddr, size, TRUE) != KERN_SUCCESS) {
                   3290:                                error = KERN_FAILURE;
                   3291:                                if(!(VSM_ISCLR(*vsmap_ptr))) {
                   3292:                                        /* unmap the new backing store object */
                   3293:                                        ps_clunmap(vs, offset, size);
                   3294:                                }
                   3295:                                /* original vsmap */
                   3296:                                *vsmap_ptr = original_read_vsmap;
                   3297:                                VSM_CLR(write_vsmap);
                   3298:                        } else {
                   3299:                               if((offset + size) & 
                   3300:                                        ((vm_page_size << vs->vs_clshift)
                   3301:                                        - 1)) { 
                   3302:                                        /* There is more to transfer in this
                   3303:                                           cluster
                   3304:                                        */
                   3305:                                        write_vsmap = *vsmap_ptr;
                   3306:                                        *vsmap_ptr = read_vsmap;
                   3307:                                } else {
                   3308:                                        /* discard the old backing object */
                   3309:                                        write_vsmap = *vsmap_ptr;
                   3310:                                        *vsmap_ptr = read_vsmap;
                   3311:                                        ps_clunmap(vs, offset, size);
                   3312:                                        *vsmap_ptr = write_vsmap;
                   3313:                                        VSM_CLR(write_vsmap);
                   3314:                                        VSM_CLR(original_read_vsmap);
                   3315:                                }
                   3316:                        }
                   3317:                } else {
                   3318:                        size_wanted = size;
                   3319:                        if (error == KERN_SUCCESS) {
                   3320:                                if (residual == size) {
                   3321:                                        /*
                   3322:                                         * If a read operation returns no error
                   3323:                                         * and no data moved, we turn it into
                   3324:                                         * an error, assuming we're reading at
                   3325:                                         * or beyond EOF.
                   3326:                                         * Fall through and error the entire
                   3327:                                         * range.
                   3328:                                         */
                   3329:                                        error = KERN_FAILURE;
                   3330:                                        *vsmap_ptr = original_read_vsmap;
                   3331:                                        VSM_CLR(write_vsmap);
                   3332:                                        continue;
                   3333:                                } else {
                   3334:                                        /*
                   3335:                                         * Otherwise, we have partial read. 
                   3336:                                         * This is also considered an error
                   3337:                                         * for the purposes of cluster transfer
                   3338:                                         */
                   3339:                                        error = KERN_FAILURE;
                   3340:                                        *vsmap_ptr = original_read_vsmap;
                   3341:                                        VSM_CLR(write_vsmap);
                   3342:                                        continue;
                   3343:                                }
                   3344:                        }
                   3345: 
                   3346:                }
                   3347:                cnt -= size;
                   3348:                offset += size;
                   3349: 
                   3350:        } /* END while (cnt && (error == 0)) */
                   3351:        if(!VSM_ISCLR(write_vsmap))
                   3352:                *vsmap_ptr = write_vsmap;
                   3353: 
                   3354:        upl_un_map(kernel_map, page_list);
                   3355:        return error;
                   3356: }
                   3357: 
                   3358: kern_return_t
                   3359: default_pager_add_file(MACH_PORT_FACE backing_store,
                   3360:        int             *vp,
                   3361:        int             record_size,
                   3362:        long            size)
                   3363: {
                   3364:        backing_store_t         bs;
                   3365:        paging_segment_t        ps;
                   3366:        int                     i;
                   3367:        int                     error;
                   3368:        static char here[] = "default_pager_add_file"; 
                   3369: 
                   3370:        if ((bs = backing_store_lookup(backing_store))
                   3371:            == BACKING_STORE_NULL)
                   3372:                return KERN_INVALID_ARGUMENT;
                   3373: 
                   3374:        PSL_LOCK();
                   3375:        for (i = 0; i <= paging_segment_max; i++) {
                   3376:                ps = paging_segments[i];
                   3377:                if (ps == PAGING_SEGMENT_NULL)
                   3378:                        continue;
                   3379:                if (ps->ps_segtype != PS_FILE)
                   3380:                        continue;
                   3381: 
                   3382:                /*
                   3383:                 * Check for overlap on same device.
                   3384:                 */
                   3385:                if (ps->ps_vnode == (struct vnode *)vp) {
                   3386:                        PSL_UNLOCK();
                   3387:                        BS_UNLOCK(bs);
                   3388:                        return KERN_INVALID_ARGUMENT;
                   3389:                }
                   3390:        }
                   3391:        PSL_UNLOCK();
                   3392: 
                   3393:        /*
                   3394:         * Set up the paging segment
                   3395:         */
                   3396:        ps = (paging_segment_t) kalloc(sizeof (struct paging_segment));
                   3397:        if (ps == PAGING_SEGMENT_NULL) {
                   3398:                BS_UNLOCK(bs);
                   3399:                return KERN_RESOURCE_SHORTAGE;
                   3400:        }
                   3401: 
                   3402:        ps->ps_segtype = PS_FILE;
                   3403:        ps->ps_vnode = (struct vnode *)vp;
                   3404:        ps->ps_offset = 0;
                   3405:        ps->ps_record_shift = local_log2(vm_page_size / record_size);
                   3406:        ps->ps_recnum = size;
                   3407:        ps->ps_pgnum = size >> ps->ps_record_shift;
                   3408: 
                   3409:        ps->ps_pgcount = ps->ps_pgnum;
                   3410:        ps->ps_clshift = local_log2(bs->bs_clsize);
                   3411:        ps->ps_clcount = ps->ps_ncls = ps->ps_pgcount >> ps->ps_clshift;
                   3412:        ps->ps_hint = 0;
                   3413: 
                   3414:        PS_LOCK_INIT(ps);
                   3415:        ps->ps_bmap = (unsigned char *) kalloc(RMAPSIZE(ps->ps_ncls));
                   3416:        if (!ps->ps_bmap) {
                   3417:                kfree((vm_offset_t)ps, sizeof *ps);
                   3418:                BS_UNLOCK(bs);
                   3419:                return KERN_RESOURCE_SHORTAGE;
                   3420:        }
                   3421:        for (i = 0; i < ps->ps_ncls; i++) {
                   3422:                clrbit(ps->ps_bmap, i);
                   3423:        }
                   3424: 
                   3425:        ps->ps_going_away = FALSE;
                   3426:        ps->ps_bs = bs;
                   3427: 
                   3428:        if ((error = ps_enter(ps)) != 0) {
                   3429:                kfree((vm_offset_t)ps->ps_bmap, RMAPSIZE(ps->ps_ncls));
                   3430:                kfree((vm_offset_t)ps, sizeof *ps);
                   3431:                BS_UNLOCK(bs);
                   3432:                return KERN_RESOURCE_SHORTAGE;
                   3433:        }
                   3434: 
                   3435:        bs->bs_pages_free += ps->ps_clcount << ps->ps_clshift;
                   3436:        bs->bs_pages_total += ps->ps_clcount << ps->ps_clshift;
                   3437:        PSL_LOCK();
                   3438:        dp_pages_free += ps->ps_pgcount;
                   3439:        PSL_UNLOCK();
                   3440: 
                   3441:        BS_UNLOCK(bs);
                   3442: 
                   3443:        bs_more_space(ps->ps_clcount);
                   3444: 
                   3445:        DEBUG(DEBUG_BS_INTERNAL,
                   3446:              ("device=0x%x,offset=0x%x,count=0x%x,record_size=0x%x,shift=%d,total_size=0x%x\n",
                   3447:               device, offset, size, record_size,
                   3448:               ps->ps_record_shift, ps->ps_pgnum));
                   3449: 
                   3450:        return KERN_SUCCESS;
                   3451: }
                   3452: 
                   3453: 
                   3454: 
                   3455: kern_return_t ps_read_file(paging_segment_t, vm_offset_t, vm_offset_t, unsigned int, unsigned int *);  /* forward */
                   3456: 
                   3457: kern_return_t
                   3458: ps_read_file(
                   3459:        paging_segment_t        ps,
                   3460:        vm_offset_t             offset,
                   3461:        vm_offset_t             ioaddr,
                   3462:        unsigned int            size,
                   3463:        unsigned int            *residualp)
                   3464: {
                   3465:        kern_return_t   kr = KERN_SUCCESS;
                   3466:        vm_offset_t     dev_offset;
                   3467:        static char     here[] = "ps_read_file";
                   3468: 
                   3469:        vm_map_copy_t   device_data = NULL;
                   3470:        int             error = 0;
                   3471:        int             result;
                   3472: 
                   3473: 
                   3474:        clustered_reads[atop(size)]++;
                   3475: 
                   3476:        dev_offset = ps->ps_offset + offset;
                   3477:        
                   3478:        error = pager_vnode_pagein(ps->ps_vnode, 
                   3479:                (vm_offset_t)ioaddr, dev_offset, (vm_size_t)size, NULL);
                   3480: 
                   3481:        /* The vnode_pagein semantic is somewhat at odds with the existing   */
                   3482:        /* device_read semantic.  Partial reads are not experienced at this  */
                   3483:        /* level.  It is up to the bit map code and cluster read code to     */
                   3484:        /* check that requested data locations are actually backed, and the  */
                   3485:        /* pagein code to either read all of the requested data or return an */
                   3486:        /* error. */
                   3487: 
                   3488:        if(error)
                   3489:                result = KERN_FAILURE;
                   3490:        else {
                   3491:                *residualp = 0;
                   3492:                result = KERN_SUCCESS;
                   3493:        }
                   3494: 
                   3495:        return result;
                   3496: 
                   3497: }
                   3498: 
                   3499: kern_return_t
                   3500: ps_write_file(
                   3501:        paging_segment_t        ps,
                   3502:        vm_offset_t             offset,
                   3503:        vm_offset_t             addr,
                   3504:        unsigned int            size)
                   3505: {
                   3506:        vm_offset_t     dev_offset;
                   3507:        kern_return_t   result;
                   3508:        static char here[] = "ps_write_file";
                   3509: 
                   3510:        vm_offset_t     ioaddr;
                   3511:        int             error = 0;
                   3512: 
                   3513: 
                   3514:        clustered_writes[atop(size)]++;
                   3515:        dev_offset = ps->ps_offset + offset;
                   3516: 
                   3517:        ioaddr = addr;
                   3518: 
                   3519: 
                   3520:        if (ioaddr) {
                   3521:                if(pager_vnode_pageout(ps->ps_vnode, ioaddr, 
                   3522:                           (vm_offset_t) dev_offset, (vm_size_t)size, NULL)) {
                   3523:                                        result = KERN_FAILURE;
                   3524:                }
                   3525:                else {
                   3526:                        result = KERN_SUCCESS;
                   3527:                }
                   3528: 
                   3529:        }
                   3530:        else {
                   3531:                panic("ps_write_file: No data to copy out\n");
                   3532:                result = KERN_SUCCESS;
                   3533:        }
                   3534: 
                   3535: 
                   3536:        return result;
                   3537: }
                   3538: 
                   3539: kern_return_t
                   3540: default_pager_triggers(MACH_PORT_FACE default_pager,
                   3541:        int             hi_wat,
                   3542:        int             lo_wat,
                   3543:        int             flags,
                   3544:        MACH_PORT_FACE  trigger_port)
                   3545: {
                   3546: 
                   3547:        if(flags & HI_WAT_ALERT) {
                   3548:                if(min_pages_trigger_port)
                   3549:                        ipc_port_release_send(min_pages_trigger_port);
                   3550:                min_pages_trigger_port = trigger_port;
                   3551:                minimum_pages_remaining = hi_wat/vm_page_size;
                   3552:                bs_low = FALSE;
                   3553:        }
                   3554:        if(flags & LO_WAT_ALERT) {
                   3555:                if(max_pages_trigger_port)
                   3556:                        ipc_port_release_send(max_pages_trigger_port);
                   3557:                max_pages_trigger_port = trigger_port;
                   3558:                maximum_pages_free = lo_wat/vm_page_size;
                   3559:        }
                   3560: }

unix.superglobalmegacorp.com

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