2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 File: VolumeAllocation.c
31 Contains: Routines for accessing and modifying the volume bitmap.
35 Copyright: © 1996-2001 by Apple Computer, Inc., all rights reserved.
42 Allocate space on a volume. Can allocate space contiguously.
43 If not contiguous, then allocation may be less than what was
44 asked for. Returns the starting block number, and number of
45 blocks. (Will only do a single extent???)
47 Deallocate a contiguous run of allocation blocks.
52 Mark a contiguous range of blocks as free. The corresponding
53 bits in the volume bitmap will be cleared.
55 Mark a contiguous range of blocks as allocated. The cor-
56 responding bits in the volume bitmap are set. Also tests to see
57 if any of the blocks were previously unallocated.
59 Find a contiguous range of blocks of a given size. The caller
60 specifies where to begin the search (by block number). The
61 block number of the first block in the range is returned.
63 Find and allocate a contiguous range of blocks up to a given size. The
64 first range of contiguous free blocks found are allocated, even if there
65 are fewer blocks than requested (and even if a contiguous range of blocks
66 of the given size exists elsewhere).
68 Find and allocate a contiguous range of blocks of a given size. If
69 a contiguous range of free blocks of the given size isn't found, then
70 the allocation fails (i.e. it is "all or nothing").
73 Try to allocate space from known free space in the volume's
77 Given an allocation block number, read the bitmap block that
78 contains that allocation block into a caller-supplied buffer.
81 Release a bitmap block back into the buffer cache.
84 #include "../../hfs_macos_defs.h"
86 #include <sys/types.h>
88 #include <sys/systm.h>
91 #include "../../hfs.h"
92 #include "../../hfs_dbg.h"
93 #include "../../hfs_format.h"
94 #include "../../hfs_endian.h"
96 #include "../headers/FileMgrInternal.h"
104 kBitsWithinWordMask
= kBitsPerWord
-1
107 #define kLowBitInWordMask 0x00000001ul
108 #define kHighBitInWordMask 0x80000000ul
109 #define kAllBitsSetInWord 0xFFFFFFFFul
112 static OSErr
ReadBitmapBlock(
116 u_int32_t
*blockRef
);
118 static OSErr
ReleaseBitmapBlock(
123 static OSErr
BlockAllocateAny(
125 u_int32_t startingBlock
,
126 u_int32_t endingBlock
,
129 u_int32_t
*actualStartBlock
,
130 u_int32_t
*actualNumBlocks
);
132 static OSErr
BlockAllocateContig(
134 u_int32_t startingBlock
,
138 u_int32_t
*actualStartBlock
,
139 u_int32_t
*actualNumBlocks
);
141 static OSErr
BlockFindContiguous(
143 u_int32_t startingBlock
,
144 u_int32_t endingBlock
,
148 u_int32_t
*actualStartBlock
,
149 u_int32_t
*actualNumBlocks
);
151 static OSErr
BlockAllocateKnown(
154 u_int32_t
*actualStartBlock
,
155 u_int32_t
*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
176 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
177 ; fcb - Pointer to FCB for the file for which storage is being allocated
178 ; startingBlock - Preferred starting allocation block, 0 = no preference
179 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
180 ; or an error is returned
182 ; minBlocks - Number of blocks requested. If the allocation is non-contiguous,
183 ; less than this may actually be allocated
184 ; maxBlocks - The maximum number of blocks to allocate. If there is additional free
185 ; space after bytesRequested, then up to maxBlocks bytes should really
186 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
187 ; of the file's clump size.)
190 ; (result) - Error code, zero for successful allocation
191 ; *startBlock - Actual starting allocation block
192 ; *actualBlocks - Actual number of allocation blocks allocated
195 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
196 ;________________________________________________________________________________
200 OSErr
BlockAllocate (
201 ExtendedVCB
*vcb
, /* which volume to allocate space on */
202 u_int32_t startingBlock
, /* preferred starting block, or 0 for no preference */
203 u_int32_t minBlocks
, /* desired number of blocks to allocate */
204 u_int32_t maxBlocks
, /* maximum number of blocks to allocate */
205 Boolean forceContiguous
, /* non-zero to force contiguous allocation and to force */
206 /* minBlocks bytes to actually be allocated */
209 u_int32_t
*actualStartBlock
, /* actual first block of allocation */
210 u_int32_t
*actualNumBlocks
) /* number of blocks actually allocated; if forceContiguous */
211 /* was zero, then this may represent fewer than minBlocks */
213 u_int32_t freeBlocks
;
215 Boolean updateAllocPtr
= false; // true if nextAllocation needs to be updated
218 // Initialize outputs in case we get an error
220 *actualStartBlock
= 0;
221 *actualNumBlocks
= 0;
222 freeBlocks
= hfs_freeblks(VCBTOHFS(vcb
), 0);
225 // If the disk is already full, don't bother.
227 if (freeBlocks
== 0) {
231 if (forceContiguous
&& freeBlocks
< minBlocks
) {
236 * Clip if necessary so we don't over-subscribe the free blocks.
238 if (minBlocks
> freeBlocks
) {
239 minBlocks
= freeBlocks
;
241 if (maxBlocks
> freeBlocks
) {
242 maxBlocks
= freeBlocks
;
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) {
250 HFS_MOUNT_LOCK(vcb
, TRUE
);
251 startingBlock
= vcb
->nextAllocation
;
252 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
253 updateAllocPtr
= true;
255 if (startingBlock
>= vcb
->allocLimit
) {
256 startingBlock
= 0; /* overflow so start at beginning */
260 // If the request must be contiguous, then find a sequence of free blocks
261 // that is long enough. Otherwise, find the first free block.
263 if (forceContiguous
) {
264 err
= BlockAllocateContig(vcb
, startingBlock
, minBlocks
, maxBlocks
,
265 useMetaZone
, actualStartBlock
, actualNumBlocks
);
267 * If we allocated from a new position then
268 * also update the roving allocator.
270 if ((err
== noErr
) &&
271 (*actualStartBlock
> startingBlock
) &&
272 ((*actualStartBlock
< VCBTOHFS(vcb
)->hfs_metazone_start
) ||
273 (*actualStartBlock
> VCBTOHFS(vcb
)->hfs_metazone_end
))) {
274 HFS_MOUNT_LOCK(vcb
, TRUE
);
275 HFS_UPDATE_NEXT_ALLOCATION(vcb
, *actualStartBlock
);
276 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
280 * Scan the bitmap once, gather the N largest free extents, then
281 * allocate from these largest extents. Repeat as needed until
282 * we get all the space we needed. We could probably build up
283 * that list when the higher level caller tried (and failed) a
284 * contiguous allocation first.
286 err
= BlockAllocateKnown(vcb
, maxBlocks
, actualStartBlock
, actualNumBlocks
);
287 if (err
== dskFulErr
)
288 err
= BlockAllocateAny(vcb
, startingBlock
, vcb
->allocLimit
,
289 maxBlocks
, useMetaZone
, actualStartBlock
,
291 if (err
== dskFulErr
)
292 err
= BlockAllocateAny(vcb
, 1, startingBlock
, maxBlocks
,
293 useMetaZone
, actualStartBlock
,
298 // if we actually allocated something then go update the
299 // various bits of state that we maintain regardless of
300 // whether there was an error (i.e. partial allocations
301 // still need to update things like the free block count).
303 if (*actualNumBlocks
!= 0) {
305 // If we used the volume's roving allocation pointer, then we need to update it.
306 // Adding in the length of the current allocation might reduce the next allocate
307 // call by avoiding a re-scan of the already allocated space. However, the clump
308 // just allocated can quite conceivably end up being truncated or released when
309 // the file is closed or its EOF changed. Leaving the allocation pointer at the
310 // start of the last allocation will avoid unnecessary fragmentation in this case.
312 HFS_MOUNT_LOCK(vcb
, TRUE
);
314 if (updateAllocPtr
&&
315 ((*actualStartBlock
< VCBTOHFS(vcb
)->hfs_metazone_start
) ||
316 (*actualStartBlock
> VCBTOHFS(vcb
)->hfs_metazone_end
))) {
317 HFS_UPDATE_NEXT_ALLOCATION(vcb
, *actualStartBlock
);
320 // Update the number of free blocks on the volume
322 vcb
->freeBlocks
-= *actualNumBlocks
;
324 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
326 hfs_generate_volume_notifications(VCBTOHFS(vcb
));
334 ;________________________________________________________________________________
336 ; Routine: BlkDealloc
338 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
341 ; vcb - Pointer to ExtendedVCB for the volume to free space on
342 ; firstBlock - First allocation block to be freed
343 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
346 ; (result) - Result code
349 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
350 ;________________________________________________________________________________
354 OSErr
BlockDeallocate (
355 ExtendedVCB
*vcb
, // Which volume to deallocate space on
356 u_int32_t firstBlock
, // First block in range to deallocate
357 u_int32_t numBlocks
) // Number of contiguous blocks to deallocate
362 // If no blocks to deallocate, then exit early
364 if (numBlocks
== 0) {
370 // Call internal routine to free the sequence of blocks
372 err
= BlockMarkFree(vcb
, firstBlock
, numBlocks
);
377 // Update the volume's free block count, and mark the VCB as dirty.
379 HFS_MOUNT_LOCK(vcb
, TRUE
);
380 vcb
->freeBlocks
+= numBlocks
;
381 if (vcb
->nextAllocation
== (firstBlock
+ numBlocks
))
382 HFS_UPDATE_NEXT_ALLOCATION(vcb
, (vcb
->nextAllocation
- numBlocks
));
384 HFS_MOUNT_UNLOCK(vcb
, TRUE
);
386 hfs_generate_volume_notifications(VCBTOHFS(vcb
));
393 u_int8_t freebitcount
[16] = {
394 4, 3, 3, 2, 3, 2, 2, 1, /* 0 1 2 3 4 5 6 7 */
395 3, 2, 2, 1, 2, 1, 1, 0, /* 8 9 A B C D E F */
400 MetaZoneFreeBlocks(ExtendedVCB
*vcb
)
402 u_int32_t freeblocks
;
403 u_int32_t
*currCache
;
413 bytesleft
= freeblocks
= 0;
415 bit
= VCBTOHFS(vcb
)->hfs_metazone_start
;
419 lastbit
= VCBTOHFS(vcb
)->hfs_metazone_end
;
420 bytesperblock
= vcb
->vcbVBMIOSize
;
423 * Count all the bits from bit to lastbit.
425 while (bit
< lastbit
) {
427 * Get next bitmap block.
429 if (bytesleft
== 0) {
431 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);
434 if (ReadBitmapBlock(vcb
, bit
, &currCache
, &blockRef
) != 0) {
437 buffer
= (u_int8_t
*)currCache
;
438 bytesleft
= bytesperblock
;
441 freeblocks
+= freebitcount
[byte
& 0x0F];
442 freeblocks
+= freebitcount
[(byte
>> 4) & 0x0F];
447 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);
454 * Obtain the next allocation block (bit) that's
455 * outside the metadata allocation zone.
457 static u_int32_t
NextBitmapBlock(
461 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
463 if ((hfsmp
->hfs_flags
& HFS_METADATA_ZONE
) == 0)
466 * Skip over metadata allocation zone.
468 if ((bit
>= hfsmp
->hfs_metazone_start
) &&
469 (bit
<= hfsmp
->hfs_metazone_end
)) {
470 bit
= hfsmp
->hfs_metazone_end
+ 1;
477 ;_______________________________________________________________________
479 ; Routine: ReadBitmapBlock
481 ; Function: Read in a bitmap block corresponding to a given allocation
482 ; block (bit). Return a pointer to the bitmap block.
485 ; vcb -- Pointer to ExtendedVCB
486 ; bit -- Allocation block whose bitmap block is desired
489 ; buffer -- Pointer to bitmap block corresonding to "block"
491 ;_______________________________________________________________________
493 static OSErr
ReadBitmapBlock(
500 struct buf
*bp
= NULL
;
501 struct vnode
*vp
= NULL
;
506 * volume bitmap blocks are protected by the allocation file lock
508 REQUIRE_FILE_LOCK(vcb
->hfs_allocation_vp
, false);
510 blockSize
= (u_int32_t
)vcb
->vcbVBMIOSize
;
511 block
= (daddr64_t
)(bit
/ (blockSize
* kBitsPerByte
));
513 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
514 vp
= vcb
->hfs_allocation_vp
; /* use allocation file vnode */
517 vp
= VCBTOHFS(vcb
)->hfs_devvp
; /* use device I/O vnode */
518 block
+= vcb
->vcbVBMSt
; /* map to physical block */
521 err
= (int)buf_meta_bread(vp
, block
, blockSize
, NOCRED
, &bp
);
529 *blockRef
= (u_int32_t
)bp
;
530 *buffer
= (u_int32_t
*)buf_dataptr(bp
);
539 ;_______________________________________________________________________
541 ; Routine: ReleaseBitmapBlock
543 ; Function: Relase a bitmap block.
549 ;_______________________________________________________________________
551 static OSErr
ReleaseBitmapBlock(
556 struct buf
*bp
= (struct buf
*)blockRef
;
560 panic("ReleaseBitmapBlock: missing bp");
567 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
570 journal_modify_block_end(hfsmp
->jnl
, bp
, NULL
, NULL
);
584 _______________________________________________________________________
586 Routine: BlockAllocateContig
588 Function: Allocate a contiguous group of allocation blocks. The
589 allocation is all-or-nothing. The caller guarantees that
590 there are enough free blocks (though they may not be
591 contiguous, in which case this call will fail).
594 vcb Pointer to volume where space is to be allocated
595 startingBlock Preferred first block for allocation
596 minBlocks Minimum number of contiguous blocks to allocate
597 maxBlocks Maximum number of contiguous blocks to allocate
601 actualStartBlock First block of range allocated, or 0 if error
602 actualNumBlocks Number of blocks allocated, or 0 if error
603 _______________________________________________________________________
605 static OSErr
BlockAllocateContig(
607 u_int32_t startingBlock
,
611 u_int32_t
*actualStartBlock
,
612 u_int32_t
*actualNumBlocks
)
617 // Find a contiguous group of blocks at least minBlocks long.
618 // Determine the number of contiguous blocks available (up
623 * NOTE: If the only contiguous free extent of at least minBlocks
624 * crosses startingBlock (i.e. starts before, ends after), then we
625 * won't find it. Earlier versions *did* find this case by letting
626 * the second search look past startingBlock by minBlocks. But
627 * with the free extent cache, this can lead to duplicate entries
628 * in the cache, causing the same blocks to be allocated twice.
630 err
= BlockFindContiguous(vcb
, startingBlock
, vcb
->allocLimit
, minBlocks
,
631 maxBlocks
, useMetaZone
, actualStartBlock
, actualNumBlocks
);
632 if (err
== dskFulErr
&& startingBlock
!= 0) {
634 * Constrain the endingBlock so we don't bother looking for ranges
635 * that would overlap those found in the previous call.
637 err
= BlockFindContiguous(vcb
, 1, startingBlock
, minBlocks
, maxBlocks
,
638 useMetaZone
, actualStartBlock
, actualNumBlocks
);
641 // Now mark those blocks allocated.
644 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
650 _______________________________________________________________________
652 Routine: BlockAllocateAny
654 Function: Allocate one or more allocation blocks. If there are fewer
655 free blocks than requested, all free blocks will be
656 allocated. The caller guarantees that there is at least
660 vcb Pointer to volume where space is to be allocated
661 startingBlock Preferred first block for allocation
662 endingBlock Last block to check + 1
663 maxBlocks Maximum number of contiguous blocks to allocate
667 actualStartBlock First block of range allocated, or 0 if error
668 actualNumBlocks Number of blocks allocated, or 0 if error
669 _______________________________________________________________________
671 static OSErr
BlockAllocateAny(
673 u_int32_t startingBlock
,
674 register u_int32_t endingBlock
,
677 u_int32_t
*actualStartBlock
,
678 u_int32_t
*actualNumBlocks
)
681 register u_int32_t block
; // current block number
682 register u_int32_t currentWord
; // Pointer to current word within bitmap block
683 register u_int32_t bitMask
; // Word with given bits already set (ready to OR in)
684 register u_int32_t wordsLeft
; // Number of words left in this bitmap block
685 u_int32_t
*buffer
= NULL
;
686 u_int32_t
*currCache
= NULL
;
688 u_int32_t bitsPerBlock
;
689 u_int32_t wordsPerBlock
;
690 Boolean dirty
= false;
691 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
694 * When we're skipping the metadata zone and the start/end
695 * range overlaps with the metadata zone then adjust the
696 * start to be outside of the metadata zone. If the range
697 * is entirely inside the metadata zone then we can deny the
698 * request (dskFulErr).
700 if (!useMetaZone
&& (vcb
->hfs_flags
& HFS_METADATA_ZONE
)) {
701 if (startingBlock
<= vcb
->hfs_metazone_end
) {
702 if (endingBlock
> (vcb
->hfs_metazone_end
+ 2))
703 startingBlock
= vcb
->hfs_metazone_end
+ 1;
711 // Since this routine doesn't wrap around
712 if (maxBlocks
> (endingBlock
- startingBlock
)) {
713 maxBlocks
= endingBlock
- startingBlock
;
717 // Pre-read the first bitmap block
719 err
= ReadBitmapBlock(vcb
, startingBlock
, &currCache
, &blockRef
);
720 if (err
!= noErr
) goto Exit
;
724 // Set up the current position within the block
727 u_int32_t wordIndexInBlock
;
729 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
730 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
732 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
733 buffer
+= wordIndexInBlock
;
734 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
735 currentWord
= SWAP_BE32 (*buffer
);
736 bitMask
= kHighBitInWordMask
>> (startingBlock
& kBitsWithinWordMask
);
740 // Find the first unallocated block
743 while (block
< endingBlock
) {
744 if ((currentWord
& bitMask
) == 0)
752 bitMask
= kHighBitInWordMask
;
755 if (--wordsLeft
== 0) {
757 buffer
= currCache
= NULL
;
758 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
759 if (err
!= noErr
) goto Exit
;
762 * Skip over metadata blocks.
765 block
= NextBitmapBlock(vcb
, block
);
767 if (block
>= endingBlock
) {
772 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
773 if (err
!= noErr
) goto Exit
;
776 wordsLeft
= wordsPerBlock
;
778 currentWord
= SWAP_BE32 (*buffer
);
782 // Did we get to the end of the bitmap before finding a free block?
783 // If so, then couldn't allocate anything.
784 if (block
>= endingBlock
) {
789 // Return the first block in the allocated range
790 *actualStartBlock
= block
;
793 // If we could get the desired number of blocks before hitting endingBlock,
794 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
795 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
796 // comparison below yields identical results, but without overflow.
797 if (block
< (endingBlock
-maxBlocks
)) {
798 endingBlock
= block
+ maxBlocks
; // if we get this far, we've found enough
803 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
807 // Allocate all of the consecutive blocks
809 while ((currentWord
& bitMask
) == 0) {
810 // Allocate this block
811 currentWord
|= bitMask
;
813 // Move to the next block. If no more, then exit.
815 if (block
== endingBlock
)
821 *buffer
= SWAP_BE32 (currentWord
); // update value in bitmap
824 bitMask
= kHighBitInWordMask
;
827 if (--wordsLeft
== 0) {
829 buffer
= currCache
= NULL
;
830 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
831 if (err
!= noErr
) goto Exit
;
834 * Skip over metadata blocks.
839 nextBlock
= NextBitmapBlock(vcb
, block
);
840 if (nextBlock
!= block
) {
841 goto Exit
; /* allocation gap, so stop */
845 err
= ReadBitmapBlock(vcb
, block
, &currCache
, &blockRef
);
846 if (err
!= noErr
) goto Exit
;
851 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
854 wordsLeft
= wordsPerBlock
;
857 currentWord
= SWAP_BE32 (*buffer
);
860 *buffer
= SWAP_BE32 (currentWord
); // update the last change
864 *actualNumBlocks
= block
- *actualStartBlock
;
867 if ((*actualStartBlock
+ *actualNumBlocks
) > vcb
->allocLimit
)
868 panic("BlockAllocateAny: allocation overflow on \"%s\"", vcb
->vcbVN
);
871 *actualStartBlock
= 0;
872 *actualNumBlocks
= 0;
876 (void) ReleaseBitmapBlock(vcb
, blockRef
, dirty
);
883 _______________________________________________________________________
885 Routine: BlockAllocateKnown
887 Function: Try to allocate space from known free space in the free
891 vcb Pointer to volume where space is to be allocated
892 maxBlocks Maximum number of contiguous blocks to allocate
895 actualStartBlock First block of range allocated, or 0 if error
896 actualNumBlocks Number of blocks allocated, or 0 if error
899 dskFulErr Free extent cache is empty
900 _______________________________________________________________________
902 static OSErr
BlockAllocateKnown(
905 u_int32_t
*actualStartBlock
,
906 u_int32_t
*actualNumBlocks
)
910 u_int32_t foundBlocks
;
911 u_int32_t newStartBlock
, newBlockCount
;
913 if (vcb
->vcbFreeExtCnt
== 0)
916 // Just grab up to maxBlocks of the first (largest) free exent.
917 *actualStartBlock
= vcb
->vcbFreeExt
[0].startBlock
;
918 foundBlocks
= vcb
->vcbFreeExt
[0].blockCount
;
919 if (foundBlocks
> maxBlocks
)
920 foundBlocks
= maxBlocks
;
921 *actualNumBlocks
= foundBlocks
;
923 // Adjust the start and length of that extent.
924 newStartBlock
= vcb
->vcbFreeExt
[0].startBlock
+ foundBlocks
;
925 newBlockCount
= vcb
->vcbFreeExt
[0].blockCount
- foundBlocks
;
927 // The first extent might not be the largest anymore. Bubble up any
928 // (now larger) extents to the top of the list.
929 for (i
=1; i
<vcb
->vcbFreeExtCnt
; ++i
)
931 if (vcb
->vcbFreeExt
[i
].blockCount
> newBlockCount
)
933 vcb
->vcbFreeExt
[i
-1].startBlock
= vcb
->vcbFreeExt
[i
].startBlock
;
934 vcb
->vcbFreeExt
[i
-1].blockCount
= vcb
->vcbFreeExt
[i
].blockCount
;
942 // If this is now the smallest known free extent, then it might be smaller than
943 // other extents we didn't keep track of. So, just forget about this extent.
944 // After the previous loop, (i-1) is the index of the extent we just allocated from.
945 if (i
== vcb
->vcbFreeExtCnt
)
947 // It's now the smallest extent, so forget about it
948 --vcb
->vcbFreeExtCnt
;
952 // It's not the smallest, so store it in its proper place
953 vcb
->vcbFreeExt
[i
-1].startBlock
= newStartBlock
;
954 vcb
->vcbFreeExt
[i
-1].blockCount
= newBlockCount
;
958 if ((*actualStartBlock
+ *actualNumBlocks
) > vcb
->allocLimit
)
960 printf ("hfs: BlockAllocateKnown() found allocation overflow on \"%s\"", vcb
->vcbVN
);
961 hfs_mark_volume_inconsistent(vcb
);
962 *actualStartBlock
= 0;
963 *actualNumBlocks
= 0;
969 // Now mark the found extent in the bitmap
971 err
= BlockMarkAllocated(vcb
, *actualStartBlock
, *actualNumBlocks
);
980 _______________________________________________________________________
982 Routine: BlockMarkAllocated
984 Function: Mark a contiguous group of blocks as allocated (set in the
985 bitmap). It assumes those bits are currently marked
986 deallocated (clear in the bitmap).
989 vcb Pointer to volume where space is to be allocated
990 startingBlock First block number to mark as allocated
991 numBlocks Number of blocks to mark as allocated
992 _______________________________________________________________________
995 OSErr
BlockMarkAllocated(
997 u_int32_t startingBlock
,
998 register u_int32_t numBlocks
)
1001 register u_int32_t
*currentWord
; // Pointer to current word within bitmap block
1002 register u_int32_t wordsLeft
; // Number of words left in this bitmap block
1003 register u_int32_t bitMask
; // Word with given bits already set (ready to OR in)
1004 u_int32_t firstBit
; // Bit index within word of first bit to allocate
1005 u_int32_t numBits
; // Number of bits in word to allocate
1006 u_int32_t
*buffer
= NULL
;
1008 u_int32_t bitsPerBlock
;
1009 u_int32_t wordsPerBlock
;
1011 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
1015 // Pre-read the bitmap block containing the first word of allocation
1018 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1019 if (err
!= noErr
) goto Exit
;
1021 // Initialize currentWord, and wordsLeft.
1024 u_int32_t wordIndexInBlock
;
1026 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1027 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1029 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1030 currentWord
= buffer
+ wordIndexInBlock
;
1031 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1036 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1040 // If the first block to allocate doesn't start on a word
1041 // boundary in the bitmap, then treat that first word
1045 firstBit
= startingBlock
% kBitsPerWord
;
1046 if (firstBit
!= 0) {
1047 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1048 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1049 if (numBits
> numBlocks
) {
1050 numBits
= numBlocks
; // entire allocation is inside this one word
1051 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1054 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1055 panic("BlockMarkAllocated: blocks already allocated!");
1058 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1059 numBlocks
-= numBits
; // adjust number of blocks left to allocate
1061 ++currentWord
; // move to next word
1062 --wordsLeft
; // one less word left in this block
1066 // Allocate whole words (32 blocks) at a time.
1069 bitMask
= kAllBitsSetInWord
; // put this in a register for 68K
1070 while (numBlocks
>= kBitsPerWord
) {
1071 if (wordsLeft
== 0) {
1072 // Read in the next bitmap block
1073 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1076 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1077 if (err
!= noErr
) goto Exit
;
1079 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1080 if (err
!= noErr
) goto Exit
;
1084 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1087 // Readjust currentWord and wordsLeft
1088 currentWord
= buffer
;
1089 wordsLeft
= wordsPerBlock
;
1092 if (*currentWord
!= 0) {
1093 panic("BlockMarkAllocated: blocks already allocated!");
1096 *currentWord
= SWAP_BE32 (bitMask
);
1097 numBlocks
-= kBitsPerWord
;
1099 ++currentWord
; // move to next word
1100 --wordsLeft
; // one less word left in this block
1104 // Allocate any remaining blocks.
1107 if (numBlocks
!= 0) {
1108 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1109 if (wordsLeft
== 0) {
1110 // Read in the next bitmap block
1111 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1114 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1115 if (err
!= noErr
) goto Exit
;
1117 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1118 if (err
!= noErr
) goto Exit
;
1122 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1125 // Readjust currentWord and wordsLeft
1126 currentWord
= buffer
;
1127 wordsLeft
= wordsPerBlock
;
1130 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1131 panic("BlockMarkAllocated: blocks already allocated!");
1134 *currentWord
|= SWAP_BE32 (bitMask
); // set the bits in the bitmap
1136 // No need to update currentWord or wordsLeft
1142 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1149 _______________________________________________________________________
1151 Routine: BlockMarkFree
1153 Function: Mark a contiguous group of blocks as free (clear in the
1154 bitmap). It assumes those bits are currently marked
1155 allocated (set in the bitmap).
1158 vcb Pointer to volume where space is to be freed
1159 startingBlock First block number to mark as freed
1160 numBlocks Number of blocks to mark as freed
1161 _______________________________________________________________________
1164 OSErr
BlockMarkFree(
1166 u_int32_t startingBlock
,
1167 register u_int32_t numBlocks
)
1170 register u_int32_t
*currentWord
; // Pointer to current word within bitmap block
1171 register u_int32_t wordsLeft
; // Number of words left in this bitmap block
1172 register u_int32_t bitMask
; // Word with given bits already set (ready to OR in)
1173 u_int32_t firstBit
; // Bit index within word of first bit to allocate
1174 u_int32_t numBits
; // Number of bits in word to allocate
1175 u_int32_t
*buffer
= NULL
;
1177 u_int32_t bitsPerBlock
;
1178 u_int32_t wordsPerBlock
;
1180 struct hfsmount
*hfsmp
= VCBTOHFS(vcb
);
1181 dk_discard_t discard
;
1184 * NOTE: We use vcb->totalBlocks instead of vcb->allocLimit because we
1185 * need to be able to free blocks being relocated during hfs_truncatefs.
1187 if (startingBlock
+ numBlocks
> vcb
->totalBlocks
) {
1188 printf ("hfs: BlockMarkFree() trying to free non-existent blocks starting at %u (numBlock=%u) on volume %s\n", startingBlock
, numBlocks
, vcb
->vcbVN
);
1189 hfs_mark_volume_inconsistent(vcb
);
1194 memset(&discard
, 0, sizeof(dk_discard_t
));
1195 discard
.offset
= (uint64_t)startingBlock
* (uint64_t)vcb
->blockSize
;
1196 discard
.length
= (uint64_t)numBlocks
* (uint64_t)vcb
->blockSize
;
1200 // Pre-read the bitmap block containing the first word of allocation
1203 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1204 if (err
!= noErr
) goto Exit
;
1207 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1211 // Initialize currentWord, and wordsLeft.
1214 u_int32_t wordIndexInBlock
;
1216 bitsPerBlock
= vcb
->vcbVBMIOSize
* kBitsPerByte
;
1217 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1219 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1220 currentWord
= buffer
+ wordIndexInBlock
;
1221 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1225 // If the first block to free doesn't start on a word
1226 // boundary in the bitmap, then treat that first word
1230 firstBit
= startingBlock
% kBitsPerWord
;
1231 if (firstBit
!= 0) {
1232 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
1233 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
1234 if (numBits
> numBlocks
) {
1235 numBits
= numBlocks
; // entire allocation is inside this one word
1236 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
1238 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1241 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1242 numBlocks
-= numBits
; // adjust number of blocks left to free
1244 ++currentWord
; // move to next word
1245 --wordsLeft
; // one less word left in this block
1249 // Free whole words (32 blocks) at a time.
1252 while (numBlocks
>= kBitsPerWord
) {
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 (kAllBitsSetInWord
)) {
1276 *currentWord
= 0; // clear the entire word
1277 numBlocks
-= kBitsPerWord
;
1279 ++currentWord
; // move to next word
1280 --wordsLeft
; // one less word left in this block
1284 // Free any remaining blocks.
1287 if (numBlocks
!= 0) {
1288 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
); // set first numBlocks bits
1289 if (wordsLeft
== 0) {
1290 // Read in the next bitmap block
1291 startingBlock
+= bitsPerBlock
; // generate a block number in the next bitmap block
1294 err
= ReleaseBitmapBlock(vcb
, blockRef
, true);
1295 if (err
!= noErr
) goto Exit
;
1297 err
= ReadBitmapBlock(vcb
, startingBlock
, &buffer
, &blockRef
);
1298 if (err
!= noErr
) goto Exit
;
1302 journal_modify_block_start(hfsmp
->jnl
, (struct buf
*)blockRef
);
1305 // Readjust currentWord and wordsLeft
1306 currentWord
= buffer
;
1307 wordsLeft
= wordsPerBlock
;
1309 if ((*currentWord
& SWAP_BE32 (bitMask
)) != SWAP_BE32 (bitMask
)) {
1312 *currentWord
&= SWAP_BE32 (~bitMask
); // clear the bits in the bitmap
1314 // No need to update currentWord or wordsLeft
1320 (void)ReleaseBitmapBlock(vcb
, blockRef
, true);
1323 // it doesn't matter if this fails, it's just informational anyway
1324 VNOP_IOCTL(vcb
->hfs_devvp
, DKIOCDISCARD
, (caddr_t
)&discard
, 0, vfs_context_kernel());
1332 panic("BlockMarkFree: blocks not allocated!");
1334 printf ("hfs: BlockMarkFree() trying to free unallocated blocks on volume %s\n", vcb
->vcbVN
);
1335 hfs_mark_volume_inconsistent(vcb
);
1343 _______________________________________________________________________
1345 Routine: BlockFindContiguous
1347 Function: Find a contiguous range of blocks that are free (bits
1348 clear in the bitmap). If a contiguous range of the
1349 minimum size can't be found, an error will be returned.
1352 vcb Pointer to volume where space is to be allocated
1353 startingBlock Preferred first block of range
1354 endingBlock Last possible block in range + 1
1355 minBlocks Minimum number of blocks needed. Must be > 0.
1356 maxBlocks Maximum (ideal) number of blocks desired
1357 useMetaZone OK to dip into metadata allocation zone
1360 actualStartBlock First block of range found, or 0 if error
1361 actualNumBlocks Number of blocks found, or 0 if error
1364 noErr Found at least minBlocks contiguous
1365 dskFulErr No contiguous space found, or all less than minBlocks
1366 _______________________________________________________________________
1369 static OSErr
BlockFindContiguous(
1371 u_int32_t startingBlock
,
1372 u_int32_t endingBlock
,
1373 u_int32_t minBlocks
,
1374 u_int32_t maxBlocks
,
1375 Boolean useMetaZone
,
1376 u_int32_t
*actualStartBlock
,
1377 u_int32_t
*actualNumBlocks
)
1380 register u_int32_t currentBlock
; // Block we're currently looking at.
1381 u_int32_t firstBlock
; // First free block in current extent.
1382 u_int32_t stopBlock
; // If we get to this block, stop searching for first free block.
1383 u_int32_t foundBlocks
; // Number of contiguous free blocks in current extent.
1384 u_int32_t
*buffer
= NULL
;
1385 register u_int32_t
*currentWord
;
1386 register u_int32_t bitMask
;
1387 register u_int32_t wordsLeft
;
1388 register u_int32_t tempWord
;
1390 u_int32_t wordsPerBlock
;
1393 * When we're skipping the metadata zone and the start/end
1394 * range overlaps with the metadata zone then adjust the
1395 * start to be outside of the metadata zone. If the range
1396 * is entirely inside the metadata zone then we can deny the
1397 * request (dskFulErr).
1399 if (!useMetaZone
&& (vcb
->hfs_flags
& HFS_METADATA_ZONE
)) {
1400 if (startingBlock
<= vcb
->hfs_metazone_end
) {
1401 if (endingBlock
> (vcb
->hfs_metazone_end
+ 2))
1402 startingBlock
= vcb
->hfs_metazone_end
+ 1;
1408 if ((endingBlock
- startingBlock
) < minBlocks
)
1410 // The set of blocks we're checking is smaller than the minimum number
1411 // of blocks, so we couldn't possibly find a good range.
1415 stopBlock
= endingBlock
- minBlocks
+ 1;
1416 currentBlock
= startingBlock
;
1420 * Skip over metadata blocks.
1423 currentBlock
= NextBitmapBlock(vcb
, currentBlock
);
1426 // Pre-read the first bitmap block.
1428 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1429 if ( err
!= noErr
) goto ErrorExit
;
1432 // Figure out where currentBlock is within the buffer.
1434 wordsPerBlock
= vcb
->vcbVBMIOSize
/ kBytesPerWord
;
1436 wordsLeft
= (currentBlock
/ kBitsPerWord
) & (wordsPerBlock
-1); // Current index into buffer
1437 currentWord
= buffer
+ wordsLeft
;
1438 wordsLeft
= wordsPerBlock
- wordsLeft
;
1444 //============================================================
1445 // Look for a free block, skipping over allocated blocks.
1446 //============================================================
1449 // Check an initial partial word (if any)
1451 bitMask
= currentBlock
& kBitsWithinWordMask
;
1454 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1455 bitMask
= kHighBitInWordMask
>> bitMask
;
1456 while (tempWord
& bitMask
)
1462 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1466 // Didn't find any unused bits, so we're done with this word.
1472 // Check whole words
1474 while (currentBlock
< stopBlock
)
1476 // See if it's time to read another block.
1480 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1481 if (err
!= noErr
) goto ErrorExit
;
1484 * Skip over metadata blocks.
1487 currentBlock
= NextBitmapBlock(vcb
, currentBlock
);
1488 if (currentBlock
>= stopBlock
) {
1493 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1494 if ( err
!= noErr
) goto ErrorExit
;
1496 currentWord
= buffer
;
1497 wordsLeft
= wordsPerBlock
;
1500 // See if any of the bits are clear
1501 if ((tempWord
= SWAP_BE32(*currentWord
)) + 1) // non-zero if any bits were clear
1503 // Figure out which bit is clear
1504 bitMask
= kHighBitInWordMask
;
1505 while (tempWord
& bitMask
)
1511 break; // Found the free bit; break out to FoundUnused.
1514 // Keep looking at the next word
1515 currentBlock
+= kBitsPerWord
;
1521 // Make sure the unused bit is early enough to use
1522 if (currentBlock
>= stopBlock
)
1527 // Remember the start of the extent
1528 firstBlock
= currentBlock
;
1530 //============================================================
1531 // Count the number of contiguous free blocks.
1532 //============================================================
1535 // Check an initial partial word (if any)
1537 bitMask
= currentBlock
& kBitsWithinWordMask
;
1540 tempWord
= SWAP_BE32(*currentWord
); // Fetch the current word only once
1541 bitMask
= kHighBitInWordMask
>> bitMask
;
1542 while (bitMask
&& !(tempWord
& bitMask
))
1548 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1552 // Didn't find any used bits, so we're done with this word.
1558 // Check whole words
1560 while (currentBlock
< endingBlock
)
1562 // See if it's time to read another block.
1566 err
= ReleaseBitmapBlock(vcb
, blockRef
, false);
1567 if (err
!= noErr
) goto ErrorExit
;
1570 * Skip over metadata blocks.
1573 u_int32_t nextBlock
;
1575 nextBlock
= NextBitmapBlock(vcb
, currentBlock
);
1576 if (nextBlock
!= currentBlock
) {
1577 goto LoopExit
; /* allocation gap, so stop */
1581 err
= ReadBitmapBlock(vcb
, currentBlock
, &buffer
, &blockRef
);
1582 if ( err
!= noErr
) goto ErrorExit
;
1584 currentWord
= buffer
;
1585 wordsLeft
= wordsPerBlock
;
1588 // See if any of the bits are set
1589 if ((tempWord
= SWAP_BE32(*currentWord
)) != 0)
1591 // Figure out which bit is set
1592 bitMask
= kHighBitInWordMask
;
1593 while (!(tempWord
& bitMask
))
1599 break; // Found the used bit; break out to FoundUsed.
1602 // Keep looking at the next word
1603 currentBlock
+= kBitsPerWord
;
1607 // If we found at least maxBlocks, we can quit early.
1608 if ((currentBlock
- firstBlock
) >= maxBlocks
)
1613 // Make sure we didn't run out of bitmap looking for a used block.
1614 // If so, pin to the end of the bitmap.
1615 if (currentBlock
> endingBlock
)
1616 currentBlock
= endingBlock
;
1618 // Figure out how many contiguous free blocks there were.
1619 // Pin the answer to maxBlocks.
1620 foundBlocks
= currentBlock
- firstBlock
;
1621 if (foundBlocks
> maxBlocks
)
1622 foundBlocks
= maxBlocks
;
1623 if (foundBlocks
>= minBlocks
)
1624 break; // Found what we needed!
1626 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1627 // the allocation wasn't forced contiguous.
1628 tempWord
= vcb
->vcbFreeExtCnt
;
1629 if (tempWord
== kMaxFreeExtents
&& vcb
->vcbFreeExt
[kMaxFreeExtents
-1].blockCount
< foundBlocks
)
1631 if (tempWord
< kMaxFreeExtents
)
1633 // We're going to add this extent. Bubble any smaller extents down in the list.
1634 while (tempWord
&& vcb
->vcbFreeExt
[tempWord
-1].blockCount
< foundBlocks
)
1636 vcb
->vcbFreeExt
[tempWord
] = vcb
->vcbFreeExt
[tempWord
-1];
1639 vcb
->vcbFreeExt
[tempWord
].startBlock
= firstBlock
;
1640 vcb
->vcbFreeExt
[tempWord
].blockCount
= foundBlocks
;
1642 if (vcb
->vcbFreeExtCnt
< kMaxFreeExtents
)
1643 ++vcb
->vcbFreeExtCnt
;
1645 } while (currentBlock
< stopBlock
);
1648 // Return the outputs.
1649 if (foundBlocks
< minBlocks
)
1654 *actualStartBlock
= 0;
1655 *actualNumBlocks
= 0;
1660 *actualStartBlock
= firstBlock
;
1661 *actualNumBlocks
= foundBlocks
;
1663 * Sanity check for overflow
1665 if ((firstBlock
+ foundBlocks
) > vcb
->allocLimit
) {
1666 panic("blk allocation overflow on \"%s\" sb:0x%08x eb:0x%08x cb:0x%08x fb:0x%08x stop:0x%08x min:0x%08x found:0x%08x",
1667 vcb
->vcbVN
, startingBlock
, endingBlock
, currentBlock
,
1668 firstBlock
, stopBlock
, minBlocks
, foundBlocks
);
1673 (void) ReleaseBitmapBlock(vcb
, blockRef
, false);
1679 * Test to see if any blocks in a range are allocated.
1681 * The journal or allocation file lock must be held.
1685 hfs_isallocated(struct hfsmount
*hfsmp
, u_long startingBlock
, u_long numBlocks
)
1687 u_int32_t
*currentWord
; // Pointer to current word within bitmap block
1688 u_int32_t wordsLeft
; // Number of words left in this bitmap block
1689 u_int32_t bitMask
; // Word with given bits already set (ready to test)
1690 u_int32_t firstBit
; // Bit index within word of first bit to allocate
1691 u_int32_t numBits
; // Number of bits in word to allocate
1692 u_int32_t
*buffer
= NULL
;
1694 u_int32_t bitsPerBlock
;
1695 u_int32_t wordsPerBlock
;
1700 * Pre-read the bitmap block containing the first word of allocation
1702 error
= ReadBitmapBlock(hfsmp
, startingBlock
, &buffer
, &blockRef
);
1707 * Initialize currentWord, and wordsLeft.
1710 u_int32_t wordIndexInBlock
;
1712 bitsPerBlock
= hfsmp
->vcbVBMIOSize
* kBitsPerByte
;
1713 wordsPerBlock
= hfsmp
->vcbVBMIOSize
/ kBytesPerWord
;
1715 wordIndexInBlock
= (startingBlock
& (bitsPerBlock
-1)) / kBitsPerWord
;
1716 currentWord
= buffer
+ wordIndexInBlock
;
1717 wordsLeft
= wordsPerBlock
- wordIndexInBlock
;
1721 * First test any non word aligned bits.
1723 firstBit
= startingBlock
% kBitsPerWord
;
1724 if (firstBit
!= 0) {
1725 bitMask
= kAllBitsSetInWord
>> firstBit
;
1726 numBits
= kBitsPerWord
- firstBit
;
1727 if (numBits
> numBlocks
) {
1728 numBits
= numBlocks
;
1729 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
));
1731 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1735 numBlocks
-= numBits
;
1741 * Test whole words (32 blocks) at a time.
1743 while (numBlocks
>= kBitsPerWord
) {
1744 if (wordsLeft
== 0) {
1745 /* Read in the next bitmap block. */
1746 startingBlock
+= bitsPerBlock
;
1749 error
= ReleaseBitmapBlock(hfsmp
, blockRef
, false);
1750 if (error
) goto Exit
;
1752 error
= ReadBitmapBlock(hfsmp
, startingBlock
, &buffer
, &blockRef
);
1753 if (error
) goto Exit
;
1755 /* Readjust currentWord and wordsLeft. */
1756 currentWord
= buffer
;
1757 wordsLeft
= wordsPerBlock
;
1759 if (*currentWord
!= 0) {
1763 numBlocks
-= kBitsPerWord
;
1769 * Test any remaining blocks.
1771 if (numBlocks
!= 0) {
1772 bitMask
= ~(kAllBitsSetInWord
>> numBlocks
);
1773 if (wordsLeft
== 0) {
1774 /* Read in the next bitmap block */
1775 startingBlock
+= bitsPerBlock
;
1778 error
= ReleaseBitmapBlock(hfsmp
, blockRef
, false);
1779 if (error
) goto Exit
;
1781 error
= ReadBitmapBlock(hfsmp
, startingBlock
, &buffer
, &blockRef
);
1782 if (error
) goto Exit
;
1784 currentWord
= buffer
;
1785 wordsLeft
= wordsPerBlock
;
1787 if ((*currentWord
& SWAP_BE32 (bitMask
)) != 0) {
1794 (void)ReleaseBitmapBlock(hfsmp
, blockRef
, false);