Annotation of XNU/osfmk/default_pager/dp_backing_store.c, revision 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.