Annotation of kernel/bsd/hfs/hfs_readwrite.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:  * Copyright (c) 1993
        !            26:  *     The Regents of the University of California.  All rights reserved.
        !            27:  *
        !            28:  * Redistribution and use in source and binary forms, with or without
        !            29:  * modification, are permitted provided that the following conditions
        !            30:  * are met:
        !            31:  * 1. Redistributions of source code must retain the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer.
        !            33:  * 2. Redistributions in binary form must reproduce the above copyright
        !            34:  *    notice, this list of conditions and the following disclaimer in the
        !            35:  *    documentation and/or other materials provided with the distribution.
        !            36:  * 3. All advertising materials mentioning features or use of this software
        !            37:  *    must display the following acknowledgement:
        !            38:  *     This product includes software developed by the University of
        !            39:  *     California, Berkeley and its contributors.
        !            40:  * 4. Neither the name of the University nor the names of its contributors
        !            41:  *    may be used to endorse or promote products derived from this software
        !            42:  *    without specific prior written permission.
        !            43:  *
        !            44:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            45:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            46:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            47:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            48:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            49:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            50:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            51:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            52:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            53:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            54:  * SUCH DAMAGE.
        !            55:  *
        !            56:  *     @(#)hfs_readwrite.c     1.0
        !            57:  *     derived from @(#)ufs_readwrite.c        8.11 (Berkeley) 5/8/95
        !            58:  *
        !            59:  *     (c) 1998       Apple Computer, Inc.  All Rights Reserved
        !            60:  *     (c) 1990, 1992 NeXT Computer, Inc.  All Rights Reserved
        !            61:  *     
        !            62:  *
        !            63:  *     hfs_readwrite.c -- vnode operations to deal with reading and writing files.
        !            64:  *
        !            65:  *     MODIFICATION HISTORY:
        !            66:  *      3-Feb-1999     Pat Dirks               Merged in Joe's change to hfs_truncate to skip vinvalbuf if LEOF isn't changing (#2302796)
        !            67:  *                                                             Removed superfluous (and potentially dangerous) second call to vinvalbuf() in hfs_truncate.
        !            68:  *      2-Dec-1998     Pat Dirks               Added support for read/write bootstrap ioctls.
        !            69:  *     10-Nov-1998     Pat Dirks               Changed read/write/truncate logic to optimize block sizes for first extents of a file.
        !            70:  *                              Changed hfs_strategy to correct I/O sizes from cluser code I/O requests in light of
        !            71:  *                              different block sizing.  Changed bexpand to handle RELEASE_BUFFER flag.
        !            72:  *     22-Sep-1998     Don Brady               Changed truncate zero-fill to use bwrite after several bawrites have been queued.
        !            73:  *     11-Sep-1998     Pat Dirks               Fixed buffering logic to not rely on B_CACHE, which is set for empty buffers that
        !            74:  *                                                             have been pre-read by cluster_read (use b_validend > 0 instead).
        !            75:  *  27-Aug-1998        Pat Dirks               Changed hfs_truncate to use cluster_write in place of bawrite where possible.
        !            76:  *     25-Aug-1998     Pat Dirks               Changed hfs_write to do small device-block aligned writes into buffers without doing
        !            77:  *                                                             read-ahead of the buffer.  Added bexpand to deal with incomplete [dirty] buffers.
        !            78:  *                                                             Fixed can_cluster macro to use MAXPHYSIO instead of MAXBSIZE.
        !            79:  *     19-Aug-1998     Don Brady               Remove optimization in hfs_truncate that prevented extra physical blocks from
        !            80:  *                                                             being truncated (radar #2265750). Also set fcb->fcbEOF before calling vinvalbuf.
        !            81:  *      7-Jul-1998     Pat Dirks               Added code to honor IO_NOZEROFILL in hfs_truncate.
        !            82:  *     16-Jul-1998     Don Brady               In hfs_bmap use MAXPHYSIO instead of MAXBSIZE when calling MapFileBlockC (radar #2263753).
        !            83:  *     16-Jul-1998     Don Brady               Fix error handling in hfs_allocate (radar #2252265).
        !            84:  *     04-Jul-1998     chw                             Synchronized options in hfs_allocate with flags in call to ExtendFileC
        !            85:  *     25-Jun-1998     Don Brady               Add missing blockNo incrementing to zero fill loop in hfs_truncate.
        !            86:  *     22-Jun-1998     Don Brady               Add bp = NULL assignment after brelse in hfs_read.
        !            87:  *      4-Jun-1998     Pat Dirks               Split off from hfs_vnodeops.c
        !            88:  */
        !            89: 
        !            90: #include <sys/param.h>
        !            91: #include <sys/systm.h>
        !            92: #include <sys/resourcevar.h>
        !            93: #include <sys/kernel.h>
        !            94: #include <sys/file.h>
        !            95: #include <sys/stat.h>
        !            96: #include <sys/buf.h>
        !            97: #include <sys/proc.h>
        !            98: #include <sys/conf.h>
        !            99: #include <sys/mount.h>
        !           100: #include <mach/machine/vm_types.h>
        !           101: #include <sys/vnode.h>
        !           102: //#include <sys/vnode_if.h>
        !           103: #include <sys/malloc.h>
        !           104: #include <sys/namei.h>
        !           105: #include <sys/signalvar.h>
        !           106: #include <sys/uio.h>
        !           107: #include <sys/time.h>
        !           108: #include <sys/attr.h>
        !           109: #include <miscfs/specfs/specdev.h>
        !           110: 
        !           111: 
        !           112: #include <sys/vm.h>
        !           113: #include <libkern/libkern.h>
        !           114: #include <mach/machine/simple_lock.h>
        !           115: #include <machine/spl.h>
        !           116: #include <mach/features.h>
        !           117: #if MACH_NBC
        !           118: #include <kern/mapfs.h>
        !           119: #endif /* MACH_NBC */
        !           120: 
        !           121: #include       "hfs.h"
        !           122: #include       "hfs_dbg.h"
        !           123: #include       "hfscommon/headers/FileMgrInternal.h"
        !           124: #include       "hfscommon/headers/CatalogPrivate.h"
        !           125: 
        !           126: #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
        !           127: 
        !           128: enum {
        !           129:        MAXHFSFILESIZE = 0x7FFFFFFF             /* this needs to go in the mount structure */
        !           130: };
        !           131: 
        !           132: extern void vnode_pager_setsize( struct vnode *vp, u_long nsize);
        !           133: extern int vnode_uncache( struct vnode *vp);
        !           134: 
        !           135: /*
        !           136:  * Enabling cluster read/write operations.
        !           137:  */
        !           138: extern int doclusterread;
        !           139: extern int doclusterwrite;
        !           140: 
        !           141: #if DBG_VOP_TEST_LOCKS
        !           142: extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, char *funcname);
        !           143: #endif
        !           144: 
        !           145: int bexpand(struct buf *bp, int newsize, struct buf **nbpp, long flags);
        !           146: 
        !           147: #if DIAGNOSTIC
        !           148: void debug_check_blocksizes(struct vnode *vp);
        !           149: #endif
        !           150: 
        !           151: /*****************************************************************************
        !           152: *
        !           153: *      Operations on vnodes
        !           154: *
        !           155: *****************************************************************************/
        !           156: 
        !           157: /*
        !           158: #% read                vp      L L L
        !           159: #
        !           160:  vop_read {
        !           161:      IN struct vnode *vp;
        !           162:      INOUT struct uio *uio;
        !           163:      IN int ioflag;
        !           164:      IN struct ucred *cred;
        !           165: 
        !           166:      */
        !           167: 
        !           168: int
        !           169: hfs_read(ap)
        !           170: struct vop_read_args /* {
        !           171:     struct vnode *a_vp;
        !           172:     struct uio *a_uio;
        !           173:     int a_ioflag;
        !           174:     struct ucred *a_cred;
        !           175: } */ *ap;
        !           176: {
        !           177:     register struct vnode      *vp;
        !           178:     struct hfsnode                     *hp;
        !           179:     register struct uio        *uio;
        !           180:     struct buf                                 *bp;
        !           181:     daddr_t                            logBlockNo;
        !           182:        u_long                                  fragSize, moveSize, startOffset, ioxfersize;
        !           183:     long                                       devBlockSize = 0;
        !           184:     off_t                                      bytesRemaining;
        !           185:     int                                        retval;
        !           186:     u_short                            mode;
        !           187:        FCB                                             *fcb;
        !           188:     Boolean                            firstpass;              /* Used for cluster reading */
        !           189:     int                                        seq;                    /* Also used for cluster reading */
        !           190: 
        !           191:     DBG_FUNC_NAME("hfs_read");
        !           192:     DBG_VOP_LOCKS_DECL(1);
        !           193:     DBG_VOP_PRINT_FUNCNAME();
        !           194:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           195:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !           196: 
        !           197:     vp = ap->a_vp;
        !           198:     hp = VTOH(vp);
        !           199:     fcb = HTOFCB(hp);
        !           200:     mode = hp->h_meta->h_mode;
        !           201:     uio = ap->a_uio;
        !           202: 
        !           203: #if DIAGNOSTIC
        !           204:     if (uio->uio_rw != UIO_READ)
        !           205:         panic("%s: mode", funcname);
        !           206: #endif
        !           207: 
        !           208:     /* Can only read files */
        !           209:     if (ap->a_vp->v_type != VREG && ap->a_vp->v_type != VLNK) {                
        !           210:         DBG_VOP_LOCKS_TEST(EISDIR);
        !           211:         return (EISDIR);
        !           212:     }
        !           213:     DBG_VOP(("\tfile size Ox%lX\n", (UInt32)fcb->fcbEOF));
        !           214:     DBG_VOP(("\tstarting at offset Ox%X of file, length Ox%X\n", (u_int)uio->uio_offset, (u_int)uio->uio_resid));
        !           215: 
        !           216: #if DIAGNOSTIC
        !           217:     debug_check_blocksizes(vp);
        !           218: #endif
        !           219: 
        !           220:     /*
        !           221:      * If they didn't ask for any data, then we are done.
        !           222:      */
        !           223:     if (uio->uio_resid == 0) {
        !           224:         DBG_VOP_LOCKS_TEST(E_NONE);
        !           225:         return (E_NONE);
        !           226:     }
        !           227: 
        !           228:     /* cant read from a negative offset */
        !           229:     if (uio->uio_offset < 0) {
        !           230:         DBG_VOP_LOCKS_TEST(EINVAL);
        !           231:         return (EINVAL);
        !           232:     }
        !           233: 
        !           234:        if ((u_int64_t)uio->uio_offset > (u_int64_t)fcb->fcbEOF) {
        !           235:                if ((u_int64_t)uio->uio_offset > (u_int64_t)MAXHFSFILESIZE)
        !           236:                        retval = EFBIG;
        !           237:                else
        !           238:                retval = E_NONE;
        !           239: 
        !           240:                DBG_VOP_LOCKS_TEST(retval);
        !           241:                return (retval);
        !           242:        }
        !           243: 
        !           244:     VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize);
        !           245: 
        !           246:     for (retval = 0, bp = NULL, firstpass = TRUE; uio->uio_resid > 0; bp = NULL) {
        !           247: 
        !           248:         if ((bytesRemaining = (fcb->fcbEOF - uio->uio_offset)) <= 0)
        !           249:             break;
        !           250: 
        !           251:         MapFileOffset(hp, uio->uio_offset, &logBlockNo, &fragSize, &startOffset);
        !           252: 
        !           253:         DBG_VOP(("\tat logBlockNo Ox%X, with Ox%lX left to read\n", logBlockNo, (UInt32)uio->uio_resid));
        !           254:         moveSize = ioxfersize = fragSize;
        !           255:         DBG_VOP(("\tmoveSize = Ox%lX; ioxfersize = Ox%lX; startOffset = Ox%lX.\n",
        !           256:                                        moveSize, ioxfersize, startOffset));
        !           257:         DBG_ASSERT(moveSize >= startOffset);
        !           258:         moveSize -= startOffset;
        !           259:         if (bytesRemaining < moveSize) moveSize = bytesRemaining;
        !           260:         
        !           261:         if (uio->uio_resid < moveSize) {
        !           262:                moveSize = uio->uio_resid;
        !           263:             DBG_VOP(("\treducing moveSize to Ox%lX (uio->uio_resid).\n", moveSize)); 
        !           264:         };
        !           265: 
        !           266:         if (moveSize == 0) {
        !           267:             break;
        !           268:         };
        !           269:         DBG_VOP(("\tat logBlockNo Ox%X, extent of Ox%lX, xfer of Ox%lX; moveSize = Ox%lX\n", logBlockNo, fragSize, ioxfersize, moveSize));
        !           270:         if (( uio->uio_offset + fragSize) >= fcb->fcbEOF) {
        !           271:             retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
        !           272:         } else if (doclusterread && !(vp->v_flag & VRAOFF) && can_cluster(fragSize)) {
        !           273:             retval = cluster_read(vp, fcb->fcbEOF, logBlockNo, ioxfersize, NOCRED, &bp,
        !           274:                                                   devBlockSize, firstpass, (uio->uio_resid + startOffset), &seq);
        !           275:         } else if (logBlockNo - 1 == vp->v_lastr && !(vp->v_flag & VRAOFF)) {
        !           276:             daddr_t nextLogBlockNo = logBlockNo + 1;
        !           277:             long nextsize;
        !           278:             int nextsize_for_bsd;
        !           279:             long nextblkoffset;
        !           280: 
        !           281:             MapFileOffset(hp, uio->uio_offset + fragSize, &nextLogBlockNo, &nextsize, &nextblkoffset);
        !           282:             /* Yuck!  This copy exists just because I refuse to write the interface to MapFileOffset relying on 'int' to be 'long'... */
        !           283:             nextsize_for_bsd = nextsize;
        !           284:             retval = breadn(vp, logBlockNo, ioxfersize, &nextLogBlockNo, &nextsize_for_bsd, 1, NOCRED, &bp);
        !           285:         } else {
        !           286:             retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
        !           287:         };
        !           288: 
        !           289:         if (retval != E_NONE) {
        !           290:             if (bp) {
        !           291:                 brelse(bp);
        !           292:                 bp = NULL;
        !           293:             }
        !           294:             break;
        !           295:         };
        !           296: 
        !           297:         firstpass = FALSE;
        !           298: 
        !           299:         if (bp->b_validend > 0) {
        !           300:             /*
        !           301:                b_validoff, b_validend, b_dirtyoff, and b_dirtyend are valid for blocks in the cache:
        !           302:                The only blocks that are incomplete (b_validend < fragSize) are blocks that have been
        !           303:                partially written from the start of the buffer:
        !           304:              */
        !           305:             if (bp->b_validend < bp->b_bcount) {
        !           306:                 DBG_ASSERT((bp->b_dirtyoff == 0) && (bp->b_validoff == 0) && (bp->b_dirtyend <= bp->b_validend));
        !           307:                 /* Incomplete blocks must have only device-block multiples of data... */
        !           308:                 DBG_ASSERT((bp->b_validend % devBlockSize) == 0);
        !           309:                 bp->b_bcount = bp->b_validend;
        !           310: 
        !           311:                 if (bp->b_validend < (startOffset + moveSize)) {               /* buffer doesn't hold enough valid data for this read request */
        !           312:                     /* We stumbled onto an incomplete [but successfully acquired] buffer:
        !           313:                        try to get the full contents now because it's the only way to get
        !           314:                        the data in this logical block...
        !           315:                      */
        !           316:                     retval = bexpand(bp, ioxfersize, &bp, 0);
        !           317:                 };
        !           318:             };
        !           319:         } else {
        !           320:             /* This block was newly allocated; b_validoff, b_validend, b_dirtyoff, and b_dirtyend are
        !           321:                all set to zero, which is fine except for b_validend: */
        !           322:             DBG_ASSERT(bp->b_validoff == 0);
        !           323:             bp->b_validend = bp->b_bcount;
        !           324:             DBG_ASSERT(bp->b_dirtyoff == 0);
        !           325:             DBG_ASSERT(bp->b_dirtyend == 0);
        !           326:         };
        !           327:        
        !           328:         vp->v_lastr = logBlockNo;
        !           329: 
        !           330:         /*
        !           331:          * We should only get non-zero b_resid when an I/O retval
        !           332:          * has occurred, which should cause us to break above.
        !           333:          * However, if the short read did not cause an retval,
        !           334:          * then we want to ensure that we do not uiomove bad
        !           335:          * or uninitialized data.
        !           336:          */
        !           337:         ioxfersize -= bp->b_resid;
        !           338:         if (ioxfersize < moveSize) {                   /* XXX PPD This should take the offset into account, too! */
        !           339:             if (ioxfersize == 0)
        !           340:                 break;
        !           341:             moveSize = ioxfersize;
        !           342:         }
        !           343: 
        !           344:         DBG_VOP(("\tcopying Ox%lX bytes from %p; resid = Ox%lX...\n", moveSize, (char *)bp->b_data + startOffset, bp->b_resid));
        !           345:         if ((retval =
        !           346:              uiomove((caddr_t)bp->b_data + startOffset, (int)moveSize, uio)))
        !           347:             break;
        !           348: 
        !           349:         if (S_ISREG(mode) &&
        !           350:             (((startOffset + moveSize) == fragSize) || (uio->uio_offset == fcb->fcbEOF))) {
        !           351:             bp->b_flags |= B_AGE;
        !           352:         };
        !           353: 
        !           354:         DBG_ASSERT(bp->b_bcount == bp->b_validend);
        !           355:         brelse(bp);
        !           356:         /* Start of loop resets bp to NULL before reaching outside this block... */
        !           357:     }
        !           358: 
        !           359:     if (bp != NULL) {
        !           360:         DBG_ASSERT(bp->b_bcount == bp->b_validend);
        !           361:         brelse(bp);
        !           362:     };
        !           363:        if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord)
        !           364:        hp->h_meta->h_nodeflags |= IN_ACCESS;
        !           365: 
        !           366:     DBG_VOP_LOCKS_TEST(retval);
        !           367: 
        !           368: #if DIAGNOSTIC
        !           369:     debug_check_blocksizes(vp);
        !           370: #endif
        !           371: 
        !           372:     return (retval);
        !           373: }
        !           374: 
        !           375: /*
        !           376:  * Write data to a file or directory.
        !           377: #% write       vp      L L L
        !           378: #
        !           379:  vop_write {
        !           380:      IN struct vnode *vp;
        !           381:      INOUT struct uio *uio;
        !           382:      IN int ioflag;
        !           383:      IN struct ucred *cred;
        !           384: 
        !           385:      */
        !           386: int
        !           387: hfs_write(ap)
        !           388: struct vop_write_args /* {
        !           389:     struct vnode *a_vp;
        !           390:     struct uio *a_uio;
        !           391:     int a_ioflag;
        !           392:     struct ucred *a_cred;
        !           393: } */ *ap;
        !           394: {
        !           395:     struct hfsnode             *hp = VTOH(ap->a_vp);
        !           396:     struct uio                         *uio = ap->a_uio;
        !           397:     struct vnode               *vp = ap->a_vp ;
        !           398:     struct vnode               *dev;
        !           399:     struct buf                         *bp;
        !           400:     struct proc                *p, *cp;
        !           401:     FCB                                        *fcb = HTOFCB(hp);
        !           402:     ExtendedVCB                        *vcb = HTOVCB(hp);
        !           403:     long                               devBlockSize = 0;
        !           404:     daddr_t                    logBlockNo;
        !           405:     long                               fragSize;
        !           406:     off_t                              origFileSize, currOffset, writelimit, bytesToAdd;
        !           407:     u_long                             blkoffset, resid, xfersize, clearSize;                          
        !           408:     UInt32                             actualBytesAdded;
        !           409:     int                                        flags, ioflag;
        !           410:     int                                retval;
        !           411:     DBG_FUNC_NAME("write");
        !           412:     DBG_VOP_LOCKS_DECL(1);
        !           413:     DBG_VOP_PRINT_FUNCNAME();
        !           414:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           415:     DBG_VOP(("\thfsnode 0x%x (%s)\n", (u_int)hp, H_NAME(hp)));
        !           416:     DBG_VOP(("\tstarting at offset Ox%lX of file, length Ox%lX\n", (UInt32)uio->uio_offset, (UInt32)uio->uio_resid));
        !           417: 
        !           418:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !           419: 
        !           420:     dev = hp->h_devvp;
        !           421: 
        !           422: #if DIAGNOSTIC
        !           423:     debug_check_blocksizes(vp);
        !           424: #endif
        !           425: 
        !           426:     if (uio->uio_offset < 0) {
        !           427:         DBG_VOP_LOCKS_TEST(EINVAL);
        !           428:         return (EINVAL);
        !           429:     }
        !           430: 
        !           431:     if (uio->uio_resid == 0) {
        !           432:         DBG_VOP_LOCKS_TEST(E_NONE);
        !           433:         return (E_NONE);
        !           434:     }
        !           435: 
        !           436:     if (ap->a_vp->v_type != VREG && ap->a_vp->v_type != VLNK) {                /* Can only write files */
        !           437:         DBG_VOP_LOCKS_TEST(EISDIR);
        !           438:         return (EISDIR);
        !           439:     };
        !           440: 
        !           441:        (void)vnode_uncache(vp);                        /* XXX PPD Is this the right place to call this?  It'll VOP_UNLOCK the vnode */
        !           442: 
        !           443: #if DIAGNOSTIC
        !           444:     if (uio->uio_rw != UIO_WRITE)
        !           445:        panic("%s: mode", funcname);
        !           446: #endif
        !           447: 
        !           448:     ioflag = ap->a_ioflag;
        !           449:     uio = ap->a_uio;
        !           450:     vp = ap->a_vp;
        !           451: 
        !           452:     if (ioflag & IO_APPEND)
        !           453:        uio->uio_offset = fcb->fcbEOF;
        !           454:     if ((hp->h_meta->h_pflags & APPEND) && uio->uio_offset != fcb->fcbEOF)
        !           455:        return (EPERM);
        !           456: 
        !           457:     writelimit = uio->uio_offset + uio->uio_resid;
        !           458: 
        !           459:     /*
        !           460:     * Maybe this should be above the vnode op call, but so long as
        !           461:     * file servers have no limits, I don't think it matters.
        !           462:     */
        !           463:     p = uio->uio_procp;
        !           464:     if (vp->v_type == VREG && p &&
        !           465:         writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
        !           466:         psignal(p, SIGXFSZ);
        !           467:         return (EFBIG);
        !           468:     };
        !           469:     VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize);
        !           470: 
        !           471:     resid = uio->uio_resid;
        !           472:     origFileSize = fcb->fcbPLen;
        !           473:     flags = ioflag & IO_SYNC ? B_SYNC : 0;
        !           474: 
        !           475:     DBG_VOP(("\tLEOF is 0x%lX, PEOF is 0x%lX.\n", fcb->fcbEOF, fcb->fcbPLen));
        !           476: 
        !           477:     /*
        !           478:     NOTE:      In the following loop there are two positions tracked:
        !           479:     currOffset is the current I/O starting offset.  currOffset is never >LEOF; the
        !           480:     LEOF is nudged along with currOffset as data is zeroed or written.
        !           481:     uio->uio_offset is the start of the current I/O operation.  It may be arbitrarily
        !           482:     beyond currOffset.
        !           483: 
        !           484:     The following is true at all times:
        !           485: 
        !           486:     currOffset <= LEOF <= uio->uio_offset <= writelimit
        !           487:     */
        !           488:     currOffset = MIN(uio->uio_offset, fcb->fcbEOF);
        !           489: 
        !           490:     DBG_VOP(("\tstarting I/O loop at 0x%lX.\n", (u_long)currOffset));
        !           491: 
        !           492:     cp = CURRENT_PROC;
        !           493: 
        !           494:     for (retval = 0; uio->uio_resid > 0;) {
        !           495:         /* Now test if we need to extend the file */
        !           496:         /* Doing so will adjust the fcbPLen for us */
        !           497:         if (writelimit > (off_t)fcb->fcbPLen) {
        !           498:             /* XXX PPD Allocate only 2GB at a time until ExtendFileC's interface changes... */
        !           499:             bytesToAdd = writelimit - (off_t)fcb->fcbPLen;
        !           500:             if (bytesToAdd > (off_t)0x80000000) bytesToAdd = (off_t)0x80000000;
        !           501:             DBG_VOP(("\textending file by 0x%lX bytes; 0x%lX blocks free", (unsigned long)bytesToAdd, (unsigned long)vcb->vcbFreeBks));
        !           502:             /* lock extents b-tree (also protects volume bitmap) */
        !           503:             retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, cp);
        !           504:             if (retval != E_NONE)
        !           505:                 break;
        !           506: 
        !           507:             retval = MacToVFSError(
        !           508:                                 ExtendFileC (vcb,
        !           509:                                                 fcb,
        !           510:                                                 (unsigned long)bytesToAdd,
        !           511:                                                 kEFContigBit,
        !           512:                                                 &actualBytesAdded));
        !           513: 
        !           514:             (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, cp);
        !           515:             DBG_VOP_CONT(("\tactual bytes added = 0x%lX bytes, retval = %d...\n", actualBytesAdded, retval));
        !           516:             if ((actualBytesAdded == 0) && (retval == 0)) retval = ENOSPC;
        !           517:             if (retval != E_NONE)
        !           518:                 break;
        !           519: 
        !           520:             UpdateBlockMappingTable(hp);
        !           521: 
        !           522:             /* We successfully extended the file: take a fresh look to see how things have changed... */
        !           523:             continue;
        !           524:         };
        !           525: 
        !           526:         /* What block are we starting the write */
        !           527:         MapFileOffset(hp, currOffset, &logBlockNo, &fragSize, &blkoffset);
        !           528: 
        !           529:         xfersize = fragSize - blkoffset;
        !           530: 
        !           531:         DBG_VOP(("\tcurrOffset = Ox%lX, logBlockNo = Ox%X, blkoffset = Ox%lX, xfersize = Ox%lX, fragSize = Ox%lX.\n",
        !           532:                 (unsigned long)currOffset, logBlockNo, blkoffset, xfersize, fragSize));
        !           533: 
        !           534:         /* Make any adjustments for boundary conditions */
        !           535:         if (currOffset + (off_t)xfersize > writelimit) {
        !           536:             xfersize = writelimit - currOffset;
        !           537:             DBG_VOP(("\ttrimming xfersize to 0x%lX to match writelimit (uio_resid)...\n", xfersize));
        !           538:         };
        !           539:         
        !           540:         /*
        !           541:         * There is no need to read into bp if:
        !           542:         * We start on a block boundary and will overwrite the whole block
        !           543:         *
        !           544:         *                                              OR
        !           545:         *
        !           546:         * The transfer starts on a device block boundary and is an even
        !           547:         * multiple of the device block size (in which case we'll write
        !           548:         * through the data presented)
        !           549:         *
        !           550:         */
        !           551:         if ((blkoffset == 0) && ((xfersize >= fragSize) || (xfersize % devBlockSize == 0))) {
        !           552:             DBG_VOP(("\tRequesting %ld-byte block Ox%lX w/o read...\n", fragSize, (long)logBlockNo));
        !           553:             bp = getblk(vp, logBlockNo, fragSize, 0, 0);
        !           554:             retval = 0;
        !           555:             if (bp->b_blkno == -1) {
        !           556:                 brelse(bp);
        !           557:                 retval = EIO;          /* XXX */
        !           558:                 break;
        !           559:             }
        !           560: 
        !           561:                        if (bp->b_flags & (B_DELWRI | B_DONE | B_CACHE)) {
        !           562:                                /*
        !           563:                    This buffer is fully pre-read and may already have some modified data in it:
        !           564:                                   it doesn't need special-casing for write-through.
        !           565:                  */
        !           566:                        } else {
        !           567:                                /* This is an empty buffer just allocated for our use:
        !           568:                    b_validoff, b_validend, b_dirtyoff, and b_dirtyend are all zero,
        !           569:                    which is exactly right (b_bcount is set to fragSize). */
        !           570:                                
        !           571:                                /* XXX PPD Can't this be skipped if b_blkno != logBlockNo? */
        !           572:                                
        !           573:                 /* Setting up the physical block number is required
        !           574:                    (1) to keep cluster_write informed about which blocks can be clustered, and
        !           575:                    (2) to avoid a second call to bmap() in strategy() on the write.
        !           576:                  */
        !           577:                 if ((retval = VOP_BMAP(vp, logBlockNo, NULL, &bp->b_blkno, NULL))) {
        !           578:                     brelse(bp);
        !           579:                     break;
        !           580:                 };
        !           581: 
        !           582:                 bp->b_bcount = 0;              /* No valid data in block yet */
        !           583:                 bp->b_validend = 0;            /* No valid data in block yet */
        !           584:             };
        !           585:         } else {
        !           586:             /*
        !           587:             * This I/O transfer is not sufficiently aligned, so read the affected block into a buffer:
        !           588:             */
        !           589:             DBG_VOP(("\tRequesting block Ox%X, size = 0x%08lX...\n", logBlockNo, fragSize));
        !           590:             retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp);
        !           591:             if (retval != E_NONE) {
        !           592:                 if (bp) brelse(bp);
        !           593:                 break;
        !           594:             }
        !           595:         }
        !           596:         
        !           597:         /* Fix up the anciliary fields for this buffer, depending on whether they've been initialized yet: */
        !           598:         if (bp->b_validend > 0) {
        !           599:             /*
        !           600:                b_validoff, b_validend, b_dirtyoff, and b_dirtyend are valid for blocks in the cache:
        !           601:                The only blocks that are incomplete (b_validend < fragSize) are blocks that have been
        !           602:                partially written from the start of the buffer:
        !           603:              */
        !           604:             if (bp->b_validend < bp->b_bcount) {
        !           605:                 DBG_ASSERT((bp->b_dirtyoff == 0) && (bp->b_validoff == 0) && (bp->b_dirtyend <= bp->b_validend));
        !           606:                 /* Incomplete blocks must have only device-block multiples of data... */
        !           607:                 DBG_ASSERT((bp->b_validend % devBlockSize) == 0);
        !           608:                 bp->b_bcount = bp->b_validend;
        !           609: 
        !           610:                 if ((bp->b_validend < blkoffset) ||            /* ... valid data does not overlap (or at least abut) start of new write */
        !           611:                     (bp->b_bufsize < (blkoffset + xfersize)) ||                /* ... or isn't enough buffer space to hold entire transfer */
        !           612:                     ((blkoffset + xfersize) % devBlockSize != 0)) {    /* ... or won't leave blocksize-multiple of dirty bytes */
        !           613:                     /* We stumbled onto an incomplete [but successfully acquired] buffer:
        !           614:                        try to get the full contents now because it's the only way to get
        !           615:                        the data in this logical block...
        !           616:                      */
        !           617:                     retval = bexpand(bp, fragSize, &bp, 0);
        !           618:                 };
        !           619:             };
        !           620:         } else {
        !           621:             /* This buffer was either just allocated or just read in its entirity [see b_bcount]:
        !           622:                b_validoff, b_validend, b_dirtyoff, and b_dirtyend are all zeroed, which is almost correct. */
        !           623:             DBG_ASSERT(bp->b_validoff == 0);
        !           624:             bp->b_validend = bp->b_bcount;     /* b_bcount > 0 iff block was actually read from disk in bread */
        !           625:             DBG_ASSERT(bp->b_dirtyoff == 0);
        !           626:             DBG_ASSERT(bp->b_dirtyend == 0);
        !           627:         };
        !           628: 
        !           629:         /* See if we are starting to write within file boundaries:
        !           630:             If not, then we need to present a "hole" for the area between
        !           631:             the current EOF and the start of the current I/O operation:
        !           632: 
        !           633:             Note that currOffset is only less than uio_offset if uio_offset > LEOF...
        !           634:             */
        !           635:         if (uio->uio_offset > currOffset) {
        !           636:             clearSize = MIN(uio->uio_offset - currOffset, xfersize);
        !           637:             DBG_VOP(("\tzeroing Ox%lX bytes Ox%lX bytes into block Ox%X...\n", clearSize, blkoffset, logBlockNo));
        !           638:             bzero(bp->b_data + blkoffset, clearSize);
        !           639:             currOffset += clearSize;
        !           640:             blkoffset += clearSize;
        !           641:             xfersize -= clearSize;
        !           642:         };
        !           643: 
        !           644:         if (xfersize > 0) {
        !           645:             DBG_VOP(("\tCopying Ox%lX bytes Ox%lX bytes into block Ox%X... ioflag == 0x%X\n",
        !           646:                      xfersize, blkoffset, logBlockNo, ioflag));
        !           647:             retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio);
        !           648:             currOffset += xfersize;
        !           649:         };
        !           650: 
        !           651:         if (blkoffset + xfersize > bp->b_dirtyend) bp->b_dirtyend = blkoffset + xfersize;      /* Newly written data is now [also] dirty */
        !           652:         if (bp->b_dirtyend > bp->b_validend) bp->b_validend = bp->b_dirtyend;                          /* Data just written is now valid, too */
        !           653:         bp->b_bcount = bp->b_validend;
        !           654: 
        !           655:         DBG_ASSERT((bp->b_bcount % devBlockSize) == 0);
        !           656:         DBG_ASSERT(bp->b_bcount == bp->b_validend);
        !           657:         if (ioflag & IO_SYNC) {
        !           658:             (void)bwrite(bp);
        !           659:             //DBG_VOP(("\tissuing bwrite\n"));
        !           660:         } else if ((xfersize + blkoffset) == fragSize) {
        !           661:             if (doclusterwrite && can_cluster(fragSize)) {
        !           662:                 //DBG_VOP(("\tissuing cluster_write\n"));
        !           663:                 cluster_write(bp, fcb->fcbPLen, devBlockSize);
        !           664:             } else {
        !           665:                 //DBG_VOP(("\tissuing bawrite\n"));
        !           666:                 bp->b_flags |= B_AGE;
        !           667:                 bawrite(bp);
        !           668:             }
        !           669:         } else {
        !           670:             //DBG_VOP(("\tissuing bdwrite\n"));
        !           671:             bdwrite(bp);
        !           672:         };
        !           673: 
        !           674:         /* Update the EOF if we just extended the file
        !           675:            (the PEOF has already been moved out and the block mapping table has been updated): */
        !           676:         if (currOffset > fcb->fcbEOF) {
        !           677:             DBG_VOP(("\textending EOF to 0x%lX...\n", fcb->fcbEOF));
        !           678:         fcb->fcbEOF = currOffset;
        !           679: #if MACH_NBC
        !           680:             if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
        !           681: #endif /* MACH_NBC */
        !           682:             vnode_pager_setsize(vp, (u_long)fcb->fcbEOF);
        !           683: #if MACH_NBC
        !           684:             }
        !           685: #endif /* MACH_NBC */
        !           686:         };
        !           687: 
        !           688:         if (retval || (resid == 0))
        !           689:             break;
        !           690:         hp->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !           691:     };
        !           692:     /*
        !           693:     * If we successfully wrote any data, and we are not the superuser
        !           694:     * we clear the setuid and setgid bits as a precaution against
        !           695:     * tampering.
        !           696:     */
        !           697:     if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
        !           698:        hp->h_meta->h_mode &= ~(ISUID | ISGID);
        !           699:     if (retval) {
        !           700:         if (ioflag & IO_UNIT) {
        !           701:             (void)VOP_TRUNCATE(vp, origFileSize,
        !           702:                             ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
        !           703:             uio->uio_offset -= resid - uio->uio_resid;
        !           704:             uio->uio_resid = resid;
        !           705:         }
        !           706:     } else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
        !           707:        retval = VOP_UPDATE(vp, &time, &time, 1);
        !           708:     
        !           709: #if DIAGNOSTIC
        !           710:     debug_check_blocksizes(vp);
        !           711: #endif
        !           712: 
        !           713:     DBG_VOP_LOCKS_TEST(retval);
        !           714:     return (retval);
        !           715: }
        !           716: 
        !           717: 
        !           718: /*
        !           719: 
        !           720: #% ioctl       vp      U U U
        !           721: #
        !           722:  vop_ioctl {
        !           723:      IN struct vnode *vp;
        !           724:      IN u_long command;
        !           725:      IN caddr_t data;
        !           726:      IN int fflag;
        !           727:      IN struct ucred *cred;
        !           728:      IN struct proc *p;
        !           729: 
        !           730:      */
        !           731: 
        !           732: 
        !           733: /* ARGSUSED */
        !           734: int
        !           735: hfs_ioctl(ap)
        !           736: struct vop_ioctl_args /* {
        !           737:     struct vnode *a_vp;
        !           738:     int  a_command;
        !           739:     caddr_t  a_data;
        !           740:     int  a_fflag;
        !           741:     struct ucred *a_cred;
        !           742:     struct proc *a_p;
        !           743: } */ *ap;
        !           744: {
        !           745:     DBG_FUNC_NAME("ioctl");
        !           746:     DBG_VOP_LOCKS_DECL(1);
        !           747:     DBG_VOP_PRINT_FUNCNAME();
        !           748:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           749: 
        !           750:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
        !           751: 
        !           752:     switch (ap->a_command) {
        !           753:        
        !           754:     case 1:
        !           755:     {   register struct hfsnode *hp;
        !           756:         register struct vnode *vp;
        !           757:        register struct radvisory *ra;
        !           758:        FCB *fcb;
        !           759:        int devBlockSize = 0;
        !           760:        int error;
        !           761:        long size;
        !           762:        daddr_t lbn;
        !           763: 
        !           764:        vp = ap->a_vp;
        !           765: 
        !           766:        VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
        !           767:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
        !           768: 
        !           769:        ra = (struct radvisory *)(ap->a_data);
        !           770:        hp = VTOH(vp);
        !           771: 
        !           772:        fcb = HTOFCB(hp);
        !           773: 
        !           774:        if ((u_int64_t)ra->ra_offset >= (u_int64_t)fcb->fcbEOF) {
        !           775:            VOP_UNLOCK(vp, 0, ap->a_p);
        !           776:            DBG_VOP_LOCKS_TEST(EFBIG);
        !           777:            return (EFBIG);
        !           778:        }
        !           779:        VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize);
        !           780:        size = hp->h_meta->h_logBlockSize;
        !           781: 
        !           782:        if ( !(can_cluster(size))) {
        !           783:            VOP_UNLOCK(vp, 0, ap->a_p);
        !           784:            DBG_VOP_LOCKS_TEST(EINVAL);
        !           785:            return (EINVAL);
        !           786:        }
        !           787:        size = MIN(size, MAXBSIZE);
        !           788:        lbn = ra->ra_offset / size;
        !           789: 
        !           790:        error = advisory_read(vp, fcb->fcbEOF, lbn, size, size, ra->ra_count, devBlockSize);
        !           791:        VOP_UNLOCK(vp, 0, ap->a_p);
        !           792: 
        !           793:        DBG_VOP_LOCKS_TEST(error);
        !           794:        return (error);
        !           795:     }
        !           796: 
        !           797:     case 2: /* F_READBOOTBLOCKS */
        !           798:     case 3: /* F_WRITEBOOTBLOCKS */
        !           799:       {
        !           800:            struct vnode *vp = ap->a_vp;
        !           801:            struct hfsnode *hp = VTOH(vp);
        !           802:            struct fbootstraptransfer *btd = (struct fbootstraptransfer *)ap->a_data;
        !           803:            u_long devBlockSize;
        !           804:            int error;
        !           805:            struct iovec aiov;
        !           806:            struct uio auio;
        !           807:            u_long blockNumber;
        !           808:            u_long blockOffset;
        !           809:            u_long xfersize;
        !           810:            struct buf *bp;
        !           811: 
        !           812:         if ((vp->v_flag & VROOT) == 0) return EINVAL;
        !           813:         if (btd->fbt_offset + btd->fbt_length > 1024) return EINVAL;
        !           814:            
        !           815:            aiov.iov_base = btd->fbt_buffer;
        !           816:            aiov.iov_len = btd->fbt_length;
        !           817:            
        !           818:            auio.uio_iov = &aiov;
        !           819:            auio.uio_iovcnt = 1;
        !           820:            auio.uio_offset = btd->fbt_offset;
        !           821:            auio.uio_resid = btd->fbt_length;
        !           822:            auio.uio_segflg = UIO_USERSPACE;
        !           823:            auio.uio_rw = (ap->a_command == 3) ? UIO_WRITE : UIO_READ; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
        !           824:            auio.uio_procp = ap->a_p;
        !           825: 
        !           826:            VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize);
        !           827: 
        !           828:            while (auio.uio_resid > 0) {
        !           829:              blockNumber = auio.uio_offset / devBlockSize;
        !           830:              error = bread(hp->h_devvp, blockNumber, devBlockSize, ap->a_cred, &bp);
        !           831:              if (error) {
        !           832:               if (bp) brelse(bp);
        !           833:               return error;
        !           834:           };
        !           835: 
        !           836:           blockOffset = auio.uio_offset % devBlockSize;
        !           837:              xfersize = devBlockSize - blockOffset;
        !           838:              error = uiomove((caddr_t)bp->b_data + blockOffset, (int)xfersize, &auio);
        !           839:           if (error) {
        !           840:               brelse(bp);
        !           841:               return error;
        !           842:           };
        !           843:           if (auio.uio_rw == UIO_WRITE) {
        !           844:               error = bwrite(bp);
        !           845:               if (error) return error;
        !           846:           } else {
        !           847:               brelse(bp);
        !           848:           };
        !           849:         };
        !           850:       };
        !           851:       return 0;
        !           852: 
        !           853:     default:
        !           854:         DBG_VOP_LOCKS_TEST(ENOTTY);
        !           855:         return (ENOTTY);
        !           856:     }
        !           857: 
        !           858:     return 0;
        !           859: }
        !           860: 
        !           861: /* ARGSUSED */
        !           862: int
        !           863: hfs_select(ap)
        !           864: struct vop_select_args /* {
        !           865:     struct vnode *a_vp;
        !           866:     int  a_which;
        !           867:     int  a_fflags;
        !           868:     struct ucred *a_cred;
        !           869:     struct proc *a_p;
        !           870: } */ *ap;
        !           871: {
        !           872:     DBG_FUNC_NAME("select");
        !           873:     DBG_VOP_LOCKS_DECL(1);
        !           874:     DBG_VOP_PRINT_FUNCNAME();
        !           875:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           876: 
        !           877:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !           878: 
        !           879:     /*
        !           880:      * We should really check to see if I/O is possible.
        !           881:      */
        !           882:     DBG_VOP_LOCKS_TEST(1);
        !           883:     return (1);
        !           884: }
        !           885: 
        !           886: 
        !           887: 
        !           888: /*
        !           889:  * Mmap a file
        !           890:  *
        !           891:  * NB Currently unsupported.
        !           892: # XXX - not used
        !           893: #
        !           894:  vop_mmap {
        !           895:      IN struct vnode *vp;
        !           896:      IN int fflags;
        !           897:      IN struct ucred *cred;
        !           898:      IN struct proc *p;
        !           899: 
        !           900:      */
        !           901: 
        !           902: /* ARGSUSED */
        !           903: 
        !           904: int
        !           905: hfs_mmap(ap)
        !           906: struct vop_mmap_args /* {
        !           907:     struct vnode *a_vp;
        !           908:     int  a_fflags;
        !           909:     struct ucred *a_cred;
        !           910:     struct proc *a_p;
        !           911: } */ *ap;
        !           912: {
        !           913:     DBG_FUNC_NAME("mmap");
        !           914:     DBG_VOP_LOCKS_DECL(1);
        !           915:     DBG_VOP_PRINT_FUNCNAME();
        !           916:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           917: 
        !           918:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !           919: 
        !           920:     DBG_VOP_LOCKS_TEST(EINVAL);
        !           921:     return (EINVAL);
        !           922: }
        !           923: 
        !           924: 
        !           925: 
        !           926: /*
        !           927:  * Seek on a file
        !           928:  *
        !           929:  * Nothing to do, so just return.
        !           930: # XXX - not used
        !           931: # Needs work: Is newoff right?  What's it mean?
        !           932: #
        !           933:  vop_seek {
        !           934:      IN struct vnode *vp;
        !           935:      IN off_t oldoff;
        !           936:      IN off_t newoff;
        !           937:      IN struct ucred *cred;
        !           938:      */
        !           939: /* ARGSUSED */
        !           940: int
        !           941: hfs_seek(ap)
        !           942: struct vop_seek_args /* {
        !           943:     struct vnode *a_vp;
        !           944:     off_t  a_oldoff;
        !           945:     off_t  a_newoff;
        !           946:     struct ucred *a_cred;
        !           947: } */ *ap;
        !           948: {
        !           949:     DBG_FUNC_NAME("seek");
        !           950:     DBG_VOP_LOCKS_DECL(1);
        !           951:     DBG_VOP_PRINT_FUNCNAME();
        !           952:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !           953: 
        !           954:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !           955: 
        !           956:     DBG_VOP_LOCKS_TEST(E_NONE);
        !           957:     return (E_NONE);
        !           958: }
        !           959: 
        !           960: 
        !           961: /*
        !           962:  * Bmap converts a the logical block number of a file to its physical block
        !           963:  * number on the disk.
        !           964:  */
        !           965: 
        !           966: /*
        !           967:  * vp  - address of vnode file the file
        !           968:  * bn  - which logical block to convert to a physical block number.
        !           969:  * vpp - returns the vnode for the block special file holding the filesystem
        !           970:  *      containing the file of interest
        !           971:  * bnp - address of where to return the filesystem physical block number
        !           972: #% bmap                vp      L L L
        !           973: #% bmap                vpp     - U -
        !           974: #
        !           975:  vop_bmap {
        !           976:      IN struct vnode *vp;
        !           977:      IN daddr_t bn;
        !           978:      OUT struct vnode **vpp;
        !           979:      IN daddr_t *bnp;
        !           980:      OUT int *runp;
        !           981:      */
        !           982: /*
        !           983:  * Converts a logical block number to a physical block, and optionally returns
        !           984:  * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
        !           985:  * The physical block number is based on the device block size, currently its 512.
        !           986:  * The block run is returned in logical blocks, and is the REMAINING amount of blocks
        !           987:  */
        !           988: 
        !           989: int
        !           990: hfs_bmap(ap)
        !           991: struct vop_bmap_args /* {
        !           992:     struct vnode *a_vp;
        !           993:     daddr_t a_bn;
        !           994:     struct vnode **a_vpp;
        !           995:     daddr_t *a_bnp;
        !           996:     int *a_runp;
        !           997: } */ *ap;
        !           998: {
        !           999:     struct hfsnode             *hp = VTOH(ap->a_vp);
        !          1000:     struct hfsmount    *hfsmp = VTOHFS(ap->a_vp);
        !          1001:     int                                        retval = E_NONE;
        !          1002:     daddr_t                            logBlockSize;
        !          1003:     UInt32                             bytesContAvail = 0;
        !          1004:     struct proc                        *p = NULL;
        !          1005:     int                                        lockExtBtree;
        !          1006: 
        !          1007: #define DEBUG_BMAP 0
        !          1008: #if DEBUG_BMAP
        !          1009:     DBG_FUNC_NAME("bmap");
        !          1010:     DBG_VOP_LOCKS_DECL(2);
        !          1011:     DBG_VOP_PRINT_FUNCNAME();
        !          1012:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP((": %d --> ", ap->a_bn));
        !          1013: 
        !          1014:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1015:     if (ap->a_vpp != NULL) {
        !          1016:         DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS);
        !          1017:     } else {
        !          1018:         DBG_VOP_LOCKS_INIT(1,NULL, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
        !          1019:        };
        !          1020: #endif
        !          1021: 
        !          1022:     /*
        !          1023:      * Check for underlying vnode requests and ensure that logical
        !          1024:      * to physical mapping is requested.
        !          1025:      */
        !          1026:     if (ap->a_vpp != NULL)
        !          1027:         *ap->a_vpp = VTOH(ap->a_vp)->h_devvp;
        !          1028:     if (ap->a_bnp == NULL)
        !          1029:         return (0);
        !          1030: 
        !          1031:     lockExtBtree = hasOverflowExtents(hp);
        !          1032:     if (lockExtBtree)
        !          1033:     {
        !          1034:         p = CURRENT_PROC;
        !          1035:         retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p);
        !          1036:         if (retval)
        !          1037:             return (retval);
        !          1038:     }
        !          1039: 
        !          1040: 
        !          1041:     if (ap->a_bn < hp->h_uniformblocksizestart) {
        !          1042:         int targetLogicalBlockNo = ap->a_bn;
        !          1043:         off_t fileOffset = 0;
        !          1044:         int extent;
        !          1045:         long extentSize;
        !          1046: 
        !          1047:         logBlockSize = MAXLOGBLOCKSIZE;
        !          1048:         for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) {
        !          1049:             if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) &&
        !          1050:                 (targetLogicalBlockNo < hp->h_logicalblocktable[extent].logicalBlockCount)) {
        !          1051:                 retval = MacToVFSError(
        !          1052:                                        MapFileBlockC (HFSTOVCB(hfsmp),
        !          1053:                                                       HTOFCB(hp),
        !          1054:                                                       MAXPHYSIO,
        !          1055:                                                       fileOffset + (targetLogicalBlockNo * MAXLOGBLOCKSIZE),
        !          1056:                                                       (UInt32 *)ap->a_bnp,
        !          1057:                                                       &bytesContAvail));
        !          1058:                 /* Take the current FCB's extent length info: we could be mid-update */
        !          1059:                 if (HTOVCB(hp)->vcbSigWord == kHFSSigWord) {
        !          1060:                     extentSize = hp->h_xfcb->fcb_fcb.fcbExtRec[extent].blockCount * HTOVCB(hp)->blockSize;
        !          1061:                 } else {
        !          1062:                     extentSize = hp->h_xfcb->fcb_extFCB.extents[extent].blockCount * HTOVCB(hp)->blockSize;
        !          1063:                 };
        !          1064:                 DBG_ASSERT((bytesContAvail == MAXPHYSIO) || (bytesContAvail == (extentSize - (targetLogicalBlockNo * MAXLOGBLOCKSIZE))));
        !          1065:                 break;
        !          1066:             };
        !          1067:             targetLogicalBlockNo -= hp->h_logicalblocktable[extent].logicalBlockCount;
        !          1068:             fileOffset += hp->h_logicalblocktable[extent].extentLength;
        !          1069:         };
        !          1070:     } else {
        !          1071:         logBlockSize = hp->h_meta->h_logBlockSize;
        !          1072:         retval = MacToVFSError(
        !          1073:                                MapFileBlockC (HFSTOVCB(hfsmp),
        !          1074:                                               HTOFCB(hp),
        !          1075:                                               MAXPHYSIO,
        !          1076:                                               hp->h_optimizedblocksizelimit +
        !          1077:                                                   ((ap->a_bn - hp->h_uniformblocksizestart) * logBlockSize),
        !          1078:                                               (UInt32 *)ap->a_bnp,
        !          1079:                                               &bytesContAvail));
        !          1080: 
        !          1081:     };
        !          1082: 
        !          1083:     if (lockExtBtree) (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
        !          1084: 
        !          1085:     if (retval == E_NONE) {
        !          1086:         /* Figure out how many read ahead blocks there are */
        !          1087:         if (ap->a_runp != NULL) {
        !          1088:             if (can_cluster(logBlockSize)) {
        !          1089:                 /* Make sure this result never goes negative: */
        !          1090:                 *ap->a_runp = (bytesContAvail < logBlockSize) ? 0 : (bytesContAvail / logBlockSize) - 1;
        !          1091:             } else {
        !          1092:                 *ap->a_runp = 0;
        !          1093:             };
        !          1094:         };
        !          1095:     };
        !          1096: 
        !          1097: #if DEBUG_BMAP
        !          1098:     DBG_VOP(("%d:%d.\n", *ap->a_bnp, (bytesContAvail < logBlockSize) ? 0 : (bytesContAvail / logBlockSize) - 1));
        !          1099: 
        !          1100:     DBG_VOP_LOCKS_TEST(retval);
        !          1101: #endif
        !          1102: 
        !          1103:     if (ap->a_runp) {
        !          1104:         DBG_ASSERT((*ap->a_runp * logBlockSize) < bytesContAvail);                                                     /* At least *ap->a_runp blocks left and ... */
        !          1105:         if (can_cluster(logBlockSize)) {
        !          1106:             DBG_ASSERT(bytesContAvail - (*ap->a_runp * logBlockSize) < (2*logBlockSize));      /* ... at most 1 logical block accounted for by current block */
        !          1107:                                                                                             /* ... plus some sub-logical block sized piece */
        !          1108:         };
        !          1109:     };
        !          1110: 
        !          1111:     return (retval);
        !          1112: }
        !          1113: 
        !          1114: 
        !          1115: /*
        !          1116:  * Calculate the logical to physical mapping if not done already,
        !          1117:  * then call the device strategy routine.
        !          1118: #
        !          1119: #vop_strategy {
        !          1120: #      IN struct buf *bp;
        !          1121:     */
        !          1122: int
        !          1123: hfs_strategy(ap)
        !          1124: struct vop_strategy_args /* {
        !          1125:     struct buf *a_bp;
        !          1126: } */ *ap;
        !          1127: {
        !          1128:     register struct buf *bp = ap->a_bp;
        !          1129:     register struct vnode *vp = bp->b_vp;
        !          1130:     register struct hfsnode *hp;
        !          1131:     long logBlockSize;
        !          1132:     int retval = 0;
        !          1133:        DBG_FUNC_NAME("strategy");
        !          1134: 
        !          1135: //     DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
        !          1136: 
        !          1137:     hp = VTOH(vp);
        !          1138:     if (vp->v_type == VBLK || vp->v_type == VCHR)
        !          1139:         panic("hfs_strategy: device vnode passed!");
        !          1140: 
        !          1141:     /*
        !          1142:      * If we don't already know the filesystem relative block number
        !          1143:      * then get it using VOP_BMAP().  If VOP_BMAP() returns the block
        !          1144:      * number as -1 then we've got a hole in the file.  HFS filesystems
        !          1145:      * don't allow files with holes, so we shouldn't ever see this.
        !          1146:      */
        !          1147:     if (bp->b_blkno == bp->b_lblkno) {
        !          1148:         if ((retval = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL))) {
        !          1149:             bp->b_error = retval;
        !          1150:             bp->b_flags |= B_ERROR;
        !          1151:             biodone(bp);
        !          1152:             return (retval);
        !          1153:         }
        !          1154:         if ((long)bp->b_blkno == -1)
        !          1155:             clrbuf(bp);
        !          1156:     }
        !          1157:     if ((long)bp->b_blkno == -1) {
        !          1158:         biodone(bp);
        !          1159:         return (0);
        !          1160:     }
        !          1161:        
        !          1162:        /* Make sure some over-eager cluster code didn't generate an excessively large read: */
        !          1163:        if (bp->b_bcount != hp->h_meta->h_logBlockSize) {
        !          1164:                logBlockSize = LogicalBlockSize(hp, bp->b_lblkno);
        !          1165:         if ((bp->b_bcount > logBlockSize) && !(can_cluster(logBlockSize))) bp->b_bcount = logBlockSize;
        !          1166:        };
        !          1167:        
        !          1168:        if (bp->b_validend == 0) {
        !          1169:                /* Record the exact size of the I/O transfer about to be made: */
        !          1170:                DBG_ASSERT(bp->b_validoff == 0);
        !          1171:                bp->b_validend = bp->b_bcount;
        !          1172:                DBG_ASSERT(bp->b_dirtyoff == 0);
        !          1173:        };
        !          1174:        
        !          1175:     vp = hp->h_devvp;
        !          1176:     bp->b_dev = vp->v_rdev;
        !          1177:     DBG_VOP(("\t\t>>>%s: continuing w/ vp: 0x%x with logBlk Ox%X and phyBlk Ox%X\n", funcname, (u_int)vp, bp->b_lblkno, bp->b_blkno));
        !          1178: 
        !          1179:     return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
        !          1180: }
        !          1181: 
        !          1182: 
        !          1183: /*
        !          1184: #% reallocblks vp      L L L
        !          1185: #
        !          1186:  vop_reallocblks {
        !          1187:      IN struct vnode *vp;
        !          1188:      IN struct cluster_save *buflist;
        !          1189: 
        !          1190:      */
        !          1191: 
        !          1192: int
        !          1193: hfs_reallocblks(ap)
        !          1194: struct vop_reallocblks_args /* {
        !          1195:     struct vnode *a_vp;
        !          1196:     struct cluster_save *a_buflist;
        !          1197: } */ *ap;
        !          1198: {
        !          1199:     DBG_FUNC_NAME("reallocblks");
        !          1200:     DBG_VOP_LOCKS_DECL(1);
        !          1201:     DBG_VOP_PRINT_FUNCNAME();
        !          1202:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          1203: 
        !          1204:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1205: 
        !          1206:     /* Currently no support for clustering */          /* XXX */
        !          1207:     DBG_VOP_LOCKS_TEST(ENOSPC);
        !          1208:     return (ENOSPC);
        !          1209: }
        !          1210: 
        !          1211: 
        !          1212: 
        !          1213: /*
        !          1214: #
        !          1215: #% truncate    vp      L L L
        !          1216: #
        !          1217: vop_truncate {
        !          1218:     IN struct vnode *vp;
        !          1219:     IN off_t length;
        !          1220:     IN int flags;      (IO_SYNC)
        !          1221:     IN struct ucred *cred;
        !          1222:     IN struct proc *p;
        !          1223: };
        !          1224:  * Truncate the hfsnode hp to at most length size, freeing (or adding) the
        !          1225:  * disk blocks.
        !          1226:  */
        !          1227: int hfs_truncate(ap)
        !          1228:     struct vop_truncate_args /* {
        !          1229:         struct vnode *a_vp;
        !          1230:         off_t a_length;
        !          1231:         int a_flags;
        !          1232:         struct ucred *a_cred;
        !          1233:         struct proc *a_p;
        !          1234:     } */ *ap;
        !          1235: {
        !          1236:     register struct vnode *vp = ap->a_vp;
        !          1237:     register struct hfsnode *hp = VTOH(vp);
        !          1238:     off_t length = ap->a_length;
        !          1239:     long vflags;
        !          1240:     struct timeval tv;
        !          1241:     int retval;
        !          1242:     FCB *fcb;
        !          1243:     off_t bytesToAdd;
        !          1244:     UInt32 actualBytesAdded;
        !          1245:     long devBlockSize = 512;
        !          1246:     DBG_FUNC_NAME("truncate");
        !          1247:     DBG_VOP_LOCKS_DECL(1);
        !          1248:     DBG_VOP_PRINT_FUNCNAME();
        !          1249:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          1250:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1251: 
        !          1252: #if DIAGNOSTIC
        !          1253:     debug_check_blocksizes(ap->a_vp);
        !          1254: #endif
        !          1255: 
        !          1256:     if (length < 0) {
        !          1257:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1258:         return (EINVAL);
        !          1259:        }
        !          1260: 
        !          1261:     if (length > (off_t)MAXHFSFILESIZE) {      /* XXX need to distinguish between hfs and hfs+ */
        !          1262:                DBG_VOP_LOCKS_TEST(EFBIG);
        !          1263:                return (EFBIG);
        !          1264:        }
        !          1265: 
        !          1266:     if (vp->v_type != VREG && vp->v_type != VLNK) {            
        !          1267:         DBG_VOP_LOCKS_TEST(EISDIR);
        !          1268:         return (EISDIR);               /* hfs doesn't support truncating of directories */
        !          1269:     }
        !          1270: 
        !          1271:     fcb = HTOFCB(hp);
        !          1272:     tv = time;
        !          1273:        retval = E_NONE;
        !          1274: 
        !          1275:     DBG_VOP(("%s: truncate from Ox%lX to Ox%X bytes\n", funcname, fcb->fcbPLen, (u_int)length));
        !          1276: 
        !          1277:        /* 
        !          1278:         * we cannot just check if fcb->fcbEOF == length (as an optimization)
        !          1279:         * since there may be extra physical blocks that also need truncation
        !          1280:         */
        !          1281: 
        !          1282: #if MACH_NBC
        !          1283:     retval = mapfs_trunc(vp, (vm_offset_t)length);
        !          1284:     if (retval) {
        !          1285:         DBG_VOP_LOCKS_TEST(retval);
        !          1286:         return (retval);
        !          1287:     }
        !          1288: #endif /* MACH_NBC */
        !          1289: 
        !          1290:     /*
        !          1291:      * Lengthen the size of the file. We must ensure that the
        !          1292:      * last byte of the file is allocated. Since the smallest
        !          1293:      * value of fcbEOF is 0, length will be at least 1.
        !          1294:      */
        !          1295:        if ((u_long)length > fcb->fcbEOF) {
        !          1296:         off_t filePosition;
        !          1297:                daddr_t logBlockNo;
        !          1298:                long logBlockSize;
        !          1299:                long blkOffset;
        !          1300:                off_t bytestoclear;
        !          1301:                int blockZeroCount;
        !          1302:                struct buf *bp=NULL;
        !          1303: 
        !          1304:        /*
        !          1305:         * If we don't have enough physical space then
        !          1306:         * we need to extend the physical size.
        !          1307:         */
        !          1308:         if ((u_long)length > fcb->fcbPLen) {
        !          1309:                        /* lock extents b-tree (also protects volume bitmap) */
        !          1310:                        retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
        !          1311:             if (retval) goto Err_Exit;
        !          1312: 
        !          1313:             while (((u_long)length > fcb->fcbPLen) && (retval == E_NONE)) {
        !          1314:                 /* XXX PPD Allocate only 2GB at a time until ExtendFileC's interface changes... */
        !          1315:                 bytesToAdd = length - (off_t)fcb->fcbPLen;
        !          1316:                 if (bytesToAdd > (off_t)0x80000000) bytesToAdd = (off_t)0x80000000;
        !          1317:                 retval = MacToVFSError(
        !          1318:                                        ExtendFileC (HTOVCB(hp),
        !          1319:                                                     fcb,
        !          1320:                                                     (u_long)bytesToAdd,
        !          1321:                                                     kEFAllMask,        /* allocate all requested bytes or none */
        !          1322:                                                     &actualBytesAdded));
        !          1323: 
        !          1324:                                if (actualBytesAdded == 0 && retval == E_NONE) {
        !          1325:                                        if ((u_long)length > fcb->fcbPLen)
        !          1326:                                                length = (off_t)fcb->fcbPLen;
        !          1327:                                        break;
        !          1328:                                }
        !          1329: 
        !          1330:                 /* If we just successfully extended the file by only 2GB, try again (just to be sure): */
        !          1331:                 if (bytesToAdd == (off_t)0x80000000) continue;
        !          1332:                        } 
        !          1333:                        (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
        !          1334:                        if (retval) goto Err_Exit;
        !          1335: 
        !          1336:             DBG_ASSERT((u_long)length <= fcb->fcbPLen);
        !          1337: 
        !          1338:             UpdateBlockMappingTable(hp);
        !          1339: 
        !          1340: #if MACH_NBC
        !          1341:                if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
        !          1342: #endif /* MACH_NBC */
        !          1343:                 vnode_pager_setsize(vp, (u_long)length);
        !          1344:                 vnode_uncache(vp);
        !          1345: #if MACH_NBC
        !          1346:                }
        !          1347: #endif /* !MACH_NBC */  
        !          1348:                }
        !          1349:  
        !          1350:                if (! (ap->a_flags & IO_NOZEROFILL)) {
        !          1351:              /*
        !          1352:               * zero out any new logical space...
        !          1353:               */
        !          1354:             VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize);
        !          1355: 
        !          1356:                        bytestoclear = length - (off_t)fcb->fcbEOF;
        !          1357:             filePosition = (off_t)fcb->fcbEOF;
        !          1358:                        while (bytestoclear > 0) {
        !          1359:                 MapFileOffset(hp, filePosition, &logBlockNo, &logBlockSize, &blkOffset);
        !          1360:                                blockZeroCount = MIN(bytestoclear, logBlockSize - blkOffset);
        !          1361:                                if ((blkOffset == 0) && (bytestoclear >= logBlockSize)) {
        !          1362:                                        bp = getblk(vp, logBlockNo, logBlockSize, 0, 0);
        !          1363:                     retval = 0;
        !          1364:                     if (bp->b_flags & (B_DELWRI | B_DONE | B_CACHE)) {
        !          1365:                         /*
        !          1366:                            This buffer is fully pre-read and may already have some modified data in it:
        !          1367:                            it doesn't need special-casing for write-through.
        !          1368:                          */
        !          1369:                     } else {
        !          1370:                         /* This is an empty buffer just allocated for our use: */
        !          1371: 
        !          1372:                         /* XXX PPD Can't this be skipped if b_blkno != logBlockNo? */
        !          1373: 
        !          1374:                         /* Setting up the physical block number is required
        !          1375:                            (1) to keep cluster_write informed about which blocks can be clustered, and
        !          1376:                            (2) to avoid a second call to bmap() in strategy() on the write.
        !          1377:                          */
        !          1378:                         if ((retval = VOP_BMAP(vp, logBlockNo, NULL, &bp->b_blkno, NULL))) {
        !          1379:                             brelse(bp);
        !          1380:                             break;
        !          1381:                         };
        !          1382: 
        !          1383:                         bp->b_bcount = 0;              /* No valid data in block yet */
        !          1384:                         bp->b_validend = 0;            /* No valid data in block yet */
        !          1385:                     };
        !          1386:                                } else {
        !          1387:                                        retval = bread(vp, logBlockNo, logBlockSize, ap->a_cred, &bp);
        !          1388:                     if (retval) {
        !          1389:                         brelse(bp);
        !          1390:                         goto Err_Exit;
        !          1391:                     }
        !          1392:                                }
        !          1393:        
        !          1394:                 /*
        !          1395:                    Fix up the anciliary fields for this buffer, depending on whether they've been initialized yet,
        !          1396:                    and check to see whether we need to get more data than what was just found in the cache:
        !          1397:                  */
        !          1398:                 if (bp->b_validend > 0) {
        !          1399:                     /*
        !          1400:                        b_validoff, b_validend, b_dirtyoff, and b_dirtyend are valid for blocks in the cache:
        !          1401:                        The only blocks that are incomplete (b_validend < fragSize) are blocks that have been
        !          1402:                        partially written from the start of the buffer:
        !          1403:                      */
        !          1404:                     if (bp->b_validend < bp->b_bcount) {
        !          1405:                         /*
        !          1406:                            We stumbled onto an incomplete [but successfully acquired] buffer:
        !          1407:                            try to get the full contents now because it's the only way to get
        !          1408:                            the data in this logical block...
        !          1409:                          */
        !          1410:                         DBG_ASSERT((bp->b_dirtyoff == 0) && (bp->b_validoff == 0) && (bp->b_dirtyend <= bp->b_validend));
        !          1411:                         /* Incomplete blocks must have only device-block multiples of data... */
        !          1412:                         DBG_ASSERT((bp->b_validend % devBlockSize) == 0);
        !          1413:                         bp->b_bcount = bp->b_validend;
        !          1414: 
        !          1415:                         retval = bexpand(bp, logBlockSize, &bp, 0);
        !          1416:                     };
        !          1417:                 } else {
        !          1418:                     /* This buffer was either just allocated or just read in its entirity [see b_bcount]: */
        !          1419:                     DBG_ASSERT(bp->b_validoff == 0);
        !          1420:                     bp->b_validend = bp->b_bcount;     /* b_bcount > 0 iff block was actually read from disk in bread */
        !          1421:                     DBG_ASSERT(bp->b_dirtyoff == 0);
        !          1422:                     DBG_ASSERT(bp->b_dirtyend == 0);
        !          1423:                 };
        !          1424: 
        !          1425:                                bzero((char *)bp->b_data + blkOffset, blockZeroCount);
        !          1426:                                
        !          1427:                 if (blkOffset + blockZeroCount > bp->b_dirtyend) bp->b_dirtyend = blkOffset + blockZeroCount;
        !          1428:                 if (bp->b_dirtyend > bp->b_validend) bp->b_validend = bp->b_dirtyend;
        !          1429:                 if (bp->b_validend > bp->b_bcount) bp->b_bcount = bp->b_validend;
        !          1430:                 DBG_ASSERT(bp->b_bcount % devBlockSize == 0);
        !          1431:                 DBG_ASSERT(bp->b_bcount == bp->b_validend);
        !          1432:                 bp->b_flags |= B_DIRTY | B_AGE;
        !          1433:                 if (ap->a_flags & IO_SYNC) {
        !          1434:                     bwrite(bp);
        !          1435:                 } else if (doclusterwrite &&  can_cluster(logBlockSize)) {
        !          1436:                     cluster_write(bp, fcb->fcbPLen, devBlockSize);
        !          1437:                                } else if (logBlockNo % 32) {
        !          1438:                                        bawrite(bp);
        !          1439:                } else {
        !          1440:                     bwrite(bp);        /* wait after we issue 32 requests */
        !          1441:                };
        !          1442: 
        !          1443:                                bytestoclear -= blockZeroCount;
        !          1444:                                if (blkOffset > 0)
        !          1445:                                        blkOffset = 0;
        !          1446: 
        !          1447:                 filePosition += blockZeroCount;
        !          1448:                        }
        !          1449:                }
        !          1450: 
        !          1451:                fcb->fcbEOF = (u_long)length;
        !          1452: 
        !          1453:    } else { /* Shorten the size of the file */
        !          1454: 
        !          1455:        if (fcb->fcbEOF > (u_long)length) {
        !          1456:                /*
        !          1457:                 * Any buffers that are past the truncation point need to be
        !          1458:                 * invalidated (to maintain buffer cache consistency).  For
        !          1459:                 * simplicity, we invalidate all the buffers by calling vinvalbuf.
        !          1460:                 */
        !          1461:                vflags = ((length > 0) ? V_SAVE : 0);   /* XXX PPD Should we set SAVE_META? */
        !          1462:                retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
        !          1463:        }
        !          1464:         /* lock extents b-tree (also protects volume bitmap) */
        !          1465:         retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
        !          1466:         if (retval) goto Err_Exit;
        !          1467: 
        !          1468:         retval = MacToVFSError(
        !          1469:                                TruncateFileC(  
        !          1470:                                              HTOVCB(hp),
        !          1471:                                              fcb,
        !          1472:                                              (u_long)length,
        !          1473:                                              false));
        !          1474:         (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
        !          1475:         if (retval) goto Err_Exit;
        !          1476: 
        !          1477:                fcb->fcbEOF = (u_long)length;
        !          1478:         if (fcb->fcbFlags &fcbModifiedMask)
        !          1479:             hp->h_meta->h_nodeflags |= IN_MODIFIED;
        !          1480: 
        !          1481:         UpdateBlockMappingTable(hp);
        !          1482: 
        !          1483: #if MACH_NBC
        !          1484:     if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
        !          1485: #endif /* MACH_NBC */
        !          1486:         vnode_pager_setsize(vp, (u_long)length);
        !          1487: #if MACH_NBC
        !          1488:     }
        !          1489: #endif /* MACH_NBC */
        !          1490: 
        !          1491:     }
        !          1492: 
        !          1493:        hp->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          1494:        retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
        !          1495: 
        !          1496: Err_Exit:;
        !          1497: 
        !          1498: #if DIAGNOSTIC
        !          1499:     debug_check_blocksizes(ap->a_vp);
        !          1500: #endif
        !          1501: 
        !          1502:     DBG_VOP_LOCKS_TEST(retval);
        !          1503:     return (retval);
        !          1504: }
        !          1505: 
        !          1506: 
        !          1507: 
        !          1508: /*
        !          1509: #
        !          1510: #% allocate    vp      L L L
        !          1511: #
        !          1512: vop_allocate {
        !          1513:     IN struct vnode *vp;
        !          1514:     IN off_t length;
        !          1515:     IN int flags;
        !          1516:     IN struct ucred *cred;
        !          1517:     IN struct proc *p;
        !          1518: };
        !          1519:  * allocate the hfsnode hp to at most length size
        !          1520:  */
        !          1521: int hfs_allocate(ap)
        !          1522:     struct vop_allocate_args /* {
        !          1523:         struct vnode *a_vp;
        !          1524:         off_t a_length;
        !          1525:         u_int32_t  a_flags;
        !          1526:        off_t *a_bytesallocated;
        !          1527:         struct ucred *a_cred;
        !          1528:         struct proc *a_p;
        !          1529:     } */ *ap;
        !          1530: {
        !          1531:     register struct vnode *vp = ap->a_vp;
        !          1532:     register struct hfsnode *hp = VTOH(vp);
        !          1533:     off_t length = ap->a_length;
        !          1534:     long vflags;
        !          1535:     u_long startingPEOF;
        !          1536:     struct timeval tv;
        !          1537:     int retval, retval2;
        !          1538:     FCB *fcb;
        !          1539:     UInt32 actualBytesAdded;
        !          1540:     UInt32 extendFlags =0;   /* For call to ExtendFileC */
        !          1541:     DBG_FUNC_NAME("allocate");
        !          1542:     DBG_VOP_LOCKS_DECL(1);
        !          1543:     DBG_VOP_PRINT_FUNCNAME();
        !          1544:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
        !          1545:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
        !          1546: 
        !          1547:     /* Set the number of bytes allocated to 0 so that the caller will know that we
        !          1548:        did nothing.  ExtendFileC will fill this in for us if we actually allocate space */
        !          1549: 
        !          1550:     *(ap->a_bytesallocated) = 0; 
        !          1551: 
        !          1552:     /* Now for some error checking */
        !          1553: 
        !          1554:     if (length < (off_t)0) {
        !          1555:         DBG_VOP_LOCKS_TEST(EINVAL);
        !          1556:         return (EINVAL);
        !          1557:     }
        !          1558: 
        !          1559:     if (length > (u_int64_t)0x7FFFFFFF) {   /* XXX need to distinguish between hfs and hfs+ */
        !          1560:         DBG_VOP_LOCKS_TEST(EFBIG);
        !          1561:         return (EFBIG);
        !          1562:     }
        !          1563: 
        !          1564:     if (vp->v_type != VREG && vp->v_type != VLNK) {
        !          1565:         DBG_VOP_LOCKS_TEST(EISDIR);
        !          1566:         return (EISDIR);        /* hfs doesn't support truncating of directories */
        !          1567:     }
        !          1568: 
        !          1569:     /* Fill in the flags word for the call to Extend the file */
        !          1570: 
        !          1571:        if (ap->a_flags & ALLOCATECONTIG) {
        !          1572:                extendFlags |= kEFContigMask;
        !          1573:        }
        !          1574: 
        !          1575:     if (ap->a_flags & ALLOCATEALL) {
        !          1576:                extendFlags |= kEFAllMask;
        !          1577:        }
        !          1578: 
        !          1579:     fcb = HTOFCB(hp);
        !          1580:     tv = time;
        !          1581:     retval = E_NONE;
        !          1582:     startingPEOF = fcb->fcbPLen;
        !          1583: 
        !          1584:     if (ap->a_flags & ALLOCATEFROMPEOF) {
        !          1585:                length += fcb->fcbPLen;
        !          1586:        }
        !          1587: 
        !          1588:     DBG_VOP(("%s: allocate from Ox%lX to Ox%X bytes\n", funcname, fcb->fcbPLen, (u_int)length));
        !          1589: 
        !          1590:     /* If no changes are necesary, then we're done */
        !          1591:     if (fcb->fcbPLen == (u_long)length)
        !          1592:        goto Std_Exit;
        !          1593: 
        !          1594:     /*
        !          1595:     * Lengthen the size of the file. We must ensure that the
        !          1596:     * last byte of the file is allocated. Since the smallest
        !          1597:     * value of fcbPLen is 0, length will be at least 1.
        !          1598:     */
        !          1599:     if ((u_long)length > fcb->fcbPLen) {
        !          1600: 
        !          1601:                /* lock extents b-tree (also protects volume bitmap) */
        !          1602:                retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
        !          1603:                if (retval) goto Err_Exit;
        !          1604: 
        !          1605:                retval = MacToVFSError(
        !          1606:                                                                ExtendFileC(HTOVCB(hp),
        !          1607:                                                                                        fcb,
        !          1608:                                                                                        (u_long)length - fcb->fcbPLen,
        !          1609:                                                                                        extendFlags,
        !          1610:                                                                                        &actualBytesAdded));
        !          1611: 
        !          1612:                *(ap->a_bytesallocated) = actualBytesAdded;
        !          1613: 
        !          1614:                (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
        !          1615: 
        !          1616:                DBG_ASSERT((u_long)length <= fcb->fcbPLen);
        !          1617: 
        !          1618:                UpdateBlockMappingTable(hp);
        !          1619:                
        !          1620:                /*
        !          1621:                 * if we get an error and no changes were made then exit
        !          1622:                 * otherwise we must do the VOP_UPDATE to reflect the changes
        !          1623:                 */
        !          1624:         if (retval && (startingPEOF == fcb->fcbPLen)) goto Err_Exit;
        !          1625: 
        !          1626:     } else { /* Shorten the size of the file */
        !          1627: 
        !          1628:        if (fcb->fcbEOF > (u_long)length) {
        !          1629:                        /*
        !          1630:                         * Any buffers that are past the truncation point need to be
        !          1631:                         * invalidated (to maintain buffer cache consistency).  For
        !          1632:                         * simplicity, we invalidate all the buffers by calling vinvalbuf.
        !          1633:                         */
        !          1634:                        vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
        !          1635:                        (void) vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
        !          1636:                }
        !          1637: 
        !          1638:        /* lock extents b-tree (also protects volume bitmap) */
        !          1639:         retval = hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
        !          1640:         if (retval) goto Err_Exit;
        !          1641: 
        !          1642:         retval = MacToVFSError(
        !          1643:                             TruncateFileC(
        !          1644:                                             HTOVCB(hp),
        !          1645:                                             fcb,
        !          1646:                                             (u_long)length,
        !          1647:                                             false));
        !          1648:         (void) hfs_metafilelocking(HTOHFS(hp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
        !          1649: 
        !          1650:                /*
        !          1651:                 * if we get an error and no changes were made then exit
        !          1652:                 * otherwise we must do the VOP_UPDATE to reflect the changes
        !          1653:                 */
        !          1654:                if (retval && (startingPEOF == fcb->fcbPLen)) goto Err_Exit;
        !          1655:         if (fcb->fcbFlags & fcbModifiedMask)
        !          1656:             hp->h_meta->h_nodeflags |= IN_MODIFIED;
        !          1657: 
        !          1658:         DBG_ASSERT((u_long)length <= fcb->fcbPLen)  // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
        !          1659: 
        !          1660:         if (fcb->fcbEOF > fcb->fcbPLen) {
        !          1661:                        fcb->fcbEOF = fcb->fcbPLen;
        !          1662: 
        !          1663:             UpdateBlockMappingTable(hp);
        !          1664: 
        !          1665: #if MACH_NBC
        !          1666:             if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
        !          1667: #endif /* MACH_NBC */
        !          1668:                 vnode_pager_setsize(vp, (u_long)fcb->fcbEOF);
        !          1669: #if MACH_NBC
        !          1670:             }
        !          1671: #endif /* MACH_NBC */
        !          1672:         }
        !          1673:         (void)vnode_uncache(vp);
        !          1674:     }
        !          1675: 
        !          1676: Std_Exit:
        !          1677:     hp->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
        !          1678:        retval2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
        !          1679: 
        !          1680:     if (retval == 0) retval = retval2;
        !          1681: 
        !          1682: Err_Exit:
        !          1683:     DBG_VOP_LOCKS_TEST(retval);
        !          1684:     return (retval);
        !          1685: }
        !          1686: 
        !          1687: 
        !          1688: 
        !          1689: 
        !          1690: /* Pass-through pagein for HFS filesystem */
        !          1691: int
        !          1692: hfs_pagein(ap)
        !          1693:        struct vop_pagein_args /* {
        !          1694:                struct vnode *a_vp;
        !          1695:                struct uio *a_uio;
        !          1696:                int a_ioflag;
        !          1697:                struct ucred *a_cred;
        !          1698:        } */ *ap;
        !          1699: {
        !          1700:        /* pass thru to read */ 
        !          1701:        return (VOP_READ(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
        !          1702: }
        !          1703: 
        !          1704: /* Pass-through pageout for HFS filesystem */
        !          1705: int
        !          1706: hfs_pageout(ap)
        !          1707:        struct vop_pageout_args /* {
        !          1708:                struct vnode *a_vp;
        !          1709:                struct uio *a_uio;
        !          1710:                int a_ioflag;
        !          1711:                struct ucred *a_cred;
        !          1712:        } */ *ap;
        !          1713: {
        !          1714:        /* pass thru to write */ 
        !          1715:        return (VOP_WRITE(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
        !          1716: }
        !          1717: 
        !          1718: 
        !          1719: 
        !          1720: /*
        !          1721:        Try to expand the range of a buffer.
        !          1722: 
        !          1723:     Possible values for 'flags' are:
        !          1724: 
        !          1725:         RELEASE_BUFFER - to specify that the expanded buffer need not be held
        !          1726:        
        !          1727:        Calling bexpand with nbpp == &bp to expand a given buffer is OK;
        !          1728:        even on errors, the current buffer (bp) is always brelse-ed!
        !          1729:  */
        !          1730: int
        !          1731: bexpand(struct buf *bp, int newsize, struct buf **nbpp, long flags)
        !          1732: {
        !          1733:        struct vnode *ovp;
        !          1734:        daddr_t olblkno;
        !          1735:        struct ucred *ocred;
        !          1736:        int odirtyend;
        !          1737:        int releasebp = 1;
        !          1738:        struct buf *tbp = NULL;
        !          1739:     struct buf *nbp = NULL;
        !          1740:        int retval = 0;
        !          1741:        
        !          1742:     DBG_ASSERT(bp != NULL);
        !          1743:     if (nbpp == NULL) DBG_ASSERT(flags & RELEASE_BUFFER);
        !          1744: 
        !          1745:        if (bp->b_validend >= newsize) {
        !          1746:         /* Sufficient amount already read or written into buffer: */
        !          1747:         nbp = bp;                                                              /* nbp is checked against bp in exit path */
        !          1748:                retval = 0;
        !          1749:                goto stdexit;
        !          1750:        };
        !          1751:        
        !          1752:        if (nbpp) *nbpp = NULL;                                         /* Just to be clean, and to ensure != bp... */
        !          1753: 
        !          1754:        ovp = bp->b_vp;
        !          1755:        olblkno = bp->b_lblkno;
        !          1756:        ocred = bp->b_rcred;
        !          1757:        odirtyend = bp->b_dirtyend;
        !          1758:        
        !          1759:        if (bp->b_flags & B_DELWRI) {
        !          1760:                /* This buffer holds dirtied data that must be preserved: */
        !          1761:                /* XXX PPD 9/28/98 Should assert that b_dirtyoff == 0 here, but not this late in the game... */
        !          1762:                tbp = geteblk(odirtyend);                               /* Grab a new [temporary] buffer big enough to
        !          1763:                                                                                                   hold the dirty parts of this buffer for a sec. */
        !          1764:                if (tbp == NULL) {
        !          1765:                        retval = ENOMEM;
        !          1766:                        goto errexit;
        !          1767:                };
        !          1768:                bcopy(bp->b_data, tbp->b_data, odirtyend);
        !          1769:        };
        !          1770:        
        !          1771:        /* It's now safe to trash the entire current contents of the buffer */
        !          1772:        bp->b_flags |= B_INVAL;
        !          1773:     DBG_ASSERT((bp->b_validend == 0) || (bp->b_validend == bp->b_bcount));
        !          1774:        brelse(bp);
        !          1775:        releasebp = 0;
        !          1776: 
        !          1777: //  if (((flags & RELEASE_BUFFER) == 0) || (tbp != NULL)) {
        !          1778:     if (1) {
        !          1779:         retval = bread(ovp, olblkno, newsize, ocred, &nbp);    /* Read in the requested data */
        !          1780:         if (retval != 0) goto errexit;
        !          1781: 
        !          1782:         nbp->b_validoff = 0;
        !          1783:         nbp->b_validend = newsize;
        !          1784:         nbp->b_dirtyoff = 0;
        !          1785:         nbp->b_dirtyend = 0;
        !          1786: 
        !          1787:         if (tbp) {
        !          1788:             /* Restore the modified data from the old buffer: */
        !          1789:             bcopy(tbp->b_data, nbp->b_data, odirtyend);
        !          1790:             nbp->b_dirtyend = odirtyend;
        !          1791:             DBG_ASSERT((bp->b_validend == 0) || (bp->b_validend == bp->b_bcount));
        !          1792:             bdwrite(nbp);                                                                              /* Mark this block dirty and move to appropriate buffer */
        !          1793: 
        !          1794:             if (flags & RELEASE_BUFFER) {
        !          1795:                 nbp = NULL;                                                                            /* Forget about the new buffer just written */
        !          1796:             } else {
        !          1797:                 /* Get the buffer back on behalf of our caller, even reading it back in in the
        !          1798:                    unlikely case it's been flushed and re-used since the bdwrite(), above: */
        !          1799:                 retval = bread(ovp, olblkno, newsize, ocred, nbpp);
        !          1800:                 if (retval != 0) goto errexit;
        !          1801:                 nbp->b_validoff = 0;
        !          1802:                 nbp->b_validend = newsize;
        !          1803:                 nbp->b_dirtyoff = 0;
        !          1804:                 nbp->b_dirtyend = odirtyend;
        !          1805:             };
        !          1806: 
        !          1807:             brelse(tbp);
        !          1808:             tbp = NULL;                                                                                        /* Just in case we hit errors later */
        !          1809:         };
        !          1810:     };
        !          1811:        goto stdexit;
        !          1812: 
        !          1813: errexit:
        !          1814:        if (tbp) brelse(tbp);
        !          1815: 
        !          1816:     if (releasebp && (bp != nbp)) {
        !          1817:         DBG_ASSERT((bp->b_validend == 0) || (bp->b_validend == bp->b_bcount));
        !          1818:         brelse(bp);
        !          1819:     };
        !          1820: 
        !          1821: stdexit:;
        !          1822:     if (nbpp) *nbpp = nbp;
        !          1823: 
        !          1824:     if ((flags & RELEASE_BUFFER) && (nbp != NULL)) {
        !          1825:         brelse(nbp);
        !          1826:     };
        !          1827: 
        !          1828: #if DIAGNOSTIC
        !          1829:     debug_check_blocksizes(bp->b_vp);
        !          1830: #endif
        !          1831: 
        !          1832:        return retval;
        !          1833: }

unix.superglobalmegacorp.com

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