]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
ae4fccf6f0bc38097538ef81945c4e331d1303b6
2 * Copyright (c) 2000-2002 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-2001 by Apple Computer, Inc., all rights reserved.
36 Allocate space on a volume. Can allocate space contiguously.
37 If not contiguous, then allocation may be less than what was
38 asked for. Returns the starting block number, and number of
39 blocks. (Will only do a single extent???)
41 Deallocate a contiguous run of allocation blocks.
46 Mark a contiguous range of blocks as free. The corresponding
47 bits in the volume bitmap will be cleared.
49 Mark a contiguous range of blocks as allocated. The cor-
50 responding bits in the volume bitmap are set. Also tests to see
51 if any of the blocks were previously unallocated.
53 Find a contiguous range of blocks of a given size. The caller
54 specifies where to begin the search (by block number). The
55 block number of the first block in the range is returned.
57 Find and allocate a contiguous range of blocks up to a given size. The
58 first range of contiguous free blocks found are allocated, even if there
59 are fewer blocks than requested (and even if a contiguous range of blocks
60 of the given size exists elsewhere).
62 Find and allocate a contiguous range of blocks of a given size. If
63 a contiguous range of free blocks of the given size isn't found, then
64 the allocation fails (i.e. it is "all or nothing").
67 Try to allocate space from known free space in the volume's
71 Given an allocation block number, read the bitmap block that
72 contains that allocation block into a caller-supplied buffer.
75 Release a bitmap block back into the buffer cache.
78 #include "../../hfs_macos_defs.h"
80 #include <sys/types.h>
82 #include <sys/systm.h>
84 #include "../../hfs.h"
85 #include "../../hfs_dbg.h"
86 #include "../../hfs_format.h"
87 #include "../../hfs_endian.h"
89 #include "../headers/FileMgrInternal.h"
97 kBitsWithinWordMask
= kBitsPerWord
-1
100 #define kLowBitInWordMask 0x00000001ul
101 #define kHighBitInWordMask 0x80000000ul
102 #define kAllBitsSetInWord 0xFFFFFFFFul
105 static OSErr
ReadBitmapBlock(
111 static OSErr
ReleaseBitmapBlock(
116 static OSErr
BlockAllocateAny(
118 UInt32 startingBlock
,
121 UInt32
*actualStartBlock
,
122 UInt32
*actualNumBlocks
);
124 static OSErr
BlockAllocateContig(
126 UInt32 startingBlock
,
129 UInt32
*actualStartBlock
,
130 UInt32
*actualNumBlocks
);
132 static OSErr
BlockFindContiguous(
134 UInt32 startingBlock
,
138 UInt32
*actualStartBlock
,
139 UInt32
*actualNumBlocks
);
141 static OSErr
BlockMarkAllocated(
143 UInt32 startingBlock
,
146 static OSErr
BlockMarkFree(
148 UInt32 startingBlock
,
151 static OSErr
BlockAllocateKnown(
154 UInt32
*actualStartBlock
,
155 UInt32
*actualNumBlocks
);
159 ;________________________________________________________________________________
163 ; Function: Allocate space on a volume. If contiguous allocation is requested,
164 ; at least the requested number of bytes will be allocated or an
165 ; error will be returned. If contiguous allocation is not forced,
166 ; the space will be allocated at the first free fragment following
167 ; the requested starting allocation block. If there is not enough
168 ; room there, a block of less than the requested size will be
171 ; If the requested starting block is 0 (for new file allocations),
172 ; the volume's allocation block pointer will be used as a starting
175 ; All requests will be rounded up to the next highest clump size, as
176 ; indicated in the file's FCB.
179 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
180 ; fcb - Pointer to FCB for the file for which storage is being allocated
181 ; startingBlock - Preferred starting allocation block, 0 = no preference
182 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
183 ; or an error is returned
184 ; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
185 ; less than this may actually be allocated
186 ; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
187 ; space after bytesRequested, then up to bytesMaximum bytes should really
188 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
189 ; of the file's clump size.)
192 ; (result) - Error code, zero for successful allocation
193 ; *startBlock - Actual starting allocation block
194 ; *actualBlocks - Actual number of allocation blocks allocated
197 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
198 ;________________________________________________________________________________
201 OSErr
BlockAllocate (
202 ExtendedVCB
*vcb
, /* which volume to allocate space on */
203 UInt32 startingBlock
, /* preferred starting block, or 0 for no preference */
204 SInt64 bytesRequested
, /* desired number of BYTES to allocate */
205 SInt64 bytesMaximum
, /* maximum number of bytes to allocate */
206 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
207 /* bytesRequested bytes to actually be allocated */
208 UInt32
*actualStartBlock
, /* actual first block of allocation */
209 UInt32
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
210 /* was zero, then this may represent fewer than bytesRequested */
214 UInt32 minBlocks
; // minimum number of allocation blocks requested
215 UInt32 maxBlocks
; // number of allocation blocks requested, rounded to clump size
216 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
219 // Initialize outputs in case we get an error
221 *actualStartBlock
= 0;
222 *actualNumBlocks
= 0;
225 // Compute the number of allocation blocks requested, and maximum
227 minBlocks
= FileBytesToBlocks(bytesRequested
, vcb
->blockSize
);
228 maxBlocks
= FileBytesToBlocks(bytesMaximum
, vcb
->blockSize
);
231 // If the disk is already full, don't bother.
233 if (hfs_freeblks(VCBTOHFS(vcb
), 0) == 0) {
237 if (forceContiguous
&& hfs_freeblks(VCBTOHFS(vcb
), 0) < minBlocks
) {
243 // If caller didn't specify a starting block number, then use the volume's
244 // next block to allocate from.
246 if (startingBlock
== 0) {
248 startingBlock
= vcb
->nextAllocation
;
250 updateAllocPtr
= true;
254 // If the request must be contiguous, then find a sequence of free blocks
255 // that is long enough. Otherwise, find the first free block.
257 if (forceContiguous
) {
258 err
= BlockAllocateContig(vcb
, startingBlock
, minBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
260 * If we allocated from a new position then
261 * also update the roving allocatior.
263 if ((err
== noErr
) && (*actualStartBlock
> startingBlock
))
264 vcb
->nextAllocation
= *actualStartBlock
;
267 * Scan the bitmap once, gather the N largest free extents, then
268 * allocate from these largest extents. Repeat as needed until
269 * we get all the space we needed. We could probably build up
270 * that list when the higher level caller tried (and failed) a
271 * contiguous allocation first.
273 err
= BlockAllocateKnown(vcb
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
274 if (err
== dskFulErr
)
275 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->totalBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
276 if (err
== dskFulErr
)
277 err
= BlockAllocateAny(vcb
, 0, startingBlock
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
282 // If we used the volume's roving allocation pointer, then we need to update it.
283 // Adding in the length of the current allocation might reduce the next allocate
284 // call by avoiding a re-scan of the already allocated space. However, the clump
285 // just allocated can quite conceivably end up being truncated or released when
286 // the file is closed or its EOF changed. Leaving the allocation pointer at the
287 // start of the last allocation will avoid unnecessary fragmentation in this case.
292 vcb
->nextAllocation
= *actualStartBlock
;
295 // Update the number of free blocks on the volume
297 vcb
->freeBlocks
-= *actualNumBlocks
;
310 ;________________________________________________________________________________
312 ; Routine: BlkDealloc
314 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
317 ; vcb - Pointer to ExtendedVCB for the volume to free space on
318 ; firstBlock - First allocation block to be freed
319 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
322 ; (result) - Result code
325 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
326 ;________________________________________________________________________________
329 OSErr
BlockDeallocate (
330 ExtendedVCB
*vcb
, // Which volume to deallocate space on
331 UInt32 firstBlock
, // First block in range to deallocate
332 UInt32 numBlocks
) // Number of contiguous blocks to deallocate
337 // If no blocks to deallocate, then exit early
339 if (numBlocks
== 0) {
345 // Call internal routine to free the sequence of blocks
347 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
352 // Update the volume's free block count, and mark the VCB as dirty.
355 vcb
->freeBlocks
+= numBlocks
;
356 if (vcb
->nextAllocation
== (firstBlock
+ numBlocks
))
357 vcb
->nextAllocation
-= numBlocks
;
368 ;_______________________________________________________________________
370 ; Routine: FileBytesToBlocks
372 ; Function: Divide numerator by denominator, rounding up the result if there
373 ; was a remainder. This is frequently used for computing the number
374 ; of whole and/or partial blocks used by some count of bytes.
375 ; Actuall divides a 64 bit by a 32 bit into a 32bit result
377 ; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
378 ;_______________________________________________________________________
380 UInt32
FileBytesToBlocks(
386 quotient
= (UInt32
)(numerator
/ denominator
);
387 if (quotient
* denominator
!= numerator
)
396 ;_______________________________________________________________________
398 ; Routine: ReadBitmapBlock
400 ; Function: Read in a bitmap block corresponding to a given allocation
401 ; block (bit). Return a pointer to the bitmap block.
404 ; vcb -- Pointer to ExtendedVCB
405 ; bit -- Allocation block whose bitmap block is desired
408 ; buffer -- Pointer to bitmap block corresonding to "block"
410 ;_______________________________________________________________________
412 static OSErr
ReadBitmapBlock(
419 struct buf
*bp
= NULL
;
420 struct vnode
*vp
= NULL
;
425 * volume bitmap blocks are protected by the Extents B-tree lock
427 REQUIRE_FILE_LOCK(vcb
->extentsRefNum
, false);
429 blockSize
= (UInt32
)vcb
->vcbVBMIOSize
;
430 block
= bit
/ (blockSize
* kBitsPerByte
);
432 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
433 vp
= vcb
->allocationsRefNum
; /* use allocation file vnode */
436 vp
= VCBTOHFS(vcb
)->hfs_devvp
; /* use device I/O vnode */
437 block
+= vcb
->vcbVBMSt
; /* map to physical block */
440 err
= meta_bread(vp
, block
, blockSize
, NOCRED
, &bp
);
448 *blockRef
= (UInt32
)bp
;
449 *buffer
= (UInt32
*)bp
->b_data
;
458 ;_______________________________________________________________________
460 ; Routine: ReleaseBitmapBlock
462 ; Function: Relase a bitmap block.
468 ;_______________________________________________________________________
470 static OSErr
ReleaseBitmapBlock(
475 struct buf
*bp
= (struct buf
*)blockRef
;
490 _______________________________________________________________________
492 Routine: BlockAllocateContig
494 Function: Allocate a contiguous group of allocation blocks. The
495 allocation is all-or-nothing. The caller guarantees that
496 there are enough free blocks (though they may not be
497 contiguous, in which case this call will fail).
500 vcb Pointer to volume where space is to be allocated
501 startingBlock Preferred first block for allocation
502 minBlocks Minimum number of contiguous blocks to allocate
503 maxBlocks Maximum number of contiguous blocks to allocate
506 actualStartBlock First block of range allocated, or 0 if error
507 actualNumBlocks Number of blocks allocated, or 0 if error
508 _______________________________________________________________________
510 static OSErr
BlockAllocateContig(
512 UInt32 startingBlock
,
515 UInt32
*actualStartBlock
,
516 UInt32
*actualNumBlocks
)
521 // Find a contiguous group of blocks at least minBlocks long.
522 // Determine the number of contiguous blocks available (up
527 * NOTE: If the only contiguous free extent of at least minBlocks
528 * crosses startingBlock (i.e. starts before, ends after), then we
529 * won't find it. Earlier versions *did* find this case by letting
530 * the second search look past startingBlock by minBlocks. But
531 * with the free extent cache, this can lead to duplicate entries
532 * in the cache, causing the same blocks to be allocated twice.
534 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->totalBlocks
, minBlocks
, maxBlocks
,
535 actualStartBlock
, actualNumBlocks
);
536 if (err
== dskFulErr
&& startingBlock
!= 0) {
538 * Constrain the endingBlock so we don't bother looking for ranges
539 * that would overlap those found in the previous call.
541 err
= BlockFindContiguous(vcb
, 0, startingBlock
, minBlocks
, maxBlocks
,
542 actualStartBlock
, actualNumBlocks
);
544 if (err
!= noErr
) goto Exit
;
547 // Now mark those blocks allocated.
549 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
553 *actualStartBlock
= 0;
554 *actualNumBlocks
= 0;
561 _______________________________________________________________________
563 Routine: BlockAllocateAny
565 Function: Allocate one or more allocation blocks. If there are fewer
566 free blocks than requested, all free blocks will be
567 allocated. The caller guarantees that there is at least
571 vcb Pointer to volume where space is to be allocated
572 startingBlock Preferred first block for allocation
573 endingBlock Last block to check + 1
574 maxBlocks Maximum number of contiguous blocks to allocate
577 actualStartBlock First block of range allocated, or 0 if error
578 actualNumBlocks Number of blocks allocated, or 0 if error
579 _______________________________________________________________________
581 static OSErr
BlockAllocateAny(
583 UInt32 startingBlock
,
584 register UInt32 endingBlock
,
586 UInt32
*actualStartBlock
,
587 UInt32
*actualNumBlocks
)
590 register UInt32 block
; // current block number
591 register UInt32 currentWord
; // Pointer to current word within bitmap block
592 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
593 register UInt32 wordsLeft
; // Number of words left in this bitmap block
594 UInt32
*buffer
= NULL
;
595 UInt32
*currCache
= NULL
;
598 UInt32 wordsPerBlock
;
599 Boolean dirty
= false;
601 // Since this routine doesn't wrap around
602 if (maxBlocks
> (endingBlock
- startingBlock
)) {
603 maxBlocks
= endingBlock
- startingBlock
;
607 // Pre-read the first bitmap block
609 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
, &blockRef
);
610 if (err
!= noErr
) goto Exit
;
614 // Set up the current position within the block
617 UInt32 wordIndexInBlock
;
619 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
620 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
622 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
623 buffer
+= wordIndexInBlock
;
624 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
625 currentWord
= SWAP_BE32 (*buffer
);
626 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
630 // Find the first unallocated block
633 while (block
< endingBlock
) {
634 if ((currentWord
& bitMask
) == 0)
642 bitMask
= kHighBitInWordMask
;
645 if (--wordsLeft
== 0) {
647 buffer
= currCache
= NULL
;
648 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
649 if (err
!= noErr
) goto Exit
;
651 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
652 if (err
!= noErr
) goto Exit
;
655 wordsLeft
= wordsPerBlock
;
658 currentWord
= SWAP_BE32 (*buffer
);
662 // Did we get to the end of the bitmap before finding a free block?
663 // If so, then couldn't allocate anything.
664 if (block
== endingBlock
) {
669 // Return the first block in the allocated range
670 *actualStartBlock
= block
;
673 // If we could get the desired number of blocks before hitting endingBlock,
674 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
675 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
676 // comparison below yields identical results, but without overflow.
677 if (block
< (endingBlock
-maxBlocks
)) {
678 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
682 // Allocate all of the consecutive blocks
684 while ((currentWord
& bitMask
) == 0) {
685 // Allocate this block
686 currentWord
|= bitMask
;
688 // Move to the next block. If no more, then exit.
690 if (block
== endingBlock
)
696 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
699 bitMask
= kHighBitInWordMask
;
702 if (--wordsLeft
== 0) {
704 buffer
= currCache
= NULL
;
705 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
706 if (err
!= noErr
) goto Exit
;
708 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
709 if (err
!= noErr
) goto Exit
;
712 wordsLeft
= wordsPerBlock
;
715 currentWord
= SWAP_BE32 (*buffer
);
718 *buffer
= SWAP_BE32 (currentWord
); // update the last change
722 *actualNumBlocks
= block
- *actualStartBlock
;
725 *actualStartBlock
= 0;
726 *actualNumBlocks
= 0;
730 (void) ReleaseBitmapBlock(vcb
, blockRef
, dirty
);
737 _______________________________________________________________________
739 Routine: BlockAllocateKnown
741 Function: Try to allocate space from known free space in the free
745 vcb Pointer to volume where space is to be allocated
746 maxBlocks Maximum number of contiguous blocks to allocate
749 actualStartBlock First block of range allocated, or 0 if error
750 actualNumBlocks Number of blocks allocated, or 0 if error
753 dskFulErr Free extent cache is empty
754 _______________________________________________________________________
756 static OSErr
BlockAllocateKnown(
759 UInt32
*actualStartBlock
,
760 UInt32
*actualNumBlocks
)
764 UInt32 newStartBlock
, newBlockCount
;
766 if (vcb
->vcbFreeExtCnt
== 0)
769 // Just grab up to maxBlocks of the first (largest) free exent.
770 *actualStartBlock
= vcb
->vcbFreeExt
[0].startBlock
;
771 foundBlocks
= vcb
->vcbFreeExt
[0].blockCount
;
772 if (foundBlocks
> maxBlocks
)
773 foundBlocks
= maxBlocks
;
774 *actualNumBlocks
= foundBlocks
;
776 // Adjust the start and length of that extent.
777 newStartBlock
= vcb
->vcbFreeExt
[0].startBlock
+ foundBlocks
;
778 newBlockCount
= vcb
->vcbFreeExt
[0].blockCount
- foundBlocks
;
780 // The first extent might not be the largest anymore. Bubble up any
781 // (now larger) extents to the top of the list.
782 for (i
=1; i
<vcb
->vcbFreeExtCnt
; ++i
)
784 if (vcb
->vcbFreeExt
[i
].blockCount
> newBlockCount
)
786 vcb
->vcbFreeExt
[i
-1].startBlock
= vcb
->vcbFreeExt
[i
].startBlock
;
787 vcb
->vcbFreeExt
[i
-1].blockCount
= vcb
->vcbFreeExt
[i
].blockCount
;
795 // If this is now the smallest known free extent, then it might be smaller than
796 // other extents we didn't keep track of. So, just forget about this extent.
797 // After the previous loop, (i-1) is the index of the extent we just allocated from.
798 if (i
== vcb
->vcbFreeExtCnt
)
800 // It's now the smallest extent, so forget about it
801 --vcb
->vcbFreeExtCnt
;
805 // It's not the smallest, so store it in its proper place
806 vcb
->vcbFreeExt
[i
-1].startBlock
= newStartBlock
;
807 vcb
->vcbFreeExt
[i
-1].blockCount
= newBlockCount
;
811 // Now mark the found extent in the bitmap
813 return BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
819 _______________________________________________________________________
821 Routine: BlockMarkAllocated
823 Function: Mark a contiguous group of blocks as allocated (set in the
824 bitmap). It assumes those bits are currently marked
825 deallocated (clear in the bitmap).
828 vcb Pointer to volume where space is to be allocated
829 startingBlock First block number to mark as allocated
830 numBlocks Number of blocks to mark as allocated
831 _______________________________________________________________________
833 static OSErr
BlockMarkAllocated(
835 UInt32 startingBlock
,
836 register UInt32 numBlocks
)
839 register UInt32
*currentWord
; // Pointer to current word within bitmap block
840 register UInt32 wordsLeft
; // Number of words left in this bitmap block
841 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
842 UInt32 firstBit
; // Bit index within word of first bit to allocate
843 UInt32 numBits
; // Number of bits in word to allocate
844 UInt32
*buffer
= NULL
;
847 UInt32 wordsPerBlock
;
850 // Pre-read the bitmap block containing the first word of allocation
853 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
854 if (err
!= noErr
) goto Exit
;
856 // Initialize currentWord, and wordsLeft.
859 UInt32 wordIndexInBlock
;
861 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
862 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
864 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
865 currentWord
= buffer
+ wordIndexInBlock
;
866 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
870 // If the first block to allocate doesn't start on a word
871 // boundary in the bitmap, then treat that first word
875 firstBit
= startingBlock
% kBitsPerWord
;
877 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
878 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
879 if (numBits
> numBlocks
) {
880 numBits
= numBlocks
; // entire allocation is inside this one word
881 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
884 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
885 panic("BlockMarkAllocated: blocks already allocated!");
888 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
889 numBlocks
-= numBits
; // adjust number of blocks left to allocate
891 ++currentWord
; // move to next word
892 --wordsLeft
; // one less word left in this block
896 // Allocate whole words (32 blocks) at a time.
899 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
900 while (numBlocks
>= kBitsPerWord
) {
901 if (wordsLeft
== 0) {
902 // Read in the next bitmap block
903 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
906 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
907 if (err
!= noErr
) goto Exit
;
909 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
910 if (err
!= noErr
) goto Exit
;
912 // Readjust currentWord and wordsLeft
913 currentWord
= buffer
;
914 wordsLeft
= wordsPerBlock
;
917 if (*currentWord
!= 0) {
918 panic("BlockMarkAllocated: blocks already allocated!");
921 *currentWord
= SWAP_BE32 (bitMask
);
922 numBlocks
-= kBitsPerWord
;
924 ++currentWord
; // move to next word
925 --wordsLeft
; // one less word left in this block
929 // Allocate any remaining blocks.
932 if (numBlocks
!= 0) {
933 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
934 if (wordsLeft
== 0) {
935 // Read in the next bitmap block
936 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
939 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
940 if (err
!= noErr
) goto Exit
;
942 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
943 if (err
!= noErr
) goto Exit
;
945 // Readjust currentWord and wordsLeft
946 currentWord
= buffer
;
947 wordsLeft
= wordsPerBlock
;
950 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
951 panic("BlockMarkAllocated: blocks already allocated!");
954 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
956 // No need to update currentWord or wordsLeft
962 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
969 _______________________________________________________________________
971 Routine: BlockMarkFree
973 Function: Mark a contiguous group of blocks as free (clear in the
974 bitmap). It assumes those bits are currently marked
975 allocated (set in the bitmap).
978 vcb Pointer to volume where space is to be freed
979 startingBlock First block number to mark as freed
980 numBlocks Number of blocks to mark as freed
981 _______________________________________________________________________
983 static OSErr
BlockMarkFree(
985 UInt32 startingBlock
,
986 register UInt32 numBlocks
)
989 register UInt32
*currentWord
; // Pointer to current word within bitmap block
990 register UInt32 wordsLeft
; // Number of words left in this bitmap block
991 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
992 UInt32 firstBit
; // Bit index within word of first bit to allocate
993 UInt32 numBits
; // Number of bits in word to allocate
994 UInt32
*buffer
= NULL
;
997 UInt32 wordsPerBlock
;
1000 // Pre-read the bitmap block containing the first word of allocation
1003 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1004 if (err
!= noErr
) goto Exit
;
1006 // Initialize currentWord, and wordsLeft.
1009 UInt32 wordIndexInBlock
;
1011 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1012 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1014 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1015 currentWord
= buffer
+ wordIndexInBlock
;
1016 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1020 // If the first block to free doesn't start on a word
1021 // boundary in the bitmap, then treat that first word
1025 firstBit
= startingBlock
% kBitsPerWord
;
1026 if (firstBit
!= 0) {
1027 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1028 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1029 if (numBits
> numBlocks
) {
1030 numBits
= numBlocks
; // entire allocation is inside this one word
1031 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1034 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1035 panic("BlockMarkFree: blocks not allocated!");
1038 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1039 numBlocks
-= numBits
; // adjust number of blocks left to free
1041 ++currentWord
; // move to next word
1042 --wordsLeft
; // one less word left in this block
1046 // Free whole words (32 blocks) at a time.
1049 while (numBlocks
>= kBitsPerWord
) {
1050 if (wordsLeft
== 0) {
1051 // Read in the next bitmap block
1052 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1055 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1056 if (err
!= noErr
) goto Exit
;
1058 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1059 if (err
!= noErr
) goto Exit
;
1061 // Readjust currentWord and wordsLeft
1062 currentWord
= buffer
;
1063 wordsLeft
= wordsPerBlock
;
1067 if (*currentWord
!= SWAP_BE32 (kAllBitsSetInWord
)) {
1068 panic("BlockMarkFree: blocks not allocated!");
1071 *currentWord
= 0; // clear the entire word
1072 numBlocks
-= kBitsPerWord
;
1074 ++currentWord
; // move to next word
1075 --wordsLeft
; // one less word left in this block
1079 // Free any remaining blocks.
1082 if (numBlocks
!= 0) {
1083 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1084 if (wordsLeft
== 0) {
1085 // Read in the next bitmap block
1086 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1089 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1090 if (err
!= noErr
) goto Exit
;
1092 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1093 if (err
!= noErr
) goto Exit
;
1095 // Readjust currentWord and wordsLeft
1096 currentWord
= buffer
;
1097 wordsLeft
= wordsPerBlock
;
1100 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1101 panic("BlockMarkFree: blocks not allocated!");
1104 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1106 // No need to update currentWord or wordsLeft
1112 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1119 _______________________________________________________________________
1121 Routine: BlockFindContiguous
1123 Function: Find a contiguous range of blocks that are free (bits
1124 clear in the bitmap). If a contiguous range of the
1125 minimum size can't be found, an error will be returned.
1128 vcb Pointer to volume where space is to be allocated
1129 startingBlock Preferred first block of range
1130 endingBlock Last possible block in range + 1
1131 minBlocks Minimum number of blocks needed. Must be > 0.
1132 maxBlocks Maximum (ideal) number of blocks desired
1135 actualStartBlock First block of range found, or 0 if error
1136 actualNumBlocks Number of blocks found, or 0 if error
1139 noErr Found at least minBlocks contiguous
1140 dskFulErr No contiguous space found, or all less than minBlocks
1141 _______________________________________________________________________
1144 static OSErr
BlockFindContiguous(
1146 UInt32 startingBlock
,
1150 UInt32
*actualStartBlock
,
1151 UInt32
*actualNumBlocks
)
1154 register UInt32 currentBlock
; // Block we're currently looking at.
1155 UInt32 firstBlock
; // First free block in current extent.
1156 UInt32 stopBlock
; // If we get to this block, stop searching for first free block.
1157 UInt32 foundBlocks
; // Number of contiguous free blocks in current extent.
1158 UInt32
*buffer
= NULL
;
1159 register UInt32
*currentWord
;
1160 register UInt32 bitMask
;
1161 register UInt32 wordsLeft
;
1162 register UInt32 tempWord
;
1164 UInt32 wordsPerBlock
;
1166 if ((endingBlock
- startingBlock
) < minBlocks
)
1168 // The set of blocks we're checking is smaller than the minimum number
1169 // of blocks, so we couldn't possibly find a good range.
1173 stopBlock
= endingBlock
- minBlocks
+ 1;
1174 currentBlock
= startingBlock
;
1178 // Pre-read the first bitmap block.
1180 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1181 if ( err
!= noErr
) goto ErrorExit
;
1184 // Figure out where currentBlock is within the buffer.
1186 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1188 wordsLeft
= (startingBlock
/ kBitsPerWord
) & (wordsPerBlock
-1); // Current index into buffer
1189 currentWord
= buffer
+ wordsLeft
;
1190 wordsLeft
= wordsPerBlock
- wordsLeft
;
1196 //============================================================
1197 // Look for a free block, skipping over allocated blocks.
1198 //============================================================
1201 // Check an initial partial word (if any)
1203 bitMask
= currentBlock
& kBitsWithinWordMask
;
1206 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1207 bitMask
= kHighBitInWordMask
>> bitMask
;
1208 while (tempWord
& bitMask
)
1214 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1218 // Didn't find any unused bits, so we're done with this word.
1224 // Check whole words
1226 while (currentBlock
< stopBlock
)
1228 // See if it's time to read another block.
1232 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1233 if (err
!= noErr
) goto ErrorExit
;
1235 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1236 if ( err
!= noErr
) goto ErrorExit
;
1238 currentWord
= buffer
;
1239 wordsLeft
= wordsPerBlock
;
1242 // See if any of the bits are clear
1243 if ((tempWord
= SWAP_BE32(*currentWord
)) + 1) // non-zero if any bits were clear
1245 // Figure out which bit is clear
1246 bitMask
= kHighBitInWordMask
;
1247 while (tempWord
& bitMask
)
1253 break; // Found the free bit; break out to FoundUnused.
1256 // Keep looking at the next word
1257 currentBlock
+= kBitsPerWord
;
1263 // Make sure the unused bit is early enough to use
1264 if (currentBlock
>= stopBlock
)
1269 // Remember the start of the extent
1270 firstBlock
= currentBlock
;
1272 //============================================================
1273 // Count the number of contiguous free blocks.
1274 //============================================================
1277 // Check an initial partial word (if any)
1279 bitMask
= currentBlock
& kBitsWithinWordMask
;
1282 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1283 bitMask
= kHighBitInWordMask
>> bitMask
;
1284 while (bitMask
&& !(tempWord
& bitMask
))
1290 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1294 // Didn't find any used bits, so we're done with this word.
1300 // Check whole words
1302 while (currentBlock
< endingBlock
)
1304 // See if it's time to read another block.
1308 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1309 if (err
!= noErr
) goto ErrorExit
;
1311 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1312 if ( err
!= noErr
) goto ErrorExit
;
1314 currentWord
= buffer
;
1315 wordsLeft
= wordsPerBlock
;
1318 // See if any of the bits are set
1319 if ((tempWord
= SWAP_BE32(*currentWord
)) != 0)
1321 // Figure out which bit is set
1322 bitMask
= kHighBitInWordMask
;
1323 while (!(tempWord
& bitMask
))
1329 break; // Found the used bit; break out to FoundUsed.
1332 // Keep looking at the next word
1333 currentBlock
+= kBitsPerWord
;
1337 // If we found at least maxBlocks, we can quit early.
1338 if ((currentBlock
- firstBlock
) >= maxBlocks
)
1343 // Make sure we didn't run out of bitmap looking for a used block.
1344 // If so, pin to the end of the bitmap.
1345 if (currentBlock
> endingBlock
)
1346 currentBlock
= endingBlock
;
1348 // Figure out how many contiguous free blocks there were.
1349 // Pin the answer to maxBlocks.
1350 foundBlocks
= currentBlock
- firstBlock
;
1351 if (foundBlocks
> maxBlocks
)
1352 foundBlocks
= maxBlocks
;
1353 if (foundBlocks
>= minBlocks
)
1354 break; // Found what we needed!
1356 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1357 // the allocation wasn't forced contiguous.
1358 tempWord
= vcb
->vcbFreeExtCnt
;
1359 if (tempWord
== kMaxFreeExtents
&& vcb
->vcbFreeExt
[kMaxFreeExtents
-1].blockCount
< foundBlocks
)
1361 if (tempWord
< kMaxFreeExtents
)
1363 // We're going to add this extent. Bubble any smaller extents down in the list.
1364 while (tempWord
&& vcb
->vcbFreeExt
[tempWord
-1].blockCount
< foundBlocks
)
1366 vcb
->vcbFreeExt
[tempWord
] = vcb
->vcbFreeExt
[tempWord
-1];
1369 vcb
->vcbFreeExt
[tempWord
].startBlock
= firstBlock
;
1370 vcb
->vcbFreeExt
[tempWord
].blockCount
= foundBlocks
;
1372 if (vcb
->vcbFreeExtCnt
< kMaxFreeExtents
)
1373 ++vcb
->vcbFreeExtCnt
;
1375 } while (currentBlock
< stopBlock
);
1378 // Return the outputs.
1379 if (foundBlocks
< minBlocks
)
1384 *actualStartBlock
= 0;
1385 *actualNumBlocks
= 0;
1390 *actualStartBlock
= firstBlock
;
1391 *actualNumBlocks
= foundBlocks
;
1395 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);