Annotation of kernel/bsd/hfs/hfscommon/Misc/VolumeAllocation.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:        File:           VolumeAllocation.c
                     27: 
                     28:        Contains:       Routines for accessing and modifying the volume bitmap.
                     29: 
                     30:        Version:        HFS Plus 1.0
                     31: 
                     32:        Copyright:      � 1996-1997 by Apple Computer, Inc., all rights reserved.
                     33: 
                     34:        File Ownership:
                     35: 
                     36:                DRI:                            Mark Day
                     37: 
                     38:                Other Contact:          Greg Parks
                     39: 
                     40:                Technology:                     HFS+
                     41: 
                     42:        Writers:
                     43: 
                     44:                (djb)   Don Brady
                     45:                (DSH)   Deric Horn
                     46:                (msd)   Mark Day
                     47: 
                     48:        Change History (most recent first):
                     49:          <Rhap>         4/27/98        djb             Remove unneccessary DebugStr in BlockVerifyAllocated.
                     50:          <Rhap>         4/17/98        djb             Add VCB locking.
                     51:          <Rhap>         4/13/98        djb             Add RequireFileLock checking to ReadBitmapBlock.
                     52:          <Rhap>         3/31/98        djb             Sync up with final HFSVolumes.h header file.
                     53: 
                     54:          <12>  1       0/31/97         DSH             Modify BlockVerifyAllocated() so DFA can call without actually
                     55:                                                                        writing to the disk.
                     56:          <CS11>        10/20/97        msd             The way BlockAllocate rounds up to a multiple of the clump size
                     57:                                                                        is wrong. ExtendFileC should do the round-up and pass the result
                     58:                                                                        into BlockAllocate. Removed the fcb parameter to BlockAllocate;
                     59:                                                                        added a bytesMaximum parameter.
                     60:          <CS10>        10/17/97        msd             Conditionalize DebugStrs.
                     61:           <CS9>          9/4/97        djb             Add logging to BlockAllocate.
                     62:           <CS8>          9/4/97        msd             Add a histogram of allocation sizes. Use DEBUG_BUILD instead of
                     63:                                                                        VSM_DEBUG to generate DebugStr messages.
                     64:           <CS7>         8/14/97        msd             Bug 1662332. Don't mark blocks dirty in UpdateFreeCount. In
                     65:                                                                        BlockVerifyAllocated, only mark blocks dirty if they've actually
                     66:                                                                        changed.
                     67:           <CS6>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
                     68:                                                                        collision
                     69:           <CS5>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
                     70:           <CS4>         6/12/97        msd             Export BlockAllocateAny and UpdateVCBFreeBlks.
                     71:                 <3>      5/8/97        DSH             Added comments and ascii diagram of new BlockFindContiguous()
                     72:                                                                        algorithm.
                     73:                 <2>      5/7/97        DSH             New faster BlockFindContiguous algorithm.  It searches backwards
                     74:                                                                        until a dirty bit is found instead of forwards.
                     75:           <CS1>         4/25/97        djb             first checked in
                     76: 
                     77:         <HFS21>         4/14/97        msd             Fix UpdateVCBFreeBlks so free space calculation doesn't overflow
                     78:                                                                        on volumes bigger than 4GB.
                     79:         <HFS20>          4/4/97        djb             Get in sync with volume format changes.
                     80:         <HFS19>         1/27/97        msd             Speed up BlockCheck and UpdateFreeCount. Removed DebugStr from
                     81:                                                                        BlockCheck; there are now DebugStr's in BlockVerifyAllocated,
                     82:                                                                        before the bitmap gets fixed (so potential problems can be
                     83:                                                                        debugged easier). Adjusted comments about internal routines.
                     84:                                                                        Changed names of "Fast" routines back to their original names
                     85:                                                                        (since the originals are now removed).
                     86:         <HFS18>         1/24/97        msd             Speed up allocation and deallocation.
                     87:         <HFS17>         1/21/97        msd             Add instrumentation for function entry/exit.  BlockAllocate and
                     88:                                                                        ReadBitMapBlock use the event tag to log bytes requested and
                     89:                                                                        block number (respectively).
                     90:         <HFS16>         1/15/97        djb             Add HFS+ supprt to BlockCheck (for MountCheck).
                     91:         <HFS15>         1/13/97        DSH             Use vcb->nextAllocation instead of vcbAllocPtr.
                     92:         <HFS14>          1/9/97        djb             UpdateVCBFreeBlks is not converting correctly.
                     93:         <HFS13>          1/6/97        djb             Use vcb's allocationsRefNum to access allocation file.
                     94:         <HFS12>          1/2/97        DSH             Added UpdateVCBFreeBlks() to update vcbFreeBks whenever we
                     95:                                                                        update vcb->freeblocks.
                     96:         <HFS11>        12/19/96        DSH             All refs to VCB are now refs to ExtendedVCB
                     97:         <HFS10>        12/12/96        msd             DivideAndRoundUp should not be declared as static.
                     98:          <HFS9>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
                     99:          <HFS8>         12/4/96        DSH             PrecompiledHeaders
                    100:          <HFS7>        11/27/96        djb             Added AllocateFreeSpace for HFS wrapper support.
                    101:          <HFS6>        11/27/96        msd             Changed ReadBitmapBlock to read from HFS+ allocation file.
                    102:                                                                        Temporarily uses the vcbVBMSt field of the VCB as the allocation
                    103:                                                                        file's refnum until extended VCB changes are checked in.
                    104:          <HFS5>        11/26/96        msd             VSM and FileExtentMapping routines use FCB instead of FCBRec.
                    105:          <HFS4>        11/20/96        DSH             Changed a parameter in GetBlock_glue, so I also changed the
                    106:                                                                        caller.
                    107:          <HFS3>        11/20/96        msd             Include FilesInternal.h. Remove definition of MarkVCBDirty
                    108:                                                                        (since it is now in FilesInternal.h).
                    109:          <HFS2>        11/12/96        msd             Need to bound allocations to be within the last allocation block
                    110:                                                                        of the volume (function AllocateAt).
                    111:          <HFS1>        11/11/96        msd             first checked in
                    112: */
                    113: 
                    114: /*
                    115: Public routines:
                    116:        BlockAllocate
                    117:                                        Allocate space on a volume.  Can allocate space contiguously.
                    118:                                        If not contiguous, then allocation may be less than what was
                    119:                                        asked for.  Returns the starting block number, and number of
                    120:                                        blocks.  (Will only do a single extent???)
                    121:        BlockDeallocate
                    122:                                        Deallocate a contiguous run of allocation blocks.
                    123:        BlockCheck
                    124:                                        Makes sure that the blocks associated with an extent record
                    125:                                        are in fact allocated in the bitmap.  The bits will be set
                    126:                                        if needed.  Returns whether any bits needed to be set.
                    127:        UpdateFreeCount
                    128:                                        Computes the number of free allocation blocks on a volume.
                    129:                                        The vcb's free block count is updated.
                    130: 
                    131:        AllocateFreeSpace
                    132:                                        Allocates all the remaining free space (used for embedding HFS+ volumes).
                    133: 
                    134:        BlockAllocateAny
                    135:                                        Find and allocate a contiguous range of blocks up to a given size.  The
                    136:                                        first range of contiguous free blocks found are allocated, even if there
                    137:                                        are fewer blocks than requested (and even if a contiguous range of blocks
                    138:                                        of the given size exists elsewhere).
                    139: 
                    140:        UpdateVCBFreeBlks
                    141:                                        Given an ExtenddVCB, calculate the vcbFreeBks value
                    142:                                        so that vcbFreeBks*vcbAlBlkSiz == freeBlocks*blockSize.
                    143: 
                    144: Internal routines:
                    145:        BlockVerifyAllocated
                    146:                                        Makes sure that a contiguous range of blocks are marked as used
                    147:                                        in the bitmap.  If not, those blocks will be marked as used.  A
                    148:                                        boolean is returned to indicate whether any unmarked blocks were
                    149:                                        found (and fixed).
                    150:        BlockMarkFree
                    151:                                        Mark a contiguous range of blocks as free.  The corresponding
                    152:                                        bits in the volume bitmap will be cleared.
                    153:        BlockMarkAllocated
                    154:                                        Mark a contiguous range of blocks as allocated.  The cor-
                    155:                                        responding bits in the volume bitmap are set.  Also tests to see
                    156:                                        if any of the blocks were previously unallocated.
                    157:        FindContiguous
                    158:                                        Find a contiguous range of blocks of a given size.  The caller
                    159:                                        specifies where to begin the search (by block number).  The
                    160:                                        block number of the first block in the range is returned.
                    161:        BlockAllocateContig
                    162:                                        Find and allocate a contiguous range of blocks of a given size.  If
                    163:                                        a contiguous range of free blocks of the given size isn't found, then
                    164:                                        the allocation fails (i.e. it is "all or nothing").
                    165:        ReadBitmapBlock
                    166:                                        Given an allocation block number, read the bitmap block that
                    167:                                        contains that allocation block into a caller-supplied buffer.
                    168: */
                    169: 
                    170: #include "../headers/system/ConditionalMacros.h"
                    171: 
                    172: #if ( PRAGMA_LOAD_SUPPORTED )
                    173:         #pragma        load    PrecompiledHeaders
                    174: #else
                    175:        #if TARGET_OS_MAC
                    176:                #include <FSM.h>
                    177:        #else
                    178:         #include "../headers/system/MacOSStubs.h"
                    179: #include <sys/types.h>
                    180: #include <sys/buf.h>
                    181: #include <sys/systm.h>
                    182: 
                    183: #include "../../hfs.h"
                    184: #include "../../hfs_dbg.h"
                    185:        #endif  /* TARGET_OS_MAC */
                    186: #endif /* PRAGMA_LOAD_SUPPORTED */
                    187: 
                    188: 
                    189: #if HFSInstrumentation
                    190:        #include "Instrumentation.h"
                    191: #endif
                    192:        
                    193: #include "../headers/HFSVolumes.h"
                    194: #include "../headers/FileMgrInternal.h"
                    195: 
                    196: #include "../headers/system/HFSInstrumentation.h"
                    197: 
                    198: #if TARGET_OS_RHAPSODY
                    199: #define EXPLICIT_BUFFER_RELEASES 1
                    200: #endif
                    201: 
                    202: enum {
                    203:        kBitsPerByte                    =       8,
                    204:        kBitsPerWord                    =       32,
                    205:        kWordsPerBlock                  =       128,
                    206:        kBytesPerBlock                  =       512,
                    207:        kBitsPerBlock                   =       4096,
                    208:        
                    209:        kBitsWithinWordMask             =       kBitsPerWord-1,
                    210:        kBitsWithinBlockMask    =       kBitsPerBlock-1,
                    211:        kWordsWithinBlockMask   =       kWordsPerBlock-1,
                    212:        
                    213:        kExtentsPerRecord               =       3
                    214: };
                    215: 
                    216: #define kLowBitInWordMask      0x00000001ul
                    217: #define kHighBitInWordMask     0x80000000ul
                    218: #define kAllBitsSetInWord      0xFFFFFFFFul
                    219: 
                    220: 
                    221: static OSErr BlockVerifyAllocated(
                    222:        ExtendedVCB             *vcb,
                    223:        UInt32                  startBlock,
                    224:        UInt32                  blockCount,
                    225:        Boolean                 *foundUnmarkedBlock);
                    226: 
                    227: static OSErr ReadBitmapBlock(
                    228:        ExtendedVCB             *vcb,
                    229:        UInt32                  block,
                    230:        UInt32                  **buffer);
                    231: 
                    232: static OSErr BlockAllocateContig(
                    233:        ExtendedVCB             *vcb,
                    234:        UInt32                  startingBlock,
                    235:        UInt32                  minBlocks,
                    236:        UInt32                  maxBlocks,
                    237:        UInt32                  *actualStartBlock,
                    238:        UInt32                  *actualNumBlocks);
                    239: 
                    240: static OSErr BlockFindContiguous(
                    241:        ExtendedVCB             *vcb,
                    242:        UInt32                  startingBlock,
                    243:        UInt32                  endingBlock,
                    244:        UInt32                  minBlocks,
                    245:        UInt32                  maxBlocks,
                    246:        UInt32                  *actualStartBlock,
                    247:        UInt32                  *actualNumBlocks);
                    248: 
                    249: static OSErr BlockMarkAllocated(
                    250:        ExtendedVCB             *vcb,
                    251:        UInt32                  startingBlock,
                    252:        UInt32                  numBlocks);
                    253: 
                    254: static OSErr BlockMarkFree(
                    255:        ExtendedVCB             *vcb,
                    256:        UInt32                  startingBlock,
                    257:        UInt32                  numBlocks);
                    258: 
                    259: #if TARGET_OS_RHAPSODY && DIAGNOSTIC
                    260:        #if DIAGNOSTIC
                    261:                extern void RequireFileLock(FileReference file, int shareable);
                    262:        #else
                    263:                #define RequireFileLock(f)
                    264:        #endif
                    265: #endif
                    266: 
                    267: /*
                    268: ;________________________________________________________________________________
                    269: ;
                    270: ; Routine:        BlkAlloc
                    271: ;
                    272: ; Function:    Allocate space on a volume.     If contiguous allocation is requested,
                    273: ;                         at least the requested number of bytes will be allocated or an
                    274: ;                         error will be returned.      If contiguous allocation is not forced,
                    275: ;                         the space will be allocated at the first free fragment following
                    276: ;                         the requested starting allocation block.  If there is not enough
                    277: ;                         room there, a block of less than the requested size will be
                    278: ;                         allocated.
                    279: ;
                    280: ;                         If the requested starting block is 0 (for new file allocations),
                    281: ;                         the volume's allocation block pointer will be used as a starting
                    282: ;                         point.
                    283: ;
                    284: ;                         All requests will be rounded up to the next highest clump size, as
                    285: ;                         indicated in the file's FCB.
                    286: ;
                    287: ; Input Arguments:
                    288: ;       vcb                     - Pointer to ExtendedVCB for the volume to allocate space on
                    289: ;       fcb                     - Pointer to FCB for the file for which storage is being allocated
                    290: ;       startingBlock   - Preferred starting allocation block, 0 = no preference
                    291: ;       forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
                    292: ;                                         or an error is returned
                    293: ;       bytesRequested  - Number of bytes requested.   If the allocation is non-contiguous,
                    294: ;                                         less than this may actually be allocated
                    295: ;       bytesMaximum    - The maximum number of bytes to allocate.  If there is additional free
                    296: ;                                         space after bytesRequested, then up to bytesMaximum bytes should really
                    297: ;                                         be allocated.  (Used by ExtendFileC to round up allocations to a multiple
                    298: ;                                         of the file's clump size.)
                    299: ;
                    300: ; Output:
                    301: ;       (result)                - Error code, zero for successful allocation
                    302: ;       *startBlock     - Actual starting allocation block
                    303: ;       *actualBlocks   - Actual number of allocation blocks allocated
                    304: ;
                    305: ; Side effects:
                    306: ;       The volume bitmap is read and updated; the volume bitmap cache may be changed.
                    307: ;
                    308: ; Modification history:
                    309: ;      <06Oct85>  PWD  Changed to check for errors after calls to ReadBM and NextWord
                    310: ;                                      Relocated call to MarkBlock in allocation loop
                    311: ;                                      Changed to call NextBit
                    312: ; <21Oct85>   PWD      Changed to check VCBFreeBks before attempting to allocate any block.
                    313: ;                                      Speed up scan for free space by checking for all 1's.
                    314: ;________________________________________________________________________________
                    315: */
                    316: 
                    317: OSErr BlockAllocate (
                    318:        ExtendedVCB             *vcb,                           /* which volume to allocate space on */
                    319:        UInt32                  startingBlock,          /* preferred starting block, or 0 for no preference */
                    320:        UInt32                  bytesRequested,         /* desired number of BYTES to allocate */
                    321:        UInt32                  bytesMaximum,           /* maximum number of bytes to allocate */
                    322:        Boolean                 forceContiguous,        /* non-zero to force contiguous allocation and to force */
                    323:                                                                                /* bytesRequested bytes to actually be allocated */
                    324:        UInt32                  *actualStartBlock,      /* actual first block of allocation */
                    325:        UInt32                  *actualNumBlocks)       /* number of blocks actually allocated; if forceContiguous */
                    326:                                                                                /* was zero, then this may represent fewer than bytesRequested */
                    327:                                                                                /* bytes */
                    328: {
                    329:        OSErr                   err;
                    330:        UInt32                  minBlocks;                                      //      minimum number of allocation blocks requested
                    331:        UInt32                  maxBlocks;                                      //      number of allocation blocks requested, rounded to clump size
                    332:        Boolean                 updateAllocPtr = false;         //      true if nextAllocation needs to be updated
                    333: 
                    334:        LogStartTime(kTraceBlockAllocate);
                    335: 
                    336: #if HFSInstrumentation
                    337:        InstSplitHistogramClassRef      histogram;
                    338:        InstTraceClassRef                       trace;
                    339:        InstEventTag                            eventTag;
                    340:        
                    341:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockAllocate", 'hfs+', kInstEnableClassMask, &trace);
                    342:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                    343: 
                    344:        err = InstCreateSplitHistogramClass(kInstRootClassRef, "HFS:VSM:BlockAllocate size", 0, 512, 16384, 262144, 16384,
                    345:                                                                                kInstEnableClassMask, &histogram);
                    346:        if (err != noErr) DebugStr("\pError from InstCreateHistogramClass");
                    347: 
                    348:        eventTag = bytesRequested;              // a cheap way to get bytesRequested into the log
                    349:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                    350:        InstUpdateHistogram( histogram, bytesRequested, 1);
                    351: #endif
                    352: 
                    353:        //
                    354:        //      Initialize outputs in case we get an error
                    355:        //
                    356:        *actualStartBlock = 0;
                    357:        *actualNumBlocks = 0;
                    358:        
                    359:        //
                    360:        //      Compute the number of allocation blocks requested, and maximum
                    361:        //
                    362:        minBlocks = DivideAndRoundUp(bytesRequested, vcb->blockSize);
                    363:        maxBlocks = DivideAndRoundUp(bytesMaximum, vcb->blockSize);
                    364:        
                    365:        //
                    366:        //      If the disk is already full, don't bother.
                    367:        //
                    368:        if (vcb->freeBlocks == 0) {
                    369:                err = dskFulErr;
                    370:                goto Exit;
                    371:        }
                    372:        if (forceContiguous && vcb->freeBlocks < minBlocks) {
                    373:                err = dskFulErr;
                    374:                goto Exit;
                    375:        }
                    376:        
                    377:        //
                    378:        //      If caller didn't specify a starting block number, then use the volume's
                    379:        //      next block to allocate from.
                    380:        //
                    381:        if (startingBlock == 0) {
                    382:                VCB_LOCK(vcb);
                    383:                startingBlock = vcb->nextAllocation;
                    384:                VCB_UNLOCK(vcb);
                    385:                updateAllocPtr = true;
                    386:        }
                    387:        
                    388:        //
                    389:        //      If the request must be contiguous, then find a sequence of free blocks
                    390:        //      that is long enough.  Otherwise, find the first free block.
                    391:        //
                    392:        if (forceContiguous) {
                    393:                err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
                    394:        } else {
                    395:                err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
                    396:                if (err == dskFulErr) {
                    397:                        err = BlockAllocateAny(vcb, 0, startingBlock, maxBlocks, actualStartBlock, actualNumBlocks);
                    398:                        };
                    399:        }
                    400: 
                    401:        if (err == noErr) {
                    402:                //
                    403:                //      If we used the volume's roving allocation pointer, then we need to update it.
                    404:                //      Adding in the length of the current allocation might reduce the next allocate
                    405:                //      call by avoiding a re-scan of the already allocated space.  However, the clump
                    406:                //      just allocated can quite conceivably end up being truncated or released when
                    407:                //      the file is closed or its EOF changed.  Leaving the allocation pointer at the
                    408:                //      start of the last allocation will avoid unnecessary fragmentation in this case.
                    409:                //
                    410:                VCB_LOCK(vcb);
                    411: 
                    412:                if (updateAllocPtr)
                    413:                        vcb->nextAllocation = *actualStartBlock;
                    414:                
                    415:                //
                    416:                //      Update the number of free blocks on the volume
                    417:                //
                    418:                vcb->freeBlocks -= *actualNumBlocks;
                    419:                VCB_UNLOCK(vcb);
                    420: 
                    421:                UpdateVCBFreeBlks( vcb );
                    422:                MarkVCBDirty(vcb);
                    423:        }
                    424:        
                    425: Exit:
                    426: 
                    427: #if HFSInstrumentation
                    428:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                    429: #endif
                    430:        LogEndTime(kTraceBlockAllocate, err);
                    431: 
                    432:        return err;
                    433: }
                    434: 
                    435: 
                    436: /*
                    437: ;________________________________________________________________________________
                    438: ;
                    439: ; Routine:        UpdateVCBFreeBlks
                    440: ;
                    441: ; Function:    Whenever the freeBlocks field in the ExtendedVCB is updated,
                    442: ;                         we must also recalculate the (UInt16) vcbFreeBks field in the
                    443: ;                         traditional HFS VCB structure.
                    444: ;
                    445: ; Input Arguments:
                    446: ;       vcb            - Pointer to ExtendedVCB for the volume to free space on
                    447: ;________________________________________________________________________________
                    448: */
                    449: void UpdateVCBFreeBlks( ExtendedVCB *vcb )
                    450: {
                    451:        UInt32  hfsCompatabilityFreeBlocks;
                    452:        UInt32  plusBlockSize;
                    453:        UInt32  hfsBlockSize;
                    454:        
                    455:        #if DEBUG_BUILD
                    456:                if ( vcb->vcbSigWord == kHFSSigWord && vcb->freeBlocks > 0xFFFF )
                    457:                        DebugStr("\p UpdateVCBFreeBlks: freeBlocks overflow!");
                    458:        #endif
                    459:        
                    460:        //
                    461:        //�� The following calculation will overflow on volumes 2 TB or bigger.
                    462:        //
                    463:        //      We divide both the true allocation block size and HFS-compatible allocation block size
                    464:        //      by 512 since that reduces the magnitude of the numbers (with no overflow until
                    465:        //      4 GB * 512 = 2 TB).  Since allocation blocks for both HFS and HFS Plus must be a
                    466:        //      multiple of 512, then there will be no roundoff error.
                    467:        //
                    468:        plusBlockSize = vcb->blockSize >> 9;                            //      Divide by 512
                    469:        hfsBlockSize = ((UInt32) vcb->vcbAlBlkSiz) >> 9;        //      Divide by 512
                    470:        
                    471:        hfsCompatabilityFreeBlocks = (vcb->freeBlocks * plusBlockSize) / hfsBlockSize;
                    472:        
                    473:        if ( hfsCompatabilityFreeBlocks > 0xFFFF )
                    474:                vcb->vcbFreeBks = 0xFFFF;
                    475:        else
                    476:                vcb->vcbFreeBks = (UInt16) hfsCompatabilityFreeBlocks;
                    477: }
                    478: 
                    479: 
                    480: /*
                    481: ;________________________________________________________________________________
                    482: ;
                    483: ; Routine:        BlkDealloc
                    484: ;
                    485: ; Function:    Update the bitmap to deallocate a run of disk allocation blocks
                    486: ;
                    487: ; Input Arguments:
                    488: ;       vcb            - Pointer to ExtendedVCB for the volume to free space on
                    489: ;       firstBlock     - First allocation block to be freed
                    490: ;       numBlocks      - Number of allocation blocks to free up (must be > 0!)
                    491: ;
                    492: ; Output:
                    493: ;       (result)       - Result code
                    494: ;
                    495: ; Side effects:
                    496: ;       The volume bitmap is read and updated; the volume bitmap cache may be changed.
                    497: ;
                    498: ; Modification history:
                    499: ;
                    500: ;      <06Oct85>  PWD  Changed to check for error after calls to ReadBM and NextWord
                    501: ;                                      Now calls NextBit to read successive bits from the bitmap
                    502: ;________________________________________________________________________________
                    503: */
                    504: 
                    505: OSErr BlockDeallocate (
                    506:        ExtendedVCB             *vcb,                   //      Which volume to deallocate space on
                    507:        UInt32                  firstBlock,             //      First block in range to deallocate
                    508:        UInt32                  numBlocks)              //      Number of contiguous blocks to deallocate
                    509: {
                    510:        OSErr                   err;
                    511:        
                    512: #if HFSInstrumentation
                    513:        InstTraceClassRef       trace;
                    514:        InstEventTag            eventTag;
                    515:        
                    516:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockDeallocate", 'hfs+', kInstEnableClassMask, &trace);
                    517:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                    518: 
                    519:        eventTag = InstCreateEventTag();
                    520:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                    521: #endif
                    522: 
                    523:        //
                    524:        //      If no blocks to deallocate, then exit early
                    525:        //
                    526:        if (numBlocks == 0) {
                    527:                err = noErr;
                    528:                goto Exit;
                    529:        }
                    530: 
                    531:        //
                    532:        //      Call internal routine to free the sequence of blocks
                    533:        //
                    534:        err = BlockMarkFree(vcb, firstBlock, numBlocks);
                    535:        if (err)
                    536:                goto Exit;
                    537: 
                    538:        //
                    539:        //      Update the volume's free block count, and mark the VCB as dirty.
                    540:        //
                    541:        VCB_LOCK(vcb);
                    542:        vcb->freeBlocks += numBlocks;
                    543:        VCB_UNLOCK(vcb);
                    544:        UpdateVCBFreeBlks( vcb );
                    545:        MarkVCBDirty(vcb);
                    546: 
                    547: Exit:
                    548: 
                    549: #if HFSInstrumentation
                    550:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                    551: #endif
                    552: 
                    553:        return err;
                    554: }
                    555: 
                    556: 
                    557: 
                    558: /*
                    559: ;_______________________________________________________________________
                    560: ;
                    561: ; Routine:             BlkChk
                    562: ;
                    563: ; Input Arguments:
                    564: ;      extents         -- pointer to extent record
                    565: ;      vcb                     -- ExtendedVCB for volume
                    566: ;
                    567: ; Output:
                    568: ;      (result)        -- 0 if block was already allocated
                    569: ;                                                                 -1 otherwise
                    570: ;
                    571: ; Called By:   MountVol
                    572: ; Function:    Make sure the extents in the extent record are marked as
                    573: ;                              allocated in the volume bitmap.  The allocation blocks mapped
                    574: ;                              by the extent record are marked in the bitmap if they weren't
                    575: ;                              already marked (in which case D0 is set).
                    576: ;
                    577: ; Modification History:
                    578: ;        3-Jul-85      PWD  New today.
                    579: ;       <06Oct85>      PWD  Added check for errors after calls to ReadBM and NextWord
                    580: ;_______________________________________________________________________
                    581: */
                    582: 
                    583: SInt32 BlockCheck (
                    584:        ExtendedVCB                     *vcb,                   //      Volume to check
                    585:        HFSPlusExtentRecord     extents)                //      List of extents to verify as allocated
                    586: {
                    587:        OSErr   err;
                    588:        Boolean trouble = false;                //      Assume everything went OK
                    589:        Boolean foundUnmarkedBlock;     
                    590:        int             i, extentsPerRecord;
                    591: 
                    592: #if HFSInstrumentation
                    593:        InstTraceClassRef       trace;
                    594:        InstEventTag            eventTag;
                    595:        
                    596:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockCheck", 'hfs+', kInstEnableClassMask, &trace);
                    597:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                    598: 
                    599:        eventTag = InstCreateEventTag();
                    600:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                    601: #endif
                    602: 
                    603:        if (vcb->vcbSigWord == kHFSPlusSigWord)
                    604:                extentsPerRecord = kHFSPlusExtentDensity;
                    605:        else
                    606:                extentsPerRecord = kHFSExtentDensity;
                    607:        
                    608: 
                    609: 
                    610:        for (i = 0; i < extentsPerRecord; i++) {
                    611:                if (extents[i].blockCount != 0) {               //      if no blocks, then no extent to check
                    612:                        err = BlockVerifyAllocated(vcb, extents[i].startBlock, extents[i].blockCount, &foundUnmarkedBlock);
                    613:                        if (err)
                    614:                                return err;
                    615:                        trouble |= foundUnmarkedBlock;
                    616:                }
                    617:        }
                    618: 
                    619: #if HFSInstrumentation
                    620:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                    621: #endif
                    622: 
                    623:        if (trouble)
                    624:                return -1;
                    625:        else
                    626:                return 0;
                    627: }
                    628: 
                    629: 
                    630: 
                    631: /*
                    632: ;_______________________________________________________________________
                    633: ;
                    634: ; Routine:             UpdateFree
                    635: ; Arguments:   vcb     -- ExtendedVCB for volume
                    636: ;
                    637: ; Called By:   MountVol
                    638: ; Function:    This routine is used as part of the MountVol consistency check
                    639: ;                              to figure out the number of free allocation blocks in the volume.
                    640: ;
                    641: ; Modification History:
                    642: ;      <08Sep85>  LAK  New today.
                    643: ;      <06Oct85>  PWD  Added explicit check for errors after calls to ReadBM, NextWord
                    644: ;                                      Now calls NextBit.
                    645: ;_______________________________________________________________________
                    646: */
                    647: 
                    648: OSErr UpdateFreeCount (
                    649:        ExtendedVCB     *vcb)                           //      Volume whose free block count should be updated
                    650: {
                    651:        OSErr                   err;
                    652:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
                    653:        register UInt32 numBlocks;              //      Number of blocks left to scan
                    654:        register UInt32 freeCount;              //      Running count of free blocks found so far
                    655:        register UInt32 temp;
                    656:        UInt32                  blockNum;               //      Block number of first block in this bitmap block
                    657:        UInt32                  *buffer = NULL; //      Pointer to bitmap block
                    658:        register UInt32 *currentWord;   //      Pointer to current word in bitmap block
                    659:        
                    660: #if HFSInstrumentation
                    661:        InstTraceClassRef       trace;
                    662:        InstEventTag            eventTag;
                    663:        
                    664:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:UpdateFreeCount", 'hfs+', kInstEnableClassMask, &trace);
                    665:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                    666: 
                    667:        eventTag = InstCreateEventTag();
                    668:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                    669: #endif
                    670: 
                    671:        //
                    672:        //      Pre-read the first bitmap block
                    673:        //
                    674: 
                    675:        err = ReadBitmapBlock(vcb, 0, &buffer);
                    676:        if (err != noErr) goto Exit;
                    677: 
                    678:        //
                    679:        //      Initialize buffer stuff
                    680:        //
                    681:        currentWord = buffer;
                    682:        wordsLeft = kWordsPerBlock;
                    683:        numBlocks = vcb->totalBlocks;
                    684:        freeCount = 0;
                    685:        blockNum = 0;
                    686:        
                    687:        //
                    688:        //      Scan whole words first
                    689:        //
                    690:        
                    691:        while (numBlocks >= kBitsPerWord) {
                    692:                //      See if it's time to move to the next bitmap block
                    693:                if (wordsLeft == 0) {
                    694:                        //      Read in the next bitmap block
                    695:                        blockNum += kBitsPerBlock;                              //      generate a block number in the next bitmap block
                    696:                        
                    697: #if EXPLICIT_BUFFER_RELEASES
                    698:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                    699:                        if (err != noErr) goto Exit;
                    700:                        buffer = NULL;
                    701: #endif
                    702:                        err = ReadBitmapBlock(vcb, blockNum, &buffer);
                    703:                        if (err != noErr) goto Exit;
                    704:                        
                    705:                        //      Readjust currentWord, wordsLeft
                    706:                        currentWord = buffer;
                    707:                        wordsLeft = kWordsPerBlock;
                    708:                }
                    709:                
                    710:                //      We count free blocks by inverting the word in the bitmap and counting set bits.
                    711:                temp = ~(*currentWord);
                    712:                while (temp) {
                    713:                        ++freeCount;
                    714:                        temp &= temp-1;                 //      this clears least significant bit that is currently set
                    715:                }
                    716: 
                    717:                numBlocks -= kBitsPerWord;
                    718:                ++currentWord;                                                          //      move to next word
                    719:                --wordsLeft;                                                            //      one less word left in this block
                    720:        }
                    721:        
                    722:        //
                    723:        //      Check any remaining blocks.
                    724:        //
                    725:        
                    726:        if (numBlocks != 0) {
                    727:                if (wordsLeft == 0) {
                    728:                        //      Read in the next bitmap block
                    729:                        blockNum += kBitsPerBlock;                              //      generate a block number in the next bitmap block
                    730:                        
                    731: #if EXPLICIT_BUFFER_RELEASES
                    732:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                    733:                        if (err != noErr) goto Exit;
                    734:                        buffer = NULL;
                    735: #endif
                    736:                        err = ReadBitmapBlock(vcb, blockNum, &buffer);
                    737:                        if (err != noErr) goto Exit;
                    738:                        
                    739:                        //      Readjust currentWord, wordsLeft
                    740:                        currentWord = buffer;
                    741:                        wordsLeft = kWordsPerBlock;
                    742:                }
                    743:                
                    744:                //      We count free blocks by inverting the word in the bitmap and counting set bits.
                    745:                temp = ~(*currentWord);
                    746:                while (numBlocks != 0) {
                    747:                        if (temp & kHighBitInWordMask)
                    748:                                ++freeCount;
                    749:                        temp <<= 1;
                    750:                        --numBlocks;
                    751:                }
                    752:        }
                    753: 
                    754:        VCB_LOCK(vcb);
                    755:        vcb->freeBlocks = freeCount;
                    756:        VCB_UNLOCK(vcb);
                    757:        UpdateVCBFreeBlks( vcb );
                    758: 
                    759: Exit:
                    760: 
                    761: #if EXPLICIT_BUFFER_RELEASES
                    762:        if (buffer) {
                    763:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
                    764:        };
                    765: #endif
                    766: 
                    767: #if HFSInstrumentation
                    768:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                    769: #endif
                    770: 
                    771:        return err;
                    772: }
                    773: 
                    774: 
                    775: 
                    776: /*
                    777: ;_______________________________________________________________________
                    778: ;
                    779: ; Routine:             AllocateFreeSpace
                    780: ; Arguments:   vcb     -- ExtendedVCB for volume
                    781: ;
                    782: ; Called By:   HFSDiskInitComponent
                    783: ; Function:    This routine is used as part of DiskInit to create an
                    784: ;                              embedded HFS+ volume.
                    785: ;
                    786: ; Note: Assumes that the free space is contiguous (true for a freshly erased disk)
                    787: ;_______________________________________________________________________
                    788: */
                    789: 
                    790: OSErr AllocateFreeSpace (
                    791:        ExtendedVCB             *vcb,                           //      Volume whose free space is about to be expropriated
                    792:        UInt32                  *startBlock,            // return where free space starts
                    793:        UInt32                  *actualBlocks)          // return the number of blocks in free space
                    794: {
                    795:        OSErr                   err;
                    796: 
                    797:        err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, vcb->freeBlocks, startBlock, actualBlocks);
                    798: 
                    799:        if (err == noErr) {
                    800:                VCB_LOCK(vcb);
                    801:                vcb->freeBlocks = 0;    // sorry, no more blocks left!
                    802:                vcb->vcbFreeBks = 0;
                    803:                VCB_UNLOCK(vcb);
                    804:                MarkVCBDirty(vcb);
                    805:        }
                    806:        
                    807:        return err;
                    808: }
                    809: 
                    810: /*
                    811: ;_______________________________________________________________________
                    812: ;
                    813: ; Routine:     DivideAndRoundUp
                    814: ;
                    815: ; Function:    Divide numerator by denominator, rounding up the result if there
                    816: ;                      was a remainder.  This is frequently used for computing the number
                    817: ;                      of whole and/or partial blocks used by some count of bytes.
                    818: ;_______________________________________________________________________
                    819: */
                    820: UInt32 DivideAndRoundUp(
                    821:        UInt32 numerator,
                    822:        UInt32 denominator)
                    823: {
                    824:        UInt32  quotient;
                    825:        
                    826:        quotient = numerator / denominator;
                    827:        if (quotient * denominator != numerator)
                    828:                quotient++;
                    829:        
                    830:        return quotient;
                    831: }
                    832: 
                    833: 
                    834: 
                    835: /*
                    836: ;_______________________________________________________________________
                    837: ;
                    838: ; Routine:     ReadBitmapBlock
                    839: ;
                    840: ; Function:    Read in a bitmap block corresponding to a given allocation
                    841: ;                      block.  Return a pointer to the bitmap block.
                    842: ;
                    843: ; Inputs:
                    844: ;      vcb                     --      Pointer to ExtendedVCB
                    845: ;      block           --      Allocation block whose bitmap block is desired
                    846: ;
                    847: ; Outputs:
                    848: ;      buffer          --      Pointer to bitmap block corresonding to "block"
                    849: ;_______________________________________________________________________
                    850: */
                    851: static OSErr ReadBitmapBlock(
                    852:        ExtendedVCB             *vcb,
                    853:        UInt32                  block,
                    854:        UInt32                  **buffer)
                    855: {
                    856:        OSErr                   err;
                    857: 
                    858: #if HFSInstrumentation
                    859:        InstTraceClassRef       trace;
                    860:        InstEventTag            eventTag;
                    861:        
                    862:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:ReadBitmapBlock", 'hfs+', kInstEnableClassMask, &trace);
                    863:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                    864: 
                    865:        eventTag = block;               // a cheap way to get the block number into the log
                    866:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                    867: #endif
                    868: 
                    869:        err = noErr;
                    870: 
                    871:   #if TARGET_OS_RHAPSODY
                    872:        RequireFileLock(vcb->extentsRefNum, false);     /* bitmap blocks are covered by the Extents B-tree lock */
                    873:   #endif
                    874: 
                    875:        if (vcb->vcbSigWord == kHFSSigWord) {
                    876:                //
                    877:                //      HFS: Turn block number into physical block offset within the
                    878:                //      bitmap, and then the physical block within the volume.
                    879:                //
                    880:                block /= kBitsPerBlock;         // block offset within bitmap
                    881:                block += vcb->vcbVBMSt;         // block within whole volume
                    882:        }
                    883:        else {
                    884:                FCB             *allocFile;
                    885:                UInt32  startBlock;
                    886:                UInt32  availableBytes;
                    887:                
                    888:                //
                    889:                //      HFS+: Read from allocation file.  We simply convert the block number into a byte
                    890:                //      offset within the allocation file and then determine which block that byte is in.
                    891:                //
                    892:                allocFile = GetFileControlBlock(vcb->allocationsRefNum);
                    893: 
                    894:                //
                    895:                //      Find out which physical block holds byte #offset in allocation file.  Note that we
                    896:                //      map only 1 byte (the one we asked for).
                    897:                //
                    898:                err = MapFileBlockC(vcb, allocFile, 1, block/kBitsPerByte, &startBlock, &availableBytes);
                    899:                block = startBlock;
                    900:        }
                    901: 
                    902:        if (err == noErr) {
                    903: #if TARGET_OS_MAC
                    904:             err = GetBlock_glue(
                    905: #if EXPLICIT_BUFFER_RELEASES
                    906:                                                                0,                                              // No options
                    907: #else
                    908:                                 gbReleaseMask,                 // Release block immediately.  We only work on one
                    909:                                                                                //      block at a time.  Call MarkBlock later if dirty.
                    910: #endif
                    911:                                 block,                                 // Physical block on volume
                    912:                                 (Ptr *) buffer,                        //      A place to return the buffer pointer
                    913:                                 vcb->vcbVRefNum,               //      Which volume to read from
                    914:                                 vcb);                                  //      Cache queue header for volume bitmap
                    915: #else
                    916:             err = GetBlock_glue(
                    917: #if EXPLICIT_BUFFER_RELEASES
                    918:                                                                0,                                              // No options
                    919: #else
                    920:                                 gbReleaseMask,                 // Release block immediately.  We only work on one
                    921:                                                                                                                // block at a time.  Call MarkBlock later if dirty.
                    922: #endif
                    923:                                 block,                                 // Physical block on volume
                    924:                                 (Ptr *) buffer,                        // A place to return the buffer pointer
                    925:                                 kNoFileReference,              // Not a file read
                    926:                                 vcb);                                  // Volume to read from
                    927: #endif
                    928:        }
                    929: 
                    930: #if HFSInstrumentation
                    931:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                    932: #endif
                    933: 
                    934:        return err;
                    935: }
                    936: 
                    937: 
                    938: 
                    939: /*
                    940: _______________________________________________________________________
                    941: 
                    942: Routine:       BlockAllocateContig
                    943: 
                    944: Function:      Allocate a contiguous group of allocation blocks.  The
                    945:                        allocation is all-or-nothing.  The caller guarantees that
                    946:                        there are enough free blocks (though they may not be
                    947:                        contiguous, in which case this call will fail).
                    948: 
                    949: Inputs:
                    950:        vcb                             Pointer to volume where space is to be allocated
                    951:        startingBlock   Preferred first block for allocation
                    952:        minBlocks               Minimum number of contiguous blocks to allocate
                    953:        maxBlocks               Maximum number of contiguous blocks to allocate
                    954: 
                    955: Outputs:
                    956:        actualStartBlock        First block of range allocated, or 0 if error
                    957:        actualNumBlocks         Number of blocks allocated, or 0 if error
                    958: _______________________________________________________________________
                    959: */
                    960: static OSErr BlockAllocateContig(
                    961:        ExtendedVCB             *vcb,
                    962:        UInt32                  startingBlock,
                    963:        UInt32                  minBlocks,
                    964:        UInt32                  maxBlocks,
                    965:        UInt32                  *actualStartBlock,
                    966:        UInt32                  *actualNumBlocks)
                    967: {
                    968:        OSErr   err;
                    969: 
                    970:        //
                    971:        //      Find a contiguous group of blocks at least minBlocks long.
                    972:        //      Determine the number of contiguous blocks available (up
                    973:        //      to maxBlocks).
                    974:        //
                    975:        err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
                    976:                                                                  actualStartBlock, actualNumBlocks);
                    977:        if (err == dskFulErr) {
                    978:                //�� Should constrain the endingBlock here, so we don't bother looking for ranges
                    979:                //�� that start after startingBlock, since we already checked those.
                    980:                err = BlockFindContiguous(vcb, 0, vcb->totalBlocks, minBlocks, maxBlocks,
                    981:                                                                          actualStartBlock, actualNumBlocks);
                    982:        }
                    983:        if (err != noErr) goto Exit;
                    984: 
                    985:        //
                    986:        //      Now mark those blocks allocated.
                    987:        //
                    988:        err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
                    989:        
                    990: Exit:
                    991:        if (err != noErr) {
                    992:                *actualStartBlock = 0;
                    993:                *actualNumBlocks = 0;
                    994:        }
                    995:        
                    996:        return err;
                    997: }
                    998: 
                    999: extern OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr);
                   1000: 
                   1001: /*
                   1002: _______________________________________________________________________
                   1003: 
                   1004: Routine:       BlockAllocateAny
                   1005: 
                   1006: Function:      Allocate one or more allocation blocks.  If there are fewer
                   1007:                        free blocks than requested, all free blocks will be
                   1008:                        allocated.  The caller guarantees that there is at least
                   1009:                        one free block.
                   1010: 
                   1011: Inputs:
                   1012:        vcb                             Pointer to volume where space is to be allocated
                   1013:        startingBlock   Preferred first block for allocation
                   1014:        endingBlock             Last block to check + 1
                   1015:        maxBlocks               Maximum number of contiguous blocks to allocate
                   1016: 
                   1017: Outputs:
                   1018:        actualStartBlock        First block of range allocated, or 0 if error
                   1019:        actualNumBlocks         Number of blocks allocated, or 0 if error
                   1020: _______________________________________________________________________
                   1021: */
                   1022: OSErr BlockAllocateAny(
                   1023:        ExtendedVCB             *vcb,
                   1024:        UInt32                  startingBlock,
                   1025:        register UInt32 endingBlock,
                   1026:        UInt32                  maxBlocks,
                   1027:        UInt32                  *actualStartBlock,
                   1028:        UInt32                  *actualNumBlocks)
                   1029: {
                   1030:        OSErr                   err;
                   1031:        register UInt32 block;                  //      current block number
                   1032:        register UInt32 currentWord;    //      Pointer to current word within bitmap block
                   1033:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
                   1034:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
                   1035:     UInt32                     *buffer = NULL;
                   1036:     UInt32                     *currCache = NULL;
                   1037: 
                   1038: #if DIAGNOSTIC
                   1039:     struct buf *bp = NULL;
                   1040:     int mappingEntry;
                   1041: #endif
                   1042: 
                   1043:        //      Since this routine doesn't wrap around
                   1044:        if (maxBlocks > (endingBlock - startingBlock)) {
                   1045:                maxBlocks = endingBlock - startingBlock;
                   1046:        }
                   1047: 
                   1048:     DBG_TREE (("\nAllocating starting at %ld, maxblocks %ld\n", startingBlock, maxBlocks));    
                   1049:        //
                   1050:        //      Pre-read the first bitmap block
                   1051:        //
                   1052:     err = ReadBitmapBlock(vcb, startingBlock, &currCache);
                   1053:     DBG_TREE (("\n1. Read bit map at %ld, buffer is 0x%x\n", startingBlock, (int)currCache));  
                   1054:        if (err != noErr) goto Exit;
                   1055:     buffer = currCache;
                   1056:     MarkBlock_glue((Ptr) currCache);           //      this block will be dirty
                   1057:     DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1058: 
                   1059:        //
                   1060:        //      Set up the current position within the block
                   1061:        //
                   1062:        {
                   1063:                UInt32 wordIndexInBlock;
                   1064: 
                   1065:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
                   1066:                buffer += wordIndexInBlock;
                   1067:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
                   1068:                currentWord = *buffer;
                   1069:                bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask);
                   1070:        }
                   1071:        
                   1072:        //
                   1073:        //      Find the first unallocated block
                   1074:        //
                   1075:        block=startingBlock;
                   1076:        while (block < endingBlock) {
                   1077:                if ((currentWord & bitMask) == 0)
                   1078:                        break;
                   1079:                
                   1080:                //      Next bit
                   1081:                ++block;
                   1082:                bitMask >>= 1;
                   1083:                if (bitMask == 0) {
                   1084:                        //      Next word
                   1085:                        bitMask = kHighBitInWordMask;
                   1086:                        ++buffer;
                   1087:                        
                   1088:                        if (--wordsLeft == 0) {
                   1089:                                //      Next block
                   1090: #if EXPLICIT_BUFFER_RELEASES
                   1091:                DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1092:                err = RelBlock_glue((Ptr)currCache, rbDefault);
                   1093:                                if (err != noErr) goto Exit;
                   1094:                 buffer = currCache = NULL;
                   1095: #endif
                   1096:                 err = ReadBitmapBlock(vcb, block, &currCache);
                   1097:                                if (err != noErr) goto Exit;
                   1098:                 buffer = currCache;
                   1099:                 DBG_TREE (("\n2. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));      
                   1100:                 DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1101:                 MarkBlock_glue((Ptr) currCache);               //      this block will be dirty
                   1102: 
                   1103:                                wordsLeft = kWordsPerBlock;
                   1104:                        }
                   1105:                        
                   1106:                        currentWord = *buffer;
                   1107:                }
                   1108:        }
                   1109: 
                   1110:        //      Did we get to the end of the bitmap before finding a free block?
                   1111:        //      If so, then couldn't allocate anything.
                   1112:        if (block == endingBlock) {
                   1113:                err = dskFulErr;
                   1114:                goto Exit;
                   1115:        }
                   1116: 
                   1117:        //      Return the first block in the allocated range
                   1118:        *actualStartBlock = block;
                   1119:        
                   1120:        //      If we could get the desired number of blocks before hitting endingBlock,
                   1121:        //      then adjust endingBlock so we won't keep looking.  Ideally, the comparison
                   1122:        //      would be (block + maxBlocks) < endingBlock, but that could overflow.  The
                   1123:        //      comparison below yields identical results, but without overflow.
                   1124:        if (block < (endingBlock-maxBlocks)) {
                   1125:                endingBlock = block + maxBlocks;        //      if we get this far, we've found enough
                   1126:        }
                   1127:        
                   1128:        //
                   1129:        //      Allocate all of the consecutive blocks
                   1130:        //
                   1131:        while ((currentWord & bitMask) == 0) {
                   1132:                //      Allocate this block
                   1133:                currentWord |= bitMask;
                   1134:                
                   1135:                //      Move to the next block.  If no more, then exit.
                   1136:                ++block;
                   1137:                if (block == endingBlock)
                   1138:                        break;
                   1139: 
                   1140:                //      Next bit
                   1141:                bitMask >>= 1;
                   1142:                if (bitMask == 0) {
                   1143:                        *buffer = currentWord;                                  //      update value in bitmap
                   1144:                        
                   1145:                        //      Next word
                   1146:                        bitMask = kHighBitInWordMask;
                   1147:                        ++buffer;
                   1148:                        
                   1149:                        if (--wordsLeft == 0) {
                   1150:                                //      Next block
                   1151: #if EXPLICIT_BUFFER_RELEASES
                   1152:                DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1153:                        err = RelBlock_glue((Ptr)currCache, rbDefault);
                   1154:                                if (err != noErr) goto Exit;
                   1155:                 buffer = currCache = NULL;
                   1156: #endif
                   1157:                 err = ReadBitmapBlock(vcb, block, &currCache);
                   1158:                                if (err != noErr) goto Exit;
                   1159:                 buffer = currCache;
                   1160:                 DBG_TREE (("\n3. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));      
                   1161:                 DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1162:                 MarkBlock_glue((Ptr) currCache);               //      this block will be dirty
                   1163: 
                   1164:                                wordsLeft = kWordsPerBlock;
                   1165:                        }
                   1166:                        
                   1167:                        currentWord = *buffer;
                   1168:                }
                   1169:        }
                   1170:        *buffer = currentWord;                                                  //      update the last change
                   1171: 
                   1172: Exit:
                   1173:        if (err == noErr) {
                   1174:                *actualNumBlocks = block - *actualStartBlock;
                   1175:        }
                   1176:        else {
                   1177:                *actualStartBlock = 0;
                   1178:                *actualNumBlocks = 0;
                   1179:        }
                   1180:        
                   1181: #if EXPLICIT_BUFFER_RELEASES
                   1182:     if (currCache) {
                   1183:         DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
                   1184:         (void)RelBlock_glue((Ptr)currCache, rbDefault);                /* Ignore any additional errors */
                   1185:         };
                   1186: #endif
                   1187: 
                   1188:        return err;
                   1189: }
                   1190: 
                   1191: 
                   1192: 
                   1193: /*
                   1194: _______________________________________________________________________
                   1195: 
                   1196: Routine:       BlockMarkAllocated
                   1197: 
                   1198: Function:      Mark a contiguous group of blocks as allocated (set in the
                   1199:                        bitmap).  It assumes those bits are currently marked
                   1200:                        deallocated (clear in the bitmap).
                   1201: 
                   1202: Inputs:
                   1203:        vcb                             Pointer to volume where space is to be allocated
                   1204:        startingBlock   First block number to mark as allocated
                   1205:        numBlocks               Number of blocks to mark as allocated
                   1206: _______________________________________________________________________
                   1207: */
                   1208: static OSErr BlockMarkAllocated(
                   1209:        ExtendedVCB             *vcb,
                   1210:        UInt32                  startingBlock,
                   1211:        register UInt32 numBlocks)
                   1212: {
                   1213:        OSErr                   err;
                   1214:        register UInt32 *currentWord;   //      Pointer to current word within bitmap block
                   1215:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
                   1216:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
                   1217:        UInt32                  firstBit;               //      Bit index within word of first bit to allocate
                   1218:        UInt32                  numBits;                //      Number of bits in word to allocate
                   1219:        UInt32                  *buffer = NULL;
                   1220: 
                   1221: #if HFSInstrumentation
                   1222:        InstTraceClassRef       trace;
                   1223:        InstEventTag            eventTag;
                   1224:        
                   1225:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkAllocated", 'hfs+', kInstEnableClassMask, &trace);
                   1226:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                   1227: 
                   1228:        eventTag = InstCreateEventTag();
                   1229:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                   1230: #endif
                   1231: 
                   1232:        //
                   1233:        //      Pre-read the bitmap block containing the first word of allocation
                   1234:        //
                   1235: 
                   1236:        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1237:        if (err != noErr) goto Exit;
                   1238:        MarkBlock_glue((Ptr) buffer);           //      this block will be dirty
                   1239: 
                   1240:        //
                   1241:        //      Initialize currentWord, and wordsLeft.
                   1242:        //
                   1243:        {
                   1244:                UInt32 wordIndexInBlock;
                   1245: 
                   1246:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
                   1247:                currentWord = buffer + wordIndexInBlock;
                   1248:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
                   1249:        }
                   1250:        
                   1251:        //
                   1252:        //      If the first block to allocate doesn't start on a word
                   1253:        //      boundary in the bitmap, then treat that first word
                   1254:        //      specially.
                   1255:        //
                   1256: 
                   1257:        firstBit = startingBlock % kBitsPerWord;
                   1258:        if (firstBit != 0) {
                   1259:                bitMask = kAllBitsSetInWord >> firstBit;        //      turn off all bits before firstBit
                   1260:                numBits = kBitsPerWord - firstBit;                      //      number of remaining bits in this word
                   1261:                if (numBits > numBlocks) {
                   1262:                        numBits = numBlocks;                                    //      entire allocation is inside this one word
                   1263:                        bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits));        //      turn off bits after last
                   1264:                }
                   1265: #if DEBUG_BUILD
                   1266:                if ((*currentWord & bitMask) != 0) {
                   1267:                        DebugStr("\pFATAL: blocks already allocated!");
                   1268:                        //err = fsDSIntErr;
                   1269:                        //goto Exit;
                   1270:                }
                   1271: #endif
                   1272:                *currentWord |= bitMask;                                        //      set the bits in the bitmap
                   1273:                numBlocks -= numBits;                                           //      adjust number of blocks left to allocate
                   1274: 
                   1275:                ++currentWord;                                                          //      move to next word
                   1276:                --wordsLeft;                                                            //      one less word left in this block
                   1277:        }
                   1278: 
                   1279:        //
                   1280:        //      Allocate whole words (32 blocks) at a time.
                   1281:        //
                   1282: 
                   1283:        bitMask = kAllBitsSetInWord;                                    //      put this in a register for 68K
                   1284:        while (numBlocks >= kBitsPerWord) {
                   1285:                if (wordsLeft == 0) {
                   1286:                        //      Read in the next bitmap block
                   1287:                        startingBlock += kBitsPerBlock;                 //      generate a block number in the next bitmap block
                   1288:                        
                   1289: #if EXPLICIT_BUFFER_RELEASES
                   1290:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1291:                        if (err != noErr) goto Exit;
                   1292:                        buffer = NULL;
                   1293: #endif
                   1294:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1295:                        if (err != noErr) goto Exit;
                   1296:                        MarkBlock_glue((Ptr) buffer);                   //      this block will be dirty
                   1297:                        
                   1298:                        //      Readjust currentWord and wordsLeft
                   1299:                        currentWord = buffer;
                   1300:                        wordsLeft = kWordsPerBlock;
                   1301:                }
                   1302: #if DEBUG_BUILD
                   1303:                if (*currentWord != 0) {
                   1304:                        DebugStr("\pFATAL: blocks already allocated!");
                   1305:                        //err = fsDSIntErr;
                   1306:                        //goto Exit;
                   1307:                }
                   1308: #endif
                   1309:                *currentWord = bitMask;
                   1310:                numBlocks -= kBitsPerWord;
                   1311: 
                   1312:                ++currentWord;                                                          //      move to next word
                   1313:                --wordsLeft;                                                            //      one less word left in this block
                   1314:        }
                   1315:        
                   1316:        //
                   1317:        //      Allocate any remaining blocks.
                   1318:        //
                   1319:        
                   1320:        if (numBlocks != 0) {
                   1321:                bitMask = ~(kAllBitsSetInWord >> numBlocks);    //      set first numBlocks bits
                   1322:                if (wordsLeft == 0) {
                   1323:                        //      Read in the next bitmap block
                   1324:                        startingBlock += kBitsPerBlock;                         //      generate a block number in the next bitmap block
                   1325:                        
                   1326: #if EXPLICIT_BUFFER_RELEASES
                   1327:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1328:                        if (err != noErr) goto Exit;
                   1329:                        buffer = NULL;
                   1330: #endif
                   1331:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1332:                        if (err != noErr) goto Exit;
                   1333:                        MarkBlock_glue((Ptr) buffer);                           //      this block will be dirty
                   1334:                        
                   1335:                        //      Readjust currentWord and wordsLeft
                   1336:                        currentWord = buffer;
                   1337:                        wordsLeft = kWordsPerBlock;
                   1338:                }
                   1339: #if DEBUG_BUILD
                   1340:                if ((*currentWord & bitMask) != 0) {
                   1341:                        DebugStr("\pFATAL: blocks already allocated!");
                   1342:                        //err = fsDSIntErr;
                   1343:                        //goto Exit;
                   1344:                }
                   1345: #endif
                   1346:                *currentWord |= bitMask;                                                //      set the bits in the bitmap
                   1347: 
                   1348:                //      No need to update currentWord or wordsLeft
                   1349:        }
                   1350: 
                   1351: Exit:
                   1352: 
                   1353: #if EXPLICIT_BUFFER_RELEASES
                   1354:        if (buffer) {
                   1355:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
                   1356:        };
                   1357: #endif
                   1358: 
                   1359: #if HFSInstrumentation
                   1360:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                   1361: #endif
                   1362: 
                   1363:        return err;
                   1364: }
                   1365: 
                   1366: 
                   1367: 
                   1368: /*
                   1369: _______________________________________________________________________
                   1370: 
                   1371: Routine:       BlockMarkFree
                   1372: 
                   1373: Function:      Mark a contiguous group of blocks as free (clear in the
                   1374:                        bitmap).  It assumes those bits are currently marked
                   1375:                        allocated (set in the bitmap).
                   1376: 
                   1377: Inputs:
                   1378:        vcb                             Pointer to volume where space is to be freed
                   1379:        startingBlock   First block number to mark as freed
                   1380:        numBlocks               Number of blocks to mark as freed
                   1381: _______________________________________________________________________
                   1382: */
                   1383: static OSErr BlockMarkFree(
                   1384:        ExtendedVCB             *vcb,
                   1385:        UInt32                  startingBlock,
                   1386:        register UInt32 numBlocks)
                   1387: {
                   1388:        OSErr                   err;
                   1389:        register UInt32 *currentWord;   //      Pointer to current word within bitmap block
                   1390:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
                   1391:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
                   1392:        UInt32                  firstBit;               //      Bit index within word of first bit to allocate
                   1393:        UInt32                  numBits;                //      Number of bits in word to allocate
                   1394:        UInt32                  *buffer = NULL;
                   1395: 
                   1396: #if HFSInstrumentation
                   1397:        InstTraceClassRef       trace;
                   1398:        InstEventTag            eventTag;
                   1399:        
                   1400:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkFree", 'hfs+', kInstEnableClassMask, &trace);
                   1401:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                   1402: 
                   1403:        eventTag = InstCreateEventTag();
                   1404:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                   1405: #endif
                   1406: 
                   1407:        //
                   1408:        //      Pre-read the bitmap block containing the first word of allocation
                   1409:        //
                   1410: 
                   1411:        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1412:        if (err != noErr) goto Exit;
                   1413:        MarkBlock_glue((Ptr) buffer);           //      this block will be dirty
                   1414: 
                   1415:        //
                   1416:        //      Initialize currentWord, and wordsLeft.
                   1417:        //
                   1418:        {
                   1419:                UInt32 wordIndexInBlock;
                   1420: 
                   1421:                wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
                   1422:                currentWord = buffer + wordIndexInBlock;
                   1423:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
                   1424:        }
                   1425:        
                   1426:        //
                   1427:        //      If the first block to free doesn't start on a word
                   1428:        //      boundary in the bitmap, then treat that first word
                   1429:        //      specially.
                   1430:        //
                   1431: 
                   1432:        firstBit = startingBlock % kBitsPerWord;
                   1433:        if (firstBit != 0) {
                   1434:                bitMask = kAllBitsSetInWord >> firstBit;        //      turn off all bits before firstBit
                   1435:                numBits = kBitsPerWord - firstBit;                      //      number of remaining bits in this word
                   1436:                if (numBits > numBlocks) {
                   1437:                        numBits = numBlocks;                                    //      entire allocation is inside this one word
                   1438:                        bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits));        //      turn off bits after last
                   1439:                }
                   1440: #if DEBUG_BUILD
                   1441:                if ((*currentWord & bitMask) != bitMask) {
                   1442:                        DebugStr("\pFATAL: blocks not allocated!");
                   1443:                        //err = fsDSIntErr;
                   1444:                        //goto Exit;
                   1445:                }
                   1446: #endif
                   1447:                *currentWord &= ~bitMask;                                       //      clear the bits in the bitmap
                   1448:                numBlocks -= numBits;                                           //      adjust number of blocks left to free
                   1449: 
                   1450:                ++currentWord;                                                          //      move to next word
                   1451:                --wordsLeft;                                                            //      one less word left in this block
                   1452:        }
                   1453: 
                   1454:        //
                   1455:        //      Allocate whole words (32 blocks) at a time.
                   1456:        //
                   1457: 
                   1458:        while (numBlocks >= kBitsPerWord) {
                   1459:                if (wordsLeft == 0) {
                   1460:                        //      Read in the next bitmap block
                   1461:                        startingBlock += kBitsPerBlock;                 //      generate a block number in the next bitmap block
                   1462:                        
                   1463: #if EXPLICIT_BUFFER_RELEASES
                   1464:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1465:                        if (err != noErr) goto Exit;
                   1466:                        buffer = NULL;
                   1467: #endif
                   1468:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1469:                        if (err != noErr) goto Exit;
                   1470:                        MarkBlock_glue((Ptr) buffer);                   //      this block will be dirty
                   1471:                        
                   1472:                        //      Readjust currentWord and wordsLeft
                   1473:                        currentWord = buffer;
                   1474:                        wordsLeft = kWordsPerBlock;
                   1475:                }
                   1476: 
                   1477: #if DEBUG_BUILD
                   1478:                if (*currentWord != kAllBitsSetInWord) {
                   1479:                        DebugStr("\pFATAL: blocks not allocated!");
                   1480:                        //err = fsDSIntErr;
                   1481:                        //goto Exit;
                   1482:                }
                   1483: #endif
                   1484:                *currentWord = 0;                                                       //      clear the entire word
                   1485:                numBlocks -= kBitsPerWord;
                   1486:                
                   1487:                ++currentWord;                                                          //      move to next word
                   1488:                --wordsLeft;                                                            //      one less word left in this block
                   1489:        }
                   1490:        
                   1491:        //
                   1492:        //      Allocate any remaining blocks.
                   1493:        //
                   1494:        
                   1495:        if (numBlocks != 0) {
                   1496:                bitMask = ~(kAllBitsSetInWord >> numBlocks);    //      set first numBlocks bits
                   1497:                if (wordsLeft == 0) {
                   1498:                        //      Read in the next bitmap block
                   1499:                        startingBlock += kBitsPerBlock;                         //      generate a block number in the next bitmap block
                   1500:                        
                   1501: #if EXPLICIT_BUFFER_RELEASES
                   1502:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1503:                        if (err != noErr) goto Exit;
                   1504:                        buffer = NULL;
                   1505: #endif
                   1506:                        err = ReadBitmapBlock(vcb, startingBlock, &buffer);
                   1507:                        if (err != noErr) goto Exit;
                   1508:                        MarkBlock_glue((Ptr) buffer);                           //      this block will be dirty
                   1509:                        
                   1510:                        //      Readjust currentWord and wordsLeft
                   1511:                        currentWord = buffer;
                   1512:                        wordsLeft = kWordsPerBlock;
                   1513:                }
                   1514: #if DEBUG_BUILD
                   1515:                if ((*currentWord & bitMask) != bitMask) {
                   1516:                        DebugStr("\pFATAL: blocks not allocated!");
                   1517:                        //err = fsDSIntErr;
                   1518:                        //goto Exit;
                   1519:                }
                   1520: #endif
                   1521:                *currentWord &= ~bitMask;                                               //      clear the bits in the bitmap
                   1522: 
                   1523:                //      No need to update currentWord or wordsLeft
                   1524:        }
                   1525: 
                   1526: Exit:
                   1527: 
                   1528: #if EXPLICIT_BUFFER_RELEASES
                   1529:        if (buffer) {
                   1530:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
                   1531:        };
                   1532: #endif
                   1533: 
                   1534: #if HFSInstrumentation
                   1535:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                   1536: #endif
                   1537: 
                   1538:        return err;
                   1539: }
                   1540: 
                   1541: 
                   1542: 
                   1543: static OSErr BlockVerifyAllocated(
                   1544:        ExtendedVCB             *vcb,
                   1545:        UInt32                  startBlock,
                   1546:        register UInt32 numBlocks,
                   1547:        Boolean                 *foundUnmarkedBlock)
                   1548: {
                   1549:        OSErr                   err;
                   1550:        register UInt32 wordsLeft;              //      Number of words left in this bitmap block
                   1551:        register UInt32 bitMask;                //      Word with given bits already set (ready to OR in)
                   1552:        UInt32                  firstBit;               //      Bit index within word of first bit to allocate
                   1553:        UInt32                  numBits;                //      Number of bits in word to allocate
                   1554:        UInt32                  *buffer = NULL; //      Pointer to bitmap block
                   1555:        register UInt32 *currentWord;   //      Pointer to current word in bitmap block
                   1556:        
                   1557: #if HFSInstrumentation
                   1558:        InstTraceClassRef       trace;
                   1559:        InstEventTag            eventTag;
                   1560:        
                   1561:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockVerifyAllocated", 'hfs+', kInstEnableClassMask, &trace);
                   1562:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                   1563: 
                   1564:        eventTag = startBlock;
                   1565:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                   1566: #endif
                   1567: 
                   1568:        //
                   1569:        //      Assume everything's OK
                   1570:        //
                   1571:        *foundUnmarkedBlock = false;
                   1572: 
                   1573:        //
                   1574:        //      Pre-read the bitmap block containing the first word to check
                   1575:        //
                   1576: 
                   1577:        err = ReadBitmapBlock(vcb, startBlock, &buffer);
                   1578:        if (err != noErr) goto Exit;
                   1579: 
                   1580:        //
                   1581:        //      Initialize buffer stuff
                   1582:        //
                   1583:        {
                   1584:                UInt32 wordIndexInBlock;
                   1585: 
                   1586:                wordIndexInBlock = (startBlock & kBitsWithinBlockMask) / kBitsPerWord;
                   1587:                currentWord = buffer + wordIndexInBlock;
                   1588:                wordsLeft = kWordsPerBlock - wordIndexInBlock;
                   1589:        }
                   1590:        
                   1591:        //
                   1592:        //      If the first block to check doesn't start on a word
                   1593:        //      boundary in the bitmap, then treat that first word
                   1594:        //      specially.
                   1595:        //
                   1596: 
                   1597:        firstBit = startBlock % kBitsPerWord;
                   1598:        if (firstBit != 0) {
                   1599:                bitMask = kAllBitsSetInWord >> firstBit;        //      turn off all bits before firstBit
                   1600:                numBits = kBitsPerWord - firstBit;                      //      number of remaining bits in this word
                   1601:                if (numBits > numBlocks) {
                   1602:                        numBits = numBlocks;                                    //      entire allocation is inside this one word
                   1603:                        bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits));        //      turn off bits after last
                   1604:                }
                   1605: 
                   1606:                //      Make sure all the bits are set
                   1607:                if ((*currentWord & bitMask) != bitMask) {
                   1608:                        *foundUnmarkedBlock = true;                             //      found an error
                   1609:                        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                   1610:                        {
                   1611:                                *currentWord |= bitMask;                        // set the bits in the bitmap
                   1612:                                MarkBlock_glue((Ptr) buffer);           // this block is now dirty
                   1613:                        }
                   1614:                }
                   1615:                
                   1616:                numBlocks -= numBits;                                           //      adjust number of blocks left to check
                   1617:                ++currentWord;                                                          //      move to next word
                   1618:                --wordsLeft;                                                            //      one less word left in this block
                   1619:        }
                   1620: 
                   1621:        //
                   1622:        //      Check whole words (32 blocks) at a time.
                   1623:        //
                   1624: 
                   1625:        bitMask = kAllBitsSetInWord;                                    //      put this in a register for 68K
                   1626:        while (numBlocks >= kBitsPerWord) {
                   1627:                //      See if it's time to move to the next bitmap block
                   1628:                if (wordsLeft == 0) {
                   1629:                        //      Read in the next bitmap block
                   1630:                        startBlock += kBitsPerBlock;                    //      generate a block number in the next bitmap block
                   1631:                        
                   1632: #if EXPLICIT_BUFFER_RELEASES
                   1633:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1634:                        if (err != noErr) goto Exit;
                   1635:                        buffer = NULL;
                   1636: #endif
                   1637:                        err = ReadBitmapBlock(vcb, startBlock, &buffer);
                   1638:                        if (err != noErr) goto Exit;
                   1639:                        
                   1640:                        //      Readjust currentWord, wordsLeft
                   1641:                        currentWord = buffer;
                   1642:                        wordsLeft = kWordsPerBlock;
                   1643:                }
                   1644:                
                   1645:                //      Make sure all the blocks are allocated
                   1646:                if (*currentWord != bitMask) {
                   1647:                        *foundUnmarkedBlock = true;                             //      found an error
                   1648:                        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                   1649:                        {
                   1650:                                *currentWord = bitMask;                         // update the bitmap
                   1651:                                MarkBlock_glue((Ptr) buffer);           // this block is now dirty
                   1652:                        }
                   1653:                }
                   1654: 
                   1655:                numBlocks -= kBitsPerWord;
                   1656:                ++currentWord;                                                          //      move to next word
                   1657:                --wordsLeft;                                                            // one less word left in this block
                   1658:        }
                   1659:        
                   1660:        //
                   1661:        //      Check any remaining blocks.
                   1662:        //
                   1663:        
                   1664:        if (numBlocks != 0) {
                   1665:                bitMask = ~(kAllBitsSetInWord >> numBlocks);    //      set first numBlocks bits
                   1666:                if (wordsLeft == 0) {
                   1667:                        //      Read in the next bitmap block
                   1668:                        startBlock += kBitsPerBlock;                            //      generate a block number in the next bitmap block
                   1669:                        
                   1670: #if EXPLICIT_BUFFER_RELEASES
                   1671:                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1672:                        if (err != noErr) goto Exit;
                   1673:                        buffer = NULL;
                   1674: #endif
                   1675:                        err = ReadBitmapBlock(vcb, startBlock, &buffer);
                   1676:                        if (err != noErr) goto Exit;
                   1677:                        
                   1678:                        //      Readjust currentWord, wordsLeft
                   1679:                        currentWord = buffer;
                   1680:                        wordsLeft = kWordsPerBlock;
                   1681:                }
                   1682:                
                   1683:                //      Make sure all the bits are set
                   1684:                if ((*currentWord & bitMask) != bitMask) {
                   1685:                        *foundUnmarkedBlock = true;                                     //      found an error
                   1686:                        if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
                   1687:                        {
                   1688:                                *currentWord |= bitMask;                                //      set the bits in the bitmap
                   1689:                                MarkBlock_glue((Ptr) buffer);                   //      this block is now dirty
                   1690:                        }
                   1691:                }
                   1692:                
                   1693:                //      No need to update buffer pointer, etc.
                   1694:        }
                   1695: 
                   1696: Exit:
                   1697: 
                   1698: #if EXPLICIT_BUFFER_RELEASES
                   1699:        if (buffer) {
                   1700:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
                   1701:        };
                   1702: #endif
                   1703: 
                   1704: #if HFSInstrumentation
                   1705:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                   1706: #endif
                   1707: 
                   1708:        return err;
                   1709: }
                   1710: 
                   1711: 
                   1712: 
                   1713: /*
                   1714: _______________________________________________________________________
                   1715: 
                   1716: Routine:       BlockFindContiguous
                   1717: 
                   1718: Function:      Find a contiguous range of blocks that are free (bits
                   1719:                        clear in the bitmap).  If a contiguous range of the
                   1720:                        minimum size can't be found, an error will be returned.
                   1721:                        
                   1722:                        �� It would be nice if we could skip over whole words
                   1723:                        �� with all bits set.
                   1724:                        
                   1725:                        �� When we find a bit set, and are about to set freeBlocks
                   1726:                        �� to 0, we should check to see whether there are still
                   1727:                        �� minBlocks bits left in the bitmap.
                   1728: 
                   1729: Inputs:
                   1730:        vcb                             Pointer to volume where space is to be allocated
                   1731:        startingBlock   Preferred first block of range
                   1732:        endingBlock             Last possible block in range + 1
                   1733:        minBlocks               Minimum number of blocks needed.  Must be > 0.
                   1734:        maxBlocks               Maximum (ideal) number of blocks desired
                   1735: 
                   1736: Outputs:
                   1737:        actualStartBlock        First block of range found, or 0 if error
                   1738:        actualNumBlocks         Number of blocks found, or 0 if error
                   1739: _______________________________________________________________________
                   1740: */
                   1741: /*
                   1742: _________________________________________________________________________________________
                   1743:        (DSH) 5/8/97 Description of BlockFindContiguous() algorithm
                   1744:        Finds a contiguous range of free blocks by searching back to front.  This
                   1745:        allows us to skip ranges of bits knowing that they are not candidates for
                   1746:        a match because they are too small.  The below ascii diagrams illustrate
                   1747:        the algorithm in action.
                   1748:        
                   1749:        Representation of a piece of a volume bitmap file
                   1750:        If BlockFindContiguous() is called with minBlocks == 10, maxBlocks == 20
                   1751: 
                   1752: 
                   1753: Fig. 1 initialization of variables, "<--" represents direction of travel
                   1754: 
                   1755: startingBlock (passed in)
                   1756:        |
                   1757:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1758:        |                       <--|
                   1759: stopBlock                 currentBlock                        freeBlocks == 0
                   1760:                                                               countedFreeBlocks == 0
                   1761: 
                   1762: Fig. 2 dirty bit found
                   1763: 
                   1764:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1765:        |                 |
                   1766: stopBlock        currentBlock                                 freeBlocks == 3
                   1767:                                                               countedFreeBlocks == 0
                   1768: 
                   1769: Fig. 3 reset variables to search for remainder of minBlocks
                   1770: 
                   1771:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1772:        |_________________|           |                 |
                   1773:             Unsearched            stopBlock        currentBlock    freeBlocks == 0
                   1774:                                                                    countedFreeBlocks == 3
                   1775: 
                   1776: Fig. 4 minBlocks contiguous blocks found, *actualStartBlock is set
                   1777: 
                   1778:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1779:        |_________________|           |
                   1780:             Unsearched            stopBlock                      freeBlocks == 7
                   1781:                                  currentBlock                    countedFreeBlocks == 3
                   1782: 
                   1783: Fig. 5 Now run it forwards trying to accumalate up to maxBlocks if possible
                   1784: 
                   1785:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1786:        |_________________|                                | -->
                   1787:             Unsearched                               currentBlock
                   1788:                                                                      *actualNumBlocks == 10
                   1789: 
                   1790: Fig. 6 Dirty bit is found, return actual number of contiguous blocks found
                   1791: 
                   1792:        1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
                   1793:        |_________________|                                                  |
                   1794:             Unsearched                                                 currentBlock
                   1795:                                                                      *actualNumBlocks == 16
                   1796: _________________________________________________________________________________________
                   1797: */
                   1798: 
                   1799: static OSErr BlockFindContiguous(
                   1800:        ExtendedVCB             *vcb,
                   1801:        UInt32                  startingBlock,
                   1802:        register UInt32 endingBlock,
                   1803:        UInt32                  minBlocks,
                   1804:        UInt32                  maxBlocks,
                   1805:        UInt32                  *actualStartBlock,
                   1806:        UInt32                  *actualNumBlocks)
                   1807: {
                   1808:        OSErr                   err;
                   1809:        register UInt32 bitMask;                        //      mask of bit within word for currentBlock
                   1810:        register UInt32 tempWord;                       //      bitmap word currently being examined
                   1811:        register UInt32 freeBlocks;                     //      number of contiguous free blocks so far
                   1812:        register UInt32 currentBlock;           //      block number we're currently examining
                   1813:        UInt32                  wordsLeft;                      //      words remaining in bitmap block
                   1814:        UInt32                  *buffer = NULL;
                   1815:        register UInt32 *currentWord;
                   1816:        
                   1817:        UInt32                  stopBlock;                      //      when all blocks until stopBlock are free, we found enough
                   1818:        UInt32                  countedFreeBlocks;      //      how many contiguous free block behind stopBlock
                   1819:        UInt32                  currentSector;          //      which allocations file sector
                   1820: 
                   1821: #if HFSInstrumentation
                   1822:        InstTraceClassRef               trace;
                   1823:        InstEventTag                    eventTag;
                   1824:        
                   1825:        err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockFindContiguous", 'hfs+', kInstEnableClassMask, &trace);
                   1826:        if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
                   1827: 
                   1828:        eventTag = InstCreateEventTag();
                   1829:        InstLogTraceEvent( trace, eventTag, kInstStartEvent);
                   1830: #endif
                   1831: 
                   1832:        if ((endingBlock - startingBlock) < minBlocks) {
                   1833:                //      The set of blocks we're checking is smaller than the minimum number
                   1834:                //      of blocks, so we couldn't possibly find a good range.
                   1835:                err = dskFulErr;
                   1836:                goto Exit;
                   1837:        }
                   1838:        
                   1839:        //      Search for min blocks from back to front.
                   1840:        //      If min blocks is found, advance the allocation pointer up to max blocks
                   1841:        
                   1842:        //
                   1843:        //      Pre-read the bitmap block containing currentBlock
                   1844:        //
                   1845:        stopBlock               = startingBlock;
                   1846:        currentBlock    = startingBlock + minBlocks - 1;                //      (-1) to include startingBlock
                   1847:        
                   1848:        err = ReadBitmapBlock( vcb, currentBlock, &buffer );
                   1849:        if ( err != noErr ) goto Exit;
                   1850:        
                   1851:        //
                   1852:        //      Init buffer, currentWord, wordsLeft, and bitMask
                   1853:        //
                   1854:        {
                   1855:                UInt32 wordIndexInBlock;
                   1856: 
                   1857:                wordIndexInBlock = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
                   1858:                currentWord             = buffer + wordIndexInBlock;
                   1859:                                
                   1860:                wordsLeft               = wordIndexInBlock;
                   1861:                tempWord                = *currentWord;
                   1862:                bitMask                 = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
                   1863:                currentSector   = currentBlock / kBitsPerBlock;
                   1864:        }
                   1865:        
                   1866:        //
                   1867:        //      Look for maxBlocks free blocks.  If we find an allocated block,
                   1868:        //      see if we've found minBlocks.
                   1869:        //
                   1870:        freeBlocks                      = 0;
                   1871:        countedFreeBlocks       = 0;
                   1872: 
                   1873:        while ( currentBlock >= stopBlock )
                   1874:        {
                   1875:                //      Check current bit
                   1876:                if ((tempWord & bitMask) == 0)
                   1877:                {
                   1878:                        ++freeBlocks;
                   1879:                }
                   1880:                else                                                                                                                    //      Used bitmap block found
                   1881:                {
                   1882:                        if ( ( freeBlocks +  countedFreeBlocks ) >= minBlocks )
                   1883:                        {
                   1884:                                break;                                                                                                  //      Found enough
                   1885:                        }
                   1886:                        else
                   1887:                        {
                   1888:                                //      We found a dirty bit, so we want to check if the next (minBlocks-freeBlocks) blocks
                   1889:                                //      are free beyond what we have already checked. At Fig.2 setting up for Fig.3
                   1890:                                
                   1891:                                stopBlock                       = currentBlock + 1 + freeBlocks;        //      Advance stop condition
                   1892:                                currentBlock            += minBlocks;
                   1893:                                if ( currentBlock >= endingBlock ) break;
                   1894:                                countedFreeBlocks       = freeBlocks;
                   1895:                                freeBlocks                      = 0;                                                            //      Not enough; look for another range
                   1896: 
                   1897:                                if ( currentSector != currentBlock / kBitsPerBlock )
                   1898:                                {
                   1899: #if EXPLICIT_BUFFER_RELEASES
                   1900:                                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1901:                                        if (err != noErr) goto Exit;
                   1902:                                        buffer = NULL;
                   1903: #endif
                   1904:                                        err = ReadBitmapBlock( vcb, currentBlock, &buffer );
                   1905:                                        if (err != noErr) goto Exit;
                   1906:                                        currentSector = currentBlock / kBitsPerBlock;
                   1907:                                }
                   1908:                                        
                   1909:                                wordsLeft       = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
                   1910:                                currentWord     = buffer + wordsLeft;
                   1911:                                tempWord        = *currentWord;
                   1912:                                bitMask         = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
                   1913: 
                   1914:                                continue;                                                                                               //      Back to the while loop
                   1915:                        }
                   1916:                }
                   1917:                
                   1918:                //      Move to next bit
                   1919:                --currentBlock;
                   1920:                bitMask <<= 1;
                   1921:                if (bitMask == 0)                                                                                               //      On a word boundry, start masking words
                   1922:                {
                   1923:                        bitMask = kLowBitInWordMask;
                   1924: 
                   1925:                        //      Move to next word
                   1926: NextWord:
                   1927:                        if ( wordsLeft != 0 )
                   1928:                        {
                   1929:                                --currentWord;
                   1930:                                --wordsLeft;
                   1931:                        }
                   1932:                        else
                   1933:                        {
                   1934:                                //      Read in the next bitmap block
                   1935: #if EXPLICIT_BUFFER_RELEASES
                   1936:                                err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1937:                                if (err != noErr) goto Exit;
                   1938:                                buffer = NULL;
                   1939: #endif
                   1940:                                err = ReadBitmapBlock( vcb, currentBlock, &buffer );
                   1941:                                if (err != noErr) goto Exit;
                   1942:                                
                   1943:                                //      Adjust currentWord, wordsLeft, currentSector
                   1944:                                currentSector   = currentBlock / kBitsPerBlock;
                   1945:                                currentWord             = buffer + kWordsPerBlock - 1;  //      Last word in buffer
                   1946:                                wordsLeft               = kWordsPerBlock - 1;
                   1947:                        }
                   1948:                        
                   1949:                        tempWord = *currentWord;                                                        //      Grab the current word
                   1950: 
                   1951:                        //
                   1952:                        //      If we found a whole word of free blocks, quickly skip over it.
                   1953:                        //      NOTE: we could actually go beyond the end of the bitmap if the
                   1954:                        //      number of allocation blocks on the volume is not a multiple of
                   1955:                        //      32.  If this happens, we'll adjust currentBlock and freeBlocks
                   1956:                        //      after the loop.
                   1957:                        //
                   1958:                        if ( tempWord == 0 )
                   1959:                        {
                   1960:                                freeBlocks              += kBitsPerWord;
                   1961:                                currentBlock    -= kBitsPerWord;
                   1962:                                if ( freeBlocks + countedFreeBlocks >= minBlocks )
                   1963:                                        break;                                                                  //      Found enough
                   1964:                                goto NextWord;
                   1965:                        }
                   1966:                }
                   1967:        }
                   1968: 
                   1969:        if ( freeBlocks + countedFreeBlocks < minBlocks )
                   1970:        {
                   1971:                *actualStartBlock       = 0;
                   1972:                *actualNumBlocks        = 0;
                   1973:                err                                     = dskFulErr;
                   1974:                goto Exit;
                   1975:        }
                   1976: 
                   1977:        //
                   1978:        //      When we get here, we know we've found minBlocks continuous space.
                   1979:        //      At Fig.4, setting up for Fig.5
                   1980:        //      From here we do a forward search accumalating additional free blocks.
                   1981:        //
                   1982:        
                   1983:        *actualNumBlocks        = minBlocks;
                   1984:        *actualStartBlock       = stopBlock - countedFreeBlocks;        //      ActualStartBlock is set to return to the user
                   1985:        currentBlock            = *actualStartBlock + minBlocks;        //      Right after found free space
                   1986:        
                   1987:        //      Now lets see if we can run the actualNumBlocks number all the way up to maxBlocks
                   1988:        if ( currentSector != currentBlock / kBitsPerBlock )
                   1989:        {
                   1990: #if EXPLICIT_BUFFER_RELEASES
                   1991:                err = RelBlock_glue((Ptr)buffer, rbDefault);
                   1992:                if (err != noErr) goto Exit;
                   1993:                buffer = NULL;
                   1994: #endif
                   1995:                err = ReadBitmapBlock( vcb, currentBlock, &buffer );
                   1996:                if (err != noErr)
                   1997:                {
                   1998:                        err     = noErr;                                                                        //      We already found the space
                   1999:                        goto Exit;
                   2000:                }
                   2001:                
                   2002:                currentSector = currentBlock / kBitsPerBlock;
                   2003:        }
                   2004: 
                   2005:        //
                   2006:        //      Init buffer, currentWord, wordsLeft, and bitMask
                   2007:        //
                   2008:        {
                   2009:                UInt32 wordIndexInBlock;
                   2010: 
                   2011:                wordIndexInBlock = (currentBlock & kBitsWithinBlockMask) / kBitsPerWord;
                   2012:                currentWord             = buffer + wordIndexInBlock;
                   2013:                tempWord                = *currentWord;
                   2014:                wordsLeft               = kWordsPerBlock - wordIndexInBlock;
                   2015:                bitMask                 = kHighBitInWordMask >> (currentBlock & kBitsWithinWordMask);
                   2016:        }
                   2017: 
                   2018:        if ( *actualNumBlocks < maxBlocks )
                   2019:        {
                   2020:                while ( currentBlock < endingBlock )
                   2021:                {
                   2022:                                
                   2023:                        if ( (tempWord & bitMask) == 0 )
                   2024:                        {
                   2025:                                *actualNumBlocks        += 1;
                   2026:                                
                   2027:                                if ( *actualNumBlocks == maxBlocks )
                   2028:                                        break;
                   2029:                        }
                   2030:                        else
                   2031:                        {
                   2032:                                break;
                   2033:                        }
                   2034:        
                   2035:                        //      Move to next bit
                   2036:                        ++currentBlock;
                   2037:                        bitMask >>= 1;
                   2038:                        if (bitMask == 0)
                   2039:                        {
                   2040:                                bitMask = kHighBitInWordMask;
                   2041:                                ++currentWord;
                   2042:        
                   2043:                                if ( --wordsLeft == 0)
                   2044:                                {
                   2045: #if EXPLICIT_BUFFER_RELEASES
                   2046:                                        err = RelBlock_glue((Ptr)buffer, rbDefault);
                   2047:                                        if (err != noErr) goto Exit;
                   2048:                                        buffer = NULL;
                   2049: #endif
                   2050:                                        err = ReadBitmapBlock(vcb, currentBlock, &buffer);
                   2051:                                        if (err != noErr) break;
                   2052:                                        
                   2053:                                        //      Adjust currentWord, wordsLeft
                   2054:                                        currentWord             = buffer;
                   2055:                                        wordsLeft               = kWordsPerBlock;
                   2056:                                }
                   2057:                                tempWord = *currentWord;                        //      grab the current word
                   2058:                        }
                   2059:                }
                   2060:        }
                   2061:        
                   2062: Exit:
                   2063: 
                   2064: #if EXPLICIT_BUFFER_RELEASES
                   2065:        if (buffer) {
                   2066:                (void)RelBlock_glue((Ptr)buffer, rbDefault);            /* Ignore any additional errors */
                   2067:        };
                   2068: #endif
                   2069: 
                   2070: #if HFSInstrumentation
                   2071:        InstLogTraceEvent( trace, eventTag, kInstEndEvent);
                   2072: #endif
                   2073: 
                   2074:        return err;
                   2075: }
                   2076: 
                   2077: 

unix.superglobalmegacorp.com

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