]>
git.saurik.com Git - hfs.git/blob - fsck_hfs/dfalib/SAllocate.c
2 * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 Contains: Routines for accessing and modifying the volume bitmap.
30 Copyright: © 1996-1999 by Apple Computer, Inc., all rights reserved.
37 Allocate space on a volume. Can allocate space contiguously.
38 If not contiguous, then allocation may be less than what was
39 asked for. Returns the starting block number, and number of
40 blocks. (Will only do a single extent???)
42 Deallocate a contiguous run of allocation blocks.
46 Find and allocate a contiguous range of blocks up to a given size. The
47 first range of contiguous free blocks found are allocated, even if there
48 are fewer blocks than requested (and even if a contiguous range of blocks
49 of the given size exists elsewhere).
52 Mark a contiguous range of blocks as free. The corresponding
53 bits in the volume bitmap will be cleared.
55 Mark a contiguous range of blocks as allocated. The cor-
56 responding bits in the volume bitmap are set. Also tests to see
57 if any of the blocks were previously unallocated.
59 Find a contiguous range of blocks of a given size. The caller
60 specifies where to begin the search (by block number). The
61 block number of the first block in the range is returned.
63 Find and allocate a contiguous range of blocks of a given size. If
64 a contiguous range of free blocks of the given size isn't found, then
65 the allocation fails (i.e. it is "all or nothing").
67 Given an allocation block number, read the bitmap block that
68 contains that allocation block into a caller-supplied buffer.
71 #include "Scavenger.h"
77 kBitsWithinWordMask
= kBitsPerWord
-1
80 #define kBytesPerBlock ( (vcb->vcbSignature == kHFSSigWord) ? kHFSBlockSize : vcb->vcbAllocationFile->fcbBlockSize )
81 #define kWordsPerBlock ( kBytesPerBlock / 4 )
82 #define kBitsPerBlock ( kBytesPerBlock * kBitsPerByte )
83 #define kBitsWithinBlockMask ( kBitsPerBlock - 1 )
84 #define kWordsWithinBlockMask ( kWordsPerBlock - 1 )
86 #define kLowBitInWordMask 0x00000001u
87 #define kHighBitInWordMask 0x80000000u
88 #define kAllBitsSetInWord 0xFFFFFFFFu
91 static OSErr
ReadBitmapBlock(
94 BlockDescriptor
*block
);
96 static OSErr
ReleaseBitmapBlock(
99 BlockDescriptor
*block
);
101 static OSErr
BlockAllocateContig(
103 UInt32 startingBlock
,
106 UInt32
*actualStartBlock
,
107 UInt32
*actualNumBlocks
);
109 static OSErr
BlockAllocateAny(
111 UInt32 startingBlock
,
112 register UInt32 endingBlock
,
114 UInt32
*actualStartBlock
,
115 UInt32
*actualNumBlocks
);
117 static OSErr
BlockFindContiguous(
119 UInt32 startingBlock
,
123 UInt32
*actualStartBlock
,
124 UInt32
*actualNumBlocks
);
126 static OSErr
BlockMarkAllocated(
128 UInt32 startingBlock
,
131 static OSErr
BlockMarkFree(
133 UInt32 startingBlock
,
137 ;________________________________________________________________________________
139 ; Routine: BlockAllocate
141 ; Function: Allocate space on a volume. If contiguous allocation is requested,
142 ; at least the requested number of bytes will be allocated or an
143 ; error will be returned. If contiguous allocation is not forced,
144 ; the space will be allocated at the first free fragment following
145 ; the requested starting allocation block. If there is not enough
146 ; room there, a block of less than the requested size will be
149 ; If the requested starting block is 0 (for new file allocations),
150 ; the volume's allocation block pointer will be used as a starting
153 ; The function uses on-disk volume bitmap for allocation
154 ; and updates it with newly allocated blocks. It also
155 ; updates the in-memory volume bitmap.
158 ; vcb - Pointer to SVCB for the volume to allocate space on
159 ; fcb - Pointer to FCB for the file for which storage is being allocated
160 ; startingBlock - Preferred starting allocation block, 0 = no preference
161 ; forceContiguous - Force contiguous flag - if bit 0 set, allocation is contiguous
162 ; or an error is returned
163 ; blocksRequested - Number of allocation blocks requested. If the allocation is
164 ; non-contiguous, less than this may actually be allocated
165 ; blocksMaximum - The maximum number of allocation blocks to allocate. If there
166 ; is additional free space after blocksRequested, then up to
167 ; blocksMaximum blocks should really be allocated. (Used by
168 ; ExtendFileC to round up allocations to a multiple of the
169 ; file's clump size.)
172 ; (result) - Error code, zero for successful allocation
173 ; *startBlock - Actual starting allocation block
174 ; *actualBlocks - Actual number of allocation blocks allocated
177 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
179 ; Modification history:
180 ;________________________________________________________________________________
183 OSErr
BlockAllocate (
184 SVCB
*vcb
, /* which volume to allocate space on */
185 UInt32 startingBlock
, /* preferred starting block, or 0 for no preference */
186 UInt32 blocksRequested
, /* desired number of BYTES to allocate */
187 UInt32 blocksMaximum
, /* maximum number of bytes to allocate */
188 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
189 /* bytesRequested bytes to actually be allocated */
190 UInt32
*actualStartBlock
, /* actual first block of allocation */
191 UInt32
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
192 /* was zero, then this may represent fewer than bytesRequested */
196 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
199 // Initialize outputs in case we get an error
201 *actualStartBlock
= 0;
202 *actualNumBlocks
= 0;
205 // If the disk is already full, don't bother.
207 if (vcb
->vcbFreeBlocks
== 0) {
211 if (forceContiguous
&& vcb
->vcbFreeBlocks
< blocksRequested
) {
217 // If caller didn't specify a starting block number, then use the volume's
218 // next block to allocate from.
220 if (startingBlock
== 0) {
221 startingBlock
= vcb
->vcbNextAllocation
;
222 updateAllocPtr
= true;
226 // If the request must be contiguous, then find a sequence of free blocks
227 // that is long enough. Otherwise, find the first free block.
230 err
= BlockAllocateContig(vcb
, startingBlock
, blocksRequested
, blocksMaximum
, actualStartBlock
, actualNumBlocks
);
232 // We'll try to allocate contiguous space first. If that fails, we'll fall back to finding whatever tiny
233 // extents we can find. It would be nice if we kept track of the largest N free extents so that falling
234 // back grabbed a small number of large extents.
235 err
= BlockAllocateContig(vcb
, startingBlock
, blocksRequested
, blocksMaximum
, actualStartBlock
, actualNumBlocks
);
236 if (err
== dskFulErr
)
237 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->vcbTotalBlocks
, blocksMaximum
, actualStartBlock
, actualNumBlocks
);
238 if (err
== dskFulErr
)
239 err
= BlockAllocateAny(vcb
, 0, startingBlock
, blocksMaximum
, actualStartBlock
, actualNumBlocks
);
244 // If we used the volume's roving allocation pointer, then we need to update it.
245 // Adding in the length of the current allocation might reduce the next allocate
246 // call by avoiding a re-scan of the already allocated space. However, the clump
247 // just allocated can quite conceivably end up being truncated or released when
248 // the file is closed or its EOF changed. Leaving the allocation pointer at the
249 // start of the last allocation will avoid unnecessary fragmentation in this case.
252 vcb
->vcbNextAllocation
= *actualStartBlock
;
255 // Update the number of free blocks on the volume
257 vcb
->vcbFreeBlocks
-= *actualNumBlocks
;
269 ;________________________________________________________________________________
271 ; Routine: BlockDeallocate
273 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
274 ; The on-disk volume bitmap is read and updated; the in-memory volume bitmap
278 ; vcb - Pointer to SVCB for the volume to free space on
279 ; firstBlock - First allocation block to be freed
280 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
283 ; (result) - Result code
286 ; The on-disk volume bitmap is read and updated; the in-memory volume bitmap
289 ; Modification history:
291 ; <06Oct85> PWD Changed to check for error after calls to ReadBM and NextWord
292 ; Now calls NextBit to read successive bits from the bitmap
293 ;________________________________________________________________________________
296 OSErr
BlockDeallocate (
297 SVCB
*vcb
, // Which volume to deallocate space on
298 UInt32 firstBlock
, // First block in range to deallocate
299 UInt32 numBlocks
) // Number of contiguous blocks to deallocate
305 // If no blocks to deallocate, then exit early
307 if (numBlocks
== 0) {
313 // Call internal routine to free the sequence of blocks
315 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
320 // Update the volume's free block count, and mark the VCB as dirty.
322 vcb
->vcbFreeBlocks
+= numBlocks
;
332 ;_______________________________________________________________________
334 ; Routine: DivideAndRoundUp
336 ; Function: Divide numerator by denominator, rounding up the result if there
337 ; was a remainder. This is frequently used for computing the number
338 ; of whole and/or partial blocks used by some count of bytes.
339 ;_______________________________________________________________________
341 UInt32
DivideAndRoundUp(
347 quotient
= numerator
/ denominator
;
348 if (quotient
* denominator
!= numerator
)
357 ;_______________________________________________________________________
359 ; Routine: ReadBitmapBlock
361 ; Function: Read in a bitmap block corresponding to a given allocation
362 ; block. Return a pointer to the bitmap block.
365 ; vcb -- Pointer to SVCB
366 ; block -- Allocation block whose bitmap block is desired
369 ; buffer -- Pointer to bitmap block corresonding to "block"
370 ;_______________________________________________________________________
372 static OSErr
ReadBitmapBlock(
375 BlockDescriptor
*block
)
380 if (vcb
->vcbSignature
== kHFSSigWord
) {
382 // HFS: Turn block number into physical block offset within the
383 // bitmap, and then the physical block within the volume.
385 blockNum
= bit
/ kBitsPerBlock
; /* block offset within bitmap */
386 blockNum
+= vcb
->vcbVBMSt
; /* block within whole volume */
388 err
= GetVolumeBlock(vcb
, blockNum
, kGetBlock
| kSkipEndianSwap
, block
);
391 // HFS+: "bit" is the allocation block number that we are looking for
392 // in the allocation bit map. GetFileBlock wants a file block number
393 // so we calculate how many bits (kBitsPerBlock) fit in a file
394 // block then convert that to a file block number (bit / kBitsPerBlock)
396 err
= GetFileBlock( vcb
->vcbAllocationFile
, (bit
/ kBitsPerBlock
), kGetBlock
, block
);
404 static OSErr
ReleaseBitmapBlock(
407 BlockDescriptor
*block
)
411 if (vcb
->vcbSignature
== kHFSSigWord
)
412 err
= ReleaseVolumeBlock (vcb
, block
, options
| kSkipEndianSwap
);
414 err
= ReleaseFileBlock (vcb
->vcbAllocationFile
, block
, options
);
422 _______________________________________________________________________
424 Routine: BlockAllocateContig
426 Function: Allocate a contiguous group of allocation blocks. The
427 allocation is all-or-nothing. The caller guarantees that
428 there are enough free blocks (though they may not be
429 contiguous, in which case this call will fail).
431 The function uses on-disk volume bitmap for allocation
432 and updates it with newly allocated blocks. It also
433 updates the in-memory volume bitmap.
436 vcb Pointer to volume where space is to be allocated
437 startingBlock Preferred first block for allocation
438 minBlocks Minimum number of contiguous blocks to allocate
439 maxBlocks Maximum number of contiguous blocks to allocate
442 actualStartBlock First block of range allocated, or 0 if error
443 actualNumBlocks Number of blocks allocated, or 0 if error
444 _______________________________________________________________________
446 static OSErr
BlockAllocateContig(
448 UInt32 startingBlock
,
451 UInt32
*actualStartBlock
,
452 UInt32
*actualNumBlocks
)
457 // Find a contiguous group of blocks at least minBlocks long.
458 // Determine the number of contiguous blocks available (up
461 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->vcbTotalBlocks
, minBlocks
, maxBlocks
,
462 actualStartBlock
, actualNumBlocks
);
463 if (err
== dskFulErr
) {
464 //¥¥ Should constrain the endingBlock here, so we don't bother looking for ranges
465 //¥¥ that start after startingBlock, since we already checked those.
466 err
= BlockFindContiguous(vcb
, 0, vcb
->vcbTotalBlocks
, minBlocks
, maxBlocks
,
467 actualStartBlock
, actualNumBlocks
);
469 if (err
!= noErr
) goto Exit
;
472 // Now mark those blocks allocated.
474 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
478 *actualStartBlock
= 0;
479 *actualNumBlocks
= 0;
488 _______________________________________________________________________
490 Routine: BlockAllocateAny
492 Function: Allocate one or more allocation blocks. If there are fewer
493 free blocks than requested, all free blocks will be
494 allocated. The caller guarantees that there is at least
497 The function uses on-disk volume bitmap for allocation
498 and updates it with newly allocated blocks. It also
499 updates the in-memory volume bitmap.
502 vcb Pointer to volume where space is to be allocated
503 startingBlock Preferred first block for allocation
504 endingBlock Last block to check + 1
505 maxBlocks Maximum number of contiguous blocks to allocate
508 actualStartBlock First block of range allocated, or 0 if error
509 actualNumBlocks Number of blocks allocated, or 0 if error
510 _______________________________________________________________________
512 static OSErr
BlockAllocateAny(
514 UInt32 startingBlock
,
515 register UInt32 endingBlock
,
517 UInt32
*actualStartBlock
,
518 UInt32
*actualNumBlocks
)
521 register UInt32 block
= 0; // current block number
522 register UInt32 currentWord
; // Pointer to current word within bitmap block
523 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
524 register UInt32 wordsLeft
; // Number of words left in this bitmap block
526 BlockDescriptor bd
= {0};
527 OptionBits relOpt
= kReleaseBlock
;
529 // Since this routine doesn't wrap around
530 if (maxBlocks
> (endingBlock
- startingBlock
)) {
531 maxBlocks
= endingBlock
- startingBlock
;
535 // Pre-read the first bitmap block
538 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
539 if (err
!= noErr
) goto Exit
;
540 relOpt
= kMarkBlockDirty
;
541 buffer
= (UInt32
*) bd
.buffer
;
544 // Set up the current position within the block
547 UInt32 wordIndexInBlock
;
549 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
550 buffer
+= wordIndexInBlock
;
551 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
552 currentWord
= SWAP_BE32(*buffer
);
553 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
557 // Find the first unallocated block
559 block
= startingBlock
;
560 while (block
< endingBlock
) {
561 if ((currentWord
& bitMask
) == 0)
569 bitMask
= kHighBitInWordMask
;
572 if (--wordsLeft
== 0) {
574 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
576 if (err
!= noErr
) goto Exit
;
578 err
= ReadBitmapBlock(vcb
, block
, &bd
);
579 if (err
!= noErr
) goto Exit
;
580 buffer
= (UInt32
*) bd
.buffer
;
581 relOpt
= kMarkBlockDirty
;
583 wordsLeft
= kWordsPerBlock
;
585 currentWord
= SWAP_BE32(*buffer
);
589 // Did we get to the end of the bitmap before finding a free block?
590 // If so, then couldn't allocate anything.
591 if (block
== endingBlock
) {
596 // Return the first block in the allocated range
597 *actualStartBlock
= block
;
599 // If we could get the desired number of blocks before hitting endingBlock,
600 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
601 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
602 // comparison below yields identical results, but without overflow.
603 if (block
< (endingBlock
-maxBlocks
)) {
604 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
608 // Allocate all of the consecutive blocks
610 while ((currentWord
& bitMask
) == 0) {
611 // Allocate this block
612 currentWord
|= bitMask
;
614 // Move to the next block. If no more, then exit.
616 if (block
== endingBlock
)
622 *buffer
= SWAP_BE32(currentWord
); // update value in bitmap
625 bitMask
= kHighBitInWordMask
;
628 if (--wordsLeft
== 0) {
630 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
631 if (err
!= noErr
) goto Exit
;
634 err
= ReadBitmapBlock(vcb
, block
, &bd
);
635 if (err
!= noErr
) goto Exit
;
636 buffer
= (UInt32
*) bd
.buffer
;
637 relOpt
= kMarkBlockDirty
;
639 wordsLeft
= kWordsPerBlock
;
641 currentWord
= SWAP_BE32(*buffer
);
644 *buffer
= SWAP_BE32(currentWord
); // update the last change
648 *actualNumBlocks
= block
- *actualStartBlock
;
650 /* Update the in-memory copy of bitmap */
651 (void) CaptureBitmapBits (*actualStartBlock
, *actualNumBlocks
);
654 *actualStartBlock
= 0;
655 *actualNumBlocks
= 0;
658 if (bd
.buffer
!= NULL
)
659 (void) ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
667 _______________________________________________________________________
669 Routine: BlockMarkAllocated
671 Function: Mark a contiguous group of blocks as allocated (set in the
672 bitmap). The function sets the bit independent of the
673 previous state (set/clear) of the bit.
675 The function uses on-disk volume bitmap for allocation
676 and updates it with newly allocated blocks. It also
677 updates the in-memory volume bitmap.
680 vcb Pointer to volume where space is to be allocated
681 startingBlock First block number to mark as allocated
682 numBlocks Number of blocks to mark as allocated
683 _______________________________________________________________________
685 static OSErr
BlockMarkAllocated(
687 UInt32 startingBlock
,
688 register UInt32 numBlocks
)
691 register UInt32
*currentWord
; // Pointer to current word within bitmap block
692 register UInt32 wordsLeft
; // Number of words left in this bitmap block
693 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
694 UInt32 firstBit
; // Bit index within word of first bit to allocate
695 UInt32 numBits
; // Number of bits in word to allocate
697 BlockDescriptor bd
= {0};
698 OptionBits relOpt
= kReleaseBlock
;
700 UInt32 saveNumBlocks
= numBlocks
;
701 UInt32 saveStartingBlock
= startingBlock
;
704 // Pre-read the bitmap block containing the first word of allocation
707 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
708 if (err
!= noErr
) goto Exit
;
709 buffer
= (UInt32
*) bd
.buffer
;
710 relOpt
= kMarkBlockDirty
;
713 // Initialize currentWord, and wordsLeft.
716 UInt32 wordIndexInBlock
;
718 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
719 currentWord
= buffer
+ wordIndexInBlock
;
720 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
724 // If the first block to allocate doesn't start on a word
725 // boundary in the bitmap, then treat that first word
729 firstBit
= startingBlock
% kBitsPerWord
;
731 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
732 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
733 if (numBits
> numBlocks
) {
734 numBits
= numBlocks
; // entire allocation is inside this one word
735 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
738 if ((*currentWord
& SWAP_BE32(bitMask
)) != 0) {
739 DebugStr("\pFATAL: blocks already allocated!");
744 *currentWord
|= SWAP_BE32(bitMask
); // set the bits in the bitmap
745 numBlocks
-= numBits
; // adjust number of blocks left to allocate
747 ++currentWord
; // move to next word
748 --wordsLeft
; // one less word left in this block
752 // Allocate whole words (32 blocks) at a time.
755 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
756 while (numBlocks
>= kBitsPerWord
) {
757 if (wordsLeft
== 0) {
758 // Read in the next bitmap block
759 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
761 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
762 if (err
!= noErr
) goto Exit
;
765 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
766 if (err
!= noErr
) goto Exit
;
767 buffer
= (UInt32
*) bd
.buffer
;
768 relOpt
= kMarkBlockDirty
;
770 // Readjust currentWord and wordsLeft
771 currentWord
= buffer
;
772 wordsLeft
= kWordsPerBlock
;
775 if (*currentWord
!= 0) {
776 DebugStr("\pFATAL: blocks already allocated!");
781 *currentWord
= SWAP_BE32(bitMask
);
782 numBlocks
-= kBitsPerWord
;
784 ++currentWord
; // move to next word
785 --wordsLeft
; // one less word left in this block
789 // Allocate any remaining blocks.
792 if (numBlocks
!= 0) {
793 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
794 if (wordsLeft
== 0) {
795 // Read in the next bitmap block
796 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
798 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
799 if (err
!= noErr
) goto Exit
;
802 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
803 if (err
!= noErr
) goto Exit
;
804 buffer
= (UInt32
*) bd
.buffer
;
805 relOpt
= kMarkBlockDirty
;
807 // Readjust currentWord and wordsLeft
808 currentWord
= buffer
;
809 wordsLeft
= kWordsPerBlock
;
812 if ((*currentWord
& SWAP_BE32(bitMask
)) != 0) {
813 DebugStr("\pFATAL: blocks already allocated!");
818 *currentWord
|= SWAP_BE32(bitMask
); // set the bits in the bitmap
820 // No need to update currentWord or wordsLeft
823 /* Update the in-memory copy of the volume bitmap */
824 (void) CaptureBitmapBits(saveStartingBlock
, saveNumBlocks
);
827 if (bd
.buffer
!= NULL
)
828 (void) ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
836 _______________________________________________________________________
838 Routine: BlockMarkFree
840 Function: Mark a contiguous group of blocks as free (clear in the
841 bitmap). The function clears the bit independent of the
842 previous state (set/clear) of the bit.
844 This function uses the on-disk bitmap and also updates
845 the in-memory bitmap with the deallocated blocks
848 vcb Pointer to volume where space is to be freed
849 startingBlock First block number to mark as freed
850 numBlocks Number of blocks to mark as freed
851 _______________________________________________________________________
853 static OSErr
BlockMarkFree(
855 UInt32 startingBlock
,
856 register UInt32 numBlocks
)
859 register UInt32
*currentWord
; // Pointer to current word within bitmap block
860 register UInt32 wordsLeft
; // Number of words left in this bitmap block
861 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
862 UInt32 firstBit
; // Bit index within word of first bit to allocate
863 UInt32 numBits
; // Number of bits in word to allocate
865 BlockDescriptor bd
= {0};
866 OptionBits relOpt
= kReleaseBlock
;
868 UInt32 saveNumBlocks
= numBlocks
;
869 UInt32 saveStartingBlock
= startingBlock
;
872 // Pre-read the bitmap block containing the first word of allocation
875 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
876 if (err
!= noErr
) goto Exit
;
877 buffer
= (UInt32
*) bd
.buffer
;
878 relOpt
= kMarkBlockDirty
;
881 // Initialize currentWord, and wordsLeft.
884 UInt32 wordIndexInBlock
;
886 wordIndexInBlock
= (startingBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
887 currentWord
= buffer
+ wordIndexInBlock
;
888 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
892 // If the first block to free doesn't start on a word
893 // boundary in the bitmap, then treat that first word
897 firstBit
= startingBlock
% kBitsPerWord
;
899 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
900 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
901 if (numBits
> numBlocks
) {
902 numBits
= numBlocks
; // entire allocation is inside this one word
903 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
906 if ((*currentWord
& SWAP_BE32(bitMask
)) != SWAP_BE32(bitMask
)) {
907 DebugStr("\pFATAL: blocks not allocated!");
912 *currentWord
&= SWAP_BE32(~bitMask
); // clear the bits in the bitmap
913 numBlocks
-= numBits
; // adjust number of blocks left to free
915 ++currentWord
; // move to next word
916 --wordsLeft
; // one less word left in this block
920 // Allocate whole words (32 blocks) at a time.
923 while (numBlocks
>= kBitsPerWord
) {
924 if (wordsLeft
== 0) {
925 // Read in the next bitmap block
926 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
928 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
929 if (err
!= noErr
) goto Exit
;
932 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
933 if (err
!= noErr
) goto Exit
;
934 buffer
= (UInt32
*) bd
.buffer
;
935 relOpt
= kMarkBlockDirty
;
937 // Readjust currentWord and wordsLeft
938 currentWord
= buffer
;
939 wordsLeft
= kWordsPerBlock
;
942 if (*currentWord
!= kAllBitsSetInWord
) {
943 DebugStr("\pFATAL: blocks not allocated!");
948 *currentWord
= 0; // clear the entire word
949 numBlocks
-= kBitsPerWord
;
951 ++currentWord
; // move to next word
952 --wordsLeft
; // one less word left in this block
956 // Allocate any remaining blocks.
959 if (numBlocks
!= 0) {
960 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
961 if (wordsLeft
== 0) {
962 // Read in the next bitmap block
963 startingBlock
+= kBitsPerBlock
; // generate a block number in the next bitmap block
965 err
= ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
966 if (err
!= noErr
) goto Exit
;
969 err
= ReadBitmapBlock(vcb
, startingBlock
, &bd
);
970 if (err
!= noErr
) goto Exit
;
971 buffer
= (UInt32
*) bd
.buffer
;
972 relOpt
= kMarkBlockDirty
;
974 // Readjust currentWord and wordsLeft
975 currentWord
= buffer
;
976 wordsLeft
= kWordsPerBlock
;
979 if ((*currentWord
& SWAP_BE32(bitMask
)) != SWAP_BE32(bitMask
)) {
980 DebugStr("\pFATAL: blocks not allocated!");
985 *currentWord
&= SWAP_BE32(~bitMask
); // clear the bits in the bitmap
987 // No need to update currentWord or wordsLeft
990 /* Update the in-memory copy of the volume bitmap */
991 (void) ReleaseBitmapBits(saveStartingBlock
, saveNumBlocks
);
994 if (bd
.buffer
!= NULL
)
995 (void) ReleaseBitmapBlock(vcb
, relOpt
, &bd
);
1002 _______________________________________________________________________
1004 Routine: BlockFindContiguous
1006 Function: Find a contiguous range of blocks that are free (bits
1007 clear in the bitmap). If a contiguous range of the
1008 minimum size can't be found, an error will be returned.
1010 ¥¥ It would be nice if we could skip over whole words
1011 ¥¥ with all bits set.
1013 ¥¥ When we find a bit set, and are about to set freeBlocks
1014 ¥¥ to 0, we should check to see whether there are still
1015 ¥¥ minBlocks bits left in the bitmap.
1018 vcb Pointer to volume where space is to be allocated
1019 startingBlock Preferred first block of range
1020 endingBlock Last possible block in range + 1
1021 minBlocks Minimum number of blocks needed. Must be > 0.
1022 maxBlocks Maximum (ideal) number of blocks desired
1025 actualStartBlock First block of range found, or 0 if error
1026 actualNumBlocks Number of blocks found, or 0 if error
1027 _______________________________________________________________________
1030 _________________________________________________________________________________________
1031 (DSH) 5/8/97 Description of BlockFindContiguous() algorithm
1032 Finds a contiguous range of free blocks by searching back to front. This
1033 allows us to skip ranges of bits knowing that they are not candidates for
1034 a match because they are too small. The below ascii diagrams illustrate
1035 the algorithm in action.
1037 Representation of a piece of a volume bitmap file
1038 If BlockFindContiguous() is called with minBlocks == 10, maxBlocks == 20
1041 Fig. 1 initialization of variables, "<--" represents direction of travel
1043 startingBlock (passed in)
1045 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1047 stopBlock currentBlock freeBlocks == 0
1048 countedFreeBlocks == 0
1050 Fig. 2 dirty bit found
1052 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1054 stopBlock currentBlock freeBlocks == 3
1055 countedFreeBlocks == 0
1057 Fig. 3 reset variables to search for remainder of minBlocks
1059 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1060 |_________________| | |
1061 Unsearched stopBlock currentBlock freeBlocks == 0
1062 countedFreeBlocks == 3
1064 Fig. 4 minBlocks contiguous blocks found, *actualStartBlock is set
1066 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1067 |_________________| |
1068 Unsearched stopBlock freeBlocks == 7
1069 currentBlock countedFreeBlocks == 3
1071 Fig. 5 Now run it forwards trying to accumalate up to maxBlocks if possible
1073 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1074 |_________________| | -->
1075 Unsearched currentBlock
1076 *actualNumBlocks == 10
1078 Fig. 6 Dirty bit is found, return actual number of contiguous blocks found
1080 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1081 |_________________| |
1082 Unsearched currentBlock
1083 *actualNumBlocks == 16
1084 _________________________________________________________________________________________
1086 static OSErr
BlockFindContiguous(
1088 UInt32 startingBlock
,
1089 register UInt32 endingBlock
,
1092 UInt32
*actualStartBlock
,
1093 UInt32
*actualNumBlocks
)
1096 register UInt32 bitMask
; // mask of bit within word for currentBlock
1097 register UInt32 tempWord
; // bitmap word currently being examined
1098 register UInt32 freeBlocks
; // number of contiguous free blocks so far
1099 register UInt32 currentBlock
; // block number we're currently examining
1100 UInt32 wordsLeft
; // words remaining in bitmap block
1101 UInt32
*buffer
= NULL
;
1102 register UInt32
*currentWord
;
1104 UInt32 stopBlock
; // when all blocks until stopBlock are free, we found enough
1105 UInt32 countedFreeBlocks
; // how many contiguous free block behind stopBlock
1106 UInt32 currentSector
; // which allocations file sector
1107 BlockDescriptor bd
= {0};
1109 if ((endingBlock
- startingBlock
) < minBlocks
) {
1110 // The set of blocks we're checking is smaller than the minimum number
1111 // of blocks, so we couldn't possibly find a good range.
1116 // Search for min blocks from back to front.
1117 // If min blocks is found, advance the allocation pointer up to max blocks
1120 // Pre-read the bitmap block containing currentBlock
1122 stopBlock
= startingBlock
;
1123 currentBlock
= startingBlock
+ minBlocks
- 1; // (-1) to include startingBlock
1125 err
= ReadBitmapBlock(vcb
, currentBlock
, &bd
);
1126 if ( err
!= noErr
) goto Exit
;
1127 buffer
= (UInt32
*) bd
.buffer
;
1129 // Init buffer, currentWord, wordsLeft, and bitMask
1132 UInt32 wordIndexInBlock
;
1134 wordIndexInBlock
= ( currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1135 currentWord
= buffer
+ wordIndexInBlock
;
1137 wordsLeft
= wordIndexInBlock
;
1138 tempWord
= SWAP_BE32(*currentWord
);
1139 bitMask
= kHighBitInWordMask
>> ( currentBlock
& kBitsWithinWordMask
);
1140 currentSector
= currentBlock
/ kBitsPerBlock
;
1144 // Look for maxBlocks free blocks. If we find an allocated block,
1145 // see if we've found minBlocks.
1148 countedFreeBlocks
= 0;
1150 while ( currentBlock
>= stopBlock
)
1152 // Check current bit
1153 if ((tempWord
& bitMask
) == 0)
1157 else // Used bitmap block found
1159 if ( ( freeBlocks
+ countedFreeBlocks
) >= minBlocks
)
1161 break; // Found enough
1165 // We found a dirty bit, so we want to check if the next (minBlocks-freeBlocks) blocks
1166 // are free beyond what we have already checked. At Fig.2 setting up for Fig.3
1168 stopBlock
= currentBlock
+ 1 + freeBlocks
; // Advance stop condition
1169 currentBlock
+= minBlocks
;
1170 if ( currentBlock
>= endingBlock
) break;
1171 countedFreeBlocks
= freeBlocks
;
1172 freeBlocks
= 0; // Not enough; look for another range
1174 if ( currentSector
!= currentBlock
/ kBitsPerBlock
)
1176 err
= ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1177 if (err
!= noErr
) goto Exit
;
1180 err
= ReadBitmapBlock( vcb
, currentBlock
, &bd
);
1181 if (err
!= noErr
) goto Exit
;
1182 buffer
= (UInt32
*) bd
.buffer
;
1183 currentSector
= currentBlock
/ kBitsPerBlock
;
1186 wordsLeft
= ( currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1187 currentWord
= buffer
+ wordsLeft
;
1188 tempWord
= SWAP_BE32(*currentWord
);
1189 bitMask
= kHighBitInWordMask
>> ( currentBlock
& kBitsWithinWordMask
);
1191 continue; // Back to the while loop
1198 if (bitMask
== 0) // On a word boundry, start masking words
1200 bitMask
= kLowBitInWordMask
;
1202 // Move to next word
1204 if ( wordsLeft
!= 0 )
1211 // Read in the next bitmap block
1212 err
= ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1213 if (err
!= noErr
) goto Exit
;
1216 err
= ReadBitmapBlock( vcb
, currentBlock
, &bd
);
1217 if (err
!= noErr
) goto Exit
;
1218 buffer
= (UInt32
*) bd
.buffer
;
1219 // Adjust currentWord, wordsLeft, currentSector
1220 currentSector
= currentBlock
/ kBitsPerBlock
;
1221 currentWord
= buffer
+ kWordsPerBlock
- 1; // Last word in buffer
1222 wordsLeft
= kWordsPerBlock
- 1;
1225 tempWord
= SWAP_BE32(*currentWord
); // Grab the current word
1228 // If we found a whole word of free blocks, quickly skip over it.
1229 // NOTE: we could actually go beyond the end of the bitmap if the
1230 // number of allocation blocks on the volume is not a multiple of
1231 // 32. If this happens, we'll adjust currentBlock and freeBlocks
1234 if ( tempWord
== 0 )
1236 freeBlocks
+= kBitsPerWord
;
1237 currentBlock
-= kBitsPerWord
;
1238 if ( freeBlocks
+ countedFreeBlocks
>= minBlocks
)
1239 break; // Found enough
1245 if ( freeBlocks
+ countedFreeBlocks
< minBlocks
)
1247 *actualStartBlock
= 0;
1248 *actualNumBlocks
= 0;
1254 // When we get here, we know we've found minBlocks continuous space.
1255 // At Fig.4, setting up for Fig.5
1256 // From here we do a forward search accumalating additional free blocks.
1259 *actualNumBlocks
= minBlocks
;
1260 *actualStartBlock
= stopBlock
- countedFreeBlocks
; // ActualStartBlock is set to return to the user
1261 currentBlock
= *actualStartBlock
+ minBlocks
; // Right after found free space
1263 // Now lets see if we can run the actualNumBlocks number all the way up to maxBlocks
1264 if ( currentSector
!= currentBlock
/ kBitsPerBlock
)
1266 err
= ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1267 if (err
!= noErr
) goto Exit
;
1270 err
= ReadBitmapBlock( vcb
, currentBlock
, &bd
);
1273 err
= noErr
; // We already found the space
1276 buffer
= (UInt32
*) bd
.buffer
;
1277 currentSector
= currentBlock
/ kBitsPerBlock
;
1281 // Init buffer, currentWord, wordsLeft, and bitMask
1284 UInt32 wordIndexInBlock
;
1286 wordIndexInBlock
= (currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1287 currentWord
= buffer
+ wordIndexInBlock
;
1288 tempWord
= SWAP_BE32(*currentWord
);
1289 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
;
1290 bitMask
= kHighBitInWordMask
>> (currentBlock
& kBitsWithinWordMask
);
1293 if ( *actualNumBlocks
< maxBlocks
)
1295 while ( currentBlock
< endingBlock
)
1298 if ( (tempWord
& bitMask
) == 0 )
1300 *actualNumBlocks
+= 1;
1302 if ( *actualNumBlocks
== maxBlocks
)
1315 bitMask
= kHighBitInWordMask
;
1318 if ( --wordsLeft
== 0)
1320 err
= ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1321 if (err
!= noErr
) goto Exit
;
1324 err
= ReadBitmapBlock(vcb
, currentBlock
, &bd
);
1325 if (err
!= noErr
) break;
1326 buffer
= (UInt32
*) bd
.buffer
;
1328 // Adjust currentWord, wordsLeft
1329 currentWord
= buffer
;
1330 wordsLeft
= kWordsPerBlock
;
1332 tempWord
= SWAP_BE32(*currentWord
); // grab the current word
1339 if (bd
.buffer
!= NULL
)
1340 (void) ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1346 * Find the smallest extent in the array.
1349 FindMinExt(HFSPlusExtentDescriptor
*exts
)
1352 UInt32 min
= (UInt32
)-1;
1355 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1356 if (exts
[i
].blockCount
< min
) {
1357 min
= exts
[i
].blockCount
;
1365 * Truncate any excess extents. There should be only one,
1366 * but we'll go through them all to make sure.
1369 PruneExtents(HFSPlusExtentDescriptor
*exts
, UInt32 needed
)
1375 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1377 exts
[i
].startBlock
= exts
[i
].blockCount
= 0;
1380 total
+= exts
[i
].blockCount
;
1381 if (total
> needed
) {
1382 exts
[i
].blockCount
-= total
- needed
;
1390 * A much more specialized function: simply find the 8 largest extents
1391 * to hold the needed size. It will either find enough blocks to
1392 * fit the needed size, or it will fail.
1401 register UInt32 bitMask
; // mask of bit within word for currentBlock
1402 register UInt32 tempWord
; // bitmap word currently being examined
1403 HFSPlusExtentDescriptor
*exts
= fcb
->fcbExtents32
;
1407 UInt32 firstFreeBlock
;
1408 UInt32 freeBlocks
= 0;
1409 UInt32 currentBlock
;
1411 UInt32 wordsLeft
; // words remaining in bitmap block
1412 UInt32
*buffer
= NULL
;
1413 UInt32 contigSize
= 1;
1414 register UInt32
*currentWord
;
1415 struct BlockDescriptor bd
= { 0 };
1417 vcb
= fcb
->fcbVolume
;
1419 if (vcb
->vcbFreeBlocks
< needed
) {
1422 plog("%s: %u blocks free, but need %u; ignoring for now\n", __FUNCTION__
, vcb
->vcbFreeBlocks
, needed
);
1425 memset(exts
, 0, sizeof(fcb
->fcbExtents32
)); // Zero out the extents.
1427 if (vcb
->vcbBlockSize
< fcb
->fcbBlockSize
) {
1428 contigSize
= fcb
->fcbBlockSize
/ vcb
->vcbBlockSize
; // Number of volume blocks in a btree block
1432 endingBlock
= vcb
->vcbTotalBlocks
;
1436 err
= ReadBitmapBlock(vcb
, currentBlock
, &bd
);
1437 if ( err
!= noErr
) goto done
;
1438 buffer
= (UInt32
*) bd
.buffer
;
1440 // Init buffer, currentWord, wordsLeft, and bitMask
1443 UInt32 wordIndexInBlock
;
1445 wordIndexInBlock
= ( currentBlock
& kBitsWithinBlockMask
) / kBitsPerWord
;
1446 currentWord
= buffer
+ wordIndexInBlock
;
1448 wordsLeft
= kWordsPerBlock
- wordIndexInBlock
- 1;
1449 tempWord
= SWAP_BE32(*currentWord
);
1450 bitMask
= kHighBitInWordMask
>> ( currentBlock
& kBitsWithinWordMask
);
1454 * This macro is used to cycle through the allocation bitmap.
1455 * We examine one bit in a word at a time; when we're done with that word,
1456 * we go to the next word in the block; when we're done with that block,
1457 * we get the next one. Until we're out of blocks.
1459 #define nextblock() do { \
1461 if (currentBlock == endingBlock) goto done; \
1463 if (bitMask == 0) { \
1464 bitMask = kHighBitInWordMask; \
1465 if (wordsLeft != 0) { \
1469 err = ReleaseBitmapBlock(vcb, kReleaseBlock, &bd); \
1470 if (err != noErr) goto done; \
1472 err = ReadBitmapBlock(vcb, currentBlock, &bd); \
1473 if (err != noErr) goto done; \
1474 buffer = (UInt32*)bd.buffer; \
1475 currentWord = buffer + ((currentBlock & kBitsWithinBlockMask) / kBitsPerWord); \
1476 wordsLeft = kWordsPerBlock - 1; \
1478 tempWord = SWAP_BE32(*currentWord); \
1485 * We have two while loops here. The first one, at the top, looks for
1486 * used blocks. We ignore those. The second while loop then looks
1487 * for empty blocks, and keeps track of the length of the run. It creates
1488 * an extent from these, and puts them into the exts array. We use
1489 * the funciton FindMinExt() to find the smallest one in the array, and
1490 * we only replace it if the new extent is larger. (When first starting,
1491 * all of the extents will be 0 bytes long.)
1493 * We stop when we've run out of blocks (the nextblock macro will jump
1494 * to done at that point), or when we've got enough total blocks to
1498 while ((tempWord
& bitMask
) != 0) {
1501 firstFreeBlock
= currentBlock
;
1502 while ((tempWord
& bitMask
) == 0) {
1504 if (freeBlocks
>= needed
)
1510 * We need to ensure that nodes are not split across
1511 * volume blocks -- journaling will cause an error
1514 freeBlocks
-= freeBlocks
% contigSize
;
1516 if (freeBlocks
> exts
[minIndx
].blockCount
) {
1517 total
-= exts
[minIndx
].blockCount
;
1518 exts
[minIndx
].blockCount
= freeBlocks
;
1519 exts
[minIndx
].startBlock
= firstFreeBlock
;
1520 total
+= freeBlocks
;
1521 minIndx
= FindMinExt(exts
);
1524 if (total
>= needed
) {
1532 (void)ReleaseBitmapBlock(vcb
, kReleaseBlock
, &bd
);
1536 if (total
< needed
) {
1538 plog("%s: found %u blocks but needed %u\n", __FUNCTION__
, total
, needed
);
1542 * If we've got enough blocks, we need to prune any extra.
1543 * PruneExtents() will decrement the extents in the array to
1544 * ensure we have only as much as we need. After that, we
1545 * mark them as allocated, and return.
1548 if (total
> needed
) {
1549 PruneExtents(exts
, needed
);
1551 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1552 if (exts
[i
].blockCount
) {
1553 BlockMarkAllocated(vcb
, exts
[i
].startBlock
, exts
[i
].blockCount
);
1554 vcb
->vcbFreeBlocks
-= exts
[i
].blockCount
;