2 * Copyright (c) 2000-2003 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
,
125 UInt32
*actualStartBlock
,
126 UInt32
*actualNumBlocks
);
128 static OSErr
BlockAllocateContig(
130 UInt32 startingBlock
,
134 UInt32
*actualStartBlock
,
135 UInt32
*actualNumBlocks
);
137 static OSErr
BlockFindContiguous(
139 UInt32 startingBlock
,
144 UInt32
*actualStartBlock
,
145 UInt32
*actualNumBlocks
);
147 static OSErr
BlockAllocateKnown(
150 UInt32
*actualStartBlock
,
151 UInt32
*actualNumBlocks
);
155 ;________________________________________________________________________________
159 ; Function: Allocate space on a volume. If contiguous allocation is requested,
160 ; at least the requested number of bytes will be allocated or an
161 ; error will be returned. If contiguous allocation is not forced,
162 ; the space will be allocated at the first free fragment following
163 ; the requested starting allocation block. If there is not enough
164 ; room there, a block of less than the requested size will be
167 ; If the requested starting block is 0 (for new file allocations),
168 ; the volume's allocation block pointer will be used as a starting
172 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
173 ; fcb - Pointer to FCB for the file for which storage is being allocated
174 ; startingBlock - Preferred starting allocation block, 0 = no preference
175 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
176 ; or an error is returned
178 ; minBlocks - Number of blocks requested. If the allocation is non-contiguous,
179 ; less than this may actually be allocated
180 ; maxBlocks - The maximum number of blocks to allocate. If there is additional free
181 ; space after bytesRequested, then up to maxBlocks bytes should really
182 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
183 ; of the file's clump size.)
186 ; (result) - Error code, zero for successful allocation
187 ; *startBlock - Actual starting allocation block
188 ; *actualBlocks - Actual number of allocation blocks allocated
191 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
192 ;________________________________________________________________________________
196 OSErr
BlockAllocate (
197 ExtendedVCB
*vcb
, /* which volume to allocate space on */
198 UInt32 startingBlock
, /* preferred starting block, or 0 for no preference */
199 UInt32 minBlocks
, /* desired number of blocks to allocate */
200 UInt32 maxBlocks
, /* maximum number of blocks to allocate */
201 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
202 /* minBlocks bytes to actually be allocated */
205 UInt32
*actualStartBlock
, /* actual first block of allocation */
206 UInt32
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
207 /* was zero, then this may represent fewer than minBlocks */
211 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
214 // Initialize outputs in case we get an error
216 *actualStartBlock
= 0;
217 *actualNumBlocks
= 0;
218 freeBlocks
= hfs_freeblks(VCBTOHFS(vcb
), 0);
221 // If the disk is already full, don't bother.
223 if (freeBlocks
== 0) {
227 if (forceContiguous
&& freeBlocks
< minBlocks
) {
232 * Clip if necessary so we don't over-subscribe the free blocks.
234 if (minBlocks
> freeBlocks
) {
235 minBlocks
= freeBlocks
;
237 if (maxBlocks
> freeBlocks
) {
238 maxBlocks
= freeBlocks
;
242 // If caller didn't specify a starting block number, then use the volume's
243 // next block to allocate from.
245 if (startingBlock
== 0) {
247 startingBlock
= vcb
->nextAllocation
;
249 updateAllocPtr
= true;
251 if (startingBlock
>= vcb
->totalBlocks
) {
252 startingBlock
= 0; /* overflow so start at beginning */
256 // If the request must be contiguous, then find a sequence of free blocks
257 // that is long enough. Otherwise, find the first free block.
259 if (forceContiguous
) {
260 err
= BlockAllocateContig(vcb
, startingBlock
, minBlocks
, maxBlocks
,
261 useMetaZone
, actualStartBlock
, actualNumBlocks
);
263 * If we allocated from a new position then
264 * also update the roving allocatior.
266 if ((err
== noErr
) &&
267 (*actualStartBlock
> startingBlock
) &&
268 ((*actualStartBlock
< VCBTOHFS(vcb
)->hfs_metazone_start
) ||
269 (*actualStartBlock
> VCBTOHFS(vcb
)->hfs_metazone_end
))) {
270 vcb
->nextAllocation
= *actualStartBlock
; /* XXX */
274 * Scan the bitmap once, gather the N largest free extents, then
275 * allocate from these largest extents. Repeat as needed until
276 * we get all the space we needed. We could probably build up
277 * that list when the higher level caller tried (and failed) a
278 * contiguous allocation first.
280 err
= BlockAllocateKnown(vcb
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
281 if (err
== dskFulErr
)
282 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->totalBlocks
,
283 maxBlocks
, useMetaZone
, actualStartBlock
,
285 if (err
== dskFulErr
)
286 err
= BlockAllocateAny(vcb
, 1, startingBlock
, maxBlocks
,
287 useMetaZone
, actualStartBlock
,
293 // If we used the volume's roving allocation pointer, then we need to update it.
294 // Adding in the length of the current allocation might reduce the next allocate
295 // call by avoiding a re-scan of the already allocated space. However, the clump
296 // just allocated can quite conceivably end up being truncated or released when
297 // the file is closed or its EOF changed. Leaving the allocation pointer at the
298 // start of the last allocation will avoid unnecessary fragmentation in this case.
302 if (updateAllocPtr
&&
303 ((*actualStartBlock
< VCBTOHFS(vcb
)->hfs_metazone_start
) ||
304 (*actualStartBlock
> VCBTOHFS(vcb
)->hfs_metazone_end
))) {
305 vcb
->nextAllocation
= *actualStartBlock
;
308 // Update the number of free blocks on the volume
310 vcb
->freeBlocks
-= *actualNumBlocks
;
311 hfs_generate_volume_notifications(VCBTOHFS(vcb
));
324 ;________________________________________________________________________________
326 ; Routine: BlkDealloc
328 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
331 ; vcb - Pointer to ExtendedVCB for the volume to free space on
332 ; firstBlock - First allocation block to be freed
333 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
336 ; (result) - Result code
339 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
340 ;________________________________________________________________________________
344 OSErr
BlockDeallocate (
345 ExtendedVCB
*vcb
, // Which volume to deallocate space on
346 UInt32 firstBlock
, // First block in range to deallocate
347 UInt32 numBlocks
) // Number of contiguous blocks to deallocate
352 // If no blocks to deallocate, then exit early
354 if (numBlocks
== 0) {
360 // Call internal routine to free the sequence of blocks
362 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
367 // Update the volume's free block count, and mark the VCB as dirty.
370 vcb
->freeBlocks
+= numBlocks
;
371 hfs_generate_volume_notifications(VCBTOHFS(vcb
));
372 if (vcb
->nextAllocation
== (firstBlock
+ numBlocks
))
373 vcb
->nextAllocation
-= numBlocks
;
383 UInt8 freebitcount
[16] = {
384 4, 3, 3, 2, 3, 2, 2, 1, /* 0 1 2 3 4 5 6 7 */
385 3, 2, 2, 1, 2, 1, 1, 0, /* 8 9 A B C D E F */
390 MetaZoneFreeBlocks(ExtendedVCB
*vcb
)
402 bytesleft
= freeblocks
= 0;
403 bit
= VCBTOHFS(vcb
)->hfs_metazone_start
;
407 lastbit
= VCBTOHFS(vcb
)->hfs_metazone_end
;
408 bytesperblock
= vcb
->vcbVBMIOSize
;
411 * Count all the bits from bit to lastbit.
413 while (bit
< lastbit
) {
415 * Get next bitmap block.
417 if (bytesleft
== 0) {
419 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);
422 if (ReadBitmapBlock(vcb
, bit
, &currCache
, &blockRef
) != 0) {
425 buffer
= (UInt8
*)currCache
;
426 bytesleft
= bytesperblock
;
429 freeblocks
+= freebitcount
[byte
& 0x0F];
430 freeblocks
+= freebitcount
[(byte
>> 4) & 0x0F];
435 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);
442 * Obtain the next allocation block (bit) that's
443 * outside the metadata allocation zone.
445 static UInt32
NextBitmapBlock(
449 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
451 if ((hfsmp
->hfs_flags
& HFS_METADATA_ZONE
) == 0)
454 * Skip over metadata allocation zone.
456 if ((bit
>= hfsmp
->hfs_metazone_start
) &&
457 (bit
<= hfsmp
->hfs_metazone_end
)) {
458 bit
= hfsmp
->hfs_metazone_end
+ 1;
465 ;_______________________________________________________________________
467 ; Routine: ReadBitmapBlock
469 ; Function: Read in a bitmap block corresponding to a given allocation
470 ; block (bit). Return a pointer to the bitmap block.
473 ; vcb -- Pointer to ExtendedVCB
474 ; bit -- Allocation block whose bitmap block is desired
477 ; buffer -- Pointer to bitmap block corresonding to "block"
479 ;_______________________________________________________________________
481 static OSErr
ReadBitmapBlock(
488 struct buf
*bp
= NULL
;
489 struct vnode
*vp
= NULL
;
494 * volume bitmap blocks are protected by the Extents B-tree lock
496 REQUIRE_FILE_LOCK(vcb
->extentsRefNum
, false);
498 blockSize
= (UInt32
)vcb
->vcbVBMIOSize
;
499 block
= bit
/ (blockSize
* kBitsPerByte
);
501 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
502 vp
= vcb
->allocationsRefNum
; /* use allocation file vnode */
505 vp
= VCBTOHFS(vcb
)->hfs_devvp
; /* use device I/O vnode */
506 block
+= vcb
->vcbVBMSt
; /* map to physical block */
509 err
= meta_bread(vp
, block
, blockSize
, NOCRED
, &bp
);
517 *blockRef
= (UInt32
)bp
;
518 *buffer
= (UInt32
*)bp
->b_data
;
527 ;_______________________________________________________________________
529 ; Routine: ReleaseBitmapBlock
531 ; Function: Relase a bitmap block.
537 ;_______________________________________________________________________
539 static OSErr
ReleaseBitmapBlock(
544 struct buf
*bp
= (struct buf
*)blockRef
;
548 panic("ReleaseBitmapBlock: missing bp");
555 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
558 journal_modify_block_end(hfsmp
->jnl
, bp
);
572 _______________________________________________________________________
574 Routine: BlockAllocateContig
576 Function: Allocate a contiguous group of allocation blocks. The
577 allocation is all-or-nothing. The caller guarantees that
578 there are enough free blocks (though they may not be
579 contiguous, in which case this call will fail).
582 vcb Pointer to volume where space is to be allocated
583 startingBlock Preferred first block for allocation
584 minBlocks Minimum number of contiguous blocks to allocate
585 maxBlocks Maximum number of contiguous blocks to allocate
589 actualStartBlock First block of range allocated, or 0 if error
590 actualNumBlocks Number of blocks allocated, or 0 if error
591 _______________________________________________________________________
593 static OSErr
BlockAllocateContig(
595 UInt32 startingBlock
,
599 UInt32
*actualStartBlock
,
600 UInt32
*actualNumBlocks
)
605 // Find a contiguous group of blocks at least minBlocks long.
606 // Determine the number of contiguous blocks available (up
611 * NOTE: If the only contiguous free extent of at least minBlocks
612 * crosses startingBlock (i.e. starts before, ends after), then we
613 * won't find it. Earlier versions *did* find this case by letting
614 * the second search look past startingBlock by minBlocks. But
615 * with the free extent cache, this can lead to duplicate entries
616 * in the cache, causing the same blocks to be allocated twice.
618 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->totalBlocks
, minBlocks
,
619 maxBlocks
, useMetaZone
, actualStartBlock
, actualNumBlocks
);
620 if (err
== dskFulErr
&& startingBlock
!= 0) {
622 * Constrain the endingBlock so we don't bother looking for ranges
623 * that would overlap those found in the previous call.
625 err
= BlockFindContiguous(vcb
, 1, startingBlock
, minBlocks
, maxBlocks
,
626 useMetaZone
, actualStartBlock
, actualNumBlocks
);
628 if (err
!= noErr
) goto Exit
;
631 if ((*actualStartBlock
+ *actualNumBlocks
) > vcb
->totalBlocks
)
632 panic("BlockAllocateContig: allocation overflow on \"%s\"", vcb
->vcbVN
);
635 // Now mark those blocks allocated.
637 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
641 *actualStartBlock
= 0;
642 *actualNumBlocks
= 0;
649 _______________________________________________________________________
651 Routine: BlockAllocateAny
653 Function: Allocate one or more allocation blocks. If there are fewer
654 free blocks than requested, all free blocks will be
655 allocated. The caller guarantees that there is at least
659 vcb Pointer to volume where space is to be allocated
660 startingBlock Preferred first block for allocation
661 endingBlock Last block to check + 1
662 maxBlocks Maximum number of contiguous blocks to allocate
666 actualStartBlock First block of range allocated, or 0 if error
667 actualNumBlocks Number of blocks allocated, or 0 if error
668 _______________________________________________________________________
670 static OSErr
BlockAllocateAny(
672 UInt32 startingBlock
,
673 register UInt32 endingBlock
,
676 UInt32
*actualStartBlock
,
677 UInt32
*actualNumBlocks
)
680 register UInt32 block
; // current block number
681 register UInt32 currentWord
; // Pointer to current word within bitmap block
682 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
683 register UInt32 wordsLeft
; // Number of words left in this bitmap block
684 UInt32
*buffer
= NULL
;
685 UInt32
*currCache
= NULL
;
688 UInt32 wordsPerBlock
;
689 Boolean dirty
= false;
690 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
692 // Since this routine doesn't wrap around
693 if (maxBlocks
> (endingBlock
- startingBlock
)) {
694 maxBlocks
= endingBlock
- startingBlock
;
698 * Skip over metadata blocks.
701 startingBlock
= NextBitmapBlock(vcb
, startingBlock
);
704 // Pre-read the first bitmap block
706 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
, &blockRef
);
707 if (err
!= noErr
) goto Exit
;
711 // Set up the current position within the block
714 UInt32 wordIndexInBlock
;
716 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
717 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
719 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
720 buffer
+= wordIndexInBlock
;
721 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
722 currentWord
= SWAP_BE32 (*buffer
);
723 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
727 // Find the first unallocated block
730 while (block
< endingBlock
) {
731 if ((currentWord
& bitMask
) == 0)
739 bitMask
= kHighBitInWordMask
;
742 if (--wordsLeft
== 0) {
744 buffer
= currCache
= NULL
;
745 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
746 if (err
!= noErr
) goto Exit
;
749 * Skip over metadata blocks.
752 block
= NextBitmapBlock(vcb
, block
);
753 if (block
>= endingBlock
) {
758 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
759 if (err
!= noErr
) goto Exit
;
762 wordsLeft
= wordsPerBlock
;
764 currentWord
= SWAP_BE32 (*buffer
);
768 // Did we get to the end of the bitmap before finding a free block?
769 // If so, then couldn't allocate anything.
770 if (block
>= endingBlock
) {
775 // Return the first block in the allocated range
776 *actualStartBlock
= block
;
779 // If we could get the desired number of blocks before hitting endingBlock,
780 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
781 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
782 // comparison below yields identical results, but without overflow.
783 if (block
< (endingBlock
-maxBlocks
)) {
784 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
789 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
793 // Allocate all of the consecutive blocks
795 while ((currentWord
& bitMask
) == 0) {
796 // Allocate this block
797 currentWord
|= bitMask
;
799 // Move to the next block. If no more, then exit.
801 if (block
== endingBlock
)
807 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
810 bitMask
= kHighBitInWordMask
;
813 if (--wordsLeft
== 0) {
815 buffer
= currCache
= NULL
;
816 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
817 if (err
!= noErr
) goto Exit
;
820 * Skip over metadata blocks.
825 nextBlock
= NextBitmapBlock(vcb
, block
);
826 if (nextBlock
!= block
) {
827 goto Exit
; /* allocation gap, so stop */
831 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
832 if (err
!= noErr
) goto Exit
;
837 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
840 wordsLeft
= wordsPerBlock
;
843 currentWord
= SWAP_BE32 (*buffer
);
846 *buffer
= SWAP_BE32 (currentWord
); // update the last change
850 *actualNumBlocks
= block
- *actualStartBlock
;
853 if ((*actualStartBlock
+ *actualNumBlocks
) > vcb
->totalBlocks
)
854 panic("BlockAllocateAny: allocation overflow on \"%s\"", vcb
->vcbVN
);
857 *actualStartBlock
= 0;
858 *actualNumBlocks
= 0;
862 (void) ReleaseBitmapBlock(vcb
, blockRef
, dirty
);
869 _______________________________________________________________________
871 Routine: BlockAllocateKnown
873 Function: Try to allocate space from known free space in the free
877 vcb Pointer to volume where space is to be allocated
878 maxBlocks Maximum number of contiguous blocks to allocate
881 actualStartBlock First block of range allocated, or 0 if error
882 actualNumBlocks Number of blocks allocated, or 0 if error
885 dskFulErr Free extent cache is empty
886 _______________________________________________________________________
888 static OSErr
BlockAllocateKnown(
891 UInt32
*actualStartBlock
,
892 UInt32
*actualNumBlocks
)
896 UInt32 newStartBlock
, newBlockCount
;
898 if (vcb
->vcbFreeExtCnt
== 0)
901 // Just grab up to maxBlocks of the first (largest) free exent.
902 *actualStartBlock
= vcb
->vcbFreeExt
[0].startBlock
;
903 foundBlocks
= vcb
->vcbFreeExt
[0].blockCount
;
904 if (foundBlocks
> maxBlocks
)
905 foundBlocks
= maxBlocks
;
906 *actualNumBlocks
= foundBlocks
;
908 // Adjust the start and length of that extent.
909 newStartBlock
= vcb
->vcbFreeExt
[0].startBlock
+ foundBlocks
;
910 newBlockCount
= vcb
->vcbFreeExt
[0].blockCount
- foundBlocks
;
912 // The first extent might not be the largest anymore. Bubble up any
913 // (now larger) extents to the top of the list.
914 for (i
=1; i
<vcb
->vcbFreeExtCnt
; ++i
)
916 if (vcb
->vcbFreeExt
[i
].blockCount
> newBlockCount
)
918 vcb
->vcbFreeExt
[i
-1].startBlock
= vcb
->vcbFreeExt
[i
].startBlock
;
919 vcb
->vcbFreeExt
[i
-1].blockCount
= vcb
->vcbFreeExt
[i
].blockCount
;
927 // If this is now the smallest known free extent, then it might be smaller than
928 // other extents we didn't keep track of. So, just forget about this extent.
929 // After the previous loop, (i-1) is the index of the extent we just allocated from.
930 if (i
== vcb
->vcbFreeExtCnt
)
932 // It's now the smallest extent, so forget about it
933 --vcb
->vcbFreeExtCnt
;
937 // It's not the smallest, so store it in its proper place
938 vcb
->vcbFreeExt
[i
-1].startBlock
= newStartBlock
;
939 vcb
->vcbFreeExt
[i
-1].blockCount
= newBlockCount
;
943 if ((*actualStartBlock
+ *actualNumBlocks
) > vcb
->totalBlocks
)
944 panic("BlockAllocateKnown: allocation overflow on \"%s\"", vcb
->vcbVN
);
947 // Now mark the found extent in the bitmap
949 return BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
955 _______________________________________________________________________
957 Routine: BlockMarkAllocated
959 Function: Mark a contiguous group of blocks as allocated (set in the
960 bitmap). It assumes those bits are currently marked
961 deallocated (clear in the bitmap).
964 vcb Pointer to volume where space is to be allocated
965 startingBlock First block number to mark as allocated
966 numBlocks Number of blocks to mark as allocated
967 _______________________________________________________________________
970 OSErr
BlockMarkAllocated(
972 UInt32 startingBlock
,
973 register UInt32 numBlocks
)
976 register UInt32
*currentWord
; // Pointer to current word within bitmap block
977 register UInt32 wordsLeft
; // Number of words left in this bitmap block
978 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
979 UInt32 firstBit
; // Bit index within word of first bit to allocate
980 UInt32 numBits
; // Number of bits in word to allocate
981 UInt32
*buffer
= NULL
;
984 UInt32 wordsPerBlock
;
986 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
990 // Pre-read the bitmap block containing the first word of allocation
993 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
994 if (err
!= noErr
) goto Exit
;
996 // Initialize currentWord, and wordsLeft.
999 UInt32 wordIndexInBlock
;
1001 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1002 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1004 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1005 currentWord
= buffer
+ wordIndexInBlock
;
1006 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1011 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1015 // If the first block to allocate doesn't start on a word
1016 // boundary in the bitmap, then treat that first word
1020 firstBit
= startingBlock
% kBitsPerWord
;
1021 if (firstBit
!= 0) {
1022 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1023 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1024 if (numBits
> numBlocks
) {
1025 numBits
= numBlocks
; // entire allocation is inside this one word
1026 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1029 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1030 panic("BlockMarkAllocated: blocks already allocated!");
1033 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1034 numBlocks
-= numBits
; // adjust number of blocks left to allocate
1036 ++currentWord
; // move to next word
1037 --wordsLeft
; // one less word left in this block
1041 // Allocate whole words (32 blocks) at a time.
1044 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
1045 while (numBlocks
>= kBitsPerWord
) {
1046 if (wordsLeft
== 0) {
1047 // Read in the next bitmap block
1048 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1051 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1052 if (err
!= noErr
) goto Exit
;
1054 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1055 if (err
!= noErr
) goto Exit
;
1059 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1062 // Readjust currentWord and wordsLeft
1063 currentWord
= buffer
;
1064 wordsLeft
= wordsPerBlock
;
1067 if (*currentWord
!= 0) {
1068 panic("BlockMarkAllocated: blocks already allocated!");
1071 *currentWord
= SWAP_BE32 (bitMask
);
1072 numBlocks
-= kBitsPerWord
;
1074 ++currentWord
; // move to next word
1075 --wordsLeft
; // one less word left in this block
1079 // Allocate 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
;
1097 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1100 // Readjust currentWord and wordsLeft
1101 currentWord
= buffer
;
1102 wordsLeft
= wordsPerBlock
;
1105 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1106 panic("BlockMarkAllocated: blocks already allocated!");
1109 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1111 // No need to update currentWord or wordsLeft
1117 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1124 _______________________________________________________________________
1126 Routine: BlockMarkFree
1128 Function: Mark a contiguous group of blocks as free (clear in the
1129 bitmap). It assumes those bits are currently marked
1130 allocated (set in the bitmap).
1133 vcb Pointer to volume where space is to be freed
1134 startingBlock First block number to mark as freed
1135 numBlocks Number of blocks to mark as freed
1136 _______________________________________________________________________
1139 OSErr
BlockMarkFree(
1141 UInt32 startingBlock
,
1142 register UInt32 numBlocks
)
1145 register UInt32
*currentWord
; // Pointer to current word within bitmap block
1146 register UInt32 wordsLeft
; // Number of words left in this bitmap block
1147 register UInt32 bitMask
; // Word with given bits already set (ready to OR in)
1148 UInt32 firstBit
; // Bit index within word of first bit to allocate
1149 UInt32 numBits
; // Number of bits in word to allocate
1150 UInt32
*buffer
= NULL
;
1152 UInt32 bitsPerBlock
;
1153 UInt32 wordsPerBlock
;
1155 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
1157 if (startingBlock
+ numBlocks
> vcb
->totalBlocks
) {
1158 panic("hfs: block mark free: trying to free non-existent blocks (%d %d %d)\n",
1159 startingBlock
, numBlocks
, vcb
->totalBlocks
);
1164 // Pre-read the bitmap block containing the first word of allocation
1167 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1168 if (err
!= noErr
) goto Exit
;
1171 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1175 // Initialize currentWord, and wordsLeft.
1178 UInt32 wordIndexInBlock
;
1180 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1181 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1183 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1184 currentWord
= buffer
+ wordIndexInBlock
;
1185 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1189 // If the first block to free doesn't start on a word
1190 // boundary in the bitmap, then treat that first word
1194 firstBit
= startingBlock
% kBitsPerWord
;
1195 if (firstBit
!= 0) {
1196 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1197 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1198 if (numBits
> numBlocks
) {
1199 numBits
= numBlocks
; // entire allocation is inside this one word
1200 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1202 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1205 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1206 numBlocks
-= numBits
; // adjust number of blocks left to free
1208 ++currentWord
; // move to next word
1209 --wordsLeft
; // one less word left in this block
1213 // Free whole words (32 blocks) at a time.
1216 while (numBlocks
>= kBitsPerWord
) {
1217 if (wordsLeft
== 0) {
1218 // Read in the next bitmap block
1219 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1222 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1223 if (err
!= noErr
) goto Exit
;
1225 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1226 if (err
!= noErr
) goto Exit
;
1230 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1233 // Readjust currentWord and wordsLeft
1234 currentWord
= buffer
;
1235 wordsLeft
= wordsPerBlock
;
1237 if (*currentWord
!= SWAP_BE32 (kAllBitsSetInWord
)) {
1240 *currentWord
= 0; // clear the entire word
1241 numBlocks
-= kBitsPerWord
;
1243 ++currentWord
; // move to next word
1244 --wordsLeft
; // one less word left in this block
1248 // Free any remaining blocks.
1251 if (numBlocks
!= 0) {
1252 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1253 if (wordsLeft
== 0) {
1254 // Read in the next bitmap block
1255 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1258 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1259 if (err
!= noErr
) goto Exit
;
1261 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1262 if (err
!= noErr
) goto Exit
;
1266 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1269 // Readjust currentWord and wordsLeft
1270 currentWord
= buffer
;
1271 wordsLeft
= wordsPerBlock
;
1273 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1276 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1278 // No need to update currentWord or wordsLeft
1284 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1290 panic("BlockMarkFree: blocks not allocated!");
1292 printf("hfs: WARNING - blocks on volume %s not allocated!\n", vcb
->vcbVN
);
1293 vcb
->vcbAtrb
|= kHFSVolumeInconsistentMask
;
1302 _______________________________________________________________________
1304 Routine: BlockFindContiguous
1306 Function: Find a contiguous range of blocks that are free (bits
1307 clear in the bitmap). If a contiguous range of the
1308 minimum size can't be found, an error will be returned.
1311 vcb Pointer to volume where space is to be allocated
1312 startingBlock Preferred first block of range
1313 endingBlock Last possible block in range + 1
1314 minBlocks Minimum number of blocks needed. Must be > 0.
1315 maxBlocks Maximum (ideal) number of blocks desired
1316 useMetaZone OK to dip into metadata allocation zone
1319 actualStartBlock First block of range found, or 0 if error
1320 actualNumBlocks Number of blocks found, or 0 if error
1323 noErr Found at least minBlocks contiguous
1324 dskFulErr No contiguous space found, or all less than minBlocks
1325 _______________________________________________________________________
1328 static OSErr
BlockFindContiguous(
1330 UInt32 startingBlock
,
1334 Boolean useMetaZone
,
1335 UInt32
*actualStartBlock
,
1336 UInt32
*actualNumBlocks
)
1339 register UInt32 currentBlock
; // Block we're currently looking at.
1340 UInt32 firstBlock
; // First free block in current extent.
1341 UInt32 stopBlock
; // If we get to this block, stop searching for first free block.
1342 UInt32 foundBlocks
; // Number of contiguous free blocks in current extent.
1343 UInt32
*buffer
= NULL
;
1344 register UInt32
*currentWord
;
1345 register UInt32 bitMask
;
1346 register UInt32 wordsLeft
;
1347 register UInt32 tempWord
;
1349 UInt32 wordsPerBlock
;
1351 if ((endingBlock
- startingBlock
) < minBlocks
)
1353 // The set of blocks we're checking is smaller than the minimum number
1354 // of blocks, so we couldn't possibly find a good range.
1358 stopBlock
= endingBlock
- minBlocks
+ 1;
1359 currentBlock
= startingBlock
;
1363 * Skip over metadata blocks.
1366 currentBlock
= NextBitmapBlock(vcb
, currentBlock
);
1369 // Pre-read the first bitmap block.
1371 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1372 if ( err
!= noErr
) goto ErrorExit
;
1375 // Figure out where currentBlock is within the buffer.
1377 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1379 wordsLeft
= (currentBlock
/ kBitsPerWord
) & (wordsPerBlock
-1); // Current index into buffer
1380 currentWord
= buffer
+ wordsLeft
;
1381 wordsLeft
= wordsPerBlock
- wordsLeft
;
1387 //============================================================
1388 // Look for a free block, skipping over allocated blocks.
1389 //============================================================
1392 // Check an initial partial word (if any)
1394 bitMask
= currentBlock
& kBitsWithinWordMask
;
1397 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1398 bitMask
= kHighBitInWordMask
>> bitMask
;
1399 while (tempWord
& bitMask
)
1405 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1409 // Didn't find any unused bits, so we're done with this word.
1415 // Check whole words
1417 while (currentBlock
< stopBlock
)
1419 // See if it's time to read another block.
1423 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1424 if (err
!= noErr
) goto ErrorExit
;
1427 * Skip over metadata blocks.
1430 currentBlock
= NextBitmapBlock(vcb
, currentBlock
);
1431 if (currentBlock
>= stopBlock
)
1435 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1436 if ( err
!= noErr
) goto ErrorExit
;
1438 currentWord
= buffer
;
1439 wordsLeft
= wordsPerBlock
;
1442 // See if any of the bits are clear
1443 if ((tempWord
= SWAP_BE32(*currentWord
)) + 1) // non-zero if any bits were clear
1445 // Figure out which bit is clear
1446 bitMask
= kHighBitInWordMask
;
1447 while (tempWord
& bitMask
)
1453 break; // Found the free bit; break out to FoundUnused.
1456 // Keep looking at the next word
1457 currentBlock
+= kBitsPerWord
;
1463 // Make sure the unused bit is early enough to use
1464 if (currentBlock
>= stopBlock
)
1469 // Remember the start of the extent
1470 firstBlock
= currentBlock
;
1472 //============================================================
1473 // Count the number of contiguous free blocks.
1474 //============================================================
1477 // Check an initial partial word (if any)
1479 bitMask
= currentBlock
& kBitsWithinWordMask
;
1482 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1483 bitMask
= kHighBitInWordMask
>> bitMask
;
1484 while (bitMask
&& !(tempWord
& bitMask
))
1490 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1494 // Didn't find any used bits, so we're done with this word.
1500 // Check whole words
1502 while (currentBlock
< endingBlock
)
1504 // See if it's time to read another block.
1508 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1509 if (err
!= noErr
) goto ErrorExit
;
1512 * Skip over metadata blocks.
1517 nextBlock
= NextBitmapBlock(vcb
, currentBlock
);
1518 if (nextBlock
!= currentBlock
) {
1519 break; /* allocation gap, so stop */
1523 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1524 if ( err
!= noErr
) goto ErrorExit
;
1526 currentWord
= buffer
;
1527 wordsLeft
= wordsPerBlock
;
1530 // See if any of the bits are set
1531 if ((tempWord
= SWAP_BE32(*currentWord
)) != 0)
1533 // Figure out which bit is set
1534 bitMask
= kHighBitInWordMask
;
1535 while (!(tempWord
& bitMask
))
1541 break; // Found the used bit; break out to FoundUsed.
1544 // Keep looking at the next word
1545 currentBlock
+= kBitsPerWord
;
1549 // If we found at least maxBlocks, we can quit early.
1550 if ((currentBlock
- firstBlock
) >= maxBlocks
)
1555 // Make sure we didn't run out of bitmap looking for a used block.
1556 // If so, pin to the end of the bitmap.
1557 if (currentBlock
> endingBlock
)
1558 currentBlock
= endingBlock
;
1560 // Figure out how many contiguous free blocks there were.
1561 // Pin the answer to maxBlocks.
1562 foundBlocks
= currentBlock
- firstBlock
;
1563 if (foundBlocks
> maxBlocks
)
1564 foundBlocks
= maxBlocks
;
1565 if (foundBlocks
>= minBlocks
)
1566 break; // Found what we needed!
1568 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1569 // the allocation wasn't forced contiguous.
1570 tempWord
= vcb
->vcbFreeExtCnt
;
1571 if (tempWord
== kMaxFreeExtents
&& vcb
->vcbFreeExt
[kMaxFreeExtents
-1].blockCount
< foundBlocks
)
1573 if (tempWord
< kMaxFreeExtents
)
1575 // We're going to add this extent. Bubble any smaller extents down in the list.
1576 while (tempWord
&& vcb
->vcbFreeExt
[tempWord
-1].blockCount
< foundBlocks
)
1578 vcb
->vcbFreeExt
[tempWord
] = vcb
->vcbFreeExt
[tempWord
-1];
1581 vcb
->vcbFreeExt
[tempWord
].startBlock
= firstBlock
;
1582 vcb
->vcbFreeExt
[tempWord
].blockCount
= foundBlocks
;
1584 if (vcb
->vcbFreeExtCnt
< kMaxFreeExtents
)
1585 ++vcb
->vcbFreeExtCnt
;
1587 } while (currentBlock
< stopBlock
);
1590 // Return the outputs.
1591 if (foundBlocks
< minBlocks
)
1596 *actualStartBlock
= 0;
1597 *actualNumBlocks
= 0;
1602 *actualStartBlock
= firstBlock
;
1603 *actualNumBlocks
= foundBlocks
;
1607 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);