Annotation of kernel/bsd/hfs/hfs_readwrite.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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