2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 File: VolumeAllocation.c
25 Contains: Routines for accessing and modifying the volume bitmap.
29 Copyright: © 1996-2000 by Apple Computer, Inc., all rights reserved.
35 Other Contact: Greg Parks
45 Change History (most recent first):
46 <MacOSX> 1/22/2000 djb Removed unused BlockCheck and BlockVerifyAllocated routines.
47 <MacOSX> 4/27/98 djb Remove references to unused/legacy vcbFreeBks.
48 <MacOSX> 4/27/98 djb Remove unneccessary DebugStr in BlockVerifyAllocated.
49 <MacOSX> 4/17/98 djb Add VCB locking.
50 <MacOSX> 4/13/98 djb Add RequireFileLock checking to ReadBitmapBlock.
51 <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
53 <12> 1 0/31/97 DSH Modify BlockVerifyAllocated() so DFA can call without actually
55 <CS11> 10/20/97 msd The way BlockAllocate rounds up to a multiple of the clump size
56 is wrong. ExtendFileC should do the round-up and pass the result
57 into BlockAllocate. Removed the fcb parameter to BlockAllocate;
58 added a bytesMaximum parameter.
59 <CS10> 10/17/97 msd Conditionalize DebugStrs.
60 <CS9> 9/4/97 djb Add logging to BlockAllocate.
61 <CS8> 9/4/97 msd Add a histogram of allocation sizes. Use DEBUG_BUILD instead of
62 VSM_DEBUG to generate DebugStr messages.
63 <CS7> 8/14/97 msd Bug 1662332. Don't mark blocks dirty in UpdateFreeCount. In
64 BlockVerifyAllocated, only mark blocks dirty if they've actually
66 <CS6> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
68 <CS5> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
69 <CS4> 6/12/97 msd Export BlockAllocateAny and UpdateVCBFreeBlks.
70 <3> 5/8/97 DSH Added comments and ascii diagram of new BlockFindContiguous()
72 <2> 5/7/97 DSH New faster BlockFindContiguous algorithm. It searches backwards
73 until a dirty bit is found instead of forwards.
74 <CS1> 4/25/97 djb first checked in
76 <HFS21> 4/14/97 msd Fix UpdateVCBFreeBlks so free space calculation doesn't overflow
77 on volumes bigger than 4GB.
78 <HFS20> 4/4/97 djb Get in sync with volume format changes.
79 <HFS19> 1/27/97 msd Speed up BlockCheck and UpdateFreeCount. Removed DebugStr from
80 BlockCheck; there are now DebugStr's in BlockVerifyAllocated,
81 before the bitmap gets fixed (so potential problems can be
82 debugged easier). Adjusted comments about internal routines.
83 Changed names of "Fast" routines back to their original names
84 (since the originals are now removed).
85 <HFS18> 1/24/97 msd Speed up allocation and deallocation.
86 <HFS17> 1/21/97 msd Add instrumentation for function entry/exit. BlockAllocate and
87 ReadBitMapBlock use the event tag to log bytes requested and
88 block number (respectively).
89 <HFS16> 1/15/97 djb Add HFS+ supprt to BlockCheck (for MountCheck).
90 <HFS15> 1/13/97 DSH Use vcb->nextAllocation instead of vcbAllocPtr.
91 <HFS14> 1/9/97 djb UpdateVCBFreeBlks is not converting correctly.
92 <HFS13> 1/6/97 djb Use vcb's allocationsRefNum to access allocation file.
93 <HFS12> 1/2/97 DSH Added UpdateVCBFreeBlks() to update vcbFreeBks whenever we
94 update vcb->freeblocks.
95 <HFS11> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB
96 <HFS10> 12/12/96 msd DivideAndRoundUp should not be declared as static.
97 <HFS9> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
98 <HFS8> 12/4/96 DSH PrecompiledHeaders
99 <HFS7> 11/27/96 djb Added AllocateFreeSpace for HFS wrapper support.
100 <HFS6> 11/27/96 msd Changed ReadBitmapBlock to read from HFS+ allocation file.
101 Temporarily uses the vcbVBMSt field of the VCB as the allocation
102 file's refnum until extended VCB changes are checked in.
103 <HFS5> 11/26/96 msd VSM and FileExtentMapping routines use FCB instead of FCBRec.
104 <HFS4> 11/20/96 DSH Changed a parameter in GetBlock_glue, so I also changed the
106 <HFS3> 11/20/96 msd Include FilesInternal.h. Remove definition of MarkVCBDirty
107 (since it is now in FilesInternal.h).
108 <HFS2> 11/12/96 msd Need to bound allocations to be within the last allocation block
109 of the volume (function AllocateAt).
110 <HFS1> 11/11/96 msd first checked in
116 Allocate space on a volume. Can allocate space contiguously.
117 If not contiguous, then allocation may be less than what was
118 asked for. Returns the starting block number, and number of
119 blocks. (Will only do a single extent???)
121 Deallocate a contiguous run of allocation blocks.
123 Computes the number of free allocation blocks on a volume.
124 The vcb's free block count is updated.
127 Allocates all the remaining free space (used for embedding HFS+ volumes).
130 Find and allocate a contiguous range of blocks up to a given size. The
131 first range of contiguous free blocks found are allocated, even if there
132 are fewer blocks than requested (and even if a contiguous range of blocks
133 of the given size exists elsewhere).
136 Given an ExtenddVCB, calculate the vcbFreeBks value
137 so that vcbFreeBks*vcbAlBlkSiz == freeBlocks*blockSize.
141 Mark a contiguous range of blocks as free. The corresponding
142 bits in the volume bitmap will be cleared.
144 Mark a contiguous range of blocks as allocated. The cor-
145 responding bits in the volume bitmap are set. Also tests to see
146 if any of the blocks were previously unallocated.
148 Find a contiguous range of blocks of a given size. The caller
149 specifies where to begin the search (by block number). The
150 block number of the first block in the range is returned.
152 Find and allocate a contiguous range of blocks of a given size. If
153 a contiguous range of free blocks of the given size isn't found, then
154 the allocation fails (i.e. it is "all or nothing").
156 Given an allocation block number, read the bitmap block that
157 contains that allocation block into a caller-supplied buffer.
160 #include "../../hfs_macos_defs.h"
162 #include <sys/types.h>
164 #include <sys/systm.h>
166 #include "../../hfs.h"
167 #include "../../hfs_dbg.h"
168 #include "../../hfs_format.h"
169 #include "../../hfs_endian.h"
171 #include "../headers/FileMgrInternal.h"
173 #include "../headers/HFSInstrumentation.h"
175 #define EXPLICIT_BUFFER_RELEASES 1
180 kWordsPerBlock
= 128,
181 kBytesPerBlock
= 512,
182 kBitsPerBlock
= 4096,
184 kBitsWithinWordMask
= kBitsPerWord
-1,
185 kBitsWithinBlockMask
= kBitsPerBlock
-1,
186 kWordsWithinBlockMask
= kWordsPerBlock
-1,
188 kExtentsPerRecord
= 3
191 #define kLowBitInWordMask 0x00000001ul
192 #define kHighBitInWordMask 0x80000000ul
193 #define kAllBitsSetInWord 0xFFFFFFFFul
196 static OSErr
ReadBitmapBlock(
201 static OSErr
BlockAllocateContig(
203 UInt32 startingBlock
,
206 UInt32
*actualStartBlock
,
207 UInt32
*actualNumBlocks
);
209 static OSErr
BlockFindContiguous(
211 UInt32 startingBlock
,
215 UInt32
*actualStartBlock
,
216 UInt32
*actualNumBlocks
);
218 static OSErr
BlockMarkAllocated(
220 UInt32 startingBlock
,
223 static OSErr
BlockMarkFree(
225 UInt32 startingBlock
,
230 ;________________________________________________________________________________
234 ; Function: Allocate space on a volume. If contiguous allocation is requested,
235 ; at least the requested number of bytes will be allocated or an
236 ; error will be returned. If contiguous allocation is not forced,
237 ; the space will be allocated at the first free fragment following
238 ; the requested starting allocation block. If there is not enough
239 ; room there, a block of less than the requested size will be
242 ; If the requested starting block is 0 (for new file allocations),
243 ; the volume's allocation block pointer will be used as a starting
246 ; All requests will be rounded up to the next highest clump size, as
247 ; indicated in the file's FCB.
250 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
251 ; fcb - Pointer to FCB for the file for which storage is being allocated
252 ; startingBlock - Preferred starting allocation block, 0 = no preference
253 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
254 ; or an error is returned
255 ; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
256 ; less than this may actually be allocated
257 ; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
258 ; space after bytesRequested, then up to bytesMaximum bytes should really
259 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
260 ; of the file's clump size.)
263 ; (result) - Error code, zero for successful allocation
264 ; *startBlock - Actual starting allocation block
265 ; *actualBlocks - Actual number of allocation blocks allocated
268 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
270 ; Modification history:
271 ; <06Oct85> PWD Changed to check for errors after calls to ReadBM and NextWord
272 ; Relocated call to MarkBlock in allocation loop
273 ; Changed to call NextBit
274 ; <21Oct85> PWD Changed to check VCBFreeBks before attempting to allocate any block.
275 ; Speed up scan for free space by checking for all 1's.
276 ;________________________________________________________________________________
279 OSErr
BlockAllocate (
280 ExtendedVCB
*vcb
, /* which volume to allocate space on */
281 UInt32 startingBlock
, /* preferred starting block, or 0 for no preference */
282 SInt64 bytesRequested
, /* desired number of BYTES to allocate */
283 SInt64 bytesMaximum
, /* maximum number of bytes to allocate */
284 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
285 /* bytesRequested bytes to actually be allocated */
286 UInt32
*actualStartBlock
, /* actual first block of allocation */
287 UInt32
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
288 /* was zero, then this may represent fewer than bytesRequested */
292 UInt32 minBlocks
; // minimum number of allocation blocks requested
293 UInt32 maxBlocks
; // number of allocation blocks requested, rounded to clump size
294 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
296 LogStartTime(kTraceBlockAllocate
);
298 #if HFSInstrumentation
299 InstSplitHistogramClassRef histogram
;
300 InstTraceClassRef trace
;
301 InstEventTag eventTag
;
303 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:BlockAllocate", 'hfs+', kInstEnableClassMask
, &trace
);
304 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
306 err
= InstCreateSplitHistogramClass(kInstRootClassRef
, "HFS:VSM:BlockAllocate size", 0, 512, 16384, 262144, 16384,
307 kInstEnableClassMask
, &histogram
);
308 if (err
!= noErr
) DebugStr("\pError from InstCreateHistogramClass");
310 eventTag
= bytesRequested
; // a cheap way to get bytesRequested into the log
311 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
312 InstUpdateHistogram( histogram
, bytesRequested
, 1);
316 // Initialize outputs in case we get an error
318 *actualStartBlock
= 0;
319 *actualNumBlocks
= 0;
322 // Compute the number of allocation blocks requested, and maximum
324 minBlocks
= FileBytesToBlocks(bytesRequested
, vcb
->blockSize
);
325 maxBlocks
= FileBytesToBlocks(bytesMaximum
, vcb
->blockSize
);
328 // If the disk is already full, don't bother.
330 if (vcb
->freeBlocks
== 0) {
334 if (forceContiguous
&& vcb
->freeBlocks
< minBlocks
) {
340 // If caller didn't specify a starting block number, then use the volume's
341 // next block to allocate from.
343 if (startingBlock
== 0) {
345 startingBlock
= vcb
->nextAllocation
;
347 updateAllocPtr
= true;
351 // If the request must be contiguous, then find a sequence of free blocks
352 // that is long enough. Otherwise, find the first free block.
354 if (forceContiguous
) {
355 err
= BlockAllocateContig(vcb
, startingBlock
, minBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
357 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->totalBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
358 if (err
== dskFulErr
) {
359 err
= BlockAllocateAny(vcb
, 0, startingBlock
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
365 // If we used the volume's roving allocation pointer, then we need to update it.
366 // Adding in the length of the current allocation might reduce the next allocate
367 // call by avoiding a re-scan of the already allocated space. However, the clump
368 // just allocated can quite conceivably end up being truncated or released when
369 // the file is closed or its EOF changed. Leaving the allocation pointer at the
370 // start of the last allocation will avoid unnecessary fragmentation in this case.
375 vcb
->nextAllocation
= *actualStartBlock
;
378 // Update the number of free blocks on the volume
380 vcb
->freeBlocks
-= *actualNumBlocks
;
383 UpdateVCBFreeBlks( vcb
);
389 #if HFSInstrumentation
390 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
392 LogEndTime(kTraceBlockAllocate
, err
);
399 ;________________________________________________________________________________
401 ; Routine: UpdateVCBFreeBlks
403 ; Function: Whenever the freeBlocks field in the ExtendedVCB is updated,
404 ; we must also recalculate the (UInt16) vcbFreeBks field in the
405 ; traditional HFS VCB structure.
408 ; vcb - Pointer to ExtendedVCB for the volume to free space on
409 ;________________________________________________________________________________
411 void UpdateVCBFreeBlks( ExtendedVCB
*vcb
)
414 if ( vcb
->vcbSigWord
== kHFSSigWord
&& vcb
->freeBlocks
> 0xFFFF )
415 DebugStr("\p UpdateVCBFreeBlks: freeBlocks overflow!");
421 ;________________________________________________________________________________
423 ; Routine: BlkDealloc
425 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
428 ; vcb - Pointer to ExtendedVCB for the volume to free space on
429 ; firstBlock - First allocation block to be freed
430 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
433 ; (result) - Result code
436 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
438 ; Modification history:
440 ; <06Oct85> PWD Changed to check for error after calls to ReadBM and NextWord
441 ; Now calls NextBit to read successive bits from the bitmap
442 ;________________________________________________________________________________
445 OSErr
BlockDeallocate (
446 ExtendedVCB
*vcb
, // Which volume to deallocate space on
447 UInt32 firstBlock
, // First block in range to deallocate
448 UInt32 numBlocks
) // Number of contiguous blocks to deallocate
452 #if HFSInstrumentation
453 InstTraceClassRef trace
;
454 InstEventTag eventTag
;
456 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:BlockDeallocate", 'hfs+', kInstEnableClassMask
, &trace
);
457 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
459 eventTag
= InstCreateEventTag();
460 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
464 // If no blocks to deallocate, then exit early
466 if (numBlocks
== 0) {
472 // Call internal routine to free the sequence of blocks
474 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
479 // Update the volume's free block count, and mark the VCB as dirty.
482 vcb
->freeBlocks
+= numBlocks
;
484 UpdateVCBFreeBlks( vcb
);
489 #if HFSInstrumentation
490 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
498 ;_______________________________________________________________________
500 ; Routine: UpdateFree
501 ; Arguments: vcb -- ExtendedVCB for volume
503 ; Called By: MountVol
504 ; Function: This routine is used as part of the MountVol consistency check
505 ; to figure out the number of free allocation blocks in the volume.
507 ; Modification History:
508 ; <08Sep85> LAK New today.
509 ; <06Oct85> PWD Added explicit check for errors after calls to ReadBM, NextWord
511 ;_______________________________________________________________________
514 OSErr
UpdateFreeCount (
515 ExtendedVCB
*vcb
) // Volume whose free block count should be updated
518 register UInt32 wordsLeft
; // Number of words left in this bitmap block
519 register UInt32 numBlocks
; // Number of blocks left to scan
520 register UInt32 freeCount
; // Running count of free blocks found so far
521 register UInt32 temp
;
522 UInt32 blockNum
; // Block number of first block in this bitmap block
523 UInt32
*buffer
= NULL
; // Pointer to bitmap block
524 register UInt32
*currentWord
; // Pointer to current word in bitmap block
526 #if HFSInstrumentation
527 InstTraceClassRef trace
;
528 InstEventTag eventTag
;
530 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:UpdateFreeCount", 'hfs+', kInstEnableClassMask
, &trace
);
531 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
533 eventTag
= InstCreateEventTag();
534 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
538 // Pre-read the first bitmap block
541 err
= ReadBitmapBlock(vcb
, 0, &buffer
);
542 if (err
!= noErr
) goto Exit
;
545 // Initialize buffer stuff
547 currentWord
= buffer
;
548 wordsLeft
= kWordsPerBlock
;
549 numBlocks
= vcb
->totalBlocks
;
554 // Scan whole words first
557 while (numBlocks
>= kBitsPerWord
) {
558 // See if it's time to move to the next bitmap block
559 if (wordsLeft
== 0) {
560 // Read in the next bitmap block
561 blockNum
+= kBitsPerBlock
; // generate a block number in the next bitmap block
563 #if EXPLICIT_BUFFER_RELEASES
564 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
565 if (err
!= noErr
) goto Exit
;
568 err
= ReadBitmapBlock(vcb
, blockNum
, &buffer
);
569 if (err
!= noErr
) goto Exit
;
571 // Readjust currentWord, wordsLeft
572 currentWord
= buffer
;
573 wordsLeft
= kWordsPerBlock
;
576 // We count free blocks by inverting the word in the bitmap and counting set bits.
577 temp
= ~(*currentWord
);
580 temp
&= temp
-1; // this clears least significant bit that is currently set
583 numBlocks
-= kBitsPerWord
;
584 ++currentWord
; // move to next word
585 --wordsLeft
; // one less word left in this block
589 // Check any remaining blocks.
592 if (numBlocks
!= 0) {
593 if (wordsLeft
== 0) {
594 // Read in the next bitmap block
595 blockNum
+= kBitsPerBlock
; // generate a block number in the next bitmap block
597 #if EXPLICIT_BUFFER_RELEASES
598 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
599 if (err
!= noErr
) goto Exit
;
602 err
= ReadBitmapBlock(vcb
, blockNum
, &buffer
);
603 if (err
!= noErr
) goto Exit
;
605 // Readjust currentWord, wordsLeft
606 currentWord
= buffer
;
607 wordsLeft
= kWordsPerBlock
;
610 // We count free blocks by inverting the word in the bitmap and counting set bits.
611 temp
= SWAP_BE32 (~(*currentWord
));
612 while (numBlocks
!= 0) {
613 if (temp
& kHighBitInWordMask
)
621 vcb
->freeBlocks
= freeCount
;
623 UpdateVCBFreeBlks( vcb
);
627 #if EXPLICIT_BUFFER_RELEASES
629 (void)RelBlock_glue((Ptr
)buffer
, rbDefault
); /* Ignore any additional errors */
633 #if HFSInstrumentation
634 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
643 ;_______________________________________________________________________
645 ; Routine: AllocateFreeSpace
646 ; Arguments: vcb -- ExtendedVCB for volume
648 ; Called By: HFSDiskInitComponent
649 ; Function: This routine is used as part of DiskInit to create an
650 ; embedded HFS+ volume.
652 ; Note: Assumes that the free space is contiguous (true for a freshly erased disk)
653 ;_______________________________________________________________________
656 OSErr
AllocateFreeSpace (
657 ExtendedVCB
*vcb
, // Volume whose free space is about to be expropriated
658 UInt32
*startBlock
, // return where free space starts
659 UInt32
*actualBlocks
) // return the number of blocks in free space
663 err
= BlockAllocateAny(vcb
, 0, vcb
->totalBlocks
, vcb
->freeBlocks
, startBlock
, actualBlocks
);
667 vcb
->freeBlocks
= 0; // sorry, no more blocks left!
676 ;_______________________________________________________________________
678 ; Routine: FileBytesToBlocks
680 ; Function: Divide numerator by denominator, rounding up the result if there
681 ; was a remainder. This is frequently used for computing the number
682 ; of whole and/or partial blocks used by some count of bytes.
683 ; Actuall divides a 64 bit by a 32 bit into a 32bit result
685 ; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
686 ;_______________________________________________________________________
688 UInt32
FileBytesToBlocks(
694 quotient
= (UInt32
)(numerator
/ denominator
);
695 if (quotient
* denominator
!= numerator
)
704 ;_______________________________________________________________________
706 ; Routine: ReadBitmapBlock
708 ; Function: Read in a bitmap block corresponding to a given allocation
709 ; block. Return a pointer to the bitmap block.
712 ; vcb -- Pointer to ExtendedVCB
713 ; block -- Allocation block whose bitmap block is desired
716 ; buffer -- Pointer to bitmap block corresonding to "block"
717 ;_______________________________________________________________________
719 static OSErr
ReadBitmapBlock(
726 #if HFSInstrumentation
727 InstTraceClassRef trace
;
728 InstEventTag eventTag
;
730 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:ReadBitmapBlock", 'hfs+', kInstEnableClassMask
, &trace
);
731 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
733 eventTag
= block
; // a cheap way to get the block number into the log
734 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
739 REQUIRE_FILE_LOCK(vcb
->extentsRefNum
, false); /* bitmap blocks are covered by the Extents B-tree lock */
741 if (vcb
->vcbSigWord
== kHFSSigWord
) {
743 // HFS: Turn block number into physical block offset within the
744 // bitmap, and then the physical block within the volume.
746 block
/= kBitsPerBlock
; // block offset within bitmap
747 block
+= vcb
->vcbVBMSt
; // block within whole volume
752 size_t availableBytes
;
755 // HFS+: Read from allocation file. We simply convert the block number into a byte
756 // offset within the allocation file and then determine which block that byte is in.
758 allocFile
= GetFileControlBlock(vcb
->allocationsRefNum
);
761 // Find out which physical block holds byte #offset in allocation file. Note that we
762 // map only 1 byte (the one we asked for).
764 err
= MapFileBlockC(vcb
, allocFile
, (size_t)1, (off_t
)(block
/kBitsPerByte
), &startBlock
, &availableBytes
);
770 #if EXPLICIT_BUFFER_RELEASES
773 gbReleaseMask
, // Release block immediately. We only work on one
774 // block at a time. Call MarkBlock later if dirty.
776 block
, // Physical block on volume
777 (Ptr
*) buffer
, // A place to return the buffer pointer
778 kNoFileReference
, // Not a file read
779 vcb
); // Volume to read from
782 #if HFSInstrumentation
783 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
792 _______________________________________________________________________
794 Routine: BlockAllocateContig
796 Function: Allocate a contiguous group of allocation blocks. The
797 allocation is all-or-nothing. The caller guarantees that
798 there are enough free blocks (though they may not be
799 contiguous, in which case this call will fail).
802 vcb Pointer to volume where space is to be allocated
803 startingBlock Preferred first block for allocation
804 minBlocks Minimum number of contiguous blocks to allocate
805 maxBlocks Maximum number of contiguous blocks to allocate
808 actualStartBlock First block of range allocated, or 0 if error
809 actualNumBlocks Number of blocks allocated, or 0 if error
810 _______________________________________________________________________
812 static OSErr
BlockAllocateContig(
814 UInt32 startingBlock
,
817 UInt32
*actualStartBlock
,
818 UInt32
*actualNumBlocks
)
823 // Find a contiguous group of blocks at least minBlocks long.
824 // Determine the number of contiguous blocks available (up
827 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->totalBlocks
, minBlocks
, maxBlocks
,
828 actualStartBlock
, actualNumBlocks
);
829 if (err
== dskFulErr
) {
830 //\80\80 Should constrain the endingBlock here, so we don't bother looking for ranges
831 //\80\80 that start after startingBlock, since we already checked those.
832 err
= BlockFindContiguous(vcb
, 0, vcb
->totalBlocks
, minBlocks
, maxBlocks
,
833 actualStartBlock
, actualNumBlocks
);
835 if (err
!= noErr
) goto Exit
;
838 // Now mark those blocks allocated.
840 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
844 *actualStartBlock
= 0;
845 *actualNumBlocks
= 0;
851 extern OSErr
LookupBufferMapping(caddr_t bufferAddress
, struct buf
**bpp
, int *mappingIndexPtr
);
854 _______________________________________________________________________
856 Routine: BlockAllocateAny
858 Function: Allocate one or more allocation blocks. If there are fewer
859 free blocks than requested, all free blocks will be
860 allocated. The caller guarantees that there is at least
864 vcb Pointer to volume where space is to be allocated
865 startingBlock Preferred first block for allocation
866 endingBlock Last block to check + 1
867 maxBlocks Maximum number of contiguous blocks to allocate
870 actualStartBlock First block of range allocated, or 0 if error
871 actualNumBlocks Number of blocks allocated, or 0 if error
872 _______________________________________________________________________
874 OSErr
BlockAllocateAny(
876 UInt32 startingBlock
,
877 register UInt32 endingBlock
,
879 UInt32
*actualStartBlock
,
880 UInt32
*actualNumBlocks
)
883 register UInt32 block
; // current block number
884 register UInt32 currentWord
; // Pointer to current word within bitmap block
885 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
886 register UInt32 wordsLeft
; // Number of words left in this bitmap block
887 UInt32
*buffer
= NULL
;
888 UInt32
*currCache
= NULL
;
891 struct buf
*bp
= NULL
;
895 // Since this routine doesn't wrap around
896 if (maxBlocks
> (endingBlock
- startingBlock
)) {
897 maxBlocks
= endingBlock
- startingBlock
;
900 DBG_TREE (("\nAllocating starting at %ld, maxblocks %ld\n", startingBlock
, maxBlocks
));
902 // Pre-read the first bitmap block
904 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
);
905 DBG_TREE (("\n1. Read bit map at %ld, buffer is 0x%x\n", startingBlock
, (int)currCache
));
906 if (err
!= noErr
) goto Exit
;
908 MarkBlock_glue((Ptr
) currCache
); // this block will be dirty
909 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
912 // Set up the current position within the block
915 UInt32 wordIndexInBlock
;
917 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
918 buffer
+= wordIndexInBlock
;
919 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
920 currentWord
= SWAP_BE32 (*buffer
);
921 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
925 // Find the first unallocated block
928 while (block
< endingBlock
) {
929 if ((currentWord
& bitMask
) == 0)
937 bitMask
= kHighBitInWordMask
;
940 if (--wordsLeft
== 0) {
942 #if EXPLICIT_BUFFER_RELEASES
943 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
944 err
= RelBlock_glue((Ptr
)currCache
, rbDefault
);
945 if (err
!= noErr
) goto Exit
;
946 buffer
= currCache
= NULL
;
948 err
= ReadBitmapBlock(vcb
, block
, &currCache
);
949 if (err
!= noErr
) goto Exit
;
951 DBG_TREE (("\n2. Read bit map at %ld, buffer is 0x%x\n", block
, (int)currCache
));
952 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
953 MarkBlock_glue((Ptr
) currCache
); // this block will be dirty
955 wordsLeft
= kWordsPerBlock
;
958 currentWord
= SWAP_BE32 (*buffer
);
962 // Did we get to the end of the bitmap before finding a free block?
963 // If so, then couldn't allocate anything.
964 if (block
== endingBlock
) {
969 // Return the first block in the allocated range
970 *actualStartBlock
= block
;
972 // If we could get the desired number of blocks before hitting endingBlock,
973 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
974 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
975 // comparison below yields identical results, but without overflow.
976 if (block
< (endingBlock
-maxBlocks
)) {
977 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
981 // Allocate all of the consecutive blocks
983 while ((currentWord
& bitMask
) == 0) {
984 // Allocate this block
985 currentWord
|= bitMask
;
987 // Move to the next block. If no more, then exit.
989 if (block
== endingBlock
)
995 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
998 bitMask
= kHighBitInWordMask
;
1001 if (--wordsLeft
== 0) {
1003 #if EXPLICIT_BUFFER_RELEASES
1004 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
1005 err
= RelBlock_glue((Ptr
)currCache
, rbDefault
);
1006 if (err
!= noErr
) goto Exit
;
1007 buffer
= currCache
= NULL
;
1009 err
= ReadBitmapBlock(vcb
, block
, &currCache
);
1010 if (err
!= noErr
) goto Exit
;
1012 DBG_TREE (("\n3. Read bit map at %ld, buffer is 0x%x\n", block
, (int)currCache
));
1013 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
1014 MarkBlock_glue((Ptr
) currCache
); // this block will be dirty
1016 wordsLeft
= kWordsPerBlock
;
1019 currentWord
= SWAP_BE32 (*buffer
);
1022 *buffer
= SWAP_BE32 (currentWord
); // update the last change
1026 *actualNumBlocks
= block
- *actualStartBlock
;
1029 *actualStartBlock
= 0;
1030 *actualNumBlocks
= 0;
1033 #if EXPLICIT_BUFFER_RELEASES
1035 DBG_ASSERT(! LookupBufferMapping((caddr_t
)currCache
, &bp
, &mappingEntry
));
1036 (void)RelBlock_glue((Ptr
)currCache
, rbDefault
); /* Ignore any additional errors */
1046 _______________________________________________________________________
1048 Routine: BlockMarkAllocated
1050 Function: Mark a contiguous group of blocks as allocated (set in the
1051 bitmap). It assumes those bits are currently marked
1052 deallocated (clear in the bitmap).
1055 vcb Pointer to volume where space is to be allocated
1056 startingBlock First block number to mark as allocated
1057 numBlocks Number of blocks to mark as allocated
1058 _______________________________________________________________________
1060 static OSErr
BlockMarkAllocated(
1062 UInt32 startingBlock
,
1063 register UInt32 numBlocks
)
1066 register UInt32
*currentWord
; // Pointer to current word within bitmap block
1067 register UInt32 wordsLeft
; // Number of words left in this bitmap block
1068 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
1069 UInt32 firstBit
; // Bit index within word of first bit to allocate
1070 UInt32 numBits
; // Number of bits in word to allocate
1071 UInt32
*buffer
= NULL
;
1073 #if HFSInstrumentation
1074 InstTraceClassRef trace
;
1075 InstEventTag eventTag
;
1077 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:BlockMarkAllocated", 'hfs+', kInstEnableClassMask
, &trace
);
1078 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
1080 eventTag
= InstCreateEventTag();
1081 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
1085 // Pre-read the bitmap block containing the first word of allocation
1088 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1089 if (err
!= noErr
) goto Exit
;
1090 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1093 // Initialize currentWord, and wordsLeft.
1096 UInt32 wordIndexInBlock
;
1098 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1099 currentWord
= buffer
+ wordIndexInBlock
;
1100 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
1104 // If the first block to allocate doesn't start on a word
1105 // boundary in the bitmap, then treat that first word
1109 firstBit
= startingBlock
% kBitsPerWord
;
1110 if (firstBit
!= 0) {
1111 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1112 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1113 if (numBits
> numBlocks
) {
1114 numBits
= numBlocks
; // entire allocation is inside this one word
1115 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1118 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1119 DebugStr("\pFATAL: blocks already allocated!");
1124 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1125 numBlocks
-= numBits
; // adjust number of blocks left to allocate
1127 ++currentWord
; // move to next word
1128 --wordsLeft
; // one less word left in this block
1132 // Allocate whole words (32 blocks) at a time.
1135 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
1136 while (numBlocks
>= kBitsPerWord
) {
1137 if (wordsLeft
== 0) {
1138 // Read in the next bitmap block
1139 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
1141 #if EXPLICIT_BUFFER_RELEASES
1142 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1143 if (err
!= noErr
) goto Exit
;
1146 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1147 if (err
!= noErr
) goto Exit
;
1148 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1150 // Readjust currentWord and wordsLeft
1151 currentWord
= buffer
;
1152 wordsLeft
= kWordsPerBlock
;
1155 if (*currentWord
!= 0) {
1156 DebugStr("\pFATAL: blocks already allocated!");
1161 *currentWord
= SWAP_BE32 (bitMask
);
1162 numBlocks
-= kBitsPerWord
;
1164 ++currentWord
; // move to next word
1165 --wordsLeft
; // one less word left in this block
1169 // Allocate any remaining blocks.
1172 if (numBlocks
!= 0) {
1173 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1174 if (wordsLeft
== 0) {
1175 // Read in the next bitmap block
1176 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
1178 #if EXPLICIT_BUFFER_RELEASES
1179 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1180 if (err
!= noErr
) goto Exit
;
1183 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1184 if (err
!= noErr
) goto Exit
;
1185 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1187 // Readjust currentWord and wordsLeft
1188 currentWord
= buffer
;
1189 wordsLeft
= kWordsPerBlock
;
1192 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1193 DebugStr("\pFATAL: blocks already allocated!");
1198 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1200 // No need to update currentWord or wordsLeft
1205 #if EXPLICIT_BUFFER_RELEASES
1207 (void)RelBlock_glue((Ptr
)buffer
, rbDefault
); /* Ignore any additional errors */
1211 #if HFSInstrumentation
1212 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
1221 _______________________________________________________________________
1223 Routine: BlockMarkFree
1225 Function: Mark a contiguous group of blocks as free (clear in the
1226 bitmap). It assumes those bits are currently marked
1227 allocated (set in the bitmap).
1230 vcb Pointer to volume where space is to be freed
1231 startingBlock First block number to mark as freed
1232 numBlocks Number of blocks to mark as freed
1233 _______________________________________________________________________
1235 static OSErr
BlockMarkFree(
1237 UInt32 startingBlock
,
1238 register UInt32 numBlocks
)
1241 register UInt32
*currentWord
; // Pointer to current word within bitmap block
1242 register UInt32 wordsLeft
; // Number of words left in this bitmap block
1243 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
1244 UInt32 firstBit
; // Bit index within word of first bit to allocate
1245 UInt32 numBits
; // Number of bits in word to allocate
1246 UInt32
*buffer
= NULL
;
1248 #if HFSInstrumentation
1249 InstTraceClassRef trace
;
1250 InstEventTag eventTag
;
1252 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:BlockMarkFree", 'hfs+', kInstEnableClassMask
, &trace
);
1253 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
1255 eventTag
= InstCreateEventTag();
1256 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
1260 // Pre-read the bitmap block containing the first word of allocation
1263 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1264 if (err
!= noErr
) goto Exit
;
1265 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1268 // Initialize currentWord, and wordsLeft.
1271 UInt32 wordIndexInBlock
;
1273 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1274 currentWord
= buffer
+ wordIndexInBlock
;
1275 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
1279 // If the first block to free doesn't start on a word
1280 // boundary in the bitmap, then treat that first word
1284 firstBit
= startingBlock
% kBitsPerWord
;
1285 if (firstBit
!= 0) {
1286 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1287 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1288 if (numBits
> numBlocks
) {
1289 numBits
= numBlocks
; // entire allocation is inside this one word
1290 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1293 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1294 DebugStr("\pFATAL: blocks not allocated!");
1299 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1300 numBlocks
-= numBits
; // adjust number of blocks left to free
1302 ++currentWord
; // move to next word
1303 --wordsLeft
; // one less word left in this block
1307 // Allocate whole words (32 blocks) at a time.
1310 while (numBlocks
>= kBitsPerWord
) {
1311 if (wordsLeft
== 0) {
1312 // Read in the next bitmap block
1313 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
1315 #if EXPLICIT_BUFFER_RELEASES
1316 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1317 if (err
!= noErr
) goto Exit
;
1320 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1321 if (err
!= noErr
) goto Exit
;
1322 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1324 // Readjust currentWord and wordsLeft
1325 currentWord
= buffer
;
1326 wordsLeft
= kWordsPerBlock
;
1330 if (*currentWord
!= SWAP_BE32 (kAllBitsSetInWord
)) {
1331 DebugStr("\pFATAL: blocks not allocated!");
1336 *currentWord
= 0; // clear the entire word
1337 numBlocks
-= kBitsPerWord
;
1339 ++currentWord
; // move to next word
1340 --wordsLeft
; // one less word left in this block
1344 // Allocate any remaining blocks.
1347 if (numBlocks
!= 0) {
1348 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1349 if (wordsLeft
== 0) {
1350 // Read in the next bitmap block
1351 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
1353 #if EXPLICIT_BUFFER_RELEASES
1354 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1355 if (err
!= noErr
) goto Exit
;
1358 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
);
1359 if (err
!= noErr
) goto Exit
;
1360 MarkBlock_glue((Ptr
) buffer
); // this block will be dirty
1362 // Readjust currentWord and wordsLeft
1363 currentWord
= buffer
;
1364 wordsLeft
= kWordsPerBlock
;
1367 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1368 DebugStr("\pFATAL: blocks not allocated!");
1373 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1375 // No need to update currentWord or wordsLeft
1380 #if EXPLICIT_BUFFER_RELEASES
1382 (void)RelBlock_glue((Ptr
)buffer
, rbDefault
); /* Ignore any additional errors */
1386 #if HFSInstrumentation
1387 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);
1395 _______________________________________________________________________
1397 Routine: BlockFindContiguous
1399 Function: Find a contiguous range of blocks that are free (bits
1400 clear in the bitmap). If a contiguous range of the
1401 minimum size can't be found, an error will be returned.
1403 \80\80 It would be nice if we could skip over whole words
1404 \80\80 with all bits set.
1406 \80\80 When we find a bit set, and are about to set freeBlocks
1407 \80\80 to 0, we should check to see whether there are still
1408 \80\80 minBlocks bits left in the bitmap.
1411 vcb Pointer to volume where space is to be allocated
1412 startingBlock Preferred first block of range
1413 endingBlock Last possible block in range + 1
1414 minBlocks Minimum number of blocks needed. Must be > 0.
1415 maxBlocks Maximum (ideal) number of blocks desired
1418 actualStartBlock First block of range found, or 0 if error
1419 actualNumBlocks Number of blocks found, or 0 if error
1420 _______________________________________________________________________
1423 _________________________________________________________________________________________
1424 (DSH) 5/8/97 Description of BlockFindContiguous() algorithm
1425 Finds a contiguous range of free blocks by searching back to front. This
1426 allows us to skip ranges of bits knowing that they are not candidates for
1427 a match because they are too small. The below ascii diagrams illustrate
1428 the algorithm in action.
1430 Representation of a piece of a volume bitmap file
1431 If BlockFindContiguous() is called with minBlocks == 10, maxBlocks == 20
1434 Fig. 1 initialization of variables, "<--" represents direction of travel
1436 startingBlock (passed in)
1438 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1440 stopBlock currentBlock freeBlocks == 0
1441 countedFreeBlocks == 0
1443 Fig. 2 dirty bit found
1445 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1447 stopBlock currentBlock freeBlocks == 3
1448 countedFreeBlocks == 0
1450 Fig. 3 reset variables to search for remainder of minBlocks
1452 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1453 |_________________| | |
1454 Unsearched stopBlock currentBlock freeBlocks == 0
1455 countedFreeBlocks == 3
1457 Fig. 4 minBlocks contiguous blocks found, *actualStartBlock is set
1459 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1460 |_________________| |
1461 Unsearched stopBlock freeBlocks == 7
1462 currentBlock countedFreeBlocks == 3
1464 Fig. 5 Now run it forwards trying to accumalate up to maxBlocks if possible
1466 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1467 |_________________| | -->
1468 Unsearched currentBlock
1469 *actualNumBlocks == 10
1471 Fig. 6 Dirty bit is found, return actual number of contiguous blocks found
1473 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1474 |_________________| |
1475 Unsearched currentBlock
1476 *actualNumBlocks == 16
1477 _________________________________________________________________________________________
1480 static OSErr
BlockFindContiguous(
1482 UInt32 startingBlock
,
1483 register UInt32 endingBlock
,
1486 UInt32
*actualStartBlock
,
1487 UInt32
*actualNumBlocks
)
1490 register UInt32 bitMask
; // mask of bit within word for currentBlock
1491 register UInt32 tempWord
; // bitmap word currently being examined
1492 register UInt32 freeBlocks
; // number of contiguous free blocks so far
1493 register UInt32 currentBlock
; // block number we're currently examining
1494 UInt32 wordsLeft
; // words remaining in bitmap block
1495 UInt32
*buffer
= NULL
;
1496 register UInt32
*currentWord
;
1498 UInt32 stopBlock
; // when all blocks until stopBlock are free, we found enough
1499 UInt32 countedFreeBlocks
; // how many contiguous free block behind stopBlock
1500 UInt32 currentSector
; // which allocations file sector
1502 #if HFSInstrumentation
1503 InstTraceClassRef trace
;
1504 InstEventTag eventTag
;
1506 err
= InstCreateTraceClass(kInstRootClassRef
, "HFS:VSM:BlockFindContiguous", 'hfs+', kInstEnableClassMask
, &trace
);
1507 if (err
!= noErr
) DebugStr("\pError from InstCreateTraceClass");
1509 eventTag
= InstCreateEventTag();
1510 InstLogTraceEvent( trace
, eventTag
, kInstStartEvent
);
1513 if ((endingBlock
- startingBlock
) < minBlocks
) {
1514 // The set of blocks we're checking is smaller than the minimum number
1515 // of blocks, so we couldn't possibly find a good range.
1520 // Search for min blocks from back to front.
1521 // If min blocks is found, advance the allocation pointer up to max blocks
1524 // Pre-read the bitmap block containing currentBlock
1526 stopBlock
= startingBlock
;
1527 currentBlock
= startingBlock
+ minBlocks
- 1; // (-1) to include startingBlock
1529 err
= ReadBitmapBlock( vcb
, currentBlock
, &buffer
);
1530 if ( err
!= noErr
) goto Exit
;
1533 // Init buffer, currentWord, wordsLeft, and bitMask
1536 UInt32 wordIndexInBlock
;
1538 wordIndexInBlock
= ( currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1539 currentWord
= buffer
+ wordIndexInBlock
;
1541 wordsLeft
= wordIndexInBlock
;
1542 tempWord
= SWAP_BE32 (*currentWord
);
1543 bitMask
= kHighBitInWordMask
>> ( currentBlock
& kBitsWithinWordMask
);
1544 currentSector
= currentBlock
/ kBitsPerBlock
;
1548 // Look for maxBlocks free blocks. If we find an allocated block,
1549 // see if we've found minBlocks.
1552 countedFreeBlocks
= 0;
1554 while ( currentBlock
>= stopBlock
)
1556 // Check current bit
1557 if ((tempWord
& bitMask
) == 0)
1561 else // Used bitmap block found
1563 if ( ( freeBlocks
+ countedFreeBlocks
) >= minBlocks
)
1565 break; // Found enough
1569 // We found a dirty bit, so we want to check if the next (minBlocks-freeBlocks) blocks
1570 // are free beyond what we have already checked. At Fig.2 setting up for Fig.3
1572 stopBlock
= currentBlock
+ 1 + freeBlocks
; // Advance stop condition
1573 currentBlock
+= minBlocks
;
1574 if ( currentBlock
>= endingBlock
) break;
1575 countedFreeBlocks
= freeBlocks
;
1576 freeBlocks
= 0; // Not enough; look for another range
1578 if ( currentSector
!= currentBlock
/ kBitsPerBlock
)
1580 #if EXPLICIT_BUFFER_RELEASES
1581 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1582 if (err
!= noErr
) goto Exit
;
1585 err
= ReadBitmapBlock( vcb
, currentBlock
, &buffer
);
1586 if (err
!= noErr
) goto Exit
;
1587 currentSector
= currentBlock
/ kBitsPerBlock
;
1590 wordsLeft
= ( currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1591 currentWord
= buffer
+ wordsLeft
;
1592 tempWord
= SWAP_BE32 (*currentWord
);
1593 bitMask
= kHighBitInWordMask
>> ( currentBlock
& kBitsWithinWordMask
);
1595 continue; // Back to the while loop
1602 if (bitMask
== 0) // On a word boundry, start masking words
1604 bitMask
= kLowBitInWordMask
;
1606 // Move to next word
1608 if ( wordsLeft
!= 0 )
1615 // Read in the next bitmap block
1616 #if EXPLICIT_BUFFER_RELEASES
1617 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1618 if (err
!= noErr
) goto Exit
;
1621 err
= ReadBitmapBlock( vcb
, currentBlock
, &buffer
);
1622 if (err
!= noErr
) goto Exit
;
1624 // Adjust currentWord, wordsLeft, currentSector
1625 currentSector
= currentBlock
/ kBitsPerBlock
;
1626 currentWord
= buffer
+ kWordsPerBlock
- 1; // Last word in buffer
1627 wordsLeft
= kWordsPerBlock
- 1;
1630 tempWord
= SWAP_BE32 (*currentWord
); // Grab the current word
1633 // If we found a whole word of free blocks, quickly skip over it.
1634 // NOTE: we could actually go beyond the end of the bitmap if the
1635 // number of allocation blocks on the volume is not a multiple of
1636 // 32. If this happens, we'll adjust currentBlock and freeBlocks
1639 if ( tempWord
== 0 )
1641 freeBlocks
+= kBitsPerWord
;
1642 currentBlock
-= kBitsPerWord
;
1643 if ( freeBlocks
+ countedFreeBlocks
>= minBlocks
)
1644 break; // Found enough
1650 if ( freeBlocks
+ countedFreeBlocks
< minBlocks
)
1652 *actualStartBlock
= 0;
1653 *actualNumBlocks
= 0;
1659 // When we get here, we know we've found minBlocks continuous space.
1660 // At Fig.4, setting up for Fig.5
1661 // From here we do a forward search accumalating additional free blocks.
1664 *actualNumBlocks
= minBlocks
;
1665 *actualStartBlock
= stopBlock
- countedFreeBlocks
; // ActualStartBlock is set to return to the user
1666 currentBlock
= *actualStartBlock
+ minBlocks
; // Right after found free space
1668 // Now lets see if we can run the actualNumBlocks number all the way up to maxBlocks
1669 if ( currentSector
!= currentBlock
/ kBitsPerBlock
)
1671 #if EXPLICIT_BUFFER_RELEASES
1672 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1673 if (err
!= noErr
) goto Exit
;
1676 err
= ReadBitmapBlock( vcb
, currentBlock
, &buffer
);
1679 err
= noErr
; // We already found the space
1683 currentSector
= currentBlock
/ kBitsPerBlock
;
1687 // Init buffer, currentWord, wordsLeft, and bitMask
1690 UInt32 wordIndexInBlock
;
1692 wordIndexInBlock
= (currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1693 currentWord
= buffer
+ wordIndexInBlock
;
1694 tempWord
= SWAP_BE32 (*currentWord
);
1695 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
1696 bitMask
= kHighBitInWordMask
>> (currentBlock
& kBitsWithinWordMask
);
1699 if ( *actualNumBlocks
< maxBlocks
)
1701 while ( currentBlock
< endingBlock
)
1704 if ( (tempWord
& bitMask
) == 0 )
1706 *actualNumBlocks
+= 1;
1708 if ( *actualNumBlocks
== maxBlocks
)
1721 bitMask
= kHighBitInWordMask
;
1724 if ( --wordsLeft
== 0)
1726 #if EXPLICIT_BUFFER_RELEASES
1727 err
= RelBlock_glue((Ptr
)buffer
, rbDefault
);
1728 if (err
!= noErr
) goto Exit
;
1731 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
);
1732 if (err
!= noErr
) break;
1734 // Adjust currentWord, wordsLeft
1735 currentWord
= buffer
;
1736 wordsLeft
= kWordsPerBlock
;
1738 tempWord
= SWAP_BE32 (*currentWord
); // grab the current word
1745 #if EXPLICIT_BUFFER_RELEASES
1747 (void)RelBlock_glue((Ptr
)buffer
, rbDefault
); /* Ignore any additional errors */
1751 #if HFSInstrumentation
1752 InstLogTraceEvent( trace
, eventTag
, kInstEndEvent
);