Annotation of XNU/bsd/hfs/hfs_readwrite.c, revision 1.1.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.