]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
8908358e537359ad3e23d20bb942546d30335cf0
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 File: VolumeAllocation.c
28 Contains: Routines for accessing and modifying the volume bitmap.
32 Copyright: © 1996-2001 by Apple Computer, Inc., all rights reserved.
39 Allocate space on a volume. Can allocate space contiguously.
40 If not contiguous, then allocation may be less than what was
41 asked for. Returns the starting block number, and number of
42 blocks. (Will only do a single extent???)
44 Deallocate a contiguous run of allocation blocks.
49 Mark a contiguous range of blocks as free. The corresponding
50 bits in the volume bitmap will be cleared.
52 Mark a contiguous range of blocks as allocated. The cor-
53 responding bits in the volume bitmap are set. Also tests to see
54 if any of the blocks were previously unallocated.
56 Find a contiguous range of blocks of a given size. The caller
57 specifies where to begin the search (by block number). The
58 block number of the first block in the range is returned.
60 Find and allocate a contiguous range of blocks up to a given size. The
61 first range of contiguous free blocks found are allocated, even if there
62 are fewer blocks than requested (and even if a contiguous range of blocks
63 of the given size exists elsewhere).
65 Find and allocate a contiguous range of blocks of a given size. If
66 a contiguous range of free blocks of the given size isn't found, then
67 the allocation fails (i.e. it is "all or nothing").
70 Try to allocate space from known free space in the volume's
74 Given an allocation block number, read the bitmap block that
75 contains that allocation block into a caller-supplied buffer.
78 Release a bitmap block back into the buffer cache.
81 #include "../../hfs_macos_defs.h"
83 #include <sys/types.h>
85 #include <sys/systm.h>
87 #include "../../hfs.h"
88 #include "../../hfs_dbg.h"
89 #include "../../hfs_format.h"
90 #include "../../hfs_endian.h"
92 #include "../headers/FileMgrInternal.h"
100 kBitsWithinWordMask
= kBitsPerWord
-1
103 #define kLowBitInWordMask 0x00000001ul
104 #define kHighBitInWordMask 0x80000000ul
105 #define kAllBitsSetInWord 0xFFFFFFFFul
108 static OSErr
ReadBitmapBlock(
114 static OSErr
ReleaseBitmapBlock(
119 static OSErr
BlockAllocateAny(
121 UInt32 startingBlock
,
124 UInt32
*actualStartBlock
,
125 UInt32
*actualNumBlocks
);
127 static OSErr
BlockAllocateContig(
129 UInt32 startingBlock
,
132 UInt32
*actualStartBlock
,
133 UInt32
*actualNumBlocks
);
135 static OSErr
BlockFindContiguous(
137 UInt32 startingBlock
,
141 UInt32
*actualStartBlock
,
142 UInt32
*actualNumBlocks
);
144 static OSErr
BlockMarkAllocated(
146 UInt32 startingBlock
,
149 static OSErr
BlockMarkFree(
151 UInt32 startingBlock
,
154 static OSErr
BlockAllocateKnown(
157 UInt32
*actualStartBlock
,
158 UInt32
*actualNumBlocks
);
162 ;________________________________________________________________________________
166 ; Function: Allocate space on a volume. If contiguous allocation is requested,
167 ; at least the requested number of bytes will be allocated or an
168 ; error will be returned. If contiguous allocation is not forced,
169 ; the space will be allocated at the first free fragment following
170 ; the requested starting allocation block. If there is not enough
171 ; room there, a block of less than the requested size will be
174 ; If the requested starting block is 0 (for new file allocations),
175 ; the volume's allocation block pointer will be used as a starting
178 ; All requests will be rounded up to the next highest clump size, as
179 ; indicated in the file's FCB.
182 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
183 ; fcb - Pointer to FCB for the file for which storage is being allocated
184 ; startingBlock - Preferred starting allocation block, 0 = no preference
185 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
186 ; or an error is returned
187 ; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
188 ; less than this may actually be allocated
189 ; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
190 ; space after bytesRequested, then up to bytesMaximum bytes should really
191 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
192 ; of the file's clump size.)
195 ; (result) - Error code, zero for successful allocation
196 ; *startBlock - Actual starting allocation block
197 ; *actualBlocks - Actual number of allocation blocks allocated
200 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
201 ;________________________________________________________________________________
204 OSErr
BlockAllocate (
205 ExtendedVCB
*vcb
, /* which volume to allocate space on */
206 UInt32 startingBlock
, /* preferred starting block, or 0 for no preference */
207 SInt64 bytesRequested
, /* desired number of BYTES to allocate */
208 SInt64 bytesMaximum
, /* maximum number of bytes to allocate */
209 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
210 /* bytesRequested bytes to actually be allocated */
211 UInt32
*actualStartBlock
, /* actual first block of allocation */
212 UInt32
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
213 /* was zero, then this may represent fewer than bytesRequested */
217 UInt32 minBlocks
; // minimum number of allocation blocks requested
218 UInt32 maxBlocks
; // number of allocation blocks requested, rounded to clump size
219 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
222 // Initialize outputs in case we get an error
224 *actualStartBlock
= 0;
225 *actualNumBlocks
= 0;
228 // Compute the number of allocation blocks requested, and maximum
230 minBlocks
= FileBytesToBlocks(bytesRequested
, vcb
->blockSize
);
231 maxBlocks
= FileBytesToBlocks(bytesMaximum
, vcb
->blockSize
);
234 // If the disk is already full, don't bother.
236 if (hfs_freeblks(VCBTOHFS(vcb
), 0) == 0) {
240 if (forceContiguous
&& hfs_freeblks(VCBTOHFS(vcb
), 0) < minBlocks
) {
246 // If caller didn't specify a starting block number, then use the volume's
247 // next block to allocate from.
249 if (startingBlock
== 0) {
251 startingBlock
= vcb
->nextAllocation
;
253 updateAllocPtr
= true;
257 // If the request must be contiguous, then find a sequence of free blocks
258 // that is long enough. Otherwise, find the first free block.
260 if (forceContiguous
) {
261 err
= BlockAllocateContig(vcb
, startingBlock
, minBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
263 * If we allocated from a new position then
264 * also update the roving allocatior.
266 if ((err
== noErr
) && (*actualStartBlock
> startingBlock
))
267 vcb
->nextAllocation
= *actualStartBlock
;
270 * Scan the bitmap once, gather the N largest free extents, then
271 * allocate from these largest extents. Repeat as needed until
272 * we get all the space we needed. We could probably build up
273 * that list when the higher level caller tried (and failed) a
274 * contiguous allocation first.
276 err
= BlockAllocateKnown(vcb
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
277 if (err
== dskFulErr
)
278 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->totalBlocks
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
279 if (err
== dskFulErr
)
280 err
= BlockAllocateAny(vcb
, 0, startingBlock
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
285 // If we used the volume's roving allocation pointer, then we need to update it.
286 // Adding in the length of the current allocation might reduce the next allocate
287 // call by avoiding a re-scan of the already allocated space. However, the clump
288 // just allocated can quite conceivably end up being truncated or released when
289 // the file is closed or its EOF changed. Leaving the allocation pointer at the
290 // start of the last allocation will avoid unnecessary fragmentation in this case.
295 vcb
->nextAllocation
= *actualStartBlock
;
298 // Update the number of free blocks on the volume
300 vcb
->freeBlocks
-= *actualNumBlocks
;
313 ;________________________________________________________________________________
315 ; Routine: BlkDealloc
317 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
320 ; vcb - Pointer to ExtendedVCB for the volume to free space on
321 ; firstBlock - First allocation block to be freed
322 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
325 ; (result) - Result code
328 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
329 ;________________________________________________________________________________
332 OSErr
BlockDeallocate (
333 ExtendedVCB
*vcb
, // Which volume to deallocate space on
334 UInt32 firstBlock
, // First block in range to deallocate
335 UInt32 numBlocks
) // Number of contiguous blocks to deallocate
340 // If no blocks to deallocate, then exit early
342 if (numBlocks
== 0) {
348 // Call internal routine to free the sequence of blocks
350 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
355 // Update the volume's free block count, and mark the VCB as dirty.
358 vcb
->freeBlocks
+= numBlocks
;
359 if (vcb
->nextAllocation
== (firstBlock
+ numBlocks
))
360 vcb
->nextAllocation
-= numBlocks
;
371 ;_______________________________________________________________________
373 ; Routine: FileBytesToBlocks
375 ; Function: Divide numerator by denominator, rounding up the result if there
376 ; was a remainder. This is frequently used for computing the number
377 ; of whole and/or partial blocks used by some count of bytes.
378 ; Actuall divides a 64 bit by a 32 bit into a 32bit result
380 ; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
381 ;_______________________________________________________________________
383 UInt32
FileBytesToBlocks(
389 quotient
= (UInt32
)(numerator
/ denominator
);
390 if (quotient
* denominator
!= numerator
)
399 ;_______________________________________________________________________
401 ; Routine: ReadBitmapBlock
403 ; Function: Read in a bitmap block corresponding to a given allocation
404 ; block (bit). Return a pointer to the bitmap block.
407 ; vcb -- Pointer to ExtendedVCB
408 ; bit -- Allocation block whose bitmap block is desired
411 ; buffer -- Pointer to bitmap block corresonding to "block"
413 ;_______________________________________________________________________
415 static OSErr
ReadBitmapBlock(
422 struct buf
*bp
= NULL
;
423 struct vnode
*vp
= NULL
;
428 * volume bitmap blocks are protected by the Extents B-tree lock
430 REQUIRE_FILE_LOCK(vcb
->extentsRefNum
, false);
432 blockSize
= (UInt32
)vcb
->vcbVBMIOSize
;
433 block
= bit
/ (blockSize
* kBitsPerByte
);
435 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
436 vp
= vcb
->allocationsRefNum
; /* use allocation file vnode */
439 vp
= VCBTOHFS(vcb
)->hfs_devvp
; /* use device I/O vnode */
440 block
+= vcb
->vcbVBMSt
; /* map to physical block */
443 err
= meta_bread(vp
, block
, blockSize
, NOCRED
, &bp
);
451 *blockRef
= (UInt32
)bp
;
452 *buffer
= (UInt32
*)bp
->b_data
;
461 ;_______________________________________________________________________
463 ; Routine: ReleaseBitmapBlock
465 ; Function: Relase a bitmap block.
471 ;_______________________________________________________________________
473 static OSErr
ReleaseBitmapBlock(
478 struct buf
*bp
= (struct buf
*)blockRef
;
483 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
486 journal_modify_block_end(hfsmp
->jnl
, bp
);
500 _______________________________________________________________________
502 Routine: BlockAllocateContig
504 Function: Allocate a contiguous group of allocation blocks. The
505 allocation is all-or-nothing. The caller guarantees that
506 there are enough free blocks (though they may not be
507 contiguous, in which case this call will fail).
510 vcb Pointer to volume where space is to be allocated
511 startingBlock Preferred first block for allocation
512 minBlocks Minimum number of contiguous blocks to allocate
513 maxBlocks Maximum number of contiguous blocks to allocate
516 actualStartBlock First block of range allocated, or 0 if error
517 actualNumBlocks Number of blocks allocated, or 0 if error
518 _______________________________________________________________________
520 static OSErr
BlockAllocateContig(
522 UInt32 startingBlock
,
525 UInt32
*actualStartBlock
,
526 UInt32
*actualNumBlocks
)
531 // Find a contiguous group of blocks at least minBlocks long.
532 // Determine the number of contiguous blocks available (up
537 * NOTE: If the only contiguous free extent of at least minBlocks
538 * crosses startingBlock (i.e. starts before, ends after), then we
539 * won't find it. Earlier versions *did* find this case by letting
540 * the second search look past startingBlock by minBlocks. But
541 * with the free extent cache, this can lead to duplicate entries
542 * in the cache, causing the same blocks to be allocated twice.
544 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->totalBlocks
, minBlocks
, maxBlocks
,
545 actualStartBlock
, actualNumBlocks
);
546 if (err
== dskFulErr
&& startingBlock
!= 0) {
548 * Constrain the endingBlock so we don't bother looking for ranges
549 * that would overlap those found in the previous call.
551 err
= BlockFindContiguous(vcb
, 0, startingBlock
, minBlocks
, maxBlocks
,
552 actualStartBlock
, actualNumBlocks
);
554 if (err
!= noErr
) goto Exit
;
557 // Now mark those blocks allocated.
559 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
563 *actualStartBlock
= 0;
564 *actualNumBlocks
= 0;
571 _______________________________________________________________________
573 Routine: BlockAllocateAny
575 Function: Allocate one or more allocation blocks. If there are fewer
576 free blocks than requested, all free blocks will be
577 allocated. The caller guarantees that there is at least
581 vcb Pointer to volume where space is to be allocated
582 startingBlock Preferred first block for allocation
583 endingBlock Last block to check + 1
584 maxBlocks Maximum number of contiguous blocks to allocate
587 actualStartBlock First block of range allocated, or 0 if error
588 actualNumBlocks Number of blocks allocated, or 0 if error
589 _______________________________________________________________________
591 static OSErr
BlockAllocateAny(
593 UInt32 startingBlock
,
594 register UInt32 endingBlock
,
596 UInt32
*actualStartBlock
,
597 UInt32
*actualNumBlocks
)
600 register UInt32 block
; // current block number
601 register UInt32 currentWord
; // Pointer to current word within bitmap block
602 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
603 register UInt32 wordsLeft
; // Number of words left in this bitmap block
604 UInt32
*buffer
= NULL
;
605 UInt32
*currCache
= NULL
;
608 UInt32 wordsPerBlock
;
609 Boolean dirty
= false;
610 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
612 // Since this routine doesn't wrap around
613 if (maxBlocks
> (endingBlock
- startingBlock
)) {
614 maxBlocks
= endingBlock
- startingBlock
;
618 // Pre-read the first bitmap block
620 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
, &blockRef
);
621 if (err
!= noErr
) goto Exit
;
625 // Set up the current position within the block
628 UInt32 wordIndexInBlock
;
630 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
631 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
633 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
634 buffer
+= wordIndexInBlock
;
635 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
636 currentWord
= SWAP_BE32 (*buffer
);
637 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
641 // Find the first unallocated block
644 while (block
< endingBlock
) {
645 if ((currentWord
& bitMask
) == 0)
653 bitMask
= kHighBitInWordMask
;
656 if (--wordsLeft
== 0) {
658 buffer
= currCache
= NULL
;
659 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
660 if (err
!= noErr
) goto Exit
;
662 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
663 if (err
!= noErr
) goto Exit
;
666 wordsLeft
= wordsPerBlock
;
669 currentWord
= SWAP_BE32 (*buffer
);
673 // Did we get to the end of the bitmap before finding a free block?
674 // If so, then couldn't allocate anything.
675 if (block
== endingBlock
) {
680 // Return the first block in the allocated range
681 *actualStartBlock
= block
;
684 // If we could get the desired number of blocks before hitting endingBlock,
685 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
686 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
687 // comparison below yields identical results, but without overflow.
688 if (block
< (endingBlock
-maxBlocks
)) {
689 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
694 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
698 // Allocate all of the consecutive blocks
700 while ((currentWord
& bitMask
) == 0) {
701 // Allocate this block
702 currentWord
|= bitMask
;
704 // Move to the next block. If no more, then exit.
706 if (block
== endingBlock
)
712 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
715 bitMask
= kHighBitInWordMask
;
718 if (--wordsLeft
== 0) {
720 buffer
= currCache
= NULL
;
721 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
722 if (err
!= noErr
) goto Exit
;
724 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
725 if (err
!= noErr
) goto Exit
;
730 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
733 wordsLeft
= wordsPerBlock
;
736 currentWord
= SWAP_BE32 (*buffer
);
739 *buffer
= SWAP_BE32 (currentWord
); // update the last change
743 *actualNumBlocks
= block
- *actualStartBlock
;
746 *actualStartBlock
= 0;
747 *actualNumBlocks
= 0;
751 (void) ReleaseBitmapBlock(vcb
, blockRef
, dirty
);
758 _______________________________________________________________________
760 Routine: BlockAllocateKnown
762 Function: Try to allocate space from known free space in the free
766 vcb Pointer to volume where space is to be allocated
767 maxBlocks Maximum number of contiguous blocks to allocate
770 actualStartBlock First block of range allocated, or 0 if error
771 actualNumBlocks Number of blocks allocated, or 0 if error
774 dskFulErr Free extent cache is empty
775 _______________________________________________________________________
777 static OSErr
BlockAllocateKnown(
780 UInt32
*actualStartBlock
,
781 UInt32
*actualNumBlocks
)
785 UInt32 newStartBlock
, newBlockCount
;
787 if (vcb
->vcbFreeExtCnt
== 0)
790 // Just grab up to maxBlocks of the first (largest) free exent.
791 *actualStartBlock
= vcb
->vcbFreeExt
[0].startBlock
;
792 foundBlocks
= vcb
->vcbFreeExt
[0].blockCount
;
793 if (foundBlocks
> maxBlocks
)
794 foundBlocks
= maxBlocks
;
795 *actualNumBlocks
= foundBlocks
;
797 // Adjust the start and length of that extent.
798 newStartBlock
= vcb
->vcbFreeExt
[0].startBlock
+ foundBlocks
;
799 newBlockCount
= vcb
->vcbFreeExt
[0].blockCount
- foundBlocks
;
801 // The first extent might not be the largest anymore. Bubble up any
802 // (now larger) extents to the top of the list.
803 for (i
=1; i
<vcb
->vcbFreeExtCnt
; ++i
)
805 if (vcb
->vcbFreeExt
[i
].blockCount
> newBlockCount
)
807 vcb
->vcbFreeExt
[i
-1].startBlock
= vcb
->vcbFreeExt
[i
].startBlock
;
808 vcb
->vcbFreeExt
[i
-1].blockCount
= vcb
->vcbFreeExt
[i
].blockCount
;
816 // If this is now the smallest known free extent, then it might be smaller than
817 // other extents we didn't keep track of. So, just forget about this extent.
818 // After the previous loop, (i-1) is the index of the extent we just allocated from.
819 if (i
== vcb
->vcbFreeExtCnt
)
821 // It's now the smallest extent, so forget about it
822 --vcb
->vcbFreeExtCnt
;
826 // It's not the smallest, so store it in its proper place
827 vcb
->vcbFreeExt
[i
-1].startBlock
= newStartBlock
;
828 vcb
->vcbFreeExt
[i
-1].blockCount
= newBlockCount
;
832 // Now mark the found extent in the bitmap
834 return BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
840 _______________________________________________________________________
842 Routine: BlockMarkAllocated
844 Function: Mark a contiguous group of blocks as allocated (set in the
845 bitmap). It assumes those bits are currently marked
846 deallocated (clear in the bitmap).
849 vcb Pointer to volume where space is to be allocated
850 startingBlock First block number to mark as allocated
851 numBlocks Number of blocks to mark as allocated
852 _______________________________________________________________________
854 static OSErr
BlockMarkAllocated(
856 UInt32 startingBlock
,
857 register UInt32 numBlocks
)
860 register UInt32
*currentWord
; // Pointer to current word within bitmap block
861 register UInt32 wordsLeft
; // Number of words left in this bitmap block
862 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
863 UInt32 firstBit
; // Bit index within word of first bit to allocate
864 UInt32 numBits
; // Number of bits in word to allocate
865 UInt32
*buffer
= NULL
;
868 UInt32 wordsPerBlock
;
870 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
873 // Pre-read the bitmap block containing the first word of allocation
876 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
877 if (err
!= noErr
) goto Exit
;
879 // Initialize currentWord, and wordsLeft.
882 UInt32 wordIndexInBlock
;
884 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
885 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
887 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
888 currentWord
= buffer
+ wordIndexInBlock
;
889 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
894 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
898 // If the first block to allocate doesn't start on a word
899 // boundary in the bitmap, then treat that first word
903 firstBit
= startingBlock
% kBitsPerWord
;
905 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
906 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
907 if (numBits
> numBlocks
) {
908 numBits
= numBlocks
; // entire allocation is inside this one word
909 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
912 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
913 panic("BlockMarkAllocated: blocks already allocated!");
916 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
917 numBlocks
-= numBits
; // adjust number of blocks left to allocate
919 ++currentWord
; // move to next word
920 --wordsLeft
; // one less word left in this block
924 // Allocate whole words (32 blocks) at a time.
927 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
928 while (numBlocks
>= kBitsPerWord
) {
929 if (wordsLeft
== 0) {
930 // Read in the next bitmap block
931 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
934 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
935 if (err
!= noErr
) goto Exit
;
937 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
938 if (err
!= noErr
) goto Exit
;
942 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
945 // Readjust currentWord and wordsLeft
946 currentWord
= buffer
;
947 wordsLeft
= wordsPerBlock
;
950 if (*currentWord
!= 0) {
951 panic("BlockMarkAllocated: blocks already allocated!");
954 *currentWord
= SWAP_BE32 (bitMask
);
955 numBlocks
-= kBitsPerWord
;
957 ++currentWord
; // move to next word
958 --wordsLeft
; // one less word left in this block
962 // Allocate any remaining blocks.
965 if (numBlocks
!= 0) {
966 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
967 if (wordsLeft
== 0) {
968 // Read in the next bitmap block
969 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
972 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
973 if (err
!= noErr
) goto Exit
;
975 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
976 if (err
!= noErr
) goto Exit
;
980 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
983 // Readjust currentWord and wordsLeft
984 currentWord
= buffer
;
985 wordsLeft
= wordsPerBlock
;
988 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
989 panic("BlockMarkAllocated: blocks already allocated!");
992 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
994 // No need to update currentWord or wordsLeft
1000 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1007 _______________________________________________________________________
1009 Routine: BlockMarkFree
1011 Function: Mark a contiguous group of blocks as free (clear in the
1012 bitmap). It assumes those bits are currently marked
1013 allocated (set in the bitmap).
1016 vcb Pointer to volume where space is to be freed
1017 startingBlock First block number to mark as freed
1018 numBlocks Number of blocks to mark as freed
1019 _______________________________________________________________________
1021 static OSErr
BlockMarkFree(
1023 UInt32 startingBlock
,
1024 register UInt32 numBlocks
)
1027 register UInt32
*currentWord
; // Pointer to current word within bitmap block
1028 register UInt32 wordsLeft
; // Number of words left in this bitmap block
1029 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
1030 UInt32 firstBit
; // Bit index within word of first bit to allocate
1031 UInt32 numBits
; // Number of bits in word to allocate
1032 UInt32
*buffer
= NULL
;
1034 UInt32 bitsPerBlock
;
1035 UInt32 wordsPerBlock
;
1037 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
1040 // Pre-read the bitmap block containing the first word of allocation
1043 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1044 if (err
!= noErr
) goto Exit
;
1047 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1051 // Initialize currentWord, and wordsLeft.
1054 UInt32 wordIndexInBlock
;
1056 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1057 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1059 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1060 currentWord
= buffer
+ wordIndexInBlock
;
1061 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1065 // If the first block to free doesn't start on a word
1066 // boundary in the bitmap, then treat that first word
1070 firstBit
= startingBlock
% kBitsPerWord
;
1071 if (firstBit
!= 0) {
1072 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1073 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1074 if (numBits
> numBlocks
) {
1075 numBits
= numBlocks
; // entire allocation is inside this one word
1076 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1079 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1080 panic("BlockMarkFree: blocks not allocated!");
1083 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1084 numBlocks
-= numBits
; // adjust number of blocks left to free
1086 ++currentWord
; // move to next word
1087 --wordsLeft
; // one less word left in this block
1091 // Free whole words (32 blocks) at a time.
1094 while (numBlocks
>= kBitsPerWord
) {
1095 if (wordsLeft
== 0) {
1096 // Read in the next bitmap block
1097 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1100 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1101 if (err
!= noErr
) goto Exit
;
1103 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1104 if (err
!= noErr
) goto Exit
;
1108 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1111 // Readjust currentWord and wordsLeft
1112 currentWord
= buffer
;
1113 wordsLeft
= wordsPerBlock
;
1117 if (*currentWord
!= SWAP_BE32 (kAllBitsSetInWord
)) {
1118 panic("BlockMarkFree: blocks not allocated!");
1121 *currentWord
= 0; // clear the entire word
1122 numBlocks
-= kBitsPerWord
;
1124 ++currentWord
; // move to next word
1125 --wordsLeft
; // one less word left in this block
1129 // Free any remaining blocks.
1132 if (numBlocks
!= 0) {
1133 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1134 if (wordsLeft
== 0) {
1135 // Read in the next bitmap block
1136 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1139 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1140 if (err
!= noErr
) goto Exit
;
1142 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1143 if (err
!= noErr
) goto Exit
;
1147 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1150 // Readjust currentWord and wordsLeft
1151 currentWord
= buffer
;
1152 wordsLeft
= wordsPerBlock
;
1155 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1156 panic("BlockMarkFree: blocks not allocated!");
1159 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1161 // No need to update currentWord or wordsLeft
1167 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1174 _______________________________________________________________________
1176 Routine: BlockFindContiguous
1178 Function: Find a contiguous range of blocks that are free (bits
1179 clear in the bitmap). If a contiguous range of the
1180 minimum size can't be found, an error will be returned.
1183 vcb Pointer to volume where space is to be allocated
1184 startingBlock Preferred first block of range
1185 endingBlock Last possible block in range + 1
1186 minBlocks Minimum number of blocks needed. Must be > 0.
1187 maxBlocks Maximum (ideal) number of blocks desired
1190 actualStartBlock First block of range found, or 0 if error
1191 actualNumBlocks Number of blocks found, or 0 if error
1194 noErr Found at least minBlocks contiguous
1195 dskFulErr No contiguous space found, or all less than minBlocks
1196 _______________________________________________________________________
1199 static OSErr
BlockFindContiguous(
1201 UInt32 startingBlock
,
1205 UInt32
*actualStartBlock
,
1206 UInt32
*actualNumBlocks
)
1209 register UInt32 currentBlock
; // Block we're currently looking at.
1210 UInt32 firstBlock
; // First free block in current extent.
1211 UInt32 stopBlock
; // If we get to this block, stop searching for first free block.
1212 UInt32 foundBlocks
; // Number of contiguous free blocks in current extent.
1213 UInt32
*buffer
= NULL
;
1214 register UInt32
*currentWord
;
1215 register UInt32 bitMask
;
1216 register UInt32 wordsLeft
;
1217 register UInt32 tempWord
;
1219 UInt32 wordsPerBlock
;
1221 if ((endingBlock
- startingBlock
) < minBlocks
)
1223 // The set of blocks we're checking is smaller than the minimum number
1224 // of blocks, so we couldn't possibly find a good range.
1228 stopBlock
= endingBlock
- minBlocks
+ 1;
1229 currentBlock
= startingBlock
;
1233 // Pre-read the first bitmap block.
1235 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1236 if ( err
!= noErr
) goto ErrorExit
;
1239 // Figure out where currentBlock is within the buffer.
1241 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1243 wordsLeft
= (startingBlock
/ kBitsPerWord
) & (wordsPerBlock
-1); // Current index into buffer
1244 currentWord
= buffer
+ wordsLeft
;
1245 wordsLeft
= wordsPerBlock
- wordsLeft
;
1251 //============================================================
1252 // Look for a free block, skipping over allocated blocks.
1253 //============================================================
1256 // Check an initial partial word (if any)
1258 bitMask
= currentBlock
& kBitsWithinWordMask
;
1261 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1262 bitMask
= kHighBitInWordMask
>> bitMask
;
1263 while (tempWord
& bitMask
)
1269 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1273 // Didn't find any unused bits, so we're done with this word.
1279 // Check whole words
1281 while (currentBlock
< stopBlock
)
1283 // See if it's time to read another block.
1287 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1288 if (err
!= noErr
) goto ErrorExit
;
1290 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1291 if ( err
!= noErr
) goto ErrorExit
;
1293 currentWord
= buffer
;
1294 wordsLeft
= wordsPerBlock
;
1297 // See if any of the bits are clear
1298 if ((tempWord
= SWAP_BE32(*currentWord
)) + 1) // non-zero if any bits were clear
1300 // Figure out which bit is clear
1301 bitMask
= kHighBitInWordMask
;
1302 while (tempWord
& bitMask
)
1308 break; // Found the free bit; break out to FoundUnused.
1311 // Keep looking at the next word
1312 currentBlock
+= kBitsPerWord
;
1318 // Make sure the unused bit is early enough to use
1319 if (currentBlock
>= stopBlock
)
1324 // Remember the start of the extent
1325 firstBlock
= currentBlock
;
1327 //============================================================
1328 // Count the number of contiguous free blocks.
1329 //============================================================
1332 // Check an initial partial word (if any)
1334 bitMask
= currentBlock
& kBitsWithinWordMask
;
1337 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1338 bitMask
= kHighBitInWordMask
>> bitMask
;
1339 while (bitMask
&& !(tempWord
& bitMask
))
1345 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1349 // Didn't find any used bits, so we're done with this word.
1355 // Check whole words
1357 while (currentBlock
< endingBlock
)
1359 // See if it's time to read another block.
1363 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1364 if (err
!= noErr
) goto ErrorExit
;
1366 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1367 if ( err
!= noErr
) goto ErrorExit
;
1369 currentWord
= buffer
;
1370 wordsLeft
= wordsPerBlock
;
1373 // See if any of the bits are set
1374 if ((tempWord
= SWAP_BE32(*currentWord
)) != 0)
1376 // Figure out which bit is set
1377 bitMask
= kHighBitInWordMask
;
1378 while (!(tempWord
& bitMask
))
1384 break; // Found the used bit; break out to FoundUsed.
1387 // Keep looking at the next word
1388 currentBlock
+= kBitsPerWord
;
1392 // If we found at least maxBlocks, we can quit early.
1393 if ((currentBlock
- firstBlock
) >= maxBlocks
)
1398 // Make sure we didn't run out of bitmap looking for a used block.
1399 // If so, pin to the end of the bitmap.
1400 if (currentBlock
> endingBlock
)
1401 currentBlock
= endingBlock
;
1403 // Figure out how many contiguous free blocks there were.
1404 // Pin the answer to maxBlocks.
1405 foundBlocks
= currentBlock
- firstBlock
;
1406 if (foundBlocks
> maxBlocks
)
1407 foundBlocks
= maxBlocks
;
1408 if (foundBlocks
>= minBlocks
)
1409 break; // Found what we needed!
1411 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1412 // the allocation wasn't forced contiguous.
1413 tempWord
= vcb
->vcbFreeExtCnt
;
1414 if (tempWord
== kMaxFreeExtents
&& vcb
->vcbFreeExt
[kMaxFreeExtents
-1].blockCount
< foundBlocks
)
1416 if (tempWord
< kMaxFreeExtents
)
1418 // We're going to add this extent. Bubble any smaller extents down in the list.
1419 while (tempWord
&& vcb
->vcbFreeExt
[tempWord
-1].blockCount
< foundBlocks
)
1421 vcb
->vcbFreeExt
[tempWord
] = vcb
->vcbFreeExt
[tempWord
-1];
1424 vcb
->vcbFreeExt
[tempWord
].startBlock
= firstBlock
;
1425 vcb
->vcbFreeExt
[tempWord
].blockCount
= foundBlocks
;
1427 if (vcb
->vcbFreeExtCnt
< kMaxFreeExtents
)
1428 ++vcb
->vcbFreeExtCnt
;
1430 } while (currentBlock
< stopBlock
);
1433 // Return the outputs.
1434 if (foundBlocks
< minBlocks
)
1439 *actualStartBlock
= 0;
1440 *actualNumBlocks
= 0;
1445 *actualStartBlock
= firstBlock
;
1446 *actualNumBlocks
= foundBlocks
;
1450 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);