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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1987 Carnegie-Mellon University
                     28:  * All rights reserved.  The CMU software License Agreement specifies
                     29:  * the terms and conditions for use and redistribution.
                     30:  */
                     31: 
                     32: /*
                     33:  *     File:   vnode_pager.c
                     34:  *
                     35:  *     "Swap" pager that pages to/from vnodes.  Also
                     36:  *     handles demand paging from files.
                     37:  *
                     38:  * 12-Mar-86  David Golub (dbg) at Carnegie-Mellon University
                     39:  *     Created.
                     40:  */
                     41: 
                     42: #import <mach_nbc.h>
                     43: 
                     44: #import <mach/boolean.h>
                     45: #import <sys/param.h>
                     46: #import <sys/systm.h>
                     47: #import <kern/lock.h>
                     48: #import <sys/proc.h>
                     49: #import <sys/buf.h>
                     50: #import <sys/uio.h>
                     51: #import <sys/vnode.h>
                     52: #import <ufs/ufs/quota.h>
                     53: #import <ufs/ufs/inode.h>
                     54: #import <sys/namei.h>
                     55: #import <sys/mach_swapon.h>
                     56: #import <ufs/ffs/fs.h>
                     57: #import <sys/mount.h>
                     58: #import <net/if.h>
                     59: #import <netinet/in.h>
                     60: #import <nfs/rpcv2.h>
                     61: #import <nfs/nfsproto.h>
                     62: #import <nfs/nfs.h>
                     63: #undef fs_fsok
                     64: #undef fs_tsize
                     65: #undef fs_bsize
                     66: #undef fs_blocks
                     67: #undef fs_bfree
                     68: #undef fs_bavail
                     69: 
                     70: #import <mach/mach_types.h>
                     71: #import <vm/vm_page.h>
                     72: #if defined(ppc)
                     73: #import <vm/pmap.h>
                     74: #endif /* ppc */
                     75: #import <vm/vm_map.h>
                     76: #import <vm/vm_kern.h>
                     77: #import <kern/parallel.h>
                     78: #import <kern/zalloc.h>
                     79: #import <kern/kalloc.h>
                     80: 
                     81: #import <vm/vnode_pager.h>
                     82: #import <kern/mapfs.h>
                     83: 
                     84: #import <kern/assert.h>
                     85: 
                     86: extern struct vnodeops nfs_vnodeops;
                     87: extern struct vnodeops spec_vnodeops;
                     88: 
                     89: #if    NBBY == 8
                     90: #define BYTEMASK 0xff
                     91: #else  NBBY
                     92: Define a byte mask for this machine.
                     93: #endif NBBY
                     94: 
                     95: 
                     96: #define PAGEMAP_THRESHOLD      64 /* Integral of sizeof(vm_offset_t) */
                     97: #define        PAGEMAP_ENTRIES         (PAGEMAP_THRESHOLD/sizeof(vm_offset_t))
                     98: #define        PAGEMAP_SIZE(npgs)      (npgs*sizeof(long))
                     99: 
                    100: #define        INDIR_PAGEMAP_ENTRIES(npgs) \
                    101:        (((npgs-1)/PAGEMAP_ENTRIES) + 1)
                    102: #define INDIR_PAGEMAP_SIZE(npgs) \
                    103:        (INDIR_PAGEMAP_ENTRIES(npgs) * sizeof(caddr_t))
                    104: #define INDIR_PAGEMAP(size) \
                    105:        (PAGEMAP_SIZE(size) > PAGEMAP_THRESHOLD)
                    106: 
                    107: #define RMAPSIZE(blocks) \
                    108:        (howmany(blocks,NBBY))
                    109: 
                    110: /*
                    111:  *     Sigh... with NFS/vnodes it is highly likely that we will need
                    112:  *     to allocate memory at page-out time, so use the XP hack to reserve
                    113:  *     pages and always use kalloc/zalloc instead of kget/zget.
                    114:  *     This must be fixed!!!  FIXME - XXX.
                    115:  */
                    116: 
                    117: #define kget(size)     kalloc_noblock(size)
                    118: #define zget(zone)     zalloc_noblock(zone)
                    119: 
                    120: /*
                    121:  *     Basic vnode pager data structures
                    122:  */
                    123: zone_t                 vstruct_zone;
                    124: simple_lock_data_t     vstruct_lock;
                    125: 
                    126: static queue_head_t    pager_files;
                    127: static int             pager_file_count;
                    128: static pager_file_t    pager_file_list[MAXPAGERFILES];
                    129: 
                    130: static pf_entry                seen_files[MAXPAGERFILES];
                    131: static int             seen_files_max = 0;
                    132: 
                    133: 
                    134: /*
                    135:  *     Routine:        vnode_pager_vput
                    136:  *     Function:
                    137:  *             Release one use of this vnode_pager_t
                    138:  */
                    139: void
                    140: vnode_pager_vput(vs)
                    141:        register vnode_pager_t  vs;
                    142: {
                    143: 
                    144:        simple_lock(&vstruct_lock);
                    145:        vs->vs_count--;
                    146:        simple_unlock(&vstruct_lock);
                    147: }
                    148: 
                    149: /*
                    150:  *     vnode_pager_vget:
                    151:  *
                    152:  *     Return a vnode corresponding to the specified paging space
                    153:  *     and guarantee that it will remain in memory (until furthur action
                    154:  *     is taken).
                    155:  *
                    156:  *     The vnode is returned unlocked.
                    157:  */
                    158: struct vnode *
                    159: vnode_pager_vget(vs)
                    160:        vnode_pager_t   vs;
                    161: {
                    162:        register struct vnode *vp;
                    163: 
                    164:        simple_lock(&vstruct_lock);
                    165:        vs->vs_count++;
                    166:        simple_unlock(&vstruct_lock);
                    167:        vp = vs->vs_vp;
                    168:        return(vp);
                    169: }
                    170: 
                    171: 
                    172: /*
                    173:  * vnode_pager_allocpage - allocate a page in a paging file
                    174:  */
                    175: daddr_t
                    176: vnode_pager_allocpage(pf)
                    177:      register struct pager_file *pf;
                    178: {
                    179:        int bp;                 /* byte counter */
                    180:        int i;                  /* bit counter */
                    181:        daddr_t page;           /* page number */
                    182: 
                    183:        lock_write(&pf->pf_lock);
                    184: 
                    185:        if (pf->pf_pfree == 0) {
                    186:                lock_done(&pf->pf_lock);
                    187:                return(-1);
                    188:        }
                    189: 
                    190:        /*
                    191:         *  Start at hint page and work up.
                    192:         */
                    193:        i = 0;
                    194:        for (bp = pf->pf_hint / NBBY; bp < howmany(pf->pf_npgs, NBBY); bp++) {
                    195:                if (*(pf->pf_bmap + bp) != BYTEMASK) {
                    196:                        for (i = 0; i < NBBY; i++) {
                    197:                                if (isclr((pf->pf_bmap + bp), i))
                    198:                                        break;
                    199:                        }
                    200:                        break;
                    201:                }
                    202:        }
                    203:        page = bp*NBBY+i;
                    204:        if (page >= pf->pf_npgs) {
                    205:                panic("vnode_pager_allocpage");
                    206:        }
                    207:        if (page > pf->pf_hipage) {
                    208:                pf->pf_hipage = page;
                    209:        }
                    210:        setbit(pf->pf_bmap,page);
                    211:        --pf->pf_pfree;
                    212:        pf->pf_hint = page;
                    213: 
                    214:        lock_done(&pf->pf_lock);
                    215:        return(page);
                    216: }
                    217: 
                    218: 
                    219: /*
                    220:  * vnode_pager_findpage - find an available page in some paging file, using the
                    221:  * argument as a preference.  If the pager_file argument is NULL, any file will
                    222:  * do.  Return the designated page and file in entry.
                    223:  */
                    224: kern_return_t
                    225: vnode_pager_findpage(struct pager_file *preferPf, pf_entry *entry)
                    226: {
                    227:        daddr_t result;
                    228:        pager_file_t pf;
                    229:        
                    230:        if (preferPf == PAGER_FILE_NULL) {
                    231:                if (!queue_empty(&pager_files))
                    232:                    preferPf = (pager_file_t) queue_first(&pager_files);
                    233:                else
                    234:                    return KERN_FAILURE;
                    235:        }
                    236:                
                    237:        pf = preferPf;               
                    238:        do {
                    239:                result = vnode_pager_allocpage(pf);
                    240:                if (result != -1) {
                    241:                        entry->index = pf->pf_index;
                    242:                        entry->offset = result;
                    243:                        return KERN_SUCCESS;
                    244:                }
                    245:                
                    246:                if (queue_end(&pager_files, &pf->pf_chain))
                    247:                        pf = (pager_file_t) queue_first(&pager_files);
                    248:                else
                    249:                        pf = (pager_file_t) queue_next(&pf->pf_chain);
                    250:                        
                    251:        } while (preferPf != pf);
                    252:        
                    253:        return KERN_FAILURE;
                    254: }
                    255: 
                    256: static void
                    257: vnode_pager_deallocpage(pf_entry entry)
                    258: {
                    259:        register struct pager_file *pf;
                    260:        daddr_t         page;
                    261: 
                    262:        if (entry.index == INDEX_NULL)
                    263:                return;
                    264: 
                    265:        assert(entry.index <= pager_file_count);
                    266:        
                    267:        pf = pager_file_list[entry.index];
                    268:        page = entry.offset;
                    269:        
                    270:        lock_write(&pf->pf_lock);
                    271: 
                    272:        if (page >= (daddr_t) pf->pf_npgs)
                    273:                panic("vnode_pager_deallocpage");
                    274:        if (page < pf->pf_hint)
                    275:                pf->pf_hint = page;
                    276:        clrbit(pf->pf_bmap, page);
                    277:        ++pf->pf_pfree;
                    278:        
                    279:        lock_done(&pf->pf_lock);
                    280: }
                    281: 
                    282: 
                    283: /*
                    284:  *     pagerfile_pager_create
                    285:  *
                    286:  *     Create an vstruct corresponding to the given pagerfile.
                    287:  *
                    288:  */
                    289: vnode_pager_t
                    290: pagerfile_pager_create(pf, size)
                    291:        register pager_file_t   pf;
                    292:        vm_size_t               size;
                    293: {
                    294:        register vnode_pager_t  vs;
                    295:        register int i;
                    296: 
                    297:        /*
                    298:         *      XXX This can still livelock -- if the
                    299:         *      pageout daemon needs an vnode_pager record
                    300:         *      it won't get one until someone else
                    301:         *      refills the zone.
                    302:         */
                    303: 
                    304:        vs = (struct vstruct *) zget(vstruct_zone);
                    305: 
                    306:        if (vs == VNODE_PAGER_NULL)
                    307:                return(vs);
                    308: 
                    309:        vs->vs_size = atop(round_page(size));
                    310:        
                    311:        if (vs->vs_size == 0)
                    312:                vs->vs_pmap = (pf_entry **) 0;
                    313:        else {
                    314:                if (INDIR_PAGEMAP(vs->vs_size)) {
                    315:                        vs->vs_pmap = (pf_entry **)
                    316:                                kget(INDIR_PAGEMAP_SIZE(vs->vs_size));
                    317:                } else {
                    318:                        vs->vs_pmap = (pf_entry **)
                    319:                                kget(PAGEMAP_SIZE(vs->vs_size));
                    320:                }
                    321:                if (vs->vs_pmap == (pf_entry **) 0) {
                    322:                        /*
                    323:                         * We can't sleep here, so if there are no free pages, then
                    324:                         * just return nothing.
                    325:                         */
                    326:                        zfree(vstruct_zone, (vm_offset_t) vs);
                    327:                        return(VNODE_PAGER_NULL);
                    328:                }
                    329:        
                    330:                if (INDIR_PAGEMAP(vs->vs_size)) {
                    331:                        bzero((caddr_t)vs->vs_pmap,
                    332:                                INDIR_PAGEMAP_SIZE(vs->vs_size));
                    333:                } else {
                    334:                        for (i = 0; i < vs->vs_size; i++)
                    335:                            ((pf_entry *) &vs->vs_pmap[i])->index = INDEX_NULL;
                    336:                }
                    337:        }
                    338:        
                    339:        vs->is_device = FALSE;
                    340:        vs->vs_count = 1;
                    341:        vs->vs_vp = pf->pf_vp;
                    342:        vs->vs_swapfile = TRUE;
                    343:        vs->vs_pf = pf;
                    344:        pf->pf_count++;
                    345: 
                    346:        vnode_pager_vput(vs);
                    347: 
                    348:        return(vs);
                    349: }
                    350: 
                    351: 
                    352: /*
                    353:  *  pagerfile_lookup
                    354:  *
                    355:  *  Look for an entry at the specified offset in vstruct.  If it's there,
                    356:  *  fill in the entry and return TRUE, otherwise return FALSE.
                    357:  */
                    358: static boolean_t
                    359: pagerfile_lookup(struct vstruct *vs, vm_offset_t f_offset, pf_entry *entry)
                    360: {
                    361:        vm_offset_t     f_page  = atop(f_offset);
                    362:        int             indirBlock;
                    363:        int             blockOffset;
                    364: 
                    365:         if (f_page >= vs->vs_size)
                    366:                 return FALSE;
                    367: 
                    368:        /*
                    369:         * Now look for the entry in the map.
                    370:         */
                    371:        if (INDIR_PAGEMAP(vs->vs_size)) {
                    372:                indirBlock = f_page / PAGEMAP_ENTRIES;
                    373:                blockOffset = f_page % PAGEMAP_ENTRIES;
                    374:     
                    375:                if (vs->vs_pmap[indirBlock] == NULL ||
                    376:                    vs->vs_pmap[indirBlock][blockOffset].index == INDEX_NULL)
                    377:                        return FALSE;
                    378:                else
                    379:                        *entry = vs->vs_pmap[indirBlock][blockOffset];
                    380: 
                    381:        } else {        /* direct map */
                    382:            
                    383:                if (((pf_entry *) &vs->vs_pmap[f_page])->index == INDEX_NULL)
                    384:                        return FALSE;
                    385:                else
                    386:                        *entry = *((pf_entry *) &vs->vs_pmap[f_page]);
                    387:        }
                    388:        return TRUE;
                    389: }
                    390: 
                    391: 
                    392: /*
                    393:  *     pagerfile_bmap
                    394:  *
                    395:  *     Fill in the map entry (pager file, offset) for a given f_offset into an
                    396:  *     object backed this pager map.
                    397:  *
                    398:  *     Returns: KERN_FAILURE if page not in map or no room left
                    399:  */
                    400: static kern_return_t
                    401: pagerfile_bmap(vs, f_offset, flag, entry)
                    402:        struct vstruct *vs;
                    403:        vm_offset_t f_offset;
                    404:        int flag;
                    405:        pf_entry *entry;
                    406: {
                    407:     vm_offset_t        f_page = atop(f_offset);
                    408:     boolean_t  found;
                    409:     int        i;
                    410: 
                    411:     /*
                    412:      *  Check the map to see if we can find it.  If we can't, then we'll
                    413:      *  make room below.
                    414:      */
                    415:     found = pagerfile_lookup(vs, f_offset, entry);
                    416: 
                    417:        if ((found) && (entry->index > pager_file_count))
                    418:                panic("pagerfile_bmap: bad index %d", entry->index);
                    419: 
                    420:     if (flag == B_READ)
                    421:        return found ? KERN_SUCCESS : KERN_FAILURE;
                    422:     else if (found) {
                    423:        /*
                    424:         *  Deallocate the page here, if the hint says that there's free
                    425:         *  space earlier in the file.  We do this to keep the swapfile
                    426:         *  as small as possible, and to enable the swapfile compactor.
                    427:         */
                    428:        struct pager_file *pf;
                    429: 
                    430:        if (entry->index == 0)
                    431:                panic("pagerfile_bmap: 0 index");
                    432: 
                    433:        pf = pager_file_list[entry->index];
                    434:        if (pf->pf_hint < entry->offset)
                    435:            vnode_pager_deallocpage(*entry);
                    436:        else
                    437:            return KERN_SUCCESS;
                    438:     }
                    439: 
                    440:     /*
                    441:      * If the object has grown, expand the page map.
                    442:      */
                    443:     if (f_page + 1 > vs->vs_size) {
                    444:        pf_entry        **new_pmap;
                    445:        int             new_size;
                    446: 
                    447:        new_size = f_page + 1;
                    448:        assert(new_size > 0);
                    449:        
                    450:        if (INDIR_PAGEMAP(new_size)) {  /* new map is indirect */
                    451: 
                    452:            if (vs->vs_size == 0) {
                    453:                /*
                    454:                 * Nothing to copy, just get a new
                    455:                 * map and zero it.
                    456:                 */
                    457:                new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size));
                    458:                if (new_pmap == NULL)
                    459:                        return (KERN_FAILURE);
                    460:                bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size));         
                    461:            }
                    462:            else if (INDIR_PAGEMAP(vs->vs_size)) {
                    463:            
                    464:                if (INDIR_PAGEMAP_SIZE(new_size) == 
                    465:                    INDIR_PAGEMAP_SIZE(vs->vs_size)) {
                    466:                        goto leavemapalone;
                    467:                }
                    468:                
                    469:                /* Get a new indirect map */
                    470:                new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size));
                    471:                if (new_pmap == NULL)
                    472:                        return KERN_FAILURE;
                    473: 
                    474:                bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size));
                    475: 
                    476:                /* Old map is indirect, copy the entries */
                    477:                for (i = 0; i < INDIR_PAGEMAP_ENTRIES(vs->vs_size); i++)
                    478:                        new_pmap[i] = vs->vs_pmap[i];
                    479:                        
                    480:                /* And free the old map */
                    481:                kfree(vs->vs_pmap, INDIR_PAGEMAP_SIZE(vs->vs_size));
                    482:                                
                    483:            } else {            /* old map was direct, new map is indirect */
                    484:            
                    485:                /* Get a new indirect map */
                    486:                new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size));
                    487:                if (new_pmap == NULL)
                    488:                        return KERN_FAILURE;
                    489: 
                    490:                bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size));
                    491: 
                    492:                /*
                    493:                 * Old map is direct, move it to the first indirect block.
                    494:                 */
                    495:                new_pmap[0] = (pf_entry *) kget(PAGEMAP_THRESHOLD);
                    496:                if (new_pmap[0] == NULL) {
                    497:                        kfree(new_pmap, INDIR_PAGEMAP_SIZE(new_size));
                    498:                        return KERN_FAILURE;
                    499:                }
                    500:                for (i = 0; i < vs->vs_size; i++)
                    501:                        new_pmap[0][i] = *((pf_entry *) &vs->vs_pmap[i]);
                    502:                        
                    503:                /* Initialize the remainder of the block */
                    504:                for (i = vs->vs_size; i < PAGEMAP_ENTRIES; i++)
                    505:                        new_pmap[0][i].index = INDEX_NULL;
                    506:                    
                    507:                /* And free the old map */
                    508:                kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size));
                    509:            }
                    510:            
                    511:        } else {        /* The new map is a direct one */
                    512:        
                    513:            new_pmap = (pf_entry **) kget(PAGEMAP_SIZE(new_size));
                    514:            if (new_pmap == NULL)
                    515:                    return KERN_FAILURE;
                    516: 
                    517:            /* Copy info from the old map */
                    518:            for (i = 0; i < vs->vs_size; i++)
                    519:                    new_pmap[i] = vs->vs_pmap[i];
                    520: 
                    521:            /* Initialize the rest of the new map */
                    522:            for (i = vs->vs_size; i < new_size; i++)
                    523:                    ((pf_entry *) &new_pmap[i])->index = INDEX_NULL;
                    524:                    
                    525:            if (vs->vs_size > 0)
                    526:                kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size));
                    527:        }
                    528:        
                    529:        vs->vs_pmap = new_pmap;
                    530: leavemapalone:
                    531:        vs->vs_size = new_size;
                    532:     }
                    533: 
                    534:     /*
                    535:      * Now allocate the spot for the new page.
                    536:      */
                    537:     if (INDIR_PAGEMAP(vs->vs_size)) {
                    538: 
                    539:        int indirBlock = f_page / PAGEMAP_ENTRIES;   /* the indirect block */
                    540:        int blockOffset = f_page % PAGEMAP_ENTRIES;  /* offset into block */
                    541: 
                    542:        /*
                    543:         *  In an indirect map, we may need to allocate space for the
                    544:         *  indirect block itself.
                    545:         */
                    546:        if (vs->vs_pmap[indirBlock] == NULL) {
                    547:                vs->vs_pmap[indirBlock]=(pf_entry *) kget(PAGEMAP_THRESHOLD);
                    548: 
                    549:                if (vs->vs_pmap[indirBlock] == NULL)
                    550:                        return KERN_FAILURE;
                    551: 
                    552:                for (i = 0; i < PAGEMAP_ENTRIES; i++)
                    553:                    vs->vs_pmap[indirBlock][i].index = INDEX_NULL;
                    554:        }
                    555: 
                    556:        if (vnode_pager_findpage(vs->vs_pf, entry) == KERN_FAILURE)
                    557:                return KERN_FAILURE;
                    558:        else
                    559:                vs->vs_pmap[indirBlock][blockOffset] = *entry;
                    560: 
                    561:     } else {   /* direct map */
                    562: 
                    563:        if (vnode_pager_findpage(vs->vs_pf, entry) == KERN_FAILURE)
                    564:                return KERN_FAILURE;
                    565: 
                    566:        *(pf_entry *) &vs->vs_pmap[f_page] = *entry;
                    567:     }
                    568:     
                    569:     return KERN_SUCCESS;
                    570: }
                    571: 
                    572: /*
                    573:  *     vnode_pager_create
                    574:  *
                    575:  *     Create an vstruct corresponding to the given vp.
                    576:  *
                    577:  */
                    578: vnode_pager_t
                    579: vnode_pager_create(vp)
                    580:        register struct vnode   *vp;
                    581: {
                    582:        vnode_pager_t   vs;
                    583:        struct vattr    vattr;
                    584:        vm_size_t       size;
                    585:        struct proc     *p = current_proc();
                    586:        int             error;
                    587: 
                    588:        /*
                    589:         *      XXX This can still livelock -- if the
                    590:         *      pageout daemon needs a vnode_pager record
                    591:         *      it won't get one until someone else
                    592:         *      refills the zone.
                    593:         */
                    594: 
                    595:        vs = (struct vstruct *) zalloc(vstruct_zone);
                    596: 
                    597:        if (vs == VNODE_PAGER_NULL)
                    598:                return(vs);
                    599: 
                    600:        bzero((caddr_t)vs, sizeof(struct vstruct));
                    601: 
                    602:        vs->is_device = FALSE;
                    603:        vs->vs_count = 1;
                    604:        vp->v_vm_info->pager = (vm_pager_t) vs;
                    605:        vs->vs_vp = vp;
                    606:        vs->vs_swapfile = FALSE;
                    607: 
                    608:        error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
                    609:        if (!error) {
                    610:            size = vattr.va_size;
                    611:            vp->v_vm_info->vnode_size = size;
                    612:        }
                    613:        else
                    614:            vp->v_vm_info->vnode_size = 0;
                    615:        
                    616:        VREF(vp);
                    617: 
                    618:        vnode_pager_vput(vs);
                    619: 
                    620:        return(vs);
                    621: }
                    622: 
                    623: /*
                    624:  *     vnode_pager_setup
                    625:  *
                    626:  *     Set up a vstruct for a given vnode.  This is an exported routine.
                    627:  */
                    628: vm_pager_t
                    629: vnode_pager_setup(vp, is_text, can_cache)
                    630:        struct vnode    *vp;
                    631:        boolean_t       is_text;
                    632:        boolean_t       can_cache;
                    633: {
                    634:        register pager_file_t   pf;
                    635: 
                    636:        unix_master();
                    637: 
                    638:        if (is_text)
                    639:                vp->v_flag |= VTEXT;
                    640: #if !MACH_NBC
                    641:        if(!vp->v_vm_info)
                    642:                vm_info_init(vp);
                    643: #endif /* MACH_NBC */
                    644: 
                    645:        if (vp->v_vm_info->pager == vm_pager_null) {
                    646:                /*
                    647:                 * Check to make sure this isn't in use as a pager file.
                    648:                 */
                    649:                for (pf = (pager_file_t) queue_first(&pager_files);
                    650:                     !queue_end(&pager_files, &pf->pf_chain);
                    651:                     pf = (pager_file_t) queue_next(&pf->pf_chain)) {
                    652:                        if (pf->pf_vp == vp) {
                    653:                                return(vm_pager_null);
                    654:                        }
                    655:                }
                    656:                (void) vnode_pager_create(vp);
                    657:                if (can_cache)
                    658:                        vm_object_cache_object(
                    659:                                vm_object_lookup(vp->v_vm_info->pager), TRUE);
                    660:        } 
                    661: 
                    662:        unix_release();
                    663:        /*
                    664:         * Try to keep something in the vstruct zone since we can sleep
                    665:         * here if necessary.
                    666:         */
                    667:        zfree(vstruct_zone, zalloc(vstruct_zone));
                    668:        return(vp->v_vm_info->pager);
                    669: }
                    670: 
                    671: #ifdef i386
                    672: 
                    673: static __inline__ vm_offset_t
                    674: vnode_pageio_setup(
                    675:     vm_page_t          m
                    676: )
                    677: {
                    678:     return (VM_PAGE_TO_PHYS(m));
                    679: }
                    680: 
                    681: static __inline__ void
                    682: vnode_pageio_complete(
                    683:     vm_page_t          m,
                    684:     vm_offset_t                addr
                    685: )
                    686: {
                    687:     /* do nothing */
                    688: }
                    689: 
                    690: #else  /* notdef i386 */
                    691: 
                    692: static vm_offset_t
                    693: vnode_pageio_setup(
                    694:     vm_page_t          m
                    695: )
                    696: {
                    697:     kern_return_t      result;
                    698:     vm_offset_t                addr = vm_map_min(kernel_map);
                    699: 
                    700:     result = vm_map_find(kernel_map, VM_OBJECT_NULL, 0,
                    701:                         &addr, PAGE_SIZE, TRUE);
                    702:     if (result != KERN_SUCCESS)
                    703:        return (0);
                    704: 
                    705:     pmap_enter_phys_page(VM_PAGE_TO_PHYS(m), addr);
                    706: 
                    707:     return (addr);
                    708: }
                    709: 
                    710: static void
                    711: vnode_pageio_complete(
                    712:     vm_page_t          m,
                    713:     vm_offset_t                addr
                    714: )
                    715: {
                    716:     vm_offset_t                taddr = trunc_page(addr);
                    717: 
                    718:     (void) vm_map_remove(kernel_map, taddr, taddr + PAGE_SIZE);
                    719: }
                    720: 
                    721: #endif /* notdef i386 */
                    722: 
                    723: pager_return_t
                    724: vnode_pagein(
                    725:     vm_page_t          m,
                    726:     int                        *errorp
                    727: )
                    728: {
                    729:        struct vnode    *vp;
                    730:        vnode_pager_t   vs;
                    731:        pager_return_t  result = PAGER_SUCCESS;
                    732:        vm_offset_t     f_offset;
                    733:        pf_entry        entry;
                    734:        struct proc     *p = current_proc();
                    735:        int             error = 0;
                    736: 
                    737:        unix_master();
                    738: 
                    739:        vs = (vnode_pager_t) m->object->pager;
                    740:        vp = vnode_pager_vget(vs);
                    741:        f_offset = m->offset + m->object->paging_offset;
                    742: 
                    743:        if (vs->vs_swapfile) {
                    744:            if (pagerfile_bmap(vs, f_offset, B_READ, &entry) == KERN_FAILURE)
                    745:                result = PAGER_ABSENT;
                    746:            else {
                    747:                f_offset = ptoa(entry.offset);
                    748:                vp = pager_file_list[entry.index]->pf_vp;
                    749:            }
                    750:        }
                    751: 
                    752:        if (result != PAGER_ABSENT) {
                    753:            vm_offset_t         ioaddr = vnode_pageio_setup(m);
                    754:            struct uio          auio;
                    755:            struct iovec        aiov;
                    756: 
                    757:            if (ioaddr) {
                    758:                auio.uio_iov = &aiov;
                    759:                auio.uio_iovcnt = 1;
                    760:                auio.uio_offset = f_offset;
                    761:                auio.uio_segflg = UIO_SYSSPACE;
                    762:                auio.uio_rw = UIO_READ;
                    763:                auio.uio_resid = PAGE_SIZE;
                    764:                auio.uio_procp = NULL;
                    765: 
                    766:                aiov.iov_len = PAGE_SIZE;
                    767:                aiov.iov_base = (caddr_t)ioaddr;
                    768: 
                    769:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p);
                    770: 
                    771:                m->nfspagereq=TRUE;
                    772:                error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred);
                    773:                m->nfspagereq=FALSE;
                    774:                if (error)
                    775:                    result = PAGER_ERROR;
                    776:                vp->v_vm_info->error = error;
                    777: 
                    778:                VOP_UNLOCK(vp, 0, p);
                    779: 
                    780:                if (!error && auio.uio_resid > 0)
                    781:                    (void) memset((void *)(ioaddr + PAGE_SIZE -
                    782:                                           auio.uio_resid), 0, auio.uio_resid);
                    783: 
                    784:                vnode_pageio_complete(m, ioaddr);
                    785: #ifdef ppc
                    786:                /*
                    787:                 * After a pagein, we must synchronize the processor caches.
                    788:                 * On PPC, the i-cache is not coherent in all models, thus
                    789:                 * it needs to be invalidated.
                    790:                 */
                    791:                flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE);
                    792: #endif /* ppc */
                    793:            }
                    794:            else
                    795:                result = PAGER_ERROR;
                    796:        }
                    797: 
                    798:        vnode_pager_vput(vs);
                    799: 
                    800:        if (errorp)
                    801:            *errorp = error;
                    802: 
                    803:        unix_release();
                    804: 
                    805:        return (result);
                    806: }
                    807: 
                    808: pager_return_t
                    809: vnode_pageout(
                    810:     vm_page_t          m
                    811: )
                    812: {
                    813:        struct vnode    *vp;
                    814:        vnode_pager_t   vs;
                    815:        pager_return_t  result = PAGER_SUCCESS;
                    816:        vm_offset_t     f_offset;
                    817:        vm_size_t       size = PAGE_SIZE;
                    818:        pf_entry        entry;
                    819:        struct proc     *p = current_proc();
                    820:        int             error = 0;
                    821: 
                    822:        unix_master();
                    823: 
                    824:        vs = (vnode_pager_t) m->object->pager;
                    825:        vp = vnode_pager_vget(vs);
                    826:        f_offset = m->offset + m->object->paging_offset;
                    827: 
                    828: #if    MACH_NBC
                    829:        if (!vs->vs_swapfile) {
                    830:            /*
                    831:             *  Be sure that a paging operation doesn't
                    832:             *  accidently extend the size of "mapped" file.
                    833:             *
                    834:             *  However, we do extend the size up to the current
                    835:             *  size kept in the vm_info structure.
                    836:             */
                    837:            if (f_offset + size > vp->v_vm_info->vnode_size) {
                    838:                if (f_offset > vp->v_vm_info->vnode_size)
                    839:                    size = 0;
                    840:                else
                    841:                    size = vp->v_vm_info->vnode_size - f_offset;
                    842:            }
                    843:        }
                    844: #endif MACH_NBC
                    845: 
                    846:        if (vs->vs_swapfile) {
                    847:            if (pagerfile_bmap(vs, f_offset, B_WRITE, &entry) == KERN_FAILURE)
                    848:                result = PAGER_ERROR;
                    849:            else {
                    850:                /*
                    851:                 *      If the paging operation extends the size of the
                    852:                 *      pagerfile, update the information in the vm_info
                    853:                 *      structure
                    854:                 */
                    855:                f_offset = ptoa(entry.offset);
                    856:                vp = pager_file_list[entry.index]->pf_vp;
                    857:                if (f_offset + size > vp->v_vm_info->vnode_size)
                    858:                    vp->v_vm_info->vnode_size = f_offset + size;
                    859:            }
                    860:        }
                    861: 
                    862:        if (result != PAGER_ERROR && size > 0) {
                    863:            vm_offset_t         ioaddr = vnode_pageio_setup(m);
                    864:            struct uio          auio;
                    865:            struct iovec        aiov;
                    866: 
                    867:            if (ioaddr) {
                    868:                auio.uio_iov = &aiov;
                    869:                auio.uio_iovcnt = 1;
                    870:                auio.uio_offset = f_offset;
                    871:                auio.uio_segflg = UIO_SYSSPACE;
                    872:                auio.uio_rw = UIO_WRITE;
                    873:                auio.uio_procp = NULL;
                    874:                aiov.iov_base = (caddr_t)ioaddr;
                    875: #if MACH_NBC
                    876:                auio.uio_resid = size;
                    877:                aiov.iov_len = size;
                    878: #else
                    879:                auio.uio_resid = PAGE_SIZE;
                    880:                aiov.iov_len = PAGE_SIZE;
                    881: #endif /* MACH_NBC */
                    882: 
                    883: #if MACH_NBC
                    884:                {
                    885: #define        VNODE_LOCK_RETRY_COUNT  1
                    886: #define        VNODE_LOCK_RETRY_TICKS  2
                    887: 
                    888:                        int retry = VNODE_LOCK_RETRY_COUNT;
                    889: vnode_lock_retry:
                    890:                        error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p);
                    891:                        if (error) {
                    892:                                /*
                    893:                                 * Retry the lock after yielding to other threads.
                    894:                                 * Not doing this makes the pageout thread compute bound.
                    895:                                 * Yielding lets I/O threads to run
                    896:                                 * and make forward progress.
                    897:                                 */
                    898:                                if (retry-- > 0) {
                    899:                                        thread_will_wait(current_thread());
                    900:                                        thread_set_timeout(VNODE_LOCK_RETRY_TICKS);
                    901:                                        thread_block();
                    902:                                        goto vnode_lock_retry;
                    903:                                }
                    904: 
                    905:                                result = PAGER_ERROR;
                    906:                                vnode_pageio_complete(m, ioaddr);
                    907:                                goto out;
                    908:                        }
                    909:                }
                    910: #else /* MACH_NBC */
                    911:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                    912: #endif /* MACH_NBC */
                    913: 
                    914:                error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred);
                    915:                if (error)
                    916:                    result = PAGER_ERROR;
                    917:                vp->v_vm_info->error = error;
                    918:                        
                    919:                VOP_UNLOCK(vp, 0, p);
                    920: 
                    921:                vnode_pageio_complete(m, ioaddr);
                    922:            }
                    923:            else
                    924:                result = PAGER_ERROR;
                    925:        }
                    926: 
                    927:        if (result == PAGER_SUCCESS) {
                    928:            m->clean = TRUE;                            /* XXX - wrong place */
                    929:            pmap_clear_modify(VM_PAGE_TO_PHYS(m));      /* XXX - wrong place */
                    930:        }
                    931: 
                    932: out:
                    933:        vnode_pager_vput(vs);
                    934: 
                    935:        unix_release();
                    936: 
                    937:        return (result);
                    938: }
                    939: 
                    940: /*
                    941:  *     vnode_has_page:
                    942:  *
                    943:  *     Parameters:
                    944:  *             pager
                    945:  *             id              paging object
                    946:  *             offset          Offset in paging object to test
                    947:  *
                    948:  *     Assumptions:
                    949:  *             This is only used on shadowing (copy) objects.
                    950:  *             Since copy objects are always backed by a swapfile, we just
                    951:  *             test the map for that swapfile to see if the page is present.
                    952:  */
                    953: boolean_t
                    954: vnode_has_page(pager, offset)
                    955:        vm_pager_t      pager;
                    956:        vm_offset_t     offset;
                    957: {
                    958:        vnode_pager_t   vs = (vnode_pager_t) pager;
                    959:        pf_entry        entry;
                    960: 
                    961:        /*
                    962:         * For now, we do all inode hacking on the master cpu.
                    963:         */
                    964:        unix_master();
                    965: 
                    966:        if (vs == VNODE_PAGER_NULL)
                    967:                panic("vnode_has_page: failed lookup");
                    968: 
                    969:        if (vs->vs_swapfile) {
                    970:                unix_release();
                    971:                if (pagerfile_bmap(vs, offset, B_READ, &entry) == KERN_FAILURE)
                    972:                        return FALSE;
                    973:                else
                    974:                        return TRUE;
                    975:        }
                    976:        else {
                    977:                 panic("vnode_has_page called on non-default pager");
                    978:        }
                    979:        /*NOTREACHED*/
                    980: 
                    981:        return FALSE;
                    982: }
                    983: 
                    984: 
                    985: /*
                    986:  *     Routine:        vnode_pager_file_init
                    987:  *     Function:
                    988:  *             Create a pager_file structure for a new pager file.
                    989:  *     Arguments:
                    990:  *             The file in question is specified by vnode pointer.
                    991:  *             lowat and hiwat are the low water and high water marks
                    992:  *             that the size of pager file will float between.  If
                    993:  *             the low water mark is zero, then the file will not
                    994:  *             shrink after paging space is freed.  If the high water
                    995:  *             mark is zero, the file will grow without bounds.
                    996:  *
                    997:  *     The vp is locked on entry to and exit from this function.
                    998:  */
                    999: int
                   1000: vnode_pager_file_init(pfp, vp, lowat, hiwat)
                   1001:        pager_file_t    *pfp;
                   1002:        struct vnode    *vp;
                   1003:        long lowat;
                   1004:        long hiwat;
                   1005: {
                   1006:        struct vattr    vattr;
                   1007:        register pager_file_t   pf;
                   1008:        int     error;
                   1009:        long    i;
                   1010:        struct proc     *p = current_proc();
                   1011:        struct ucred    *cred;
                   1012:        vm_size_t       size;
                   1013: 
                   1014:        *pfp = PAGER_FILE_NULL;
                   1015: 
                   1016:        /*
                   1017:         * Make sure no other object paging to this file?
                   1018:         */
                   1019: #if    MACH_NBC
                   1020:        mapfs_uncache(vp);
                   1021: #endif /* MACH_NBC */
                   1022: 
                   1023:        if(!vp->v_vm_info) {
                   1024:                vm_info_init(vp);
                   1025:        }
                   1026:        
                   1027:        if (vp->v_vm_info->mapped) {
                   1028:                return(EBUSY);
                   1029:        }
                   1030:        
                   1031:        /*
                   1032:         * Clean up the file blocks on a pager file by
                   1033:         * truncating to length "lowat".
                   1034:         */
                   1035:        error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
                   1036:        size = vattr.va_size;
                   1037:        if (size > lowat) {
                   1038:                vattr_null(&vattr);
                   1039:                vattr.va_size = size = lowat;
                   1040:                error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
                   1041:                if (error) {
                   1042:                        return(error);
                   1043:                }
                   1044:        }
                   1045: 
                   1046:        /*
                   1047:         * Initialize the vnode_size field
                   1048:         */
                   1049:        vp->v_vm_info->vnode_size = size;
                   1050: 
                   1051:        pf = (pager_file_t) kalloc(sizeof(struct pager_file));
                   1052:        VREF(vp);
                   1053:        pf->pf_vp = vp;
                   1054:        cred = p->p_ucred;
                   1055:        crhold(cred);
                   1056:        vp->v_vm_info->cred = cred;
                   1057:        pf->pf_count = 0;
                   1058:        pf->pf_hint = 0;
                   1059:        pf->pf_lowat = atop(round_page(lowat));
                   1060:        /*
                   1061:         * If no maximum space is specified, then we should make a map that
                   1062:         * can cover the entire disk, otherwise the block map need only
                   1063:         * cover the maximum space allowed.
                   1064:         */
                   1065:        if (!hiwat)
                   1066:                hiwat = vp->v_mount->mnt_stat.f_blocks * 
                   1067:                                        vp->v_mount->mnt_stat.f_bsize;
                   1068:        pf->pf_pfree = pf->pf_npgs = atop(hiwat);
                   1069:        pf->pf_bmap = (u_char *) kalloc(RMAPSIZE(pf->pf_npgs));
                   1070:        for (i = 0; i < pf->pf_npgs; i++) {
                   1071:                clrbit(pf->pf_bmap, i);
                   1072:        }
                   1073:        pf->pf_hipage = -1;
                   1074:        pf->pf_prefer = FALSE;
                   1075:        lock_init(&pf->pf_lock, TRUE);
                   1076: 
                   1077:        /*
                   1078:         * Put the new pager file in the list.
                   1079:         */
                   1080:        queue_enter(&pager_files, pf, pager_file_t, pf_chain);
                   1081:        pager_file_count++;
                   1082:        pf->pf_index = pager_file_count;
                   1083:        pager_file_list[pager_file_count] = pf;
                   1084:        *pfp = pf;
                   1085:        return (0);
                   1086: }
                   1087: 
                   1088: void
                   1089: vnode_pager_shutdown()
                   1090: {
                   1091:        pager_file_t    pf;
                   1092: 
                   1093:        while (!queue_empty(&pager_files)) {
                   1094:                pf = (pager_file_t) queue_first(&pager_files);
                   1095:                vrele(pf->pf_vp);
                   1096:                queue_remove(&pager_files, pf, pager_file_t, pf_chain);
                   1097:                pager_file_count--;
                   1098:        }
                   1099: }
                   1100: 
                   1101: 
                   1102: /*
                   1103:  *     Routine:        mach_swapon
                   1104:  *     Function:
                   1105:  *             Syscall interface to mach_swapon.
                   1106:  */
                   1107: int
                   1108: mach_swapon(filename, flags, lowat, hiwat)
                   1109:        char    *filename;
                   1110:        int     flags;
                   1111:        long    lowat;
                   1112:        long    hiwat;
                   1113: {
                   1114:        struct vnode            *vp;
                   1115:        struct nameidata        nd, *ndp;
                   1116:        struct proc             *p = current_proc();
                   1117:        pager_file_t            pf;
                   1118:        register int            error;
                   1119: 
                   1120:        ndp = &nd;
                   1121: 
                   1122:        if ((error = suser(p->p_ucred, &p->p_acflag)))
                   1123:                return (error);
                   1124: 
                   1125:        unix_master();
                   1126: 
                   1127:        /*
                   1128:         * Get a vnode for the paging area.
                   1129:         */
                   1130:        NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
                   1131:            filename, p);
                   1132:        if ((error = namei(ndp)))
                   1133:                return (error);
                   1134:        vp = ndp->ni_vp;
                   1135: 
                   1136:        if (vp->v_type != VREG) {
                   1137:                error = EINVAL;
                   1138:                goto bailout;
                   1139:        }
                   1140: 
                   1141:        /*
                   1142:         * Look to see if we are already paging to this file.
                   1143:         */
                   1144:        for (pf = (pager_file_t) queue_first(&pager_files);
                   1145:             !queue_end(&pager_files, &pf->pf_chain);
                   1146:             pf = (pager_file_t) queue_next(&pf->pf_chain)) {
                   1147:                if (pf->pf_vp == vp)
                   1148:                        break;
                   1149:        }
                   1150:        if (!queue_end(&pager_files, &pf->pf_chain)) {
                   1151:                error = EBUSY;
                   1152:                goto bailout;
                   1153:        }
                   1154: 
                   1155:        error = vnode_pager_file_init(&pf, vp, lowat, hiwat);
                   1156:        if (error) {
                   1157:                goto bailout;
                   1158:        }
                   1159:        pf->pf_prefer = ((flags & MS_PREFER) != 0);
                   1160: 
                   1161:         /*
                   1162:          * Create dummy symbol file for current mach_kernel executable.
                   1163:          * See bsd/kern/kern_symfile.c
                   1164:          */
                   1165:        output_kernel_symbols(p);
                   1166: 
                   1167:        error = 0;
                   1168: bailout:
                   1169:        if (vp) {
                   1170:                VOP_UNLOCK(vp, 0, p);
                   1171:                vrele(vp);
                   1172:        }
                   1173:        unix_release();
                   1174:        return(error);
                   1175: }
                   1176: 
                   1177: /*
                   1178:  *     Routine:        vswap_allocate
                   1179:  *     Function:
                   1180:  *             Allocate a place for paging out a kernel-created
                   1181:  *             memory object.
                   1182:  *
                   1183:  *     Implementation: 
                   1184:  *             Looks through the paging files for the one with the
                   1185:  *             most free space.  First, only "preferred" paging files
                   1186:  *             are considered, then local paging files, and then
                   1187:  *             remote paging files.  In each case, the pager file
                   1188:  *             the most free blocks will be chosen.
                   1189:  *
                   1190:  *     In/out conditions:
                   1191:  *             If the paging area is on a local disk, the inode is
                   1192:  *             returned locked.
                   1193:  */
                   1194: pager_file_t
                   1195: vswap_allocate()
                   1196: {
                   1197:        int             pass;
                   1198:        int             mostspace;
                   1199:        pager_file_t    pf, mostpf;
                   1200:        
                   1201:                extern int (**ffs_vnodeop_p)();
                   1202: 
                   1203:        mostpf = PAGER_FILE_NULL;
                   1204:        mostspace = 0;
                   1205: 
                   1206:        if (pager_file_count > 1) {
                   1207:                for (pass = 0; pass < 4; pass++) {
                   1208:                        for (pf = (pager_file_t)queue_first(&pager_files);
                   1209:                             !queue_end(&pager_files, &pf->pf_chain);
                   1210:                             pf = (pager_file_t)queue_next(&pf->pf_chain)) {
                   1211: 
                   1212:                                if ((pass < 2) && !pf->pf_prefer)
                   1213:                                        continue;
                   1214:                                if ((!(pass &1) &&
                   1215:                                     (pf->pf_vp->v_op != ffs_vnodeop_p)))
                   1216:                                        continue;
                   1217: 
                   1218:                                if (pf->pf_pfree > mostspace) {
                   1219:                                        mostspace = pf->pf_pfree;
                   1220:                                        mostpf = pf;
                   1221:                                }
                   1222:                        }
                   1223:                        /*
                   1224:                         * If we found space, then break out of loop.
                   1225:                         */
                   1226:                        if (mostpf != PAGER_FILE_NULL)
                   1227:                                break;
                   1228:                }
                   1229:        } else if (pager_file_count == 1) {
                   1230:                mostpf = (pager_file_t) queue_first(&pager_files);
                   1231:        }
                   1232: 
                   1233:        return(mostpf);
                   1234: }
                   1235: 
                   1236: vm_pager_t
                   1237: vnode_alloc(size)
                   1238:        vm_size_t       size;
                   1239: {
                   1240:        pager_file_t    pf;
                   1241:        vnode_pager_t   vs = (vnode_pager_t) vm_pager_null;
                   1242: 
                   1243: #ifdef lint
                   1244:        size++;
                   1245: #endif lint
                   1246: 
                   1247:        unix_master();
                   1248: 
                   1249:        /*
                   1250:         *      Get a pager_file, then turn it into a paging space.
                   1251:         */
                   1252: 
                   1253:        if ((pf = vswap_allocate()) == PAGER_FILE_NULL) {
                   1254:                goto out;
                   1255:        }
                   1256:        if ((vs = pagerfile_pager_create(pf, size)) ==
                   1257:            VNODE_PAGER_NULL) {
                   1258:                vs = (vnode_pager_t) vm_pager_null;
                   1259:                goto out;
                   1260:        }
                   1261: out:
                   1262:        unix_release();
                   1263:        return((vm_pager_t) vs);
                   1264: }
                   1265: 
                   1266: 
                   1267: /*
                   1268:  *  Try to truncate the paging files.
                   1269:  */
                   1270: void
                   1271: vnode_pager_truncate(pf_entry entry)
                   1272: {
                   1273:        struct pager_file *pf = pager_file_list[entry.index];
                   1274:        struct vnode    *vp = pf->pf_vp;
                   1275:        struct vattr    vattr;
                   1276:        int             error;
                   1277:        struct proc     *p = current_proc();
                   1278:        long            truncpage;
                   1279:        int             i;
                   1280: 
                   1281:        /*
                   1282:         *  If this is not the last page in the file, return now.
                   1283:         *  If the swaptimizer is enabled we cannot free blocks out from
                   1284:         *  underneath it.
                   1285:         */
                   1286:        assert(entry.offset <= pf->pf_hipage);
                   1287:        if (entry.offset < pf->pf_hipage)
                   1288:                return;
                   1289: 
                   1290:        lock_write(&pf->pf_lock);
                   1291: 
                   1292:        /*
                   1293:         * Find a new high page
                   1294:         */
                   1295:        for (i = entry.offset - 1; i >= 0; i--) {
                   1296:                if (isset(pf->pf_bmap, i)) {
                   1297:                        pf->pf_hipage = i;
                   1298:                        break;
                   1299:                }
                   1300:        }
                   1301: 
                   1302:        /*
                   1303:         *  If we are higher than the low water mark, truncate
                   1304:         *  the file.
                   1305:         */
                   1306:        truncpage = pf->pf_hipage + 1;
                   1307:        if (pf->pf_lowat == 0 || truncpage <= pf->pf_lowat ||
                   1308:            vp->v_vm_info->vnode_size < ptoa(truncpage)) {
                   1309:                lock_done(&pf->pf_lock);
                   1310:                return;
                   1311:        }
                   1312: 
                   1313:        vattr_null(&vattr);
                   1314:        vattr.va_size = ptoa(truncpage);
                   1315:        ASSERT( (int) vattr.va_size >= 0 );
                   1316: 
                   1317:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1318:        if ((error = VOP_SETATTR(vp, &vattr, vp->v_vm_info->cred, p))) {
                   1319:                printf("vnode_deallocpage: error truncating %s,"
                   1320:                        " error = %d\n", pf->pf_name, error);
                   1321:        }
                   1322:        VOP_UNLOCK(vp, 0, p);
                   1323: 
                   1324: 
                   1325:        lock_done(&pf->pf_lock);
                   1326: }
                   1327: 
                   1328: 
                   1329: static void
                   1330: visit_file(pf_entry entry)
                   1331: {
                   1332:        int     i;
                   1333: 
                   1334:        if (entry.index == INDEX_NULL)
                   1335:                return;
                   1336: 
                   1337:        for (i = 0;  i < seen_files_max;  i++)
                   1338:            if (seen_files[i].index == entry.index) {
                   1339:                seen_files[i].offset = max(seen_files[i].offset,entry.offset);
                   1340:                return;
                   1341:            }
                   1342: 
                   1343:        seen_files[seen_files_max++] = entry;
                   1344: }
                   1345: 
                   1346: 
                   1347: void
                   1348: vnode_dealloc(pager)
                   1349:        vm_pager_t      pager;
                   1350: {
                   1351:        struct vnode    *vp;
                   1352:        vnode_pager_t   vs = (vnode_pager_t) pager;
                   1353:        int             i;
                   1354: 
                   1355:        unix_master();
                   1356: 
                   1357:        vp = vnode_pager_vget(vs);
                   1358: 
                   1359:        ASSERT(vs->vs_count == 1);
                   1360: 
                   1361:        seen_files_max = 0;
                   1362:        if (vs->vs_swapfile) {
                   1363:            pager_file_t        pf;
                   1364:            int         i,j;
                   1365: 
                   1366:            ASSERT(vs->vs_pf);
                   1367: 
                   1368:            pf = vs->vs_pf;
                   1369:            if (INDIR_PAGEMAP(vs->vs_size)) {
                   1370:                for (i = 0; i < INDIR_PAGEMAP_ENTRIES(vs->vs_size); i++) {
                   1371:                    if (vs->vs_pmap[i] != NULL) {
                   1372:                        for(j = 0; j < PAGEMAP_ENTRIES; j++) {
                   1373:                            vnode_pager_deallocpage(vs->vs_pmap[i][j]);
                   1374:                            visit_file(vs->vs_pmap[i][j]);
                   1375:                        }
                   1376:                        kfree(vs->vs_pmap[i], PAGEMAP_THRESHOLD);
                   1377:                    }
                   1378:                }
                   1379:                kfree(vs->vs_pmap, INDIR_PAGEMAP_SIZE(vs->vs_size));
                   1380:            } else {
                   1381:                for (i = 0; i < vs->vs_size; i++) {
                   1382:                    vnode_pager_deallocpage(*(pf_entry *)&vs->vs_pmap[i]);
                   1383:                    visit_file(*(pf_entry *)&vs->vs_pmap[i]);
                   1384:                }
                   1385:                if (vs->vs_size > 0)
                   1386:                        kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size));
                   1387:            }
                   1388:            pf->pf_count--;
                   1389:        } else {
                   1390:            vp->v_flag &= ~VTEXT;
                   1391:            vp->v_vm_info->pager = vm_pager_null; /* so vrele will free */
                   1392:     
                   1393:            vp->v_flag |= VAGE; /* put this vnode at the head of freelist */
                   1394:            vrele(vp);
                   1395:        }
                   1396: 
                   1397:        for (i=0; i < seen_files_max; i++)
                   1398:                vnode_pager_truncate(seen_files[i]);
                   1399:        zfree(vstruct_zone, (vm_offset_t) vs);
                   1400:        unix_release();
                   1401: }
                   1402: 
                   1403: /*
                   1404:  * Remove vnode associated object from the object cache.
                   1405:  *
                   1406:  * XXX unlock the vnode if it is currently locked.
                   1407:  * We must do this since uncaching the object may result in its
                   1408:  * destruction which may initiate paging activity which may necessitate
                   1409:  * re-locking the vnode.
                   1410:  */
                   1411: int
                   1412: vnode_uncache(vp)
                   1413:        register struct vnode   *vp;
                   1414: {
                   1415:        struct proc *p = current_proc();
                   1416: 
                   1417:        if (vp->v_type != VREG)
                   1418:                return (1);
                   1419: 
                   1420:        if (vp->v_vm_info == 0 || vp->v_vm_info->pager == vm_pager_null)
                   1421:                return (1);
                   1422: 
                   1423: #ifdef DEBUG
                   1424:     if (!VOP_ISLOCKED(vp)) {
                   1425:        extern int (**nfsv2_vnodeop_p)();
                   1426: 
                   1427:                if (vp->v_op != nfsv2_vnodeop_p)
                   1428:                        panic("vnode_uncache: vnode not locked!");
                   1429:        }
                   1430: #endif
                   1431: 
                   1432:        /*
                   1433:         * The act of uncaching may cause an object to be deallocated
                   1434:         * which may need to wait for the pageout daemon which in turn
                   1435:         * may be waiting for this inode's lock, so be sure to unlock
                   1436:         * and relock later if necessary.  (This of course means that
                   1437:         * code calling this routine must be able to handle the fact
                   1438:         * that the inode has been unlocked temporarily).  This code, of
                   1439:         * course depends on the Unix master restriction for proper
                   1440:         * synchronization.
                   1441:         */
                   1442: #if    MACH_NBC
                   1443:        mapfs_uncache(vp);
                   1444: #endif /* MACH_NBC */
                   1445: 
                   1446:        VOP_UNLOCK(vp, 0, p);
                   1447:        vm_object_uncache(vp->v_vm_info->pager);
                   1448: #if MACH_NBC
                   1449:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p);
                   1450: #else
                   1451:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1452: #endif
                   1453:        return (1);
                   1454: }
                   1455: 
                   1456: void
                   1457: vnode_pager_init()
                   1458: {
                   1459:        register vm_size_t      size;
                   1460: 
                   1461:        /*
                   1462:         *      Initialize zone of paging structures.
                   1463:         */
                   1464: 
                   1465:        size = (vm_size_t) sizeof(struct vstruct);
                   1466:        vstruct_zone = zinit(size,
                   1467:                        (vm_size_t) 10000*size, /* XXX */
                   1468:                        PAGE_SIZE,
                   1469:                        FALSE, "vnode pager structures");
                   1470:        simple_lock_init(&vstruct_lock);
                   1471:        queue_init(&pager_files);
                   1472: }
                   1473: 
                   1474: void
                   1475: vnode_pager_setsize(vp, nsize)
                   1476: struct vnode *vp;
                   1477: u_long nsize;
                   1478: {
                   1479:        if (vp->v_vm_info) {
                   1480:                if (vp->v_type != VREG)
                   1481:                        panic("vnode_pager_setsize not VREG");
                   1482:                vp->v_vm_info->vnode_size = nsize;
                   1483:        }
                   1484: }
                   1485: 
                   1486: void
                   1487: vnode_pager_umount(mp)
                   1488:     register struct mount *mp;
                   1489: {
                   1490:        struct proc *p = current_proc();
                   1491:        struct vnode *vp, *nvp;
                   1492: 
                   1493: loop:
                   1494:        for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
                   1495:                if (vp->v_mount != mp)
                   1496:                        goto loop;
                   1497:                nvp = vp->v_mntvnodes.le_next;
                   1498:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1499:                (void) vnode_uncache(vp);
                   1500:                VOP_UNLOCK(vp, 0, p);
                   1501:        }
                   1502: }

unix.superglobalmegacorp.com

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