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