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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*     @(#)hfs_btreeio.c
        !            23: *
        !            24: *      (c) 1998, 2000 Apple Computer, Inc.  All Rights Reserved
        !            25: *
        !            26: *      hfs_btreeio.c -- I/O Routines for the HFS B-tree files.
        !            27: *
        !            28: *      HISTORY
        !            29: *      15-Feb-2000     Don Brady       Added ClearBTNodes.
        !            30: *      16-Jul-1998     Don Brady               In ExtendBtreeFile force all b-tree nodes to be contiguous on disk.
        !            31: *       4-Jun-1998     Pat Dirks               Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1)
        !            32: *      18-apr-1998     Don Brady               Call brelse on bread failure.
        !            33: *      17-Apr-1998     Pat Dirks               Fixed ReleaseBTreeBlock to not call brelse when bwrite or bdwrite is called.
        !            34: *      13-apr-1998     Don Brady               Add ExtendBTreeFile routine (from BTreeWrapper.c).
        !            35: *      26-mar-1998     Don Brady               SetBTreeBlockSize was incorrectly excluding 512 byte blockSize.
        !            36: *      18-feb-1998     Don Brady               Initially created file.
        !            37: *
        !            38: */
        !            39: 
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/buf.h>
        !            43: #include <sys/mount.h>
        !            44: #include <sys/vnode.h>
        !            45: 
        !            46: 
        !            47: #include "hfs.h"
        !            48: #include "hfs_dbg.h"
        !            49:        
        !            50: #include "hfscommon/headers/FileMgrInternal.h"
        !            51: #include "hfscommon/headers/BTreesPrivate.h"
        !            52: 
        !            53: #define FORCESYNCBTREEWRITES 0
        !            54: 
        !            55: static OSStatus FlushAlternate( ExtendedVCB *vcb );
        !            56: 
        !            57: static int ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount);
        !            58: 
        !            59: 
        !            60: OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount)
        !            61: {
        !            62:        BTreeControlBlockPtr    bTreePtr;
        !            63:        
        !            64:        DBG_ASSERT(vp != NULL);
        !            65:        DBG_ASSERT(VTOFCB(vp) != NULL);
        !            66:        DBG_ASSERT(VTOFCB(vp)->fcbBTCBPtr != NULL);
        !            67:        DBG_ASSERT(blockSize >= kMinNodeSize);
        !            68:     if (blockSize > MAXBSIZE )
        !            69:         return (fsBTBadNodeSize);
        !            70: 
        !            71:     DBG_TREE(("SetBlockSizeProc: blockSize=%ld for file %ld\n", blockSize, H_FILEID(VTOH(vp))));
        !            72: 
        !            73:        bTreePtr = (BTreeControlBlockPtr)(VTOH(vp)->fcbBTCBPtr);
        !            74:        bTreePtr->nodeSize = blockSize;
        !            75:        
        !            76:     return (E_NONE);
        !            77: }
        !            78: 
        !            79: 
        !            80: OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block)
        !            81: {
        !            82:     OSStatus    retval = E_NONE;
        !            83:     struct buf   *bp = NULL;
        !            84: 
        !            85:     if (options & kGetEmptyBlock)
        !            86:         bp = getblk (vp,
        !            87:                     IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size),
        !            88:                     IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size),
        !            89:                     0,
        !            90:                     0);
        !            91:     else
        !            92:         retval = bread (vp,
        !            93:                         IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size),
        !            94:                         IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size),
        !            95:                         NOCRED,
        !            96:                         &bp);
        !            97: 
        !            98:     DBG_ASSERT(bp != NULL);
        !            99:     DBG_ASSERT(bp->b_data != NULL);
        !           100:     DBG_ASSERT(bp->b_bcount == block->blockSize);
        !           101:     DBG_ASSERT(bp->b_lblkno == blockNum);
        !           102: 
        !           103:     if (bp == NULL)
        !           104:         retval = -1;   //XXX need better error
        !           105: 
        !           106:     if (retval == E_NONE) {
        !           107:         block->blockHeader = bp;
        !           108:         block->buffer = bp->b_data + IOBYTEOFFSETFORBLK(bp->b_blkno, VTOHFS(vp)->hfs_phys_block_size);
        !           109:         block->blockReadFromDisk = (bp->b_flags & B_CACHE) == 0;       /* not found in cache ==> came from disk */
        !           110:     } else {
        !           111:        if (bp)
        !           112:                        brelse(bp);
        !           113:         block->blockHeader = NULL;
        !           114:         block->buffer = NULL;
        !           115:     }
        !           116: 
        !           117:     return (retval);
        !           118: }
        !           119: 
        !           120: 
        !           121: OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options)
        !           122: {
        !           123:     OSStatus   retval = E_NONE;
        !           124:     struct buf *bp = NULL;
        !           125: 
        !           126:     bp = (struct buf *) blockPtr->blockHeader;
        !           127: 
        !           128:     if (bp == NULL) {
        !           129:         DBG_TREE(("ReleaseBlockProc: blockHeader is zero!\n"));
        !           130:         retval = -1;
        !           131:         goto exit;
        !           132:     }
        !           133: 
        !           134:     if (options & kTrashBlock) {
        !           135:         bp->b_flags |= B_INVAL;
        !           136:        brelse(bp);     /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */
        !           137:     } else {
        !           138:         if (options & kForceWriteBlock) {
        !           139:             bp->b_flags |= B_DIRTY;
        !           140:             retval = bwrite(bp);
        !           141:         } else if (options & kMarkBlockDirty) {
        !           142:             bp->b_flags |= B_DIRTY;
        !           143: #if FORCESYNCBTREEWRITES
        !           144:             bwrite(bp);
        !           145: #else
        !           146:                        if (options & kLockTransaction) {
        !           147: 
        !           148:                    /*
        !           149:                     *
        !           150:                     * Set the B_LOCKED flag and unlock the buffer, causing brelse to move
        !           151:                     * the buffer onto the LOCKED free list.  This is necessary, otherwise
        !           152:                     * getnewbuf() would try to reclaim the buffers using bawrite, which
        !           153:                     * isn't going to work.
        !           154:                     *
        !           155:                     */
        !           156:                    bp->b_flags |= B_LOCKED;
        !           157:                };
        !           158:             bdwrite(bp);
        !           159: 
        !           160: #endif
        !           161:         } else {
        !           162:                brelse(bp);     /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */
        !           163:         };
        !           164:     };
        !           165: 
        !           166: exit:
        !           167:     return (retval);
        !           168: }
        !           169: 
        !           170: 
        !           171: OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF)
        !           172: {
        !           173: #pragma unused (maxEOF)
        !           174: 
        !           175:        OSStatus        retval;
        !           176:        UInt64          actualBytesAdded;
        !           177:        UInt64          bytesToAdd;
        !           178:     UInt32             extendFlags;
        !           179:        BTreeInfoRec btInfo;
        !           180:        ExtendedVCB     *vcb;
        !           181:        FCB                     *filePtr;
        !           182:     struct proc *p = NULL;
        !           183: 
        !           184: 
        !           185:        filePtr = GetFileControlBlock(vp);
        !           186: 
        !           187:        if ( minEOF > filePtr->fcbEOF )
        !           188:        {
        !           189:                bytesToAdd = minEOF - filePtr->fcbEOF;
        !           190: 
        !           191:                if (bytesToAdd < filePtr->fcbClmpSize)
        !           192:                        bytesToAdd = filePtr->fcbClmpSize;              //XXX why not always be a mutiple of clump size?
        !           193:        }
        !           194:        else
        !           195:        {
        !           196:                DBG_TREE((" ExtendBTreeFile: minEOF is smaller than current size!"));
        !           197:                return -1;
        !           198:        }
        !           199: 
        !           200:        vcb = FCBTOVCB(filePtr);
        !           201:        
        !           202:        /*
        !           203:         * The Extents B-tree can't have overflow extents. ExtendFileC will
        !           204:         * return an error if an attempt is made to extend the Extents B-tree
        !           205:         * when the resident extents are exhausted.
        !           206:         */
        !           207:     /* XXX warning - this can leave the volume bitmap unprotected during ExtendFileC call */
        !           208:        if(H_FILEID(filePtr) != kHFSExtentsFileID)
        !           209:        {
        !           210:                p = current_proc();
        !           211:                /* lock extents b-tree (also protects volume bitmap) */
        !           212:                retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, p);
        !           213:                if (retval)
        !           214:                        return (retval);
        !           215:        }
        !           216: 
        !           217:     (void) BTGetInformation(filePtr, 0, &btInfo);
        !           218: 
        !           219:        /*
        !           220:      * The b-tree code expects nodes to be contiguous. So when
        !           221:         * the allocation block size is less than the b-tree node
        !           222:      * size, we need to force disk allocations to be contiguous.
        !           223:      */
        !           224:        if (vcb->blockSize >= btInfo.nodeSize) {
        !           225:                extendFlags = 0;
        !           226:        } else {
        !           227:                /* Ensure that all b-tree nodes are contiguous on disk */
        !           228:                extendFlags = kEFAllMask | kEFContigMask;
        !           229:        }
        !           230: 
        !           231:     retval = ExtendFileC(vcb, filePtr, bytesToAdd, extendFlags, &actualBytesAdded );
        !           232: 
        !           233:        if(H_FILEID(filePtr) != kHFSExtentsFileID)
        !           234:                (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
        !           235: 
        !           236:        if (retval)
        !           237:                return (retval);
        !           238: 
        !           239:        if (actualBytesAdded < bytesToAdd)
        !           240:                DBG_TREE((" ExtendBTreeFile: actualBytesAdded < bytesToAdd!"));
        !           241:        
        !           242:        filePtr->fcbEOF = filePtr->fcbPLen;
        !           243: 
        !           244:        retval = ClearBTNodes(vp, btInfo.nodeSize, filePtr->fcbEOF - actualBytesAdded, actualBytesAdded);       
        !           245:        if (retval)
        !           246:                return (retval);
        !           247:        
        !           248:        /*
        !           249:         * Update the Alternate MDB or Alternate VolumeHeader
        !           250:         */
        !           251:        if ((H_FILEID(filePtr) == kHFSExtentsFileID)    ||
        !           252:            (H_FILEID(filePtr) == kHFSCatalogFileID)    ||
        !           253:            (H_FILEID(filePtr) == kHFSAttributesFileID)
        !           254:           ) {
        !           255:                MarkVCBDirty( vcb );
        !           256:                if (vcb->vcbSigWord == kHFSPlusSigWord) {
        !           257:                        retval = hfs_flushvolumeheader(VCBTOHFS(vcb), 0);
        !           258:                } else {
        !           259:                        retval = hfs_flushMDB(VCBTOHFS(vcb), 0);
        !           260:                }
        !           261:                if (retval == 0) {
        !           262:                        retval = FlushAlternate(vcb);
        !           263:                }
        !           264:        }
        !           265:        
        !           266:        return retval;
        !           267: }
        !           268: 
        !           269: 
        !           270: static OSStatus
        !           271: FlushAlternate( ExtendedVCB *vcb )
        !           272: {
        !           273:        void *maindata;
        !           274:        void *altdata;
        !           275:        int result;
        !           276: 
        !           277:        /* Get the main MDB/VolumeHeader block */
        !           278:        result = GetBlock_glue(gbDefault,
        !           279:                        (vcb->hfsPlusIOPosOffset / kHFSBlockSize) + kMasterDirectoryBlock,
        !           280:                        (Ptr *)&maindata, kNoFileReference, vcb);
        !           281:        if (result) return (result);
        !           282:        
        !           283:        /* Get the alternate MDB/VolumeHeader block */
        !           284:        result = GetBlock_glue( gbDefault, vcb->altIDSector,
        !           285:                        (Ptr *)&altdata, kNoFileReference, vcb );
        !           286: 
        !           287:        if (result == 0) {
        !           288:                bcopy(maindata, altdata, kMDBSize);
        !           289: 
        !           290:                result = RelBlock_glue( (Ptr)altdata, rbWriteMask );
        !           291:        }
        !           292: 
        !           293:        (void) RelBlock_glue( (Ptr)maindata, rbFreeMask );
        !           294:        
        !           295:        return (result);
        !           296: }
        !           297: 
        !           298: 
        !           299: /*
        !           300:  * Clear out (zero) new b-tree nodes on disk.
        !           301:  */
        !           302: static int
        !           303: ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount)
        !           304: {
        !           305:        struct buf *bp = NULL;
        !           306:        daddr_t blk;
        !           307:        daddr_t blkcnt;
        !           308:     
        !           309:        blk = offset / blksize;
        !           310:        blkcnt = amount / blksize;
        !           311:        
        !           312:        while (blkcnt > 0) {
        !           313:                bp = getblk(vp, blk, blksize, 0, 0);    /* ubc: BLK_META */
        !           314:                if (bp == NULL)
        !           315:                        continue;
        !           316:                bzero((char *)bp->b_data, blksize);
        !           317:                bp->b_flags |= (B_DIRTY | B_AGE);
        !           318: 
        !           319:                 /* wait/yield every 32 blocks so we don't hog all the buffers */
        !           320:                if ((blk % 32) == 0)
        !           321:                        bwrite(bp);
        !           322:                else
        !           323:                        bawrite(bp);
        !           324:                --blkcnt;
        !           325:                ++blk;
        !           326:        }
        !           327: 
        !           328:        return (0);
        !           329: }

unix.superglobalmegacorp.com

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