]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
4fe6499214d2987b85693abafd71ddf6e88b18c8
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
;
480 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
483 journal_modify_block_end(hfsmp
->jnl
, bp
);
497 _______________________________________________________________________
499 Routine: BlockAllocateContig
501 Function: Allocate a contiguous group of allocation blocks. The
502 allocation is all-or-nothing. The caller guarantees that
503 there are enough free blocks (though they may not be
504 contiguous, in which case this call will fail).
507 vcb Pointer to volume where space is to be allocated
508 startingBlock Preferred first block for allocation
509 minBlocks Minimum number of contiguous blocks to allocate
510 maxBlocks Maximum number of contiguous blocks to allocate
513 actualStartBlock First block of range allocated, or 0 if error
514 actualNumBlocks Number of blocks allocated, or 0 if error
515 _______________________________________________________________________
517 static OSErr
BlockAllocateContig(
519 UInt32 startingBlock
,
522 UInt32
*actualStartBlock
,
523 UInt32
*actualNumBlocks
)
528 // Find a contiguous group of blocks at least minBlocks long.
529 // Determine the number of contiguous blocks available (up
534 * NOTE: If the only contiguous free extent of at least minBlocks
535 * crosses startingBlock (i.e. starts before, ends after), then we
536 * won't find it. Earlier versions *did* find this case by letting
537 * the second search look past startingBlock by minBlocks. But
538 * with the free extent cache, this can lead to duplicate entries
539 * in the cache, causing the same blocks to be allocated twice.
541 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->totalBlocks
, minBlocks
, maxBlocks
,
542 actualStartBlock
, actualNumBlocks
);
543 if (err
== dskFulErr
&& startingBlock
!= 0) {
545 * Constrain the endingBlock so we don't bother looking for ranges
546 * that would overlap those found in the previous call.
548 err
= BlockFindContiguous(vcb
, 0, startingBlock
, minBlocks
, maxBlocks
,
549 actualStartBlock
, actualNumBlocks
);
551 if (err
!= noErr
) goto Exit
;
554 // Now mark those blocks allocated.
556 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
560 *actualStartBlock
= 0;
561 *actualNumBlocks
= 0;
568 _______________________________________________________________________
570 Routine: BlockAllocateAny
572 Function: Allocate one or more allocation blocks. If there are fewer
573 free blocks than requested, all free blocks will be
574 allocated. The caller guarantees that there is at least
578 vcb Pointer to volume where space is to be allocated
579 startingBlock Preferred first block for allocation
580 endingBlock Last block to check + 1
581 maxBlocks Maximum number of contiguous blocks to allocate
584 actualStartBlock First block of range allocated, or 0 if error
585 actualNumBlocks Number of blocks allocated, or 0 if error
586 _______________________________________________________________________
588 static OSErr
BlockAllocateAny(
590 UInt32 startingBlock
,
591 register UInt32 endingBlock
,
593 UInt32
*actualStartBlock
,
594 UInt32
*actualNumBlocks
)
597 register UInt32 block
; // current block number
598 register UInt32 currentWord
; // Pointer to current word within bitmap block
599 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
600 register UInt32 wordsLeft
; // Number of words left in this bitmap block
601 UInt32
*buffer
= NULL
;
602 UInt32
*currCache
= NULL
;
605 UInt32 wordsPerBlock
;
606 Boolean dirty
= false;
607 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
609 // Since this routine doesn't wrap around
610 if (maxBlocks
> (endingBlock
- startingBlock
)) {
611 maxBlocks
= endingBlock
- startingBlock
;
615 // Pre-read the first bitmap block
617 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
, &blockRef
);
618 if (err
!= noErr
) goto Exit
;
622 // Set up the current position within the block
625 UInt32 wordIndexInBlock
;
627 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
628 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
630 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
631 buffer
+= wordIndexInBlock
;
632 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
633 currentWord
= SWAP_BE32 (*buffer
);
634 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
638 // Find the first unallocated block
641 while (block
< endingBlock
) {
642 if ((currentWord
& bitMask
) == 0)
650 bitMask
= kHighBitInWordMask
;
653 if (--wordsLeft
== 0) {
655 buffer
= currCache
= NULL
;
656 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
657 if (err
!= noErr
) goto Exit
;
659 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
660 if (err
!= noErr
) goto Exit
;
663 wordsLeft
= wordsPerBlock
;
666 currentWord
= SWAP_BE32 (*buffer
);
670 // Did we get to the end of the bitmap before finding a free block?
671 // If so, then couldn't allocate anything.
672 if (block
== endingBlock
) {
677 // Return the first block in the allocated range
678 *actualStartBlock
= block
;
681 // If we could get the desired number of blocks before hitting endingBlock,
682 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
683 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
684 // comparison below yields identical results, but without overflow.
685 if (block
< (endingBlock
-maxBlocks
)) {
686 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
691 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
695 // Allocate all of the consecutive blocks
697 while ((currentWord
& bitMask
) == 0) {
698 // Allocate this block
699 currentWord
|= bitMask
;
701 // Move to the next block. If no more, then exit.
703 if (block
== endingBlock
)
709 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
712 bitMask
= kHighBitInWordMask
;
715 if (--wordsLeft
== 0) {
717 buffer
= currCache
= NULL
;
718 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
719 if (err
!= noErr
) goto Exit
;
721 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
722 if (err
!= noErr
) goto Exit
;
727 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
730 wordsLeft
= wordsPerBlock
;
733 currentWord
= SWAP_BE32 (*buffer
);
736 *buffer
= SWAP_BE32 (currentWord
); // update the last change
740 *actualNumBlocks
= block
- *actualStartBlock
;
743 *actualStartBlock
= 0;
744 *actualNumBlocks
= 0;
748 (void) ReleaseBitmapBlock(vcb
, blockRef
, dirty
);
755 _______________________________________________________________________
757 Routine: BlockAllocateKnown
759 Function: Try to allocate space from known free space in the free
763 vcb Pointer to volume where space is to be allocated
764 maxBlocks Maximum number of contiguous blocks to allocate
767 actualStartBlock First block of range allocated, or 0 if error
768 actualNumBlocks Number of blocks allocated, or 0 if error
771 dskFulErr Free extent cache is empty
772 _______________________________________________________________________
774 static OSErr
BlockAllocateKnown(
777 UInt32
*actualStartBlock
,
778 UInt32
*actualNumBlocks
)
782 UInt32 newStartBlock
, newBlockCount
;
784 if (vcb
->vcbFreeExtCnt
== 0)
787 // Just grab up to maxBlocks of the first (largest) free exent.
788 *actualStartBlock
= vcb
->vcbFreeExt
[0].startBlock
;
789 foundBlocks
= vcb
->vcbFreeExt
[0].blockCount
;
790 if (foundBlocks
> maxBlocks
)
791 foundBlocks
= maxBlocks
;
792 *actualNumBlocks
= foundBlocks
;
794 // Adjust the start and length of that extent.
795 newStartBlock
= vcb
->vcbFreeExt
[0].startBlock
+ foundBlocks
;
796 newBlockCount
= vcb
->vcbFreeExt
[0].blockCount
- foundBlocks
;
798 // The first extent might not be the largest anymore. Bubble up any
799 // (now larger) extents to the top of the list.
800 for (i
=1; i
<vcb
->vcbFreeExtCnt
; ++i
)
802 if (vcb
->vcbFreeExt
[i
].blockCount
> newBlockCount
)
804 vcb
->vcbFreeExt
[i
-1].startBlock
= vcb
->vcbFreeExt
[i
].startBlock
;
805 vcb
->vcbFreeExt
[i
-1].blockCount
= vcb
->vcbFreeExt
[i
].blockCount
;
813 // If this is now the smallest known free extent, then it might be smaller than
814 // other extents we didn't keep track of. So, just forget about this extent.
815 // After the previous loop, (i-1) is the index of the extent we just allocated from.
816 if (i
== vcb
->vcbFreeExtCnt
)
818 // It's now the smallest extent, so forget about it
819 --vcb
->vcbFreeExtCnt
;
823 // It's not the smallest, so store it in its proper place
824 vcb
->vcbFreeExt
[i
-1].startBlock
= newStartBlock
;
825 vcb
->vcbFreeExt
[i
-1].blockCount
= newBlockCount
;
829 // Now mark the found extent in the bitmap
831 return BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
837 _______________________________________________________________________
839 Routine: BlockMarkAllocated
841 Function: Mark a contiguous group of blocks as allocated (set in the
842 bitmap). It assumes those bits are currently marked
843 deallocated (clear in the bitmap).
846 vcb Pointer to volume where space is to be allocated
847 startingBlock First block number to mark as allocated
848 numBlocks Number of blocks to mark as allocated
849 _______________________________________________________________________
851 static OSErr
BlockMarkAllocated(
853 UInt32 startingBlock
,
854 register UInt32 numBlocks
)
857 register UInt32
*currentWord
; // Pointer to current word within bitmap block
858 register UInt32 wordsLeft
; // Number of words left in this bitmap block
859 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
860 UInt32 firstBit
; // Bit index within word of first bit to allocate
861 UInt32 numBits
; // Number of bits in word to allocate
862 UInt32
*buffer
= NULL
;
865 UInt32 wordsPerBlock
;
867 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
870 // Pre-read the bitmap block containing the first word of allocation
873 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
874 if (err
!= noErr
) goto Exit
;
876 // Initialize currentWord, and wordsLeft.
879 UInt32 wordIndexInBlock
;
881 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
882 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
884 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
885 currentWord
= buffer
+ wordIndexInBlock
;
886 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
891 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
895 // If the first block to allocate doesn't start on a word
896 // boundary in the bitmap, then treat that first word
900 firstBit
= startingBlock
% kBitsPerWord
;
902 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
903 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
904 if (numBits
> numBlocks
) {
905 numBits
= numBlocks
; // entire allocation is inside this one word
906 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
909 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
910 panic("BlockMarkAllocated: blocks already allocated!");
913 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
914 numBlocks
-= numBits
; // adjust number of blocks left to allocate
916 ++currentWord
; // move to next word
917 --wordsLeft
; // one less word left in this block
921 // Allocate whole words (32 blocks) at a time.
924 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
925 while (numBlocks
>= kBitsPerWord
) {
926 if (wordsLeft
== 0) {
927 // Read in the next bitmap block
928 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
931 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
932 if (err
!= noErr
) goto Exit
;
934 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
935 if (err
!= noErr
) goto Exit
;
939 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
942 // Readjust currentWord and wordsLeft
943 currentWord
= buffer
;
944 wordsLeft
= wordsPerBlock
;
947 if (*currentWord
!= 0) {
948 panic("BlockMarkAllocated: blocks already allocated!");
951 *currentWord
= SWAP_BE32 (bitMask
);
952 numBlocks
-= kBitsPerWord
;
954 ++currentWord
; // move to next word
955 --wordsLeft
; // one less word left in this block
959 // Allocate any remaining blocks.
962 if (numBlocks
!= 0) {
963 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
964 if (wordsLeft
== 0) {
965 // Read in the next bitmap block
966 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
969 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
970 if (err
!= noErr
) goto Exit
;
972 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
973 if (err
!= noErr
) goto Exit
;
977 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
980 // Readjust currentWord and wordsLeft
981 currentWord
= buffer
;
982 wordsLeft
= wordsPerBlock
;
985 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
986 panic("BlockMarkAllocated: blocks already allocated!");
989 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
991 // No need to update currentWord or wordsLeft
997 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1004 _______________________________________________________________________
1006 Routine: BlockMarkFree
1008 Function: Mark a contiguous group of blocks as free (clear in the
1009 bitmap). It assumes those bits are currently marked
1010 allocated (set in the bitmap).
1013 vcb Pointer to volume where space is to be freed
1014 startingBlock First block number to mark as freed
1015 numBlocks Number of blocks to mark as freed
1016 _______________________________________________________________________
1018 static OSErr
BlockMarkFree(
1020 UInt32 startingBlock
,
1021 register UInt32 numBlocks
)
1024 register UInt32
*currentWord
; // Pointer to current word within bitmap block
1025 register UInt32 wordsLeft
; // Number of words left in this bitmap block
1026 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
1027 UInt32 firstBit
; // Bit index within word of first bit to allocate
1028 UInt32 numBits
; // Number of bits in word to allocate
1029 UInt32
*buffer
= NULL
;
1031 UInt32 bitsPerBlock
;
1032 UInt32 wordsPerBlock
;
1034 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
1037 // Pre-read the bitmap block containing the first word of allocation
1040 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1041 if (err
!= noErr
) goto Exit
;
1044 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1048 // Initialize currentWord, and wordsLeft.
1051 UInt32 wordIndexInBlock
;
1053 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1054 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1056 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1057 currentWord
= buffer
+ wordIndexInBlock
;
1058 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1062 // If the first block to free doesn't start on a word
1063 // boundary in the bitmap, then treat that first word
1067 firstBit
= startingBlock
% kBitsPerWord
;
1068 if (firstBit
!= 0) {
1069 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1070 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1071 if (numBits
> numBlocks
) {
1072 numBits
= numBlocks
; // entire allocation is inside this one word
1073 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1076 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1077 panic("BlockMarkFree: blocks not allocated!");
1080 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1081 numBlocks
-= numBits
; // adjust number of blocks left to free
1083 ++currentWord
; // move to next word
1084 --wordsLeft
; // one less word left in this block
1088 // Free whole words (32 blocks) at a time.
1091 while (numBlocks
>= kBitsPerWord
) {
1092 if (wordsLeft
== 0) {
1093 // Read in the next bitmap block
1094 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1097 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1098 if (err
!= noErr
) goto Exit
;
1100 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1101 if (err
!= noErr
) goto Exit
;
1105 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1108 // Readjust currentWord and wordsLeft
1109 currentWord
= buffer
;
1110 wordsLeft
= wordsPerBlock
;
1114 if (*currentWord
!= SWAP_BE32 (kAllBitsSetInWord
)) {
1115 panic("BlockMarkFree: blocks not allocated!");
1118 *currentWord
= 0; // clear the entire word
1119 numBlocks
-= kBitsPerWord
;
1121 ++currentWord
; // move to next word
1122 --wordsLeft
; // one less word left in this block
1126 // Free any remaining blocks.
1129 if (numBlocks
!= 0) {
1130 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1131 if (wordsLeft
== 0) {
1132 // Read in the next bitmap block
1133 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1136 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1137 if (err
!= noErr
) goto Exit
;
1139 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1140 if (err
!= noErr
) goto Exit
;
1144 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1147 // Readjust currentWord and wordsLeft
1148 currentWord
= buffer
;
1149 wordsLeft
= wordsPerBlock
;
1152 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1153 panic("BlockMarkFree: blocks not allocated!");
1156 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1158 // No need to update currentWord or wordsLeft
1164 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1171 _______________________________________________________________________
1173 Routine: BlockFindContiguous
1175 Function: Find a contiguous range of blocks that are free (bits
1176 clear in the bitmap). If a contiguous range of the
1177 minimum size can't be found, an error will be returned.
1180 vcb Pointer to volume where space is to be allocated
1181 startingBlock Preferred first block of range
1182 endingBlock Last possible block in range + 1
1183 minBlocks Minimum number of blocks needed. Must be > 0.
1184 maxBlocks Maximum (ideal) number of blocks desired
1187 actualStartBlock First block of range found, or 0 if error
1188 actualNumBlocks Number of blocks found, or 0 if error
1191 noErr Found at least minBlocks contiguous
1192 dskFulErr No contiguous space found, or all less than minBlocks
1193 _______________________________________________________________________
1196 static OSErr
BlockFindContiguous(
1198 UInt32 startingBlock
,
1202 UInt32
*actualStartBlock
,
1203 UInt32
*actualNumBlocks
)
1206 register UInt32 currentBlock
; // Block we're currently looking at.
1207 UInt32 firstBlock
; // First free block in current extent.
1208 UInt32 stopBlock
; // If we get to this block, stop searching for first free block.
1209 UInt32 foundBlocks
; // Number of contiguous free blocks in current extent.
1210 UInt32
*buffer
= NULL
;
1211 register UInt32
*currentWord
;
1212 register UInt32 bitMask
;
1213 register UInt32 wordsLeft
;
1214 register UInt32 tempWord
;
1216 UInt32 wordsPerBlock
;
1218 if ((endingBlock
- startingBlock
) < minBlocks
)
1220 // The set of blocks we're checking is smaller than the minimum number
1221 // of blocks, so we couldn't possibly find a good range.
1225 stopBlock
= endingBlock
- minBlocks
+ 1;
1226 currentBlock
= startingBlock
;
1230 // Pre-read the first bitmap block.
1232 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1233 if ( err
!= noErr
) goto ErrorExit
;
1236 // Figure out where currentBlock is within the buffer.
1238 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1240 wordsLeft
= (startingBlock
/ kBitsPerWord
) & (wordsPerBlock
-1); // Current index into buffer
1241 currentWord
= buffer
+ wordsLeft
;
1242 wordsLeft
= wordsPerBlock
- wordsLeft
;
1248 //============================================================
1249 // Look for a free block, skipping over allocated blocks.
1250 //============================================================
1253 // Check an initial partial word (if any)
1255 bitMask
= currentBlock
& kBitsWithinWordMask
;
1258 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1259 bitMask
= kHighBitInWordMask
>> bitMask
;
1260 while (tempWord
& bitMask
)
1266 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1270 // Didn't find any unused bits, so we're done with this word.
1276 // Check whole words
1278 while (currentBlock
< stopBlock
)
1280 // See if it's time to read another block.
1284 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1285 if (err
!= noErr
) goto ErrorExit
;
1287 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1288 if ( err
!= noErr
) goto ErrorExit
;
1290 currentWord
= buffer
;
1291 wordsLeft
= wordsPerBlock
;
1294 // See if any of the bits are clear
1295 if ((tempWord
= SWAP_BE32(*currentWord
)) + 1) // non-zero if any bits were clear
1297 // Figure out which bit is clear
1298 bitMask
= kHighBitInWordMask
;
1299 while (tempWord
& bitMask
)
1305 break; // Found the free bit; break out to FoundUnused.
1308 // Keep looking at the next word
1309 currentBlock
+= kBitsPerWord
;
1315 // Make sure the unused bit is early enough to use
1316 if (currentBlock
>= stopBlock
)
1321 // Remember the start of the extent
1322 firstBlock
= currentBlock
;
1324 //============================================================
1325 // Count the number of contiguous free blocks.
1326 //============================================================
1329 // Check an initial partial word (if any)
1331 bitMask
= currentBlock
& kBitsWithinWordMask
;
1334 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1335 bitMask
= kHighBitInWordMask
>> bitMask
;
1336 while (bitMask
&& !(tempWord
& bitMask
))
1342 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1346 // Didn't find any used bits, so we're done with this word.
1352 // Check whole words
1354 while (currentBlock
< endingBlock
)
1356 // See if it's time to read another block.
1360 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1361 if (err
!= noErr
) goto ErrorExit
;
1363 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1364 if ( err
!= noErr
) goto ErrorExit
;
1366 currentWord
= buffer
;
1367 wordsLeft
= wordsPerBlock
;
1370 // See if any of the bits are set
1371 if ((tempWord
= SWAP_BE32(*currentWord
)) != 0)
1373 // Figure out which bit is set
1374 bitMask
= kHighBitInWordMask
;
1375 while (!(tempWord
& bitMask
))
1381 break; // Found the used bit; break out to FoundUsed.
1384 // Keep looking at the next word
1385 currentBlock
+= kBitsPerWord
;
1389 // If we found at least maxBlocks, we can quit early.
1390 if ((currentBlock
- firstBlock
) >= maxBlocks
)
1395 // Make sure we didn't run out of bitmap looking for a used block.
1396 // If so, pin to the end of the bitmap.
1397 if (currentBlock
> endingBlock
)
1398 currentBlock
= endingBlock
;
1400 // Figure out how many contiguous free blocks there were.
1401 // Pin the answer to maxBlocks.
1402 foundBlocks
= currentBlock
- firstBlock
;
1403 if (foundBlocks
> maxBlocks
)
1404 foundBlocks
= maxBlocks
;
1405 if (foundBlocks
>= minBlocks
)
1406 break; // Found what we needed!
1408 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1409 // the allocation wasn't forced contiguous.
1410 tempWord
= vcb
->vcbFreeExtCnt
;
1411 if (tempWord
== kMaxFreeExtents
&& vcb
->vcbFreeExt
[kMaxFreeExtents
-1].blockCount
< foundBlocks
)
1413 if (tempWord
< kMaxFreeExtents
)
1415 // We're going to add this extent. Bubble any smaller extents down in the list.
1416 while (tempWord
&& vcb
->vcbFreeExt
[tempWord
-1].blockCount
< foundBlocks
)
1418 vcb
->vcbFreeExt
[tempWord
] = vcb
->vcbFreeExt
[tempWord
-1];
1421 vcb
->vcbFreeExt
[tempWord
].startBlock
= firstBlock
;
1422 vcb
->vcbFreeExt
[tempWord
].blockCount
= foundBlocks
;
1424 if (vcb
->vcbFreeExtCnt
< kMaxFreeExtents
)
1425 ++vcb
->vcbFreeExtCnt
;
1427 } while (currentBlock
< stopBlock
);
1430 // Return the outputs.
1431 if (foundBlocks
< minBlocks
)
1436 *actualStartBlock
= 0;
1437 *actualNumBlocks
= 0;
1442 *actualStartBlock
= firstBlock
;
1443 *actualNumBlocks
= foundBlocks
;
1447 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);