]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / VolumeAllocation.c
index e8006d1074dec873facb9737c46a85fc6cf6acf6..747eb994ee6a45d707178b8bb8371dfb53f1a2db 100644 (file)
@@ -1,21 +1,24 @@
 /*
- * 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@
  */
@@ -118,6 +121,7 @@ static OSErr BlockAllocateAny(
        UInt32                  startingBlock,
        UInt32                  endingBlock,
        UInt32                  maxBlocks,
+       Boolean                 useMetaZone,
        UInt32                  *actualStartBlock,
        UInt32                  *actualNumBlocks);
 
@@ -126,6 +130,7 @@ static OSErr BlockAllocateContig(
        UInt32                  startingBlock,
        UInt32                  minBlocks,
        UInt32                  maxBlocks,
+       Boolean                 useMetaZone,
        UInt32                  *actualStartBlock,
        UInt32                  *actualNumBlocks);
 
@@ -135,19 +140,10 @@ static OSErr BlockFindContiguous(
        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,
@@ -172,19 +168,17 @@ static OSErr BlockAllocateKnown(
 ;                         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.)
 ;
@@ -198,21 +192,22 @@ static OSErr BlockAllocateKnown(
 ;________________________________________________________________________________
 */
 
+__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
 
        //
@@ -220,25 +215,29 @@ OSErr BlockAllocate (
        //
        *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.
@@ -249,13 +248,27 @@ OSErr BlockAllocate (
                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
@@ -266,9 +279,13 @@ OSErr BlockAllocate (
                 */
                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) {
@@ -282,13 +299,16 @@ OSErr BlockAllocate (
                //
                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);
@@ -320,6 +340,7 @@ Exit:
 ;________________________________________________________________________________
 */
 
+__private_extern__
 OSErr BlockDeallocate (
        ExtendedVCB             *vcb,                   //      Which volume to deallocate space on
        UInt32                  firstBlock,             //      First block in range to deallocate
@@ -347,42 +368,98 @@ OSErr BlockDeallocate (
        //
        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);
+}
+
 
 /*
 ;_______________________________________________________________________
@@ -465,11 +542,23 @@ static OSErr ReleaseBitmapBlock(
        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);
                }
@@ -494,6 +583,7 @@ Inputs:
        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
@@ -505,6 +595,7 @@ static OSErr BlockAllocateContig(
        UInt32                  startingBlock,
        UInt32                  minBlocks,
        UInt32                  maxBlocks,
+       Boolean                 useMetaZone,
        UInt32                  *actualStartBlock,
        UInt32                  *actualNumBlocks)
 {
@@ -524,18 +615,22 @@ static OSErr BlockAllocateContig(
         * 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.
        //
@@ -550,8 +645,6 @@ Exit:
        return err;
 }
 
-extern OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr);
-
 /*
 _______________________________________________________________________
 
@@ -567,6 +660,7 @@ Inputs:
        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
@@ -578,6 +672,7 @@ static OSErr BlockAllocateAny(
        UInt32                  startingBlock,
        register UInt32 endingBlock,
        UInt32                  maxBlocks,
+       Boolean                 useMetaZone,
        UInt32                  *actualStartBlock,
        UInt32                  *actualNumBlocks)
 {
@@ -586,24 +681,31 @@ static OSErr BlockAllocateAny(
        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
@@ -628,7 +730,7 @@ static OSErr BlockAllocateAny(
        while (block < endingBlock) {
                if ((currentWord & bitMask) == 0)
                        break;
-               
+
                //      Next bit
                ++block;
                bitMask >>= 1;
@@ -636,27 +738,36 @@ static OSErr BlockAllocateAny(
                        //      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;
        }
@@ -673,6 +784,11 @@ static OSErr BlockAllocateAny(
                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
        //
@@ -696,14 +812,31 @@ static OSErr BlockAllocateAny(
                        
                        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;
                        }
                        
@@ -715,6 +848,10 @@ static OSErr BlockAllocateAny(
 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;
@@ -802,6 +939,10 @@ static OSErr BlockAllocateKnown(
                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
        //
@@ -825,7 +966,8 @@ Inputs:
        numBlocks               Number of blocks to mark as allocated
 _______________________________________________________________________
 */
-static OSErr BlockMarkAllocated(
+__private_extern__
+OSErr BlockMarkAllocated(
        ExtendedVCB             *vcb,
        UInt32                  startingBlock,
        register UInt32 numBlocks)
@@ -840,6 +982,9 @@ static OSErr BlockMarkAllocated(
        UInt32  blockRef;
        UInt32  bitsPerBlock;
        UInt32  wordsPerBlock;
+       // XXXdbg
+       struct hfsmount *hfsmp = VCBTOHFS(vcb);
+
 
        //
        //      Pre-read the bitmap block containing the first word of allocation
@@ -861,6 +1006,11 @@ static OSErr BlockMarkAllocated(
                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
@@ -904,6 +1054,11 @@ static OSErr BlockMarkAllocated(
                        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;
@@ -937,6 +1092,11 @@ static OSErr BlockMarkAllocated(
                        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;
@@ -975,7 +1135,8 @@ Inputs:
        numBlocks               Number of blocks to mark as freed
 _______________________________________________________________________
 */
-static OSErr BlockMarkFree(
+__private_extern__
+OSErr BlockMarkFree(
        ExtendedVCB             *vcb,
        UInt32                  startingBlock,
        register UInt32 numBlocks)
@@ -990,6 +1151,14 @@ static OSErr BlockMarkFree(
        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
@@ -997,6 +1166,11 @@ static OSErr BlockMarkFree(
 
        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.
        //
@@ -1025,11 +1199,9 @@ static OSErr BlockMarkFree(
                        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
 
@@ -1053,16 +1225,18 @@ static OSErr BlockMarkFree(
                        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;
                
@@ -1087,15 +1261,18 @@ static OSErr BlockMarkFree(
                        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
@@ -1107,6 +1284,17 @@ Exit:
                (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
 }
 
 
@@ -1125,6 +1313,7 @@ Inputs:
        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
@@ -1142,6 +1331,7 @@ static OSErr BlockFindContiguous(
        UInt32                  endingBlock,
        UInt32                  minBlocks,
        UInt32                  maxBlocks,
+       Boolean                 useMetaZone,
        UInt32                  *actualStartBlock,
        UInt32                  *actualNumBlocks)
 {
@@ -1158,6 +1348,15 @@ static OSErr BlockFindContiguous(
        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
@@ -1167,7 +1366,14 @@ static OSErr BlockFindContiguous(
 
        stopBlock = endingBlock - minBlocks + 1;
        currentBlock = startingBlock;
-       
+       firstBlock = 0;
+
+       /*
+        * Skip over metadata blocks.
+        */
+       if (!useMetaZone)
+               currentBlock = NextBitmapBlock(vcb, currentBlock);
+
        //
        //      Pre-read the first bitmap block.
        //
@@ -1179,7 +1385,7 @@ static OSErr BlockFindContiguous(
        //
        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;
        
@@ -1197,7 +1403,7 @@ static OSErr BlockFindContiguous(
                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)
                        {
@@ -1226,6 +1432,16 @@ static OSErr BlockFindContiguous(
                                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;
                                
@@ -1234,7 +1450,7 @@ static OSErr BlockFindContiguous(
                        }
                        
                        //      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;
@@ -1273,7 +1489,7 @@ FoundUnused:
                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))
                        {
@@ -1302,6 +1518,18 @@ FoundUnused:
                                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;
                                
@@ -1310,7 +1538,7 @@ FoundUnused:
                        }
                        
                        //      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;
@@ -1367,7 +1595,7 @@ FoundUsed:
                                ++vcb->vcbFreeExtCnt;
                }
        } while (currentBlock < stopBlock);
-
+LoopExit:
 
        //      Return the outputs.
        if (foundBlocks < minBlocks)