Annotation of XNU/bsd/hfs/hfs_readwrite.c, revision 1.1

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

unix.superglobalmegacorp.com

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