Annotation of kernel/kern/mapfs.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:  *     File:   mapfs.c
                     33:  *     Author: Avadis Tevanian, Jr.
                     34:  *
                     35:  *     Copyright (C) 1987, Avadis Tevanian, Jr.
                     36:  *
                     37:  *     Support for mapped file system implementation.
                     38:  *
                     39:  * HISTORY
                     40:  * 2-Jun-1998  Umesh Vaishampayan
                     41:  *     Changed error handling to check for all errors.
                     42:  *
                     43:  * 6-Dec-1997 A.Ramesh at Apple
                     44:  *     Made the chages for Rhapsody; Reanamed mfs to mapfs to avoid confusion
                     45:  *     with memory based filesystem.
                     46:  *
                     47:  * 18-Nov-92 Phillip Dibner at NeXT
                     48:  *     Made the i/o throttle global.   This is a hack on top of a hack and 
                     49:  *     should be fixed properly, probably in the vm system.
                     50:  *
                     51:  *  3-Sep-92 Joe Murdock at NeXT
                     52:  *     Added an i/o throttle to mfs_io as a cheap work-around for a i/o buffer
                     53:  *     resource conflict with usr-space system bottle-necks (nfs servers, etc)
                     54:  *
                     55:  *  7-Feb-92 Jim Hays
                     56:  *     There are still bugs in this code dealing with vmp_pushing wired 
                     57:  *     pages. We need to modify the sound drivers locks to be breakable
                     58:  *     except during the actual playing. 
                     59:  *
                     60:  *  3-Aug-90  Doug Mitchell at NeXT
                     61:  *     Added primitives for loadable file system support.
                     62:  *
                     63:  *  7-Mar-90  Brian Pinkerton (bpinker) at NeXT
                     64:  *     Changed mfs_trunc to return an indication of change.
                     65:  *
                     66:  *  9-Mar-88  John Seamons (jks) at NeXT
                     67:  *     SUN_VFS: allocate vm_info structures from a zone.
                     68:  *
                     69:  * 29-Jan-88  David Golub (dbg) at Carnegie-Mellon University
                     70:  *     Corrected calls to inode_pager_setup and kmem_alloc.
                     71:  *
                     72:  * 15-Sep-87  Michael Young (mwyoung) at Carnegie-Mellon University
                     73:  *     De-linted.
                     74:  *
                     75:  * 18-Jun-87  Michael Young (mwyoung) at Carnegie-Mellon University
                     76:  *     Make most of this file dependent on MACH_NBC.
                     77:  *
                     78:  * 30-Apr-87  Avadis Tevanian (avie) at Carnegie-Mellon University
                     79:  *     Created.
                     80:  */
                     81: 
                     82: #import <mach_nbc.h>
                     83: 
                     84: #import <kern/lock.h>
                     85: #import <kern/mapfs.h>
                     86: #import <kern/sched_prim.h>
                     87: #import <kern/assert.h>
                     88: 
                     89: #import <sys/param.h>
                     90: #import <sys/systm.h>
                     91: #import <sys/mount.h>
                     92: #import <sys/proc.h>
                     93: #import <sys/user.h>
                     94: #import <sys/vnode.h>
                     95: #import <sys/uio.h>
                     96: /* Needed for VOP_DEBLOCKSIZE, ip usage */
                     97: #include <ufs/ufs/quota.h>
                     98: #include <ufs/ufs/inode.h>
                     99: #import <sys/dir.h>
                    100: 
                    101: #import <vm/vm_kern.h>
                    102: #import <vm/vm_pager.h>
                    103: #import <mach/vm_param.h>
                    104: #import <mach/machine.h>
                    105: #import <vm/vnode_pager.h>
                    106: #import <vm/pmap.h>
                    107: 
                    108: #include <nfs/rpcv2.h>
                    109: #include <nfs/nfsproto.h>
                    110: #include <nfs/nfs.h>
                    111: #include <nfs/nfsnode.h>
                    112: 
                    113: #define PERFMODS 1
                    114: 
                    115: struct zone    *vm_info_zone;
                    116: 
                    117: /*
                    118:  *     Private variables and macros.
                    119:  */
                    120: 
                    121: queue_head_t           vm_info_queue;          /* lru list of structures */
                    122: decl_simple_lock_data(,        vm_info_lock_data)      /* lock for lru list */
                    123: int                    vm_info_version = 0;    /* version number */
                    124: 
                    125: 
                    126: 
                    127: 
                    128: #define        vm_info_lock()          simple_lock(&vm_info_lock_data)
                    129: #define        vm_info_unlock()        simple_unlock(&vm_info_lock_data)
                    130: 
                    131: #if    MACH_NBC
                    132: lock_data_t            mfsbuf_lock;            /* lock for active_mfsbufs */
                    133: lock_data_t            mfs_alloc_lock_data;
                    134: boolean_t              mfs_alloc_wanted;
                    135: long                   mfs_alloc_blocks = 0;
                    136: 
                    137: #define mfs_alloc_lock()       lock_write(&mfs_alloc_lock_data)
                    138: #define mfs_alloc_unlock()     lock_write_done(&mfs_alloc_lock_data)
                    139: 
                    140: vm_map_t       mfs_map;
                    141: 
                    142: /*
                    143:  *     mfs_map_size is the number of bytes of VM to use for file mapping.
                    144:  *     It should be set by machine dependent code (before the call to
                    145:  *     mapfs_init) if the default is inappropriate.
                    146:  *
                    147:  *     mfs_max_window is the largest window size that will be given to
                    148:  *     a file mapping.  A default value is computed in mapfs_init based on
                    149:  *     mfs_map_size.  This too may be set by machine dependent code
                    150:  *     if the default is not appropriate.
                    151:  *
                    152:  *     mfs_files_max is the maximum number of files that we will
                    153:  *     simultaneously leave mapped.  Note th memory for unmapped
                    154:  *     files will not necessarily leave the memory cache, but by
                    155:  *     unmapping these files the file system can throw away any
                    156:  *     file system related info (like vnodes).  Again, this value
                    157:  *     can be sent by machine dependent code if the default is not
                    158:  *     appropriate.
                    159:  */
                    160: 
                    161: #ifdef ppc
                    162: vm_size_t      mfs_map_size = 64*1024*1024;    /* size in bytes */
                    163: #else
                    164: vm_size_t      mfs_map_size = 8*1024*1024;     /* size in bytes */
                    165: #endif
                    166: vm_size_t      mfs_max_window = 0;             /* largest window to use */
                    167: 
                    168: #ifdef ppc
                    169: int            mfs_files_max = 400;            /* maximum # of files mapped */
                    170: #else
                    171: int            mfs_files_max = 100;            /* maximum # of files mapped */
                    172: #endif
                    173: int            mfs_files_mapped = 0;           /* current # mapped */
                    174: 
                    175: #define CHUNK_SIZE     (128 * 1024)
                    176: #endif /* MACH_NBC */
                    177: 
                    178: #ifdef ppc
                    179: #define MFS_MAP_SIZE_MAX       (64 * 1024 * 1024)
                    180: #else
                    181: #define MFS_MAP_SIZE_MAX       (16 * 1024 * 1024)
                    182: #endif
                    183: 
                    184: /* The MFS_MAP_SIZE_PER_UNIT is used in remap; as well as in init */
                    185: #define        MFS_MAP_SIZE_PER_UNIT   (1024 * 1024)
                    186: #define        MFS_MEMORY_UNIT         (1024 * 1024)
                    187: #define MFS_FILES_PER_UNIT     12
                    188: 
                    189: void vm_info_enqueue __P((struct vm_info *));
                    190: void vm_info_dequeue __P((struct vm_info *));
                    191: void mapfs_put __P((struct vnode *));
                    192: int mapfs_get __P((struct vnode *,vm_offset_t, vm_size_t));
                    193: int remap_vnode __P((struct vnode *,vm_offset_t, vm_size_t));
                    194: void vmp_put __P((struct vm_info *));
                    195: void vmp_get __P((struct vm_info *));
                    196: void mapfs_cache_trim __P((void));
                    197: void mapfs_memfree __P((struct vm_info *, boolean_t));
                    198: int mapfs_map_remove __P((struct vm_info *, vm_offset_t, vm_size_t, boolean_t));
                    199: void vno_flush __P((struct vnode *, vm_offset_t, vm_size_t));
                    200: void vmp_invalidate __P((struct vm_info *));
                    201: int vmp_push __P((struct vm_info *));
                    202: int vmp_push_range __P((struct vm_info *,vm_offset_t, vm_size_t));
                    203: void vmp_push_all __P((struct vm_info *));
                    204: /* Missing from headers so provided the prototypes */
                    205: void vm_object_deactivate_pages __P((vm_object_t));
                    206: void vm_object_deactivate_pages_first __P((vm_object_t));
                    207: void vm_page_deactivate __P((vm_page_t));
                    208: void vm_page_activate __P((vm_page_t));
                    209: kern_return_t vm_allocate_with_pager __P((vm_map_t, vm_offset_t *, vm_size_t, boolean_t, vm_pager_t,vm_offset_t));
                    210: 
                    211: #if PERFMODS
                    212: int mapfs_map_cleanup __P((struct vm_info *,vm_offset_t,vm_size_t,boolean_t));
                    213: #endif
                    214: 
                    215: /*
                    216:  *     mapfs_init:
                    217:  *
                    218:  *     Initialize the mapped FS module.
                    219:  */
                    220: int
                    221: mapfs_init()
                    222: {
                    223:        int                     i;
                    224: #if    MACH_NBC
                    225:        int                     min, max;
                    226: #endif /* MACH_NBC */
                    227: 
                    228:        queue_init(&vm_info_queue);
                    229:        simple_lock_init(&vm_info_lock_data);
                    230: #if    MACH_NBC
                    231:        lock_init(&mfs_alloc_lock_data, TRUE);
                    232:        mfs_alloc_wanted = FALSE;
                    233:        mfs_map = kmem_suballoc(kernel_map, &min, &max, mfs_map_size, TRUE);
                    234: 
                    235:        mfs_map_size = (int) ((long long) MFS_MAP_SIZE_PER_UNIT /
                    236:                                (long long) MFS_MEMORY_UNIT *
                    237:                                (long long) machine_info.memory_size);
                    238: 
                    239:        if (mfs_map_size > MFS_MAP_SIZE_MAX)
                    240:                mfs_map_size = MFS_MAP_SIZE_MAX;
                    241: 
                    242: #if    notdef
                    243:        mfs_files_max = (int)((long long) MFS_FILES_PER_UNIT *
                    244:                                (long long) machine_info.memory_size /
                    245:                                (long long) MFS_MEMORY_UNIT);
                    246: #endif /* notdef */
                    247:         
                    248:        /* Get atleast a Meg and instead of 5% choose 6.25% */
                    249:        if (mfs_max_window == 0)
                    250:                mfs_max_window = mfs_map_size / 16;
                    251:        if (mfs_max_window < MFS_MEMORY_UNIT)
                    252:                mfs_max_window = MFS_MEMORY_UNIT;
                    253: #endif /* MACH_NBC */
                    254:        i = (vm_size_t) sizeof (struct vm_info);
                    255:        vm_info_zone = zinit (i, 10000*i, 8192, FALSE, "vm_info zone");
                    256: 
                    257:        return(0);
                    258: }
                    259: 
                    260: /*
                    261:  *     vm_info_init:
                    262:  *
                    263:  *     Initialize a vm_info structure for a vnode.
                    264:  */
                    265: int
                    266: vm_info_init(vp)
                    267:        struct vnode *vp;
                    268: {
                    269:        register struct vm_info *vmp;
                    270: 
                    271:        vmp = vp->v_vm_info;
                    272:        if (vmp == VM_INFO_NULL)
                    273:                vmp = (struct vm_info *) zalloc(vm_info_zone);
                    274:        vmp->pager = vm_pager_null;
                    275:        vmp->map_count = 0;
                    276:        vmp->use_count = 0;
                    277:        vmp->va = 0;
                    278:        vmp->size = 0;
                    279:        vmp->offset = 0;
                    280: #if PERFMODS
                    281:        vmp->dirtysize   = 0;
                    282:        vmp->dirtyoffset = 0;
                    283: #endif
                    284:        vmp->cred = (struct ucred *) NULL;
                    285:        vmp->error = 0;
                    286: 
                    287:        vmp->queued = FALSE;
                    288:        vmp->dirty = FALSE;
                    289:        vmp->nfsdirty = FALSE;
                    290:        vmp->close_flush = TRUE;        /* for safety, reconsider later */
                    291:        vmp->invalidate = FALSE;
                    292:        vmp->busy = FALSE;
                    293:        vmp->delayed_fsync = FALSE;
                    294:        vmp->filesize = FALSE;
                    295:        vmp->mapped = FALSE;
                    296:        vmp->dying = FALSE;
                    297: 
                    298:        vmp->vnode_size = 0;
                    299:        vmp->vnode = vp;
                    300:        lock_init(&vmp->lock, TRUE);    /* sleep lock */
                    301:        vmp->object = VM_OBJECT_NULL;
                    302:        vp->v_vm_info = vmp;
                    303:        return(0);
                    304: }
                    305: 
                    306: /*
                    307:  * Loadable file system support to avoid exporting struct vm_info.
                    308:  */
                    309: void vm_info_free(struct vnode *vp)
                    310: {
                    311:        register struct vm_info *vmp = vp->v_vm_info;
                    312: 
                    313:        if (vmp == VM_INFO_NULL)
                    314:                return;
                    315: 
                    316:        /*
                    317:         * If vmp->dying is set then we have reentered.
                    318:         * Uninterruptible wait for the other thead to finish and return.
                    319:         */
                    320:        if (vmp->dying == TRUE) {
                    321:                (void)tsleep(vmp, 0, "vminfofree", 0);
                    322:                return;
                    323:        }
                    324: 
                    325:        /* Prevent other threads from racing in */
                    326:        vmp->dying = TRUE;
                    327: 
                    328: #if MACH_NBC
                    329:        mapfs_uncache(vp);              /* could block here */
                    330: #endif 
                    331:        vp->v_vm_info = VM_INFO_NULL;
                    332:        wakeup(vmp);                    /* wakeup other threads blocked on vmp */
                    333: 
                    334:        zfree(vm_info_zone, (vm_offset_t)vmp);  /* could block here */
                    335: }
                    336: 
                    337: #if    MACH_NBC  /* [ */
                    338: void
                    339: vm_info_enqueue(vmp)
                    340:        struct vm_info  *vmp;
                    341: {
                    342:        mfs_assert(!vmp->queued);
                    343:        mfs_assert(vmp->mapped);
                    344: #if 0
                    345:        mfs_assert(vmp->size);
                    346:        if ((vmp->size == 0) || !vmp->mapped)
                    347:                panic("VMP SIZE IS ZERO\n");
                    348: 
                    349: #endif 
                    350:        queue_enter(&vm_info_queue, vmp, struct vm_info *, lru_links);
                    351:        vmp->queued = TRUE;
                    352:        mfs_files_mapped++;
                    353:        vm_info_version++;
                    354: }
                    355: 
                    356: void
                    357: vm_info_dequeue(vmp)
                    358:        struct vm_info  *vmp;
                    359: {
                    360:        mfs_assert(vmp->queued);
                    361:        queue_remove(&vm_info_queue, vmp, struct vm_info *, lru_links);
                    362:        vmp->queued = FALSE;
                    363:        mfs_files_mapped--;
                    364:        vm_info_version++;
                    365: }
                    366: 
                    367: /*
                    368:  *     map_vnode:
                    369:  *
                    370:  *     Indicate that the specified vnode should be mapped into VM.
                    371:  *     A reference count is maintained for each mapped file.
                    372:  */
                    373: void
                    374: map_vnode(vp,p)
                    375:        register struct vnode   *vp;
                    376:        register struct proc *p;
                    377: {
                    378:        register struct vm_info *vmp;
                    379:        vm_pager_t      pager;
                    380:        extern lock_data_t      vm_alloc_lock;
                    381:        struct vattr vattr;
                    382: #if 1
                    383:        /* Needed as in some cases the exec, namei returned vp
                    384:         * with no vm_info attached -- XXX (Verify this )
                    385:        */
                    386:        if (vp->v_vm_info == (struct vm_info *)0)
                    387:                vm_info_init(vp);
                    388: #endif
                    389:        vmp = vp->v_vm_info;
                    390: 
                    391:        if (vmp->map_count++ > 0)
                    392:                return;         /* file already mapped */
                    393: 
                    394:        if (vmp->mapped)
                    395:                return;         /* file was still cached */
                    396: 
                    397:        vmp_get(vmp);
                    398: 
                    399:        pager = vmp->pager = (vm_pager_t) vnode_pager_setup(vp, FALSE, TRUE);
                    400:                                /* not a TEXT file, can cache */
                    401:        /*
                    402:         *      Lookup what object is actually holding this file's
                    403:         *      pages so we can flush them when necessary.  This
                    404:         *      would be done differently in an out-of-kernel implementation.
                    405:         *
                    406:         *      Note that the lookup keeps a reference to the object which
                    407:         *      we must release elsewhere.
                    408:         */
                    409:        lock_write(&vm_alloc_lock);
                    410:        vmp->object = vm_object_lookup(pager);
                    411:        vm_stat.lookups++;
                    412:        if (vmp->object == VM_OBJECT_NULL) {
                    413:                vmp->object = vm_object_allocate(0);
                    414:                vm_object_enter(vmp->object, pager);
                    415:                vm_object_setpager(vmp->object, pager, (vm_offset_t) 0, FALSE);
                    416:        }
                    417:        else {
                    418:                vm_stat.hits++;
                    419:        }
                    420:        lock_write_done(&vm_alloc_lock);
                    421: 
                    422:        vmp->error = 0;
                    423: 
                    424:        VOP_GETATTR(vp, &vattr, p->p_ucred ,p);
                    425: 
                    426:        vmp->vnode_size = vattr.va_size;        /* must be before setting
                    427:                                                   mapped below to prevent
                    428:                                                   mapfs_fsync from recursive
                    429:                                                   locking */
                    430: 
                    431:        vmp->va = 0;
                    432:        vmp->size = 0;
                    433:        vmp->offset = 0;
                    434:        vmp->mapped = TRUE;
                    435: 
                    436:        vmp_put(vmp);   /* put will queue on LRU list */
                    437: }
                    438: 
                    439: int close_flush = 1;
                    440: 
                    441: /*
                    442:  *     unmap_vnode:
                    443:  *
                    444:  *     Called when an vnode is closed.
                    445:  */
                    446: void
                    447: unmap_vnode(vp, p)
                    448:        register struct vnode   *vp;
                    449:        register struct proc    *p;
                    450: {
                    451:        register struct vm_info         *vmp;
                    452:        register struct vm_object       *object;
                    453:        int                             links;
                    454:        register struct pcred *pcred = p->p_cred;
                    455:        register struct ucred *cred = pcred->pc_ucred;
                    456:        struct vattr    vattr;
                    457: 
                    458:        vmp = vp->v_vm_info;
                    459:        if (!vmp->mapped)
                    460:                return; /* not a mapped file */
                    461:        /* 
                    462:         * If the file, which was prev mapped and closed is opened with 
                    463:         * O_NO_MFS, the map_count will be zero when close
                    464:         * is called. SO, if it is already zero, there is nothing to
                    465:         * be done here. (Otherwise 2269452 and 2269437)
                    466:         */
                    467:        if (vmp->map_count == 0)
                    468:                return;
                    469:        if (--vmp->map_count > 0) {
                    470:                return;
                    471:        }
                    472: 
                    473:        /*
                    474:         *      If there are no links left to the file then release
                    475:         *      the resources held.  If there are links left, then keep
                    476:         *      the file mapped under the assumption that someone else
                    477:         *      will soon map the same file.  However, the pages in
                    478:         *      the object are deactivated to put them near the list
                    479:         *      of pages to be reused by the VM system (this would
                    480:         *      be done differently out of the kernel, of course, then
                    481:         *      again, the primitives for this don't exist out of the
                    482:         *      kernel yet.
                    483:         */
                    484: 
                    485:        vmp->map_count++;
                    486:                
                    487:        VOP_GETATTR(vp, &vattr, cred, p);
                    488:        links = vattr.va_nlink;  /* may uncache, see below */
                    489:        vmp->map_count--;
                    490: 
                    491:        if (links == 0) {
                    492:                mapfs_memfree(vmp, FALSE);
                    493:        } else {
                    494:                /*
                    495:                 *      pushing the pages may cause an uncache
                    496:                 *      operation (thanks NFS), so gain an extra
                    497:                 *      reference to guarantee that the object
                    498:                 *      does not go away.  (Note that such an
                    499:                 *      uncache actually takes place since we have
                    500:                 *      already released the map_count above).
                    501:                 */
                    502:                object = vmp->object;
                    503:                if (close_flush || vmp->close_flush) {
                    504:                        vmp->map_count++;       /* prevent uncache race */
                    505:                        vmp_get(vmp);
                    506: #if PERFMODS
                    507:                        if (vmp->dirty)
                    508:                                (void)vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize);
                    509: #else
                    510:                        (void)vmp_push(vmp); /* Ignore errors! XXX */
                    511: #endif
                    512:                }
                    513:                vm_object_lock(object);
                    514:                vm_object_deactivate_pages(object);
                    515:                vm_object_unlock(object);
                    516:                if (close_flush || vmp->close_flush) {
                    517:                        vmp_put(vmp);
                    518:                        vmp->map_count--;
                    519:                }
                    520:        }
                    521: }
                    522: 
                    523: /*
                    524:  *     remap_vnode:
                    525:  *
                    526:  *     Remap the specified vnode (due to extension of the file perhaps).
                    527:  *     Upon return, it should be possible to access data in the file
                    528:  *     starting at the "start" address for "size" bytes.
                    529:  */
                    530: int
                    531: remap_vnode(vp, start, size)
                    532:        register struct vnode   *vp;
                    533:        vm_offset_t             start;
                    534:        register vm_size_t      size;
                    535: {
                    536:        register struct vm_info *vmp;
                    537:        vm_offset_t             addr, offset;
                    538:        kern_return_t           ret;
                    539:        int error=0;
                    540:        vmp = vp->v_vm_info;
                    541:        /*
                    542:         *      Remove old mapping (making its space available).
                    543:         */
                    544: 
                    545:        if (vmp->size > 0) {
                    546: #if PERFMODS
                    547:                if (vmp->dirty)
                    548:                        (void)vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize);
                    549:                error = mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, FALSE);
                    550: #else
                    551:                error = mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, TRUE);
                    552: #endif /* PERFMODS */
                    553:                if (error)
                    554:                        goto out;
                    555:        }
                    556: 
                    557:        offset = trunc_page(start);
                    558:        size = round_page(start + size) - offset;
                    559: 
                    560:        if (size < CHUNK_SIZE)
                    561:                size = CHUNK_SIZE;
                    562:        do {
                    563:                addr = vm_map_min(mfs_map);
                    564:                mfs_alloc_lock();
                    565:                ret = vm_allocate_with_pager(mfs_map, &addr, size, TRUE,
                    566:                                vmp->pager, offset);
                    567:                /*
                    568:                 *      If there was no space, see if we can free up mappings
                    569:                 *      on the LRU list.  If not, just wait for someone else
                    570:                 *      to free their memory.
                    571:                 */
                    572:                if (ret == KERN_NO_SPACE) {
                    573:                        register struct vm_info *vmp1;
                    574: 
                    575:                        vm_info_lock();
                    576:                        vmp1 = VM_INFO_NULL;
                    577:                        if (!queue_empty(&vm_info_queue)) {
                    578:                                vmp1 = (struct vm_info *)
                    579:                                                queue_first(&vm_info_queue);
                    580:                                vm_info_dequeue(vmp1);
                    581:                        }
                    582:                        vm_info_unlock();
                    583:                        /*
                    584:                         *      If we found someone, free up its memory.
                    585:                         */
                    586:                        if (vmp1 != VM_INFO_NULL) {
                    587:                                mfs_alloc_unlock();
                    588:                                mapfs_memfree(vmp1, TRUE);
                    589:                                mfs_alloc_lock();
                    590:                        }
                    591:                        else {
                    592:                                mfs_alloc_wanted = TRUE;
                    593:                                assert_wait(&mfs_map, FALSE);
                    594:                                mfs_alloc_blocks++;     /* statistic only */
                    595:                                mfs_alloc_unlock();
                    596:                                thread_block();
                    597:                                mfs_alloc_lock();
                    598:                        }
                    599:                }
                    600:                else if (ret != KERN_SUCCESS) {
                    601:                        printf("Unexpected error on file map, ret = %d.\n",
                    602:                                        ret);
                    603:                        panic("remap_vnode");
                    604:                }
                    605:                mfs_alloc_unlock();
                    606:        } while (ret != KERN_SUCCESS);
                    607:        /*
                    608:         *      Fill in variables corresponding to new mapping.
                    609:         */
                    610:        vmp->va = addr;
                    611:        vmp->size = size;
                    612:        vmp->offset = offset;
                    613: out:
                    614:        return(error);
                    615: }
                    616: 
                    617: /*
                    618:  *     mapfs_trunc:
                    619:  *
                    620:  *     The specified vnode is truncated to the specified size.
                    621:  *     Returns 0 if successful error otherwise.
                    622:  */
                    623: int
                    624: mapfs_trunc(vp, length)
                    625:        register struct vnode   *vp;
                    626:        register vm_offset_t    length;
                    627: {
                    628:        register struct vm_info *vmp;
                    629:        register vm_size_t      size, rsize;
                    630:        int error = 0;
                    631: 
                    632:        vmp = vp->v_vm_info;
                    633: 
                    634:        if ((vp->v_type != VREG) || (vmp == (struct vm_info *)0))
                    635:                return (0);
                    636:        if (!vmp->mapped) {     /* file not mapped, just update size */
                    637:                vmp->vnode_size = length;
                    638:                return (0);
                    639:        }
                    640:        vmp_get(vmp);
                    641: 
                    642:        vmp->nfsdirty = TRUE;
                    643:        /*
                    644:         *      Unmap everything past the new end page.
                    645:         *      Also flush any pages that may be left in the object using
                    646:         *      vno_flush (is this necessary?).
                    647:         *      rsize is the size relative to the mapped offset.
                    648:         */
                    649:        NFSTRACE4(NFSTRC_MTR, vp, length, vmp->size, vmp->offset);
                    650:        size = round_page(length);
                    651:        if (size >= vmp->offset) {
                    652:                rsize = size - vmp->offset;
                    653:        } else {
                    654:                rsize = 0;
                    655:        }
                    656:        if (rsize < vmp->size) {
                    657:                error = mapfs_map_remove(vmp, vmp->va + rsize,
                    658:                                         vmp->va + vmp->size, FALSE);
                    659:                NFSTRACE4(NFSTRC_MTR_MREM, vp, vmp->va, vmp->size, rsize);
                    660:                if (error) {
                    661: #if DIAGNOSTIC
                    662:                        kprintf("mapfs_trunc: mapfs_map_remove %d\n", error);
                    663: #endif /* DIAGNOSTIC */
                    664:                        goto out;
                    665:                }
                    666:                if ((vmp->size = rsize) == 0)           /* mapped size */
                    667:                        vmp->offset = 0;
                    668:        }
                    669:        if (vmp->vnode_size > size)
                    670:                vno_flush(vp, size, vmp->vnode_size - size);
                    671:        vmp->vnode_size = length;       /* file size */
                    672:        /*
                    673:         *      If the new length isn't page aligned, zero the extra
                    674:         *      bytes in the last page.
                    675:         */
                    676:        if (length != size) {
                    677:                vm_size_t       n;
                    678: 
                    679:                n = size - length;
                    680:                /*
                    681:                 * Make sure the bytes to be zeroed are mapped.
                    682:                 */
                    683:                if ((length < vmp->offset) ||
                    684:                   ((length + n - 1) >= (vmp->offset + vmp->size))) {
                    685:                        NFSTRACE4(NFSTRC_MTR_RMAP, vp, vmp->offset, vmp->size, n);
                    686:                        error = remap_vnode(vp, length, n);
                    687:                        if (error) {
                    688: #if DIAGNOSTIC
                    689:                                kprintf("mapfs_trunc: remap_vnode %d\n", error);
                    690: #endif /* DIAGNOSTIC */
                    691:                                goto out;
                    692:                        }
                    693:                }
                    694:                NFSTRACE(NFSTRC_MTR_DIRT, vmp->va);
                    695:                vmp->nfsdirty = TRUE;
                    696:                error = safe_bzero((void *)(vmp->va + length - vmp->offset), n);
                    697:                if (error) {
                    698:                        NFSTRACE4(NFSTRC_MTR_BZER, vp, vmp->va, vmp->offset, n);
                    699: #if DIAGNOSTIC
                    700:                        kprintf("mapfs_trunc: safe_bzero %d\n", error);
                    701:                        kprintf("mapfs_trunc: va %x vp %x n %x length %x offset %x size %x\n", vmp->va, (unsigned)vp, n, length, vmp->offset, vmp->size);
                    702: #endif /* DIAGNOSTIC */
                    703:                        goto out;
                    704:                }
                    705: 
                    706:                /*
                    707:                 *      Do NOT set dirty flag... the cached memory copy
                    708:                 *      is zeroed, but this change doesn't need to be
                    709:                 *      flushed to disk (the vnode already has the right
                    710:                 *      size.  Besides, if we set this bit, we would need
                    711:                 *      to clean it immediately to prevent a later sync
                    712:                 *      operation from incorrectly cleaning a cached-only
                    713:                 *      copy of this vmp (which causes problems with NFS
                    714:                 *      due to the fact that we have changed the mod time
                    715:                 *      by truncating and will need to do an mapfs_uncache).
                    716:                 *      NFS is a pain.  Note that this means that there
                    717:                 *      will be a dirty page left in the vmp.  If this
                    718:                 *      turns out to be a problem we'll have to set the dirty
                    719:                 *      flag and immediately do a flush.
                    720:                 *
                    721:                 *      UPDATE: 4/4/13.  We need to really flush this.
                    722:                 *      Use the map_count hack to prevent a race with
                    723:                 *      uncaching.
                    724:                 */
                    725:                vmp->dirty = TRUE;
                    726:        }
                    727: 
                    728:        vmp->map_count++;       /* prevent uncache race */
                    729:        error = vmp_push(vmp);
                    730: #if DIAGNOSTIC
                    731:        if (error)
                    732:                kprintf("mapfs_trunc: vmp_push %d\n", error);
                    733: #endif /* DIAGNOSTIC */
                    734:        vmp->map_count--;
                    735: 
                    736: out:
                    737:        vmp_put(vmp);
                    738:        return (error);
                    739: }
                    740: 
                    741: /*
                    742:  *     mapfs_get:
                    743:  *
                    744:  *     Get locked access to the specified file.  The start and size describe
                    745:  *     the address range that will be accessed in the near future and
                    746:  *     serves as a hint of where to map the file if it is not already
                    747:  *     mapped.  Upon return, it is guaranteed that there is enough VM
                    748:  *     available for remapping operations within that range (each window
                    749:  *     no larger than the chunk size).
                    750:  */
                    751: int
                    752: mapfs_get(vp, start, size)
                    753:        register struct vnode   *vp;
                    754:        vm_offset_t             start;
                    755:        register vm_size_t      size;
                    756: {
                    757:        register struct vm_info *vmp;
                    758:        int error=0;
                    759:        vmp = vp->v_vm_info;
                    760: 
                    761:        vmp_get(vmp);
                    762: 
                    763:        /*
                    764:         *      If the requested size is larger than the size we have
                    765:         *      mapped, be sure we can get enough VM now.  This size
                    766:         *      is bounded by the maximum window size.
                    767:         */
                    768: 
                    769:        if (size > mfs_max_window)
                    770:                size = mfs_max_window;
                    771: 
                    772:        if (size > vmp->size) {
                    773:                error = remap_vnode(vp, start, size);
                    774:        }
                    775:        return(error);
                    776: }
                    777: 
                    778: /*
                    779:  *     mapfs_put:
                    780:  *
                    781:  *     Indicate that locked access is no longer desired of a file.
                    782:  */
                    783: void
                    784: mapfs_put(vp)
                    785:        register struct vnode   *vp;
                    786: {
                    787:        vmp_put(vp->v_vm_info);
                    788: }
                    789: 
                    790: /*
                    791:  *     vmp_get:
                    792:  *
                    793:  *     Get exclusive access to the specified vm_info structure.
                    794:  *     NeXT: Note mapfs_fsync_invalidate inlines part of this.
                    795:  */
                    796: void
                    797: vmp_get(vmp)
                    798:        struct vm_info  *vmp;
                    799: {
                    800:        /*
                    801:         *      Remove from LRU list (if its there).
                    802:         */
                    803:        vm_info_lock();
                    804:        if (vmp->queued) {
                    805:                vm_info_dequeue(vmp);
                    806:        }
                    807:        vmp->use_count++;       /* to protect requeueing in vmp_put */
                    808:        vm_info_unlock();
                    809: 
                    810:        /*
                    811:         *      Lock out others using this file.
                    812:         */
                    813:        lock_write(&vmp->lock);
                    814:        lock_set_recursive(&vmp->lock);
                    815: }
                    816: 
                    817: /*
                    818:  *     vmp_put:
                    819:  *
                    820:  *     Release exclusive access gained in vmp_get.
                    821:  */
                    822: void
                    823: vmp_put(vmp)
                    824:        register struct vm_info *vmp;
                    825: {
                    826:        /*
                    827:         *      Place back on LRU list if noone else using it.
                    828:         */
                    829:        vm_info_lock();
                    830:        if (--vmp->use_count == 0) {
                    831:                vm_info_enqueue(vmp);
                    832:        }
                    833:        vm_info_unlock();
                    834:        /*
                    835:         *      Let others at file.
                    836:         */
                    837:        lock_clear_recursive(&vmp->lock);
                    838:        lock_write_done(&vmp->lock);
                    839: 
                    840:        if (mfs_files_mapped > mfs_files_max)
                    841:                mapfs_cache_trim();
                    842: 
                    843:        if (vmp->invalidate) {
                    844:                vmp->invalidate = FALSE;
                    845:                vmp_invalidate(vmp);
                    846:        }
                    847: }
                    848: 
                    849: /*
                    850:  *     mapfs_uncache:
                    851:  *
                    852:  *     Make sure there are no cached mappings for the specified vnode.
                    853:  */
                    854: void 
                    855: mapfs_uncache(vp)
                    856:        register struct vnode   *vp;
                    857: {
                    858:        register struct vm_info *vmp;
                    859: 
                    860:        vmp = vp->v_vm_info;
                    861:        /*
                    862:         *      If the file is mapped but there is none actively using
                    863:         *      it then remove its mappings.
                    864:         */
                    865:        if (vmp->mapped && vmp->map_count == 0) {
                    866:                mapfs_memfree(vmp, FALSE);
                    867:        }
                    868: }
                    869: 
                    870: void
                    871: mapfs_memfree(vmp, flush)
                    872:        register struct vm_info *vmp;
                    873:        boolean_t               flush;
                    874: {
                    875:        struct ucred    *cred;
                    876:        vm_object_t     object;
                    877:        int error = 0;
                    878: 
                    879:        vm_info_lock();
                    880:        if (vmp->queued) {
                    881:                vm_info_dequeue(vmp);
                    882:        }
                    883:        vm_info_unlock();
                    884: 
                    885:        lock_write(&vmp->lock);
                    886:        lock_set_recursive(&vmp->lock);
                    887: 
                    888:        if (vmp->map_count == 0) {      /* cached only */
                    889:                vmp->mapped = FALSE;    /* prevent recursive flushes */
                    890:        }
                    891: 
                    892:        error =  mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, flush);
                    893:        if (error)
                    894:                panic("mapfs_memfree: mapfs_map_remove failed %d", error); /* XXX */
                    895:        vmp->size = 0;
                    896:        vmp->va = 0;
                    897:        object = VM_OBJECT_NULL;
                    898:        if (vmp->map_count == 0) {      /* cached only */
                    899:                /*
                    900:                 * lookup (in map_vnode) gained a reference, so need to
                    901:                 * lose it.
                    902:                 */
                    903:                object = vmp->object;
                    904:                vmp->object = VM_OBJECT_NULL;
                    905:                cred = vmp->cred;
                    906:                if (cred != NOCRED) {
                    907:                        vmp->cred = NOCRED;
                    908:                        crfree(cred);
                    909:                }
                    910:        }
                    911:        lock_clear_recursive(&vmp->lock);
                    912:        lock_write_done(&vmp->lock);
                    913: 
                    914:        if (object != VM_OBJECT_NULL)
                    915:                vm_object_deallocate(object);
                    916: }
                    917: 
                    918: /*
                    919:  *     mapfs_cache_trim:
                    920:  *
                    921:  *     trim the number of files in the cache to be less than the max
                    922:  *     we want.
                    923:  */
                    924: void
                    925: mapfs_cache_trim()
                    926: {
                    927:        register struct vm_info *vmp;
                    928: 
                    929:        while (TRUE) {
                    930:                vm_info_lock();
                    931:                if (mfs_files_mapped <= mfs_files_max) {
                    932:                        vm_info_unlock();
                    933:                        return;
                    934:                }
                    935:                /*
                    936:                 * grab file at head of lru list.
                    937:                 */
                    938:                vmp = (struct vm_info *) queue_first(&vm_info_queue);
                    939:                vm_info_dequeue(vmp);
                    940:                vm_info_unlock();
                    941:                /*
                    942:                 *      Free up its memory.
                    943:                 */
                    944:                mapfs_memfree(vmp, TRUE);
                    945:        }
                    946: }
                    947: 
                    948: /*
                    949:  *     mapfs_cache_clear:
                    950:  *
                    951:  *     Clear the mapped file cache.  Note that the map_count is implicitly
                    952:  *     locked by the Unix file system code that calls this routine.
                    953:  */
                    954: int
                    955: mapfs_cache_clear()
                    956: {
                    957:        register struct vm_info *vmp;
                    958:        int                     last_version;
                    959: 
                    960:        vm_info_lock();
                    961:        last_version = vm_info_version;
                    962:        vmp = (struct vm_info *) queue_first(&vm_info_queue);
                    963:        while (!queue_end(&vm_info_queue, (queue_entry_t) vmp)) {
                    964:                if (vmp->map_count == 0) {
                    965:                        vm_info_unlock();
                    966:                        mapfs_memfree(vmp, TRUE);
                    967:                        vm_info_lock();
                    968:                        /*
                    969:                         * mapfs_memfree increments version number, causing
                    970:                         * restart below.
                    971:                         */
                    972:                }
                    973:                /*
                    974:                 *      If the version didn't change, just keep scanning
                    975:                 *      down the queue.  If the version did change, we
                    976:                 *      need to restart from the beginning.
                    977:                 */
                    978:                if (last_version == vm_info_version) {
                    979:                        vmp = (struct vm_info *) queue_next(&vmp->lru_links);
                    980:                }
                    981:                else {
                    982:                        vmp = (struct vm_info *) queue_first(&vm_info_queue);
                    983:                        last_version = vm_info_version;
                    984:                }
                    985:        }
                    986:        vm_info_unlock();
                    987:        return(0);
                    988: }
                    989: 
                    990: /*
                    991:  *     mapfs_map_remove:
                    992:  *
                    993:  *     Remove specified address range from the mfs map and wake up anyone
                    994:  *     waiting for map space.  Be sure pages are flushed back to vnode.
                    995:  */
                    996: int
                    997: mapfs_map_remove(vmp, start, end, flush)
                    998:        struct vm_info  *vmp;
                    999:        vm_offset_t     start;
                   1000:        vm_size_t       end;
                   1001:        boolean_t       flush;
                   1002: {
                   1003:        vm_object_t     object;
                   1004:        int             error = 0;
                   1005:        /*
                   1006:         *      Note:   If we do need to flush, the vmp is already
                   1007:         *      locked at this point.
                   1008:         */
                   1009:        if (flush) {
                   1010: /*             vmp->map_count++;       *//* prevent recursive flushes */
                   1011:                error = vmp_push(vmp);
                   1012: /*             vmp->map_count--;*/
                   1013:                if (error)
                   1014:                        goto out;
                   1015:        }
                   1016:                
                   1017:        /*
                   1018:         *      Free the address space.
                   1019:         */
                   1020:        mfs_alloc_lock();
                   1021:        vm_map_remove(mfs_map, start, end);
                   1022:        if (mfs_alloc_wanted) {
                   1023:                mfs_alloc_wanted = FALSE;
                   1024:                thread_wakeup(&mfs_map);
                   1025:        }
                   1026:        mfs_alloc_unlock();
                   1027:        /*
                   1028:         *      Deactivate the pages.
                   1029:         */
                   1030:        object = vmp->object;
                   1031:        if (object != VM_OBJECT_NULL) {
                   1032:                vm_object_lock(object);
                   1033:                vm_object_deactivate_pages_first(object);
                   1034:                vm_object_unlock(object);
                   1035:        }
                   1036: 
                   1037: out:
                   1038:        return(error);
                   1039: }
                   1040: 
                   1041: #if PERFMODS
                   1042: /*
                   1043:  *     mapfs_map_cleanup:
                   1044:  *
                   1045:  *     Remove specified address range from the mfs map and wake up anyone
                   1046:  *     waiting for map space.  Be sure pages are flushed back to vnode.
                   1047:  */
                   1048: int
                   1049: mapfs_map_cleanup(vmp, start, end, flush)
                   1050:        struct vm_info  *vmp;
                   1051:        vm_offset_t     start;
                   1052:        vm_size_t       end;
                   1053:        boolean_t       flush;
                   1054: {
                   1055:        /*
                   1056:         *      Free the address space.
                   1057:         */
                   1058:        mfs_alloc_lock();
                   1059:        vm_map_remove(mfs_map, start, end);
                   1060:        if (mfs_alloc_wanted) {
                   1061:                mfs_alloc_wanted = FALSE;
                   1062:                thread_wakeup(&mfs_map);
                   1063:        }
                   1064:        mfs_alloc_unlock();
                   1065:        return(0);
                   1066: }
                   1067: #endif
                   1068: 
                   1069: #ifdef notdef 
                   1070: vnode_size(vp)
                   1071:        struct vnode    *vp;
                   1072: {
                   1073:        struct vattr            vattr;
                   1074: 
                   1075:        VOP_GETATTR(vp, &vattr, u.u_cred,p);
                   1076:        return(vattr.va_size);
                   1077: }
                   1078: #endif /* notdef */
                   1079: 
                   1080: 
                   1081: int active_mfsbufs = 0;                /* global record of buf count in use by mfs */
                   1082: extern int nbuf;
                   1083: extern int nmfsbuf;            /* global limit to mfs buffer allocation */
                   1084: 
                   1085: int
                   1086: mapfs_io(vp, uio, rw, ioflag, cred)
                   1087:        register struct vnode   *vp;
                   1088:        register struct uio     *uio;
                   1089:        enum uio_rw             rw;
                   1090:        int                     ioflag;
                   1091:        struct ucred            *cred;
                   1092: {
                   1093:        register vm_offset_t    va;
                   1094:        register struct vm_info *vmp;
                   1095:        register int            n, diff, bsize;
                   1096:        int                     error=0;
                   1097: #if PERFMODS
                   1098:        vm_offset_t             newoffset;
                   1099:        vm_size_t               newsize;
                   1100:        vm_size_t               mapfsio_size;
                   1101: #endif 
                   1102:        struct ucred            *cr;
                   1103:        struct proc *p;
                   1104: 
                   1105: 
                   1106:        if (uio->uio_resid == 0) {
                   1107:                return (0);
                   1108:        }
                   1109: 
                   1110:        if ((int) uio->uio_offset < 0 ||
                   1111:            (int) ((int)uio->uio_offset + uio->uio_resid) < 0) {
                   1112:                return (EINVAL);
                   1113:        }
                   1114:        
                   1115:        mfs_assert(vp->v_type==VREG || vp->v_type==VLNK);
                   1116: 
                   1117:        p = uio->uio_procp;
                   1118:        if (p && (vp->v_type == VREG) &&
                   1119:            uio->uio_offset + uio->uio_resid >
                   1120:            p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
                   1121:          psignal(p, SIGXFSZ);
                   1122:          return (EFBIG);
                   1123:        }
                   1124: 
                   1125:        /*
                   1126:         * The following code is adapted from code in nfs_bio{read,write}.
                   1127:         * The point of having it here is to keep us as synchronized with the
                   1128:         * server as we would have been had the nfs file not been mapped. Also
                   1129:         * helping in that synchronization goal are the mapfs_memfree calls in
                   1130:         * nfs_{get,load}attrcache.
                   1131:         */
                   1132:        if (vp->v_tag == VT_NFS) {
                   1133:                struct nfsnode *np = VTONFS(vp);
                   1134:                struct proc     *p = uio->uio_procp;
                   1135:                struct vattr    vattr;
                   1136: 
                   1137:                if (rw == UIO_WRITE) {
                   1138:                        NFSTRACE4(NFSTRC_MIO_WRT, vp,
                   1139:                                 uio->uio_offset, uio->uio_resid,
                   1140:                                 (ioflag & IO_APPEND            ? 0x0010 : 0) |
                   1141:                                 (ioflag & IO_SYNC              ? 0x0020 : 0) |
                   1142:                                 (np->n_flag & NMODIFIED        ? 0x0001 : 0) |
                   1143:                                 (vp->v_vm_info->nfsdirty       ? 0x0002 : 0));
                   1144:                        if (ioflag & (IO_APPEND | IO_SYNC)) {
                   1145:                                if (np->n_flag & NMODIFIED || vp->v_vm_info->nfsdirty) {
                   1146:                                        np->n_attrstamp = 0;
                   1147:                                        if ((error = nfs_vinvalbuf(vp, V_SAVE,
                   1148:                                                                   cred, p, 1)))
                   1149:                                                return (error);
                   1150:                                }
                   1151:                                if (ioflag & IO_APPEND) {
                   1152:                                        np->n_attrstamp = 0;
                   1153:                                        if ((error = VOP_GETATTR(vp, &vattr,
                   1154:                                                                 cred, p)))
                   1155:                                                return (error);
                   1156:                                }
                   1157:                        }
                   1158:                } else { /* UIO_READ we presume */
                   1159:                        NFSTRACE4(NFSTRC_MIO_READ, vp,
                   1160:                                 uio->uio_offset, uio->uio_resid,
                   1161:                                 (np->n_flag & NMODIFIED        ? 0x0001 : 0) |
                   1162:                                 (vp->v_vm_info->nfsdirty       ? 0x0002 : 0));
                   1163:                        if (np->n_flag & NMODIFIED || vp->v_vm_info->nfsdirty) {
                   1164:                                np->n_attrstamp = 0;
                   1165:                                if ((error = VOP_GETATTR(vp, &vattr, cred, p)))
                   1166:                                        return (error);
                   1167:                                np->n_mtime = vattr.va_mtime.tv_sec;
                   1168:                        } else {
                   1169:                                if ((error = VOP_GETATTR(vp, &vattr, cred, p)))
                   1170:                                        return (error);
                   1171:                                else if (np->n_mtime != vattr.va_mtime.tv_sec) {
                   1172:                                        NFSTRACE(NFSTRC_MIO_RINV, vp);
                   1173:                                        if ((error = nfs_vinvalbuf(vp, V_SAVE,
                   1174:                                                                   cred, p, 1)))
                   1175:                                                return (error);
                   1176:                                        np->n_mtime = vattr.va_mtime.tv_sec;
                   1177:                                }
                   1178:                        }
                   1179:                }
                   1180:        }
                   1181: 
                   1182:        error = mapfs_get(vp, (vm_offset_t)uio->uio_offset, uio->uio_resid);
                   1183:        if (error)
                   1184:                goto out;
                   1185:        vmp = vp->v_vm_info;
                   1186: 
                   1187:        if ((rw == UIO_WRITE) && (ioflag & IO_APPEND)) {
                   1188:                uio->uio_offset = vmp->vnode_size;
                   1189:        }
                   1190: #if PERFMODS
                   1191:        bsize = PAGE_SIZE;
                   1192: #else
                   1193:        bsize = vp->v_mount->mnt_stat.f_bsize;
                   1194: 
                   1195: #define MAPFS_DEFAULT_BLOCKSIZE                4096
                   1196:        /* In some cases the f_bsize is not set; then force it to 
                   1197:         * default; porbably should consider changing to f_iosize
                   1198:         * but not sure whether this will be any accurate either
                   1199:         * We need this anyway
                   1200:         */
                   1201:        if (bsize == 0)
                   1202:                bsize = MAPFS_DEFAULT_BLOCKSIZE;
                   1203: #endif
                   1204:        /*
                   1205:         *      Set credentials.
                   1206:         */
                   1207:        if (rw == UIO_WRITE || (rw == UIO_READ && vmp->cred == NULL)) {
                   1208:                cred = crdup(cred);
                   1209:                cr = vmp->cred;
                   1210:                if (cr != NOCRED) {
                   1211:                        vmp->cred = NOCRED;
                   1212:                        crfree(cr);
                   1213:                }
                   1214:                vmp->cred = cred;
                   1215:        }
                   1216: 
                   1217:        /* Clear errors before we start */
                   1218:        vmp->error = 0;
                   1219: 
                   1220: #if PERFMODS
                   1221:        if (rw == UIO_WRITE) {
                   1222:                /*
                   1223:                 * set up range for this I/O
                   1224:                 */
                   1225:                newoffset = uio->uio_offset;
                   1226:                newsize   = uio->uio_resid;
                   1227: 
                   1228:                if (vmp->dirtysize) {
                   1229:                        /*
                   1230:                         * if a dirty range already exists, coalesce with the new range, but
                   1231:                         * don't update the vmp fields yet, because if there was no intersection
                   1232:                         * between the old range and the range that encompasses the new I/O
                   1233:                         * we may want to push the old range and not do the coalesce if the new coalesced
                   1234:                         * size exceeds CHUNK_SIZE
                   1235:                         */
                   1236:                        if (newoffset > vmp->dirtyoffset)
                   1237:                                newoffset = vmp->dirtyoffset;
                   1238: 
                   1239:                        if ((uio->uio_offset + uio->uio_resid) > (vmp->dirtyoffset + vmp->dirtysize))
                   1240:                                newsize = (uio->uio_offset + uio->uio_resid) - newoffset;
                   1241:                        else
                   1242:                                newsize = (vmp->dirtyoffset + vmp->dirtysize) - newoffset;
                   1243: 
                   1244:                        if (newsize > CHUNK_SIZE && ((uio->uio_offset > (vmp->dirtyoffset + vmp->dirtysize)) ||
                   1245:                                                     (uio->uio_offset + uio->uio_resid) < vmp->dirtyoffset)) {
                   1246:                                /*
                   1247:                                 * the new coalasced size exceeded CHUNK_SIZE, and there was no intersection
                   1248:                                 * with the current dirty range, so push the current dirty range....
                   1249:                                 * the new dirty range will be set to the range encompassing this I/O request
                   1250:                                 */
                   1251:                                vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize);
                   1252:                                newoffset = uio->uio_offset;
                   1253:                                newsize   = uio->uio_resid;
                   1254:                        }
                   1255:                } 
                   1256:                /*
                   1257:                 * now make sure that the proposed dirty range is fully encompassed by the
                   1258:                 * current vm mapping of the file... if not, we'll clip at either end
                   1259:                 * if there is no intersection at all with the current mapping, than
                   1260:                 * we'll set the dirty size to 0.... note that any previous dirty pages would
                   1261:                 * have been pushed above since they must have fit in the current mapping and
                   1262:                 * if the new range doesn't intersect with the current mapping, than we couldn't
                   1263:                 * have coalesced with the old range...  in this case, we'll be going through the
                   1264:                 * remap path before issuing any I/O... that path will set the dirty range accordingly
                   1265:                 */
                   1266:                if (newoffset < vmp->offset) {
                   1267:                        if ((vmp->offset - newoffset) < newsize)
                   1268:                                newsize -= vmp->offset - newoffset;
                   1269:                        else
                   1270:                                newsize = 0;
                   1271:                        newoffset = vmp->offset;
                   1272:                }
                   1273:                if ((newoffset + newsize) > (vmp->offset + vmp->size))
                   1274:                        newsize = (vmp->offset + vmp->size) - newoffset;
                   1275: 
                   1276:                vmp->dirtyoffset = newoffset;
                   1277:                vmp->dirtysize   = newsize;
                   1278:        }
                   1279: #endif /* PERFMODS */
                   1280: 
                   1281:        do {
                   1282:                n = MIN((unsigned)bsize, uio->uio_resid);
                   1283: 
                   1284:                if (rw == UIO_READ) {
                   1285:                        /*
                   1286:                         * only read up to the end of the file
                   1287:                         */
                   1288:                        if ((diff = (int)(vmp->vnode_size - uio->uio_offset)) <= 0) {
                   1289:                                mapfs_put(vp);
                   1290:                                return (0);
                   1291:                        }
                   1292:                        if (diff < n)
                   1293:                                n = diff;
                   1294:                } else if (((vm_size_t)uio->uio_offset) + n > vmp->vnode_size)
                   1295:                        vmp->vnode_size = (vm_size_t)uio->uio_offset + n;
                   1296: 
                   1297:                /*
                   1298:                 *      Check to be sure we have a valid window
                   1299:                 *      for the mapped file.
                   1300:                 */
                   1301:                if (((vm_offset_t)uio->uio_offset < vmp->offset) ||
                   1302:                   (((vm_offset_t)uio->uio_offset + n) > (vmp->offset + vmp->size))) {
                   1303: 
                   1304:                        if ((mapfsio_size = (vmp->size << 1)) > mfs_max_window)
                   1305:                                mapfsio_size = mfs_max_window;
                   1306: 
                   1307:                        error = remap_vnode(vp, (vm_offset_t)uio->uio_offset, mapfsio_size);
                   1308:                        /*
                   1309:                         * remap_vnode does a push of the dirty pages and then
                   1310:                         * sets vmp->dirtyoffset and vmp->dirtysize to 0
                   1311:                         */
                   1312:                        if (error)
                   1313:                                goto out;
                   1314:                        /*
                   1315:                         * new dirty range encompasses the remaining I/O of this request
                   1316:                         */
                   1317:                        vmp->dirtyoffset = uio->uio_offset;
                   1318:                        vmp->dirtysize   = uio->uio_resid;
                   1319: 
                   1320:                        /*
                   1321:                         * make sure the new dirty range doesn't extend beyond the end of the map
                   1322:                         */
                   1323:                        if ((vmp->dirtyoffset + vmp->dirtysize) > (vmp->offset + vmp->size))
                   1324:                                vmp->dirtysize = (vmp->offset + vmp->size) - vmp->dirtyoffset;
                   1325:                }
                   1326:                va = vmp->va + (vm_offset_t)uio->uio_offset - vmp->offset;
                   1327: 
                   1328:                vmp->busy = TRUE;
                   1329: 
                   1330:                if (rw == UIO_WRITE)
                   1331:                        vmp->nfsdirty = TRUE;
                   1332: 
                   1333:                error = uiomove((caddr_t)va, (int)n, uio);
                   1334: 
                   1335:                vmp->busy = FALSE;
                   1336: 
                   1337:                if (error)
                   1338:                        goto out;
                   1339: 
                   1340:                if (vmp->delayed_fsync) {
                   1341:                        vmp->delayed_fsync = FALSE;
                   1342: 
                   1343:                         if (rw == UIO_WRITE)
                   1344:                            vmp->dirtysize = uio->uio_offset - vmp->dirtyoffset;
                   1345: 
                   1346:                        error = vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize);
                   1347:                        if (error)
                   1348:                                goto out;
                   1349: 
                   1350:                         if (rw == UIO_WRITE) {
                   1351:                            /*
                   1352:                             * new dirty range encompasses the remaining I/O of this request
                   1353:                             */
                   1354:                            vmp->dirtyoffset = uio->uio_offset;
                   1355:                            vmp->dirtysize   = uio->uio_resid;
                   1356: 
                   1357:                            /*
                   1358:                             * make sure the new dirty range doesn't extend beyond 
                   1359:                              * the end of the map
                   1360:                             */
                   1361:                            if ((vmp->dirtyoffset + vmp->dirtysize) > (vmp->offset + vmp->size))
                   1362:                                vmp->dirtysize = (vmp->offset + vmp->size) - vmp->dirtyoffset;
                   1363:                         }
                   1364:                } else  if (rw == UIO_WRITE)
                   1365:                        /*
                   1366:                         *      Set dirty bit each time through loop just in
                   1367:                         *      case remap above caused it to be cleared.
                   1368:                         */
                   1369:                        vmp->dirty = TRUE;
                   1370: 
                   1371:                /*
                   1372:                 *      Check for errors left by the pager.  Report the
                   1373:                 *      error only once.
                   1374:                 */
                   1375:                if (vmp->error) {
                   1376:                        error = vmp->error;
                   1377:                        vmp->error = 0;
                   1378:                        /*
                   1379:                         * The error might have been a permission
                   1380:                         * error based on the credential.  We release it
                   1381:                         * so that the next person who tries a read doesn't
                   1382:                         * get stuck with it.
                   1383:                         */
                   1384:                        cr = vmp->cred;
                   1385:                        if (cr != NOCRED) {
                   1386:                                vmp->cred = NOCRED;
                   1387:                                crfree(cr);
                   1388:                        }
                   1389:                }
                   1390: 
                   1391:                /*
                   1392:                 * Test to prevent mfs from swamping the buffer cache,
                   1393:                 * locking out higher-priority transfers, like
                   1394:                 * pageins, and causing system hangs.
                   1395:                 */ 
                   1396:        } while (error == 0 && uio->uio_resid > 0);
                   1397: 
                   1398: #if PERFMODS
                   1399:        if (error == 0 && rw == UIO_WRITE) {
                   1400:                /*
                   1401:                 * Since the window may be as much as 4 Mbytes; write it out
                   1402:                 * when we reach or exceed CHUNK_SIZE to avoid flooding the
                   1403:                 * underlying disks with a huge stream of writes all at once
                   1404:                 */
                   1405:                if ((ioflag & IO_SYNC) || vmp->dirtysize >= CHUNK_SIZE) {
                   1406: 
                   1407:                        error = vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize);
                   1408: 
                   1409:                        if (error == 0 && (ioflag & IO_SYNC)) {
                   1410:                                error = VOP_FSYNC(vp, cred, MNT_WAIT, (struct proc *)0);
                   1411:                                if (error)
                   1412:                                        goto out;
                   1413:                        }
                   1414: 
                   1415:                        /* This looks like redundant info; but I am keeping this
                   1416:                         * as this worked at least from one reported case
                   1417:                         */
                   1418:                        if (vmp->error) {
                   1419:                                error = vmp->error;
                   1420:                                vmp->error = 0;
                   1421:                        }
                   1422:                }
                   1423:        }
                   1424: #else
                   1425:        if (
                   1426:                (error == 0) &&
                   1427:                (rw == UIO_WRITE) && 
                   1428:                (ioflag & IO_SYNC)) {
                   1429: 
                   1430:                
                   1431:                error = vmp_push(vmp);  /* initiate all i/o */
                   1432:                if (!error) {
                   1433:                        error = VOP_FSYNC(vp, cred, MNT_WAIT, (struct proc *)0);
                   1434:                        if (error)
                   1435:                                goto out;
                   1436:                }
                   1437:                /* This looks like redundant info; but I am keeping this
                   1438:                 * as this worked at least from one reported case
                   1439:                 */
                   1440:                if (vmp->error) {
                   1441:                        error = vmp->error;
                   1442:                        vmp->error = 0;
                   1443:                }
                   1444:        }
                   1445: #endif /* PERFMODS */
                   1446: out:
                   1447:        mapfs_put(vp);
                   1448:        return(error);
                   1449: }
                   1450: 
                   1451: /*
                   1452:  *     mapfs_sync:
                   1453:  *
                   1454:  *     Sync the mfs cache (called by sync()).
                   1455:  */
                   1456: int
                   1457: mapfs_sync()
                   1458: {
                   1459:        register struct vm_info *vmp, *next;
                   1460:        int                     last_version;
                   1461:        int error = 0;
                   1462: 
                   1463:        vm_info_lock();
                   1464:        last_version = vm_info_version;
                   1465:        vmp = (struct vm_info *) queue_first(&vm_info_queue);
                   1466:        while (!queue_end(&vm_info_queue, (queue_entry_t) vmp)) {
                   1467:                next = (struct vm_info *) queue_next(&vmp->lru_links);
                   1468:                if (vmp->dirty) {
                   1469:                        vm_info_unlock();
                   1470:                        vmp_get(vmp);
                   1471:                        error = vmp_push(vmp);
                   1472:                        vmp_put(vmp);
                   1473:                        if (error)
                   1474:                                goto out;
                   1475:                        vm_info_lock();
                   1476:                        /*
                   1477:                         *      Since we unlocked, the get and put
                   1478:                         *      operations would increment version by
                   1479:                         *      two, so add two to our version.
                   1480:                         *      If anything else happened in the meantime,
                   1481:                         *      version numbers will not match and we
                   1482:                         *      will restart.
                   1483:                         */
                   1484:                        last_version += 2;
                   1485:                }
                   1486:                /*
                   1487:                 *      If the version didn't change, just keep scanning
                   1488:                 *      down the queue.  If the version did change, we
                   1489:                 *      need to restart from the beginning.
                   1490:                 */
                   1491:                if (last_version == vm_info_version) {
                   1492:                        vmp = next;
                   1493:                }
                   1494:                else {
                   1495:                        vmp = (struct vm_info *) queue_first(&vm_info_queue);
                   1496:                        last_version = vm_info_version;
                   1497:                }
                   1498:        }
                   1499:        vm_info_unlock();
                   1500: out:
                   1501:        return(error);
                   1502: }
                   1503: 
                   1504: /*
                   1505:  *     Sync pages in specified vnode.
                   1506:  */
                   1507: int
                   1508: mapfs_fsync(vp)
                   1509:        struct vnode    *vp;
                   1510: {
                   1511:        struct vm_info  *vmp;
                   1512:        int error=0;
                   1513:        vmp = vp->v_vm_info;
                   1514:        if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) {
                   1515:                vmp_get(vmp);
                   1516:                error = vmp_push(vmp);
                   1517:                vmp_put(vmp);
                   1518: 
                   1519:                return(error);
                   1520:        }
                   1521:        return(0);
                   1522: }
                   1523: 
                   1524: 
                   1525: #if 0 /* dead code elimination */
                   1526: /*
                   1527:  *     Sync pages in specified vnode, annd invalidate clean.
                   1528:  *     The vm_info lock protects the vm_info from modification,
                   1529:  *     or removal. XXX Must protect against sync/invalidate race 
                   1530:  */
                   1531: int
                   1532: mapfs_fsync_invalidate(vp, flag)
                   1533:        struct vnode    *vp;
                   1534: {
                   1535:        struct vm_info  *vmp;
                   1536: 
                   1537:        vmp = vp->v_vm_info;
                   1538:        if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) {
                   1539: 
                   1540:                /*      Part of vmp_get(vmp), we don't actually
                   1541:                 *      need the write lock if we hold a ref as
                   1542:                 *      we are not changing the vm_info data
                   1543:                 *
                   1544:                 *      Remove from LRU list (if its there).
                   1545:                 */
                   1546:                vm_info_lock();
                   1547:                if (vmp->queued) {
                   1548:                        vm_info_dequeue(vmp);
                   1549:                }
                   1550:                vmp->use_count++;       /* to protect requeueing in vmp_put */
                   1551:                vm_info_unlock();
                   1552: 
                   1553:                if (!(flag & MFS_NOFLUSH))
                   1554:                        vmp_push_all(vmp);
                   1555: 
                   1556:                /* This is not under a lock, nor is it in vm_put XXX */
                   1557:                /* But it is below */
                   1558:                if (!(flag & MFS_NOINVALID)){
                   1559:                        vmp->invalidate = FALSE;
                   1560:                        vmp_invalidate(vmp);
                   1561:                }
                   1562:                /*
                   1563:                 *      Place back on LRU list if noone else using it.
                   1564:                 */
                   1565:                vm_info_lock();
                   1566:                if (--vmp->use_count == 0) {
                   1567:                        vm_info_enqueue(vmp);
                   1568:                }
                   1569:                vm_info_unlock();
                   1570:                return(vmp->error);
                   1571: 
                   1572:        }
                   1573:        return(0);
                   1574: }
                   1575: #endif
                   1576: 
                   1577: 
                   1578: 
                   1579: /*
                   1580:  *     Invalidate pages in specified vnode.
                   1581:  */
                   1582: int
                   1583: mapfs_invalidate(vp)
                   1584:        struct vnode    *vp;
                   1585: {
                   1586:        struct vm_info  *vmp;
                   1587: 
                   1588:        vmp = vp->v_vm_info;
                   1589:        if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) {
                   1590:                if (vmp->use_count > 0)
                   1591:                        vmp->invalidate = TRUE;
                   1592:                else {
                   1593:                        vmp_get(vmp);
                   1594:                        vmp_invalidate(vmp);
                   1595:                        vmp_put(vmp);
                   1596:                }
                   1597:        }
                   1598:        return(vmp ? vmp->error : 0);
                   1599: }
                   1600: 
                   1601: #import <vm/vm_page.h>
                   1602: #import <vm/vm_object.h>
                   1603: 
                   1604: /*
                   1605:  *     Search for and flush pages in the specified range.  For now, it is
                   1606:  *     unnecessary to flush to disk since I do that synchronously.
                   1607:  */
                   1608: void vno_flush(vp, start, size)
                   1609:        struct vnode            *vp;
                   1610:        register vm_offset_t    start;
                   1611:        vm_size_t               size;
                   1612: {
                   1613:        register vm_offset_t    end;
                   1614:        register vm_object_t    object;
                   1615:        register vm_page_t      m;
                   1616: 
                   1617:        object = vp->v_vm_info->object;
                   1618:        if (object == VM_OBJECT_NULL)
                   1619:                return;
                   1620: 
                   1621: #if SCRUBVM3
                   1622:        /* Isn't this the wrong order to aquire the lock */
                   1623: #endif
                   1624:        vm_page_lock_queues();
                   1625:        vm_object_lock(object); /* mfs code holds reference */
                   1626:        end = round_page(size + start); /* must be first */
                   1627:        start = trunc_page(start);
                   1628:        while (start < end) {
                   1629:                m = vm_page_lookup(object, start);
                   1630:                if (m != VM_PAGE_NULL) {
                   1631:                        if (m->busy) {
                   1632: #if SCRUBVM3
                   1633:                                /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC
                   1634:                                 * on SWAP */
                   1635:                                /* hint if we miss it its ok */
                   1636:                                if (m->dry_vp){
                   1637:                                    /* object and page queues locked, note
                   1638:                                     * page might not be clean wrt backing
                   1639:                                     * store */ 
                   1640:                                    (void) vm_page_completeio(m, TRUE);
                   1641:                                } else {
                   1642: #endif
                   1643:                                        PAGE_ASSERT_WAIT(m, FALSE);
                   1644:                                        vm_object_unlock(object);
                   1645:                                        vm_page_unlock_queues();
                   1646:                                        thread_block();
                   1647:                                        vm_page_lock_queues();
                   1648:                                        vm_object_lock(object);
                   1649:                                        continue;       /* try again */
                   1650: #if SCRUBVM3
                   1651:                                }
                   1652: #endif
                   1653:                        }
                   1654:                        vm_page_free(m);
                   1655:                }
                   1656:                start += PAGE_SIZE;
                   1657:        }
                   1658:        vm_object_unlock(object);
                   1659:        vm_page_unlock_queues();
                   1660: }
                   1661: 
                   1662: 
                   1663: int mfs_mdirty;
                   1664: int mfs_mclean;
                   1665: /*
                   1666:  *     Search for and free pages in the specified vmp.
                   1667:  */
                   1668: void
                   1669: vmp_invalidate(struct vm_info *vmp)
                   1670: {
                   1671:        register vm_object_t    object;
                   1672:        register vm_page_t      m;
                   1673: 
                   1674:        NFSTRACE(NFSTRC_VMP_INV, vmp);
                   1675:        object = vmp->object;
                   1676:        if (object == VM_OBJECT_NULL)
                   1677:                return;
                   1678: 
                   1679:        vm_page_lock_queues();
                   1680:        vm_object_lock(object); /* mfs code holds reference */
                   1681: 
                   1682:        /* Sanity. Different code calls this with and without the vminfo
                   1683:         * lock. The locking needs to be fixed for MP. XXX 
                   1684:         */
                   1685:        if (vmp->object != object) {
                   1686:                vm_object_unlock(object);
                   1687:                vm_page_unlock_queues();
                   1688:                return;
                   1689:        }
                   1690: 
                   1691: retry:
                   1692:        m = (vm_page_t) queue_first(&object->memq);
                   1693:        while (!queue_end(&object->memq, (queue_entry_t) m)) {
                   1694:                vm_page_t next = (vm_page_t) queue_next(&m->listq);
                   1695: 
                   1696:                /* If NFS is paging us in we are not really valid yet. XXX
                   1697:                 * Re-address this. Without this check we can block forever
                   1698:                 * waiting on the busy bit that we set. */
                   1699:                if (m->nfspagereq == TRUE){
                   1700:                        m = next;
                   1701:                        continue;
                   1702:                }
                   1703: 
                   1704:                if (m->busy) {
                   1705: #if SCRUBVM3
                   1706:                        /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC
                   1707:                         * on SWAP */
                   1708:                        /* hint if we miss it its ok */
                   1709:                        if (m->dry_vp){
                   1710:                                /* object and page queues locked, note
                   1711:                                 * page might not be clean wrt backing
                   1712:                                 * store */     
                   1713:                                (void) vm_page_completeio(m, TRUE);
                   1714:                        } else {
                   1715: #endif
                   1716:                                PAGE_ASSERT_WAIT(m, FALSE);
                   1717:                                vm_object_unlock(object);
                   1718:                                vm_page_unlock_queues();
                   1719:                                thread_block();
                   1720:                                vm_page_lock_queues();
                   1721:                                vm_object_lock(object);
                   1722:                                goto retry;
                   1723: #if SCRUBVM3
                   1724:                                }
                   1725: #endif
                   1726:                }
                   1727: 
                   1728:                /* Kill off the translation as well.
                   1729:                 * mapfs_map_remove removes them as well, but as
                   1730:                 * we have seen not everyone calls that.
                   1731:                 *
                   1732:                 * If there is a ref to this file and we are being called
                   1733:                 * and the page is wired we will skip this page. If there 
                   1734:                 * are no more refs to this file and we are being called 
                   1735:                 * the wire count should always be zero. In the future we
                   1736:                 * may want to block on the wired count. XXX joh
                   1737:                 */
                   1738:                if (m->wire_count == 0){
                   1739:                        pmap_remove_all(VM_PAGE_TO_PHYS(m));
                   1740:                        /* In the case of mfs only one guy can be in here at a
                   1741:                         * a time. In the case of mmap they can be dirtying
                   1742:                         * pages in parallel . So after our sync and invalidate
                   1743:                         * above we need to check again. If someone has re-
                   1744:                         * written them again, then they get to keep the page.
                   1745:                         * NFS does not give any assurances for multiple
                   1746:                         * writers on different nodes.
                   1747:                         */
                   1748:                        if ((m->clean == FALSE) ||
                   1749:                             pmap_is_modified(VM_PAGE_TO_PHYS(m))){
                   1750:                                mfs_mdirty++;
                   1751:                        } else {
                   1752:                                mfs_mclean++;
                   1753:                                vm_page_free(m);
                   1754:                        }
                   1755:                } 
                   1756:                m = next;
                   1757:        }
                   1758:        vm_object_unlock(object);
                   1759:        vm_page_unlock_queues();
                   1760: }
                   1761: 
                   1762: 
                   1763: /*
                   1764:  *     Search for and push (to disk) pages in the specified range.
                   1765:  *     We need some better interactions with the VM system to simplify
                   1766:  *     the code. Force tries to push the object regardless of whether 
                   1767:  *     the MFS thinks it is dirty (mmap could have written it). Some day
                   1768:  *     vmp_push could support ranges vmp_push(vmp,start,size).
                   1769:  */
                   1770: 
                   1771: /* Something must be done to handle dirty wired pages. XXX joh */
                   1772: int
                   1773: vmp_push(vmp)
                   1774:        struct vm_info          *vmp;
                   1775: {
                   1776:        register vm_offset_t    start;
                   1777:        vm_size_t               size;
                   1778:        int error=0;
                   1779: 
                   1780:        if (!vmp->dirty)
                   1781:                return(0);
                   1782:        start = vmp->offset;
                   1783:        size = vmp->size;
                   1784:        
                   1785:        /* vmp->dirty is set FALSE in vmp_push_range */
                   1786:        error = vmp_push_range(vmp, start, size);
                   1787: 
                   1788:        return(error);
                   1789: }
                   1790: 
                   1791: int
                   1792: vmp_push_range(vmp, start, size)
                   1793:        struct vm_info          *vmp;
                   1794:        register vm_offset_t    start;
                   1795:        vm_size_t               size;
                   1796: {
                   1797:        register vm_offset_t    end;
                   1798:        register vm_object_t    object;
                   1799:        register vm_page_t      m;
                   1800:        struct vattr            vattr;
                   1801:        int error=0;
                   1802: 
                   1803:        NFSTRACE4(NFSTRC_VPR, vmp->vnode, start, size, vmp->busy);
                   1804:        if (!vmp->dirty)
                   1805:                return(0);
                   1806:        if (vmp->busy) {
                   1807:                vmp->delayed_fsync = TRUE;
                   1808:                return(0);
                   1809:        }
                   1810:        vmp->dirty = FALSE;
                   1811:         vmp->dirtysize = 0;
                   1812:         vmp->dirtyoffset = 0;
                   1813: 
                   1814:        object = vmp->object;
                   1815:        /*  We are trying to catch BSd error; no need to bother
                   1816:         * about these errors for now 
                   1817:         */
                   1818:        if (object == VM_OBJECT_NULL)
                   1819:                return(0);
                   1820: 
                   1821:        vm_page_lock_queues();
                   1822:        vm_object_lock(object); /* mfs code holds reference */
                   1823: 
                   1824:        end = round_page(size + start); /* must be first */
                   1825:        start = trunc_page(start);
                   1826:        /* Cleanup error before we start */
                   1827:        vmp->error = 0;
                   1828: 
                   1829:        while (start < end) {
                   1830:                m = vm_page_lookup(object, start);
                   1831:                /* We don't want to deadlock on the page we are bring in */
                   1832:                if ((m != VM_PAGE_NULL) && (m->nfspagereq == FALSE)){
                   1833:                        if (m->busy) {
                   1834: #if SCRUBVM3
                   1835:                                /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC
                   1836:                                 * on SWAP */
                   1837:                                /* hint if we miss it its ok */
                   1838:                                if (m->dry_vp){
                   1839:                                        /* object and page queues locked, note
                   1840:                                         * page might not be clean wrt backing
                   1841:                                         * store */     
                   1842:                                        (void) vm_page_completeio(m, TRUE);
                   1843:                                } else {
                   1844: #endif
                   1845:                                        PAGE_ASSERT_WAIT(m, FALSE);
                   1846:                                        vm_object_unlock(object);
                   1847:                                        vm_page_unlock_queues();
                   1848:                                        thread_block();
                   1849:                                        vm_page_lock_queues();
                   1850:                                        vm_object_lock(object);
                   1851:                                        continue;       /* try again */
                   1852: #if SCRUBVM3
                   1853:                                }
                   1854: #endif
                   1855:                        }
                   1856:                        if (!m->active) {
                   1857:                                vm_page_activate(m); /* so deactivate works */
                   1858:                        }
                   1859:                        vm_page_deactivate(m);  /* gets dirty/laundry bit */
                   1860:                        /*
                   1861:                         *      Prevent pageout from playing with
                   1862:                         *      this page.  We know it is inactive right
                   1863:                         *      now (and are holding lots of locks keeping
                   1864:                         *      it there).
                   1865:                         */
                   1866:                        queue_remove(&vm_page_queue_inactive, m, vm_page_t,
                   1867:                                     pageq);
                   1868:                        m->inactive = FALSE;
                   1869:                        vm_page_inactive_count--;
                   1870:                        m->busy = TRUE;
                   1871:                        if (m->laundry) {
                   1872:                                pager_return_t  ret;
                   1873: 
                   1874:                                pmap_remove_all(VM_PAGE_TO_PHYS(m));
                   1875:                                object->paging_in_progress++;
                   1876:                                vm_object_unlock(object);
                   1877:                                vm_page_unlock_queues();
                   1878:                                /* should call pageout daemon code */
                   1879:                                ret = vnode_pageout(m);
                   1880:                                vm_page_lock_queues();
                   1881:                                vm_object_lock(object);
                   1882:                                object->paging_in_progress--;
                   1883:                                if (ret == PAGER_SUCCESS) {
                   1884:                                        /* vnode_pageout marks clean */
                   1885: #if PERFMODS
                   1886:                                        pmap_clear_reference(VM_PAGE_TO_PHYS(m));
                   1887: #endif /* PERFMODS */
                   1888:                                        m->laundry = FALSE;
                   1889:                                } else {
                   1890:                                        /* don't set dirty bit, unrecoverable
                   1891:                                           errors will cause update to go
                   1892:                                           crazy.  User is responsible for
                   1893:                                           retrying the write */
                   1894:                                        /* vmp->dirty = TRUE; */
                   1895:                                        error = vmp->error;
                   1896:                                        vmp->error =0;
                   1897:                                }
                   1898:                                /* if pager failed, activate below */
                   1899:                        }
                   1900:                        vm_page_activate(m);
                   1901:                        m->busy = FALSE;
                   1902:                        PAGE_WAKEUP(m);
                   1903:                }
                   1904:                start += PAGE_SIZE;
                   1905:        }
                   1906:        vmp->nfsdirty = FALSE;
                   1907:        vm_object_unlock(object);
                   1908:        vm_page_unlock_queues();
                   1909: 
                   1910:        /*
                   1911:         * On error we have to reset the true file size in the vmp
                   1912:         * structure.  The lack of a credential structure pointer
                   1913:         * would indicate nothing was changing in the file.
                   1914:         */
                   1915:        if (error && vmp->cred) {
                   1916:          vmp->filesize=TRUE;
                   1917:          VOP_GETATTR (vmp->vnode, &vattr, vmp->cred, current_proc());
                   1918:          vmp->filesize=FALSE;
                   1919:          vmp->vnode_size = vattr.va_size;
                   1920:        }
                   1921:        NFSTRACE(NFSTRC_VPR_DONE, error);
                   1922: 
                   1923:        return(error);
                   1924: }
                   1925: 
                   1926: 
                   1927: #if 0 /* dead code elimination */
                   1928: /* Something must be done to handle dirty wired pages. XXX joh */
                   1929: void
                   1930: vmp_push_all(vmp)
                   1931:        struct vm_info          *vmp;
                   1932: {
                   1933:        register vm_object_t    object;
                   1934:        register vm_page_t      m;
                   1935:        struct vattr            vattr;
                   1936:        int error=0;
                   1937: 
                   1938:        vmp->dirty = FALSE;
                   1939: 
                   1940:        object = vmp->object;
                   1941:        if (object == VM_OBJECT_NULL)
                   1942:                return;
                   1943: 
                   1944:        vm_page_lock_queues();
                   1945:        vm_object_lock(object); /* mfs code holds reference */
                   1946: 
                   1947: retry:
                   1948:        m = (vm_page_t) queue_first(&object->memq);
                   1949:        while (!queue_end(&object->memq, (queue_entry_t) m)) {
                   1950:                /* We don't want to deadlock on the page we are bring in */
                   1951:                if (m->nfspagereq == FALSE){
                   1952:                        if (m->busy) {
                   1953: #if SCRUBVM3
                   1954:                                /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC
                   1955:                                 * on SWAP */
                   1956:                                /* hint if we miss it its ok */
                   1957:                                if (m->dry_vp){
                   1958:                                        /* object and page queues locked, note
                   1959:                                         * page might not be clean wrt backing
                   1960:                                         * store */     
                   1961:                                        (void) vm_page_completeio(m, TRUE);
                   1962:                                } else {
                   1963: #endif
                   1964:                                        PAGE_ASSERT_WAIT(m, FALSE);
                   1965:                                        vm_object_unlock(object);
                   1966:                                        vm_page_unlock_queues();
                   1967:                                        thread_block();
                   1968:                                        vm_page_lock_queues();
                   1969:                                        vm_object_lock(object);
                   1970:                                        /* Page may be long gone, XXX Forward 
                   1971:                                         * progress */
                   1972:                                        goto retry;     
                   1973: #if SCRUBVM3
                   1974:                                }
                   1975: #endif
                   1976:                        }
                   1977:                        if (!m->active) {
                   1978:                                vm_page_activate(m); /* so deactivate works */
                   1979:                        }
                   1980:                        vm_page_deactivate(m);  /* gets dirty/laundry bit */
                   1981:                        /*
                   1982:                         *      Prevent pageout from playing with
                   1983:                         *      this page.  We know it is inactive right
                   1984:                         *      now (and are holding lots of locks keeping
                   1985:                         *      it there).
                   1986:                         */
                   1987:                        queue_remove(&vm_page_queue_inactive, m, vm_page_t,
                   1988:                                     pageq);
                   1989:                        m->inactive = FALSE;
                   1990:                        vm_page_inactive_count--;
                   1991:                        m->busy = TRUE;
                   1992:                        if (m->laundry) {
                   1993:                                pager_return_t  ret;
                   1994: 
                   1995:                                pmap_remove_all(VM_PAGE_TO_PHYS(m));
                   1996:                                object->paging_in_progress++;
                   1997:                                vm_object_unlock(object);
                   1998:                                vm_page_unlock_queues();
                   1999:                                /* should call pageout daemon code */
                   2000:                                ret = vnode_pageout(m);
                   2001:                                vm_page_lock_queues();
                   2002:                                vm_object_lock(object);
                   2003:                                object->paging_in_progress--;
                   2004:                                if (ret == PAGER_SUCCESS) {
                   2005:                                        /* vnode_pageout marks clean */
                   2006:                                        m->laundry = FALSE;
                   2007:                                } else {
                   2008:                                        /* don't set dirty bit, unrecoverable
                   2009:                                           errors will cause update to go
                   2010:                                           crazy.  User is responsible for
                   2011:                                           retrying the write */
                   2012:                                        /* vmp->dirty = TRUE; */
                   2013:                                        error = vmp->error;
                   2014:                                        vmp->error=0;
                   2015:                                }
                   2016:                                /* if pager failed, activate below */
                   2017:                        }
                   2018:                        vm_page_activate(m);
                   2019:                        m->busy = FALSE;
                   2020:                        PAGE_WAKEUP(m);
                   2021:                }
                   2022:                m = (vm_page_t) queue_next(&m->listq);
                   2023:        }
                   2024:        vmp->nfsdirty = FALSE;
                   2025:        vm_object_unlock(object);
                   2026:        vm_page_unlock_queues();
                   2027: 
                   2028:        /*
                   2029:         * On error we have to reset the true file size in the vmp
                   2030:         * structure.  The lack of a credential structure pointer
                   2031:         * would indicate nothing was changing in the file.
                   2032:         */
                   2033:        if (error && vmp->cred) {
                   2034:          vmp->filesize=TRUE;
                   2035:          VOP_GETATTR (vmp->vnode, &vattr, vmp->cred, current_proc());
                   2036:          vmp->filesize=FALSE;
                   2037:          vmp->vnode_size = vattr.va_size;
                   2038:        }
                   2039: }
                   2040: #endif
                   2041: 
                   2042: 
                   2043: vm_size_t vm_get_vnode_size(struct vnode *vp) 
                   2044: {
                   2045:        return(vp->v_vm_info->vnode_size);
                   2046: }
                   2047: 
                   2048: void vm_set_vnode_size(struct vnode *vp, vm_size_t vnode_size) 
                   2049: {
                   2050:        vp->v_vm_info->vnode_size = vnode_size;
                   2051: }
                   2052: 
                   2053: void vm_set_close_flush(struct vnode *vp, boolean_t close_flush)
                   2054: {
                   2055:        vp->v_vm_info->close_flush = close_flush ? 1 : 0;
                   2056: }
                   2057: 
                   2058: void vm_set_error(struct vnode *vp, int error)
                   2059: {
                   2060:        vp->v_vm_info->error = error;
                   2061: }
                   2062: #endif /* MACH_NBC  ] */

unix.superglobalmegacorp.com

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