|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.