/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
UInt32 startingBlock,
UInt32 endingBlock,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks);
UInt32 startingBlock,
UInt32 minBlocks,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks);
UInt32 endingBlock,
UInt32 minBlocks,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks);
-static OSErr BlockMarkAllocated(
- ExtendedVCB *vcb,
- UInt32 startingBlock,
- UInt32 numBlocks);
-
-static OSErr BlockMarkFree(
- ExtendedVCB *vcb,
- UInt32 startingBlock,
- UInt32 numBlocks);
-
static OSErr BlockAllocateKnown(
ExtendedVCB *vcb,
UInt32 maxBlocks,
; the volume's allocation block pointer will be used as a starting
; point.
;
-; All requests will be rounded up to the next highest clump size, as
-; indicated in the file's FCB.
-;
; Input Arguments:
; vcb - Pointer to ExtendedVCB for the volume to allocate space on
; fcb - Pointer to FCB for the file for which storage is being allocated
; startingBlock - Preferred starting allocation block, 0 = no preference
; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
; or an error is returned
-; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
+; useMetaZone -
+; minBlocks - Number of blocks requested. If the allocation is non-contiguous,
; less than this may actually be allocated
-; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
-; space after bytesRequested, then up to bytesMaximum bytes should really
+; maxBlocks - The maximum number of blocks to allocate. If there is additional free
+; space after bytesRequested, then up to maxBlocks bytes should really
; be allocated. (Used by ExtendFileC to round up allocations to a multiple
; of the file's clump size.)
;
;________________________________________________________________________________
*/
+__private_extern__
OSErr BlockAllocate (
ExtendedVCB *vcb, /* which volume to allocate space on */
UInt32 startingBlock, /* preferred starting block, or 0 for no preference */
- SInt64 bytesRequested, /* desired number of BYTES to allocate */
- SInt64 bytesMaximum, /* maximum number of bytes to allocate */
+ UInt32 minBlocks, /* desired number of blocks to allocate */
+ UInt32 maxBlocks, /* maximum number of blocks to allocate */
Boolean forceContiguous, /* non-zero to force contiguous allocation and to force */
- /* bytesRequested bytes to actually be allocated */
+ /* minBlocks bytes to actually be allocated */
+
+ Boolean useMetaZone,
UInt32 *actualStartBlock, /* actual first block of allocation */
UInt32 *actualNumBlocks) /* number of blocks actually allocated; if forceContiguous */
- /* was zero, then this may represent fewer than bytesRequested */
- /* bytes */
+ /* was zero, then this may represent fewer than minBlocks */
{
+ UInt32 freeBlocks;
OSErr err;
- UInt32 minBlocks; // minimum number of allocation blocks requested
- UInt32 maxBlocks; // number of allocation blocks requested, rounded to clump size
Boolean updateAllocPtr = false; // true if nextAllocation needs to be updated
//
//
*actualStartBlock = 0;
*actualNumBlocks = 0;
-
- //
- // Compute the number of allocation blocks requested, and maximum
- //
- minBlocks = FileBytesToBlocks(bytesRequested, vcb->blockSize);
- maxBlocks = FileBytesToBlocks(bytesMaximum, vcb->blockSize);
+ freeBlocks = hfs_freeblks(VCBTOHFS(vcb), 0);
//
// If the disk is already full, don't bother.
//
- if (vcb->freeBlocks == 0) {
+ if (freeBlocks == 0) {
err = dskFulErr;
goto Exit;
}
- if (forceContiguous && vcb->freeBlocks < minBlocks) {
+ if (forceContiguous && freeBlocks < minBlocks) {
err = dskFulErr;
goto Exit;
}
-
+ /*
+ * Clip if necessary so we don't over-subscribe the free blocks.
+ */
+ if (minBlocks > freeBlocks) {
+ minBlocks = freeBlocks;
+ }
+ if (maxBlocks > freeBlocks) {
+ maxBlocks = freeBlocks;
+ }
+
//
// If caller didn't specify a starting block number, then use the volume's
// next block to allocate from.
VCB_UNLOCK(vcb);
updateAllocPtr = true;
}
+ if (startingBlock >= vcb->totalBlocks) {
+ startingBlock = 0; /* overflow so start at beginning */
+ }
//
// If the request must be contiguous, then find a sequence of free blocks
// that is long enough. Otherwise, find the first free block.
//
if (forceContiguous) {
- err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
+ err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks,
+ useMetaZone, actualStartBlock, actualNumBlocks);
+ /*
+ * If we allocated from a new position then
+ * also update the roving allocatior.
+ */
+ if ((err == noErr) &&
+ (*actualStartBlock > startingBlock) &&
+ ((*actualStartBlock < VCBTOHFS(vcb)->hfs_metazone_start) ||
+ (*actualStartBlock > VCBTOHFS(vcb)->hfs_metazone_end))) {
+ vcb->nextAllocation = *actualStartBlock; /* XXX */
+ }
} else {
/*
* Scan the bitmap once, gather the N largest free extents, then
*/
err = BlockAllocateKnown(vcb, maxBlocks, actualStartBlock, actualNumBlocks);
if (err == dskFulErr)
- err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
+ err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks,
+ maxBlocks, useMetaZone, actualStartBlock,
+ actualNumBlocks);
if (err == dskFulErr)
- err = BlockAllocateAny(vcb, 0, startingBlock, maxBlocks, actualStartBlock, actualNumBlocks);
+ err = BlockAllocateAny(vcb, 1, startingBlock, maxBlocks,
+ useMetaZone, actualStartBlock,
+ actualNumBlocks);
}
if (err == noErr) {
//
VCB_LOCK(vcb);
- if (updateAllocPtr)
+ if (updateAllocPtr &&
+ ((*actualStartBlock < VCBTOHFS(vcb)->hfs_metazone_start) ||
+ (*actualStartBlock > VCBTOHFS(vcb)->hfs_metazone_end))) {
vcb->nextAllocation = *actualStartBlock;
-
+ }
//
// Update the number of free blocks on the volume
//
vcb->freeBlocks -= *actualNumBlocks;
+ hfs_generate_volume_notifications(VCBTOHFS(vcb));
VCB_UNLOCK(vcb);
MarkVCBDirty(vcb);
;________________________________________________________________________________
*/
+__private_extern__
OSErr BlockDeallocate (
ExtendedVCB *vcb, // Which volume to deallocate space on
UInt32 firstBlock, // First block in range to deallocate
//
VCB_LOCK(vcb);
vcb->freeBlocks += numBlocks;
+ hfs_generate_volume_notifications(VCBTOHFS(vcb));
+ if (vcb->nextAllocation == (firstBlock + numBlocks))
+ vcb->nextAllocation -= numBlocks;
VCB_UNLOCK(vcb);
MarkVCBDirty(vcb);
-
+
Exit:
return err;
}
-/*
-;_______________________________________________________________________
-;
-; Routine: FileBytesToBlocks
-;
-; Function: Divide numerator by denominator, rounding up the result if there
-; was a remainder. This is frequently used for computing the number
-; of whole and/or partial blocks used by some count of bytes.
-; Actuall divides a 64 bit by a 32 bit into a 32bit result
-;
-; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
-;_______________________________________________________________________
-*/
-UInt32 FileBytesToBlocks(
- SInt64 numerator,
- UInt32 denominator)
+UInt8 freebitcount[16] = {
+ 4, 3, 3, 2, 3, 2, 2, 1, /* 0 1 2 3 4 5 6 7 */
+ 3, 2, 2, 1, 2, 1, 1, 0, /* 8 9 A B C D E F */
+};
+
+__private_extern__
+UInt32
+MetaZoneFreeBlocks(ExtendedVCB *vcb)
{
- UInt32 quotient;
+ UInt32 freeblocks;
+ UInt32 *currCache;
+ UInt32 blockRef;
+ UInt32 bit;
+ UInt32 lastbit;
+ int bytesleft;
+ int bytesperblock;
+ UInt8 byte;
+ UInt8 *buffer;
+ blockRef = 0;
+ bytesleft = freeblocks = 0;
+ bit = VCBTOHFS(vcb)->hfs_metazone_start;
+ if (bit == 1)
+ bit = 0;
- quotient = (UInt32)(numerator / denominator);
- if (quotient * denominator != numerator)
- quotient++;
-
- return quotient;
+ lastbit = VCBTOHFS(vcb)->hfs_metazone_end;
+ bytesperblock = vcb->vcbVBMIOSize;
+
+ /*
+ * Count all the bits from bit to lastbit.
+ */
+ while (bit < lastbit) {
+ /*
+ * Get next bitmap block.
+ */
+ if (bytesleft == 0) {
+ if (blockRef) {
+ (void) ReleaseBitmapBlock(vcb, blockRef, false);
+ blockRef = 0;
+ }
+ if (ReadBitmapBlock(vcb, bit, &currCache, &blockRef) != 0) {
+ return (0);
+ }
+ buffer = (UInt8 *)currCache;
+ bytesleft = bytesperblock;
+ }
+ byte = *buffer++;
+ freeblocks += freebitcount[byte & 0x0F];
+ freeblocks += freebitcount[(byte >> 4) & 0x0F];
+ bit += kBitsPerByte;
+ --bytesleft;
+ }
+ if (blockRef)
+ (void) ReleaseBitmapBlock(vcb, blockRef, false);
+
+ return (freeblocks);
}
+/*
+ * Obtain the next allocation block (bit) that's
+ * outside the metadata allocation zone.
+ */
+static UInt32 NextBitmapBlock(
+ ExtendedVCB *vcb,
+ UInt32 bit)
+{
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
+ if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) == 0)
+ return (bit);
+ /*
+ * Skip over metadata allocation zone.
+ */
+ if ((bit >= hfsmp->hfs_metazone_start) &&
+ (bit <= hfsmp->hfs_metazone_end)) {
+ bit = hfsmp->hfs_metazone_end + 1;
+ }
+ return (bit);
+}
+
/*
;_______________________________________________________________________
Boolean dirty)
{
struct buf *bp = (struct buf *)blockRef;
+
+ if (blockRef == 0) {
+ if (dirty)
+ panic("ReleaseBitmapBlock: missing bp");
+ return (0);
+ }
if (bp) {
if (dirty) {
- bp->b_flags |= B_DIRTY;
- bdwrite(bp);
+ // XXXdbg
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
+ if (hfsmp->jnl) {
+ journal_modify_block_end(hfsmp->jnl, bp);
+ } else {
+ bdwrite(bp);
+ }
} else {
brelse(bp);
}
startingBlock Preferred first block for allocation
minBlocks Minimum number of contiguous blocks to allocate
maxBlocks Maximum number of contiguous blocks to allocate
+ useMetaZone
Outputs:
actualStartBlock First block of range allocated, or 0 if error
UInt32 startingBlock,
UInt32 minBlocks,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks)
{
* with the free extent cache, this can lead to duplicate entries
* in the cache, causing the same blocks to be allocated twice.
*/
- err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
- actualStartBlock, actualNumBlocks);
+ err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks,
+ maxBlocks, useMetaZone, actualStartBlock, actualNumBlocks);
if (err == dskFulErr && startingBlock != 0) {
/*
* Constrain the endingBlock so we don't bother looking for ranges
* that would overlap those found in the previous call.
*/
- err = BlockFindContiguous(vcb, 0, startingBlock, minBlocks, maxBlocks,
- actualStartBlock, actualNumBlocks);
+ err = BlockFindContiguous(vcb, 1, startingBlock, minBlocks, maxBlocks,
+ useMetaZone, actualStartBlock, actualNumBlocks);
}
if (err != noErr) goto Exit;
+ // sanity check
+ if ((*actualStartBlock + *actualNumBlocks) > vcb->totalBlocks)
+ panic("BlockAllocateContig: allocation overflow on \"%s\"", vcb->vcbVN);
+
//
// Now mark those blocks allocated.
//
return err;
}
-extern OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr);
-
/*
_______________________________________________________________________
startingBlock Preferred first block for allocation
endingBlock Last block to check + 1
maxBlocks Maximum number of contiguous blocks to allocate
+ useMetaZone
Outputs:
actualStartBlock First block of range allocated, or 0 if error
UInt32 startingBlock,
register UInt32 endingBlock,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks)
{
register UInt32 currentWord; // Pointer to current word within bitmap block
register UInt32 bitMask; // Word with given bits already set (ready to OR in)
register UInt32 wordsLeft; // Number of words left in this bitmap block
- UInt32 *buffer = NULL;
- UInt32 *currCache = NULL;
+ UInt32 *buffer = NULL;
+ UInt32 *currCache = NULL;
UInt32 blockRef;
UInt32 bitsPerBlock;
UInt32 wordsPerBlock;
Boolean dirty = false;
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
// Since this routine doesn't wrap around
if (maxBlocks > (endingBlock - startingBlock)) {
maxBlocks = endingBlock - startingBlock;
}
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone)
+ startingBlock = NextBitmapBlock(vcb, startingBlock);
+
//
// Pre-read the first bitmap block
//
- err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef);
+ err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef);
if (err != noErr) goto Exit;
- buffer = currCache;
+ buffer = currCache;
//
// Set up the current position within the block
while (block < endingBlock) {
if ((currentWord & bitMask) == 0)
break;
-
+
// Next bit
++block;
bitMask >>= 1;
// Next word
bitMask = kHighBitInWordMask;
++buffer;
-
+
if (--wordsLeft == 0) {
// Next block
- buffer = currCache = NULL;
+ buffer = currCache = NULL;
err = ReleaseBitmapBlock(vcb, blockRef, false);
if (err != noErr) goto Exit;
- err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone) {
+ block = NextBitmapBlock(vcb, block);
+ if (block >= endingBlock) {
+ err = dskFulErr;
+ goto Exit;
+ }
+ }
+ err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
if (err != noErr) goto Exit;
- buffer = currCache;
+ buffer = currCache;
wordsLeft = wordsPerBlock;
}
-
currentWord = SWAP_BE32 (*buffer);
}
}
// Did we get to the end of the bitmap before finding a free block?
// If so, then couldn't allocate anything.
- if (block == endingBlock) {
+ if (block >= endingBlock) {
err = dskFulErr;
goto Exit;
}
endingBlock = block + maxBlocks; // if we get this far, we've found enough
}
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
//
// Allocate all of the consecutive blocks
//
if (--wordsLeft == 0) {
// Next block
- buffer = currCache = NULL;
+ buffer = currCache = NULL;
err = ReleaseBitmapBlock(vcb, blockRef, true);
if (err != noErr) goto Exit;
- err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone) {
+ UInt32 nextBlock;
+
+ nextBlock = NextBitmapBlock(vcb, block);
+ if (nextBlock != block) {
+ goto Exit; /* allocation gap, so stop */
+ }
+ }
+
+ err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
if (err != noErr) goto Exit;
- buffer = currCache;
+ buffer = currCache;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
wordsLeft = wordsPerBlock;
}
Exit:
if (err == noErr) {
*actualNumBlocks = block - *actualStartBlock;
+
+ // sanity check
+ if ((*actualStartBlock + *actualNumBlocks) > vcb->totalBlocks)
+ panic("BlockAllocateAny: allocation overflow on \"%s\"", vcb->vcbVN);
}
else {
*actualStartBlock = 0;
vcb->vcbFreeExt[i-1].blockCount = newBlockCount;
}
+ // sanity check
+ if ((*actualStartBlock + *actualNumBlocks) > vcb->totalBlocks)
+ panic("BlockAllocateKnown: allocation overflow on \"%s\"", vcb->vcbVN);
+
//
// Now mark the found extent in the bitmap
//
numBlocks Number of blocks to mark as allocated
_______________________________________________________________________
*/
-static OSErr BlockMarkAllocated(
+__private_extern__
+OSErr BlockMarkAllocated(
ExtendedVCB *vcb,
UInt32 startingBlock,
register UInt32 numBlocks)
UInt32 blockRef;
UInt32 bitsPerBlock;
UInt32 wordsPerBlock;
+ // XXXdbg
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
//
// Pre-read the bitmap block containing the first word of allocation
wordsLeft = wordsPerBlock - wordIndexInBlock;
}
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
//
// If the first block to allocate doesn't start on a word
// boundary in the bitmap, then treat that first word
err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
if (err != noErr) goto Exit;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
// Readjust currentWord and wordsLeft
currentWord = buffer;
wordsLeft = wordsPerBlock;
err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
if (err != noErr) goto Exit;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
// Readjust currentWord and wordsLeft
currentWord = buffer;
wordsLeft = wordsPerBlock;
numBlocks Number of blocks to mark as freed
_______________________________________________________________________
*/
-static OSErr BlockMarkFree(
+__private_extern__
+OSErr BlockMarkFree(
ExtendedVCB *vcb,
UInt32 startingBlock,
register UInt32 numBlocks)
UInt32 blockRef;
UInt32 bitsPerBlock;
UInt32 wordsPerBlock;
+ // XXXdbg
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
+ if (startingBlock + numBlocks > vcb->totalBlocks) {
+ panic("hfs: block mark free: trying to free non-existent blocks (%d %d %d)\n",
+ startingBlock, numBlocks, vcb->totalBlocks);
+ }
+
//
// Pre-read the bitmap block containing the first word of allocation
err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
if (err != noErr) goto Exit;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
//
// Initialize currentWord, and wordsLeft.
//
numBits = numBlocks; // entire allocation is inside this one word
bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
}
-#if DEBUG_BUILD
if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
- panic("BlockMarkFree: blocks not allocated!");
+ goto Corruption;
}
-#endif
*currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
numBlocks -= numBits; // adjust number of blocks left to free
err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
if (err != noErr) goto Exit;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
// Readjust currentWord and wordsLeft
currentWord = buffer;
wordsLeft = wordsPerBlock;
}
-
-#if DEBUG_BUILD
if (*currentWord != SWAP_BE32 (kAllBitsSetInWord)) {
- panic("BlockMarkFree: blocks not allocated!");
+ goto Corruption;
}
-#endif
*currentWord = 0; // clear the entire word
numBlocks -= kBitsPerWord;
err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
if (err != noErr) goto Exit;
+ // XXXdbg
+ if (hfsmp->jnl) {
+ journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
+ }
+
// Readjust currentWord and wordsLeft
currentWord = buffer;
wordsLeft = wordsPerBlock;
}
-#if DEBUG_BUILD
if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
- panic("BlockMarkFree: blocks not allocated!");
+ goto Corruption;
}
-#endif
*currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
// No need to update currentWord or wordsLeft
(void)ReleaseBitmapBlock(vcb, blockRef, true);
return err;
+
+Corruption:
+#if DEBUG_BUILD
+ panic("BlockMarkFree: blocks not allocated!");
+#else
+ printf("hfs: WARNING - blocks on volume %s not allocated!\n", vcb->vcbVN);
+ vcb->vcbAtrb |= kHFSVolumeInconsistentMask;
+ MarkVCBDirty(vcb);
+ err = EIO;
+ goto Exit;
+#endif
}
endingBlock Last possible block in range + 1
minBlocks Minimum number of blocks needed. Must be > 0.
maxBlocks Maximum (ideal) number of blocks desired
+ useMetaZone OK to dip into metadata allocation zone
Outputs:
actualStartBlock First block of range found, or 0 if error
UInt32 endingBlock,
UInt32 minBlocks,
UInt32 maxBlocks,
+ Boolean useMetaZone,
UInt32 *actualStartBlock,
UInt32 *actualNumBlocks)
{
UInt32 blockRef;
UInt32 wordsPerBlock;
+ if (!useMetaZone) {
+ struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
+
+ if ((hfsmp->hfs_flags & HFS_METADATA_ZONE) &&
+ (startingBlock <= hfsmp->hfs_metazone_end))
+ startingBlock = hfsmp->hfs_metazone_end + 1;
+ }
+
if ((endingBlock - startingBlock) < minBlocks)
{
// The set of blocks we're checking is smaller than the minimum number
stopBlock = endingBlock - minBlocks + 1;
currentBlock = startingBlock;
-
+ firstBlock = 0;
+
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone)
+ currentBlock = NextBitmapBlock(vcb, currentBlock);
+
//
// Pre-read the first bitmap block.
//
//
wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
- wordsLeft = (startingBlock / kBitsPerWord) & (wordsPerBlock-1); // Current index into buffer
+ wordsLeft = (currentBlock / kBitsPerWord) & (wordsPerBlock-1); // Current index into buffer
currentWord = buffer + wordsLeft;
wordsLeft = wordsPerBlock - wordsLeft;
bitMask = currentBlock & kBitsWithinWordMask;
if (bitMask)
{
- tempWord = *currentWord; // Fetch the current word only once
+ tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
bitMask = kHighBitInWordMask >> bitMask;
while (tempWord & bitMask)
{
err = ReleaseBitmapBlock(vcb, blockRef, false);
if (err != noErr) goto ErrorExit;
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone) {
+ currentBlock = NextBitmapBlock(vcb, currentBlock);
+ if (currentBlock >= stopBlock) {
+ goto LoopExit;
+ }
+ }
+
err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
if ( err != noErr ) goto ErrorExit;
}
// See if any of the bits are clear
- if ((tempWord=*currentWord) + 1) // non-zero if any bits were clear
+ if ((tempWord = SWAP_BE32(*currentWord)) + 1) // non-zero if any bits were clear
{
// Figure out which bit is clear
bitMask = kHighBitInWordMask;
bitMask = currentBlock & kBitsWithinWordMask;
if (bitMask)
{
- tempWord = *currentWord; // Fetch the current word only once
+ tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
bitMask = kHighBitInWordMask >> bitMask;
while (bitMask && !(tempWord & bitMask))
{
err = ReleaseBitmapBlock(vcb, blockRef, false);
if (err != noErr) goto ErrorExit;
+ /*
+ * Skip over metadata blocks.
+ */
+ if (!useMetaZone) {
+ UInt32 nextBlock;
+
+ nextBlock = NextBitmapBlock(vcb, currentBlock);
+ if (nextBlock != currentBlock) {
+ goto LoopExit; /* allocation gap, so stop */
+ }
+ }
+
err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
if ( err != noErr ) goto ErrorExit;
}
// See if any of the bits are set
- if ((tempWord=*currentWord) != 0)
+ if ((tempWord = SWAP_BE32(*currentWord)) != 0)
{
// Figure out which bit is set
bitMask = kHighBitInWordMask;
++vcb->vcbFreeExtCnt;
}
} while (currentBlock < stopBlock);
-
+LoopExit:
// Return the outputs.
if (foundBlocks < minBlocks)