X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..9bccf70c0258c7cac2dcb80011b2a964d884c552:/bsd/hfs/hfs_btreeio.c diff --git a/bsd/hfs/hfs_btreeio.c b/bsd/hfs/hfs_btreeio.c index 67e52e0ef..6947a695a 100644 --- a/bsd/hfs/hfs_btreeio.c +++ b/bsd/hfs/hfs_btreeio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,32 +19,17 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* @(#)hfs_btreeio.c -* -* (c) 1998, 2000 Apple Computer, Inc. All Rights Reserved -* -* hfs_btreeio.c -- I/O Routines for the HFS B-tree files. -* -* HISTORY -* 15-Feb-2000 Don Brady Added ClearBTNodes. -* 16-Jul-1998 Don Brady In ExtendBtreeFile force all b-tree nodes to be contiguous on disk. -* 4-Jun-1998 Pat Dirks Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1) -* 18-apr-1998 Don Brady Call brelse on bread failure. -* 17-Apr-1998 Pat Dirks Fixed ReleaseBTreeBlock to not call brelse when bwrite or bdwrite is called. -* 13-apr-1998 Don Brady Add ExtendBTreeFile routine (from BTreeWrapper.c). -* 26-mar-1998 Don Brady SetBTreeBlockSize was incorrectly excluding 512 byte blockSize. -* 18-feb-1998 Don Brady Initially created file. -* -*/ #include #include #include +#include #include #include #include "hfs.h" +#include "hfs_cnode.h" #include "hfs_dbg.h" #include "hfs_endian.h" @@ -53,49 +38,37 @@ #define FORCESYNCBTREEWRITES 0 -static OSStatus FlushAlternate( ExtendedVCB *vcb ); static int ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount); +__private_extern__ OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount) { BTreeControlBlockPtr bTreePtr; DBG_ASSERT(vp != NULL); - DBG_ASSERT(VTOFCB(vp) != NULL); - DBG_ASSERT(VTOFCB(vp)->fcbBTCBPtr != NULL); DBG_ASSERT(blockSize >= kMinNodeSize); if (blockSize > MAXBSIZE ) return (fsBTBadNodeSize); - DBG_TREE(("SetBlockSizeProc: blockSize=%ld for file %ld\n", blockSize, H_FILEID(VTOH(vp)))); - - bTreePtr = (BTreeControlBlockPtr)(VTOH(vp)->fcbBTCBPtr); + bTreePtr = (BTreeControlBlockPtr)VTOF(vp)->fcbBTCBPtr; bTreePtr->nodeSize = blockSize; return (E_NONE); } +__private_extern__ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block) { OSStatus retval = E_NONE; struct buf *bp = NULL; - if (options & kGetEmptyBlock) - bp = getblk (vp, - IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size), - IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size), - 0, - 0, - BLK_META); - else - retval = meta_bread(vp, - IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size), - IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size), - NOCRED, - &bp); + if (options & kGetEmptyBlock) + bp = getblk(vp, blockNum, block->blockSize, 0, 0, BLK_META); + else + retval = meta_bread(vp, blockNum, block->blockSize, NOCRED, &bp); DBG_ASSERT(bp != NULL); DBG_ASSERT(bp->b_data != NULL); @@ -107,7 +80,7 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option if (retval == E_NONE) { block->blockHeader = bp; - block->buffer = bp->b_data + IOBYTEOFFSETFORBLK(bp->b_blkno, VTOHFS(vp)->hfs_phys_block_size); + block->buffer = bp->b_data; block->blockReadFromDisk = (bp->b_flags & B_CACHE) == 0; /* not found in cache ==> came from disk */ #if BYTE_ORDER == LITTLE_ENDIAN @@ -119,11 +92,11 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option (SWAP_BE16 (((BTHeaderRec *)((char *)block->buffer + 14))->nodeSize) != bp->b_bcount)) { /* Don't swap the descriptors at all, we don't care (this block will be invalidated) */ - SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), H_FILEID(VTOH(vp)), 3); + SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 3); /* The node needs swapping */ } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) == 0x0e00) { - SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), H_FILEID(VTOH(vp)), 0); + SWAP_BT_NODE (block, ISHFSPLUS(VTOVCB(vp)), VTOC(vp)->c_fileid, 0); #if 0 /* The node is not already in native byte order, hence corrupt */ } else if (*((UInt16 *)((char *)block->buffer + (block->blockSize - sizeof (UInt16)))) != 0x000e) { @@ -143,15 +116,16 @@ OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions option } +__private_extern__ OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options) { + extern int bdwrite_internal(struct buf *, int); OSStatus retval = E_NONE; struct buf *bp = NULL; bp = (struct buf *) blockPtr->blockHeader; if (bp == NULL) { - DBG_TREE(("ReleaseBlockProc: blockHeader is zero!\n")); retval = -1; goto exit; } @@ -161,26 +135,41 @@ OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlock brelse(bp); /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */ } else { if (options & kForceWriteBlock) { - bp->b_flags |= B_DIRTY; retval = VOP_BWRITE(bp); } else if (options & kMarkBlockDirty) { - bp->b_flags |= B_DIRTY; #if FORCESYNCBTREEWRITES VOP_BWRITE(bp); #else - if (options & kLockTransaction) { - - /* - * - * Set the B_LOCKED flag and unlock the buffer, causing brelse to move - * the buffer onto the LOCKED free list. This is necessary, otherwise - * getnewbuf() would try to reclaim the buffers using bawrite, which - * isn't going to work. - * - */ - bp->b_flags |= B_LOCKED; - }; - bdwrite(bp); + if (options & kLockTransaction) { + /* + * + * Set the B_LOCKED flag and unlock the buffer, causing brelse to move + * the buffer onto the LOCKED free list. This is necessary, otherwise + * getnewbuf() would try to reclaim the buffers using bawrite, which + * isn't going to work. + * + */ + extern int count_lock_queue __P((void)); + /* Don't hog all the buffers... */ + if (count_lock_queue() > kMaxLockedMetaBuffers) { + hfs_btsync(vp, HFS_SYNCTRANS); + /* Rollback sync time to cause a sync on lock release... */ + (void) BTSetLastSync(VTOF(vp), time.tv_sec - (kMaxSecsForFsync + 1)); + } + bp->b_flags |= B_LOCKED; + } + /* + * Delay-write this block. + * If the maximum delayed buffers has been exceeded then + * free up some buffers and fall back to an asynchronous write. + */ + if (bdwrite_internal(bp, 1) != 0) { + hfs_btsync(vp, 0); + /* Rollback sync time to cause a sync on lock release... */ + (void) BTSetLastSync(VTOF(vp), time.tv_sec - (kMaxSecsForFsync + 1)); + bp->b_flags &= ~B_LOCKED; + bawrite(bp); + } #endif } else { @@ -193,6 +182,7 @@ exit: } +__private_extern__ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) { #pragma unused (maxEOF) @@ -201,6 +191,8 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) UInt64 actualBytesAdded; UInt64 bytesToAdd; UInt32 extendFlags; + u_int32_t startAllocation; + u_int32_t fileblocks; BTreeInfoRec btInfo; ExtendedVCB *vcb; FCB *filePtr; @@ -213,16 +205,15 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) { bytesToAdd = minEOF - filePtr->fcbEOF; - if (bytesToAdd < filePtr->fcbClmpSize) - bytesToAdd = filePtr->fcbClmpSize; //XXX why not always be a mutiple of clump size? + if (bytesToAdd < filePtr->ff_clumpsize) + bytesToAdd = filePtr->ff_clumpsize; //XXX why not always be a mutiple of clump size? } else { - DBG_TREE((" ExtendBTreeFile: minEOF is smaller than current size!")); return -1; } - vcb = FCBTOVCB(filePtr); + vcb = VTOVCB(vp); /* * The Extents B-tree can't have overflow extents. ExtendFileC will @@ -230,7 +221,7 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) * when the resident extents are exhausted. */ /* XXX warning - this can leave the volume bitmap unprotected during ExtendFileC call */ - if(H_FILEID(filePtr) != kHFSExtentsFileID) + if(VTOC(vp)->c_fileid != kHFSExtentsFileID) { p = current_proc(); /* lock extents b-tree (also protects volume bitmap) */ @@ -242,10 +233,10 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) (void) BTGetInformation(filePtr, 0, &btInfo); /* - * The b-tree code expects nodes to be contiguous. So when + * The b-tree code expects nodes to be contiguous. So when * the allocation block size is less than the b-tree node - * size, we need to force disk allocations to be contiguous. - */ + * size, we need to force disk allocations to be contiguous. + */ if (vcb->blockSize >= btInfo.nodeSize) { extendFlags = 0; } else { @@ -253,18 +244,36 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) extendFlags = kEFAllMask | kEFContigMask; } - retval = ExtendFileC(vcb, filePtr, bytesToAdd, extendFlags, &actualBytesAdded ); + fileblocks = filePtr->ff_blocks; + startAllocation = vcb->nextAllocation; - if(H_FILEID(filePtr) != kHFSExtentsFileID) - (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + retval = ExtendFileC(vcb, filePtr, bytesToAdd, 0, extendFlags, &actualBytesAdded); + /* + * If a new extent was added then move the roving allocator + * reference forward by the current b-tree file size so + * there's plenty of room to grow. + */ + if ((retval == 0) && + (vcb->nextAllocation > startAllocation) && + ((vcb->nextAllocation + fileblocks) < vcb->totalBlocks)) { + vcb->nextAllocation += fileblocks; + } + + if(VTOC(vp)->c_fileid != kHFSExtentsFileID) { + /* + * Get any extents overflow b-tree changes to disk ASAP! + */ + if (retval == 0) { + (void) BTFlushPath(VTOF(vcb->extentsRefNum)); + (void) VOP_FSYNC(vcb->extentsRefNum, NOCRED, MNT_WAIT, p); + } + (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p); + } if (retval) return (retval); - - if (actualBytesAdded < bytesToAdd) - DBG_TREE((" ExtendBTreeFile: actualBytesAdded < bytesToAdd!")); - filePtr->fcbEOF = filePtr->fcbPLen; + filePtr->fcbEOF = (u_int64_t)filePtr->ff_blocks * (u_int64_t)vcb->blockSize; retval = ClearBTNodes(vp, btInfo.nodeSize, filePtr->fcbEOF - actualBytesAdded, actualBytesAdded); if (retval) @@ -273,54 +282,18 @@ OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF) /* * Update the Alternate MDB or Alternate VolumeHeader */ - if ((H_FILEID(filePtr) == kHFSExtentsFileID) || - (H_FILEID(filePtr) == kHFSCatalogFileID) || - (H_FILEID(filePtr) == kHFSAttributesFileID) + if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) || + (VTOC(vp)->c_fileid == kHFSCatalogFileID) || + (VTOC(vp)->c_fileid == kHFSAttributesFileID) ) { MarkVCBDirty( vcb ); - if (vcb->vcbSigWord == kHFSPlusSigWord) { - retval = hfs_flushvolumeheader(VCBTOHFS(vcb), 0); - } else { - retval = hfs_flushMDB(VCBTOHFS(vcb), 0); - } - if (retval == 0) { - retval = FlushAlternate(vcb); - } + retval = hfs_flushvolumeheader(VCBTOHFS(vcb), MNT_WAIT, HFS_ALTFLUSH); } return retval; } -static OSStatus -FlushAlternate( ExtendedVCB *vcb ) -{ - void *maindata; - void *altdata; - int result; - - /* Get the main MDB/VolumeHeader block */ - result = GetBlock_glue(gbDefault, - (vcb->hfsPlusIOPosOffset / kHFSBlockSize) + kMasterDirectoryBlock, - (Ptr *)&maindata, kNoFileReference, vcb); - if (result) return (result); - - /* Get the alternate MDB/VolumeHeader block */ - result = GetBlock_glue( gbDefault, vcb->altIDSector, - (Ptr *)&altdata, kNoFileReference, vcb ); - - if (result == 0) { - bcopy(maindata, altdata, kMDBSize); - - result = RelBlock_glue( (Ptr)altdata, rbWriteMask ); - } - - (void) RelBlock_glue( (Ptr)maindata, rbFreeMask ); - - return (result); -} - - /* * Clear out (zero) new b-tree nodes on disk. */ @@ -339,7 +312,7 @@ ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount) if (bp == NULL) continue; bzero((char *)bp->b_data, blksize); - bp->b_flags |= (B_DIRTY | B_AGE); + bp->b_flags |= B_AGE; /* wait/yield every 32 blocks so we don't hog all the buffers */ if ((blk % 32) == 0)