Annotation of kernel/kern/mapfs.c, revision 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.