]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
8908358e537359ad3e23d20bb942546d30335cf0
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / VolumeAllocation.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 File: VolumeAllocation.c
27
28 Contains: Routines for accessing and modifying the volume bitmap.
29
30 Version: HFS Plus 1.0
31
32 Copyright: © 1996-2001 by Apple Computer, Inc., all rights reserved.
33
34 */
35
36 /*
37 Public routines:
38 BlockAllocate
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???)
43 BlockDeallocate
44 Deallocate a contiguous run of allocation blocks.
45
46
47 Internal routines:
48 BlockMarkFree
49 Mark a contiguous range of blocks as free. The corresponding
50 bits in the volume bitmap will be cleared.
51 BlockMarkAllocated
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.
55 FindContiguous
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.
59 BlockAllocateAny
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).
64 BlockAllocateContig
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").
68
69 BlockAllocateKnown
70 Try to allocate space from known free space in the volume's
71 free extent cache.
72
73 ReadBitmapBlock
74 Given an allocation block number, read the bitmap block that
75 contains that allocation block into a caller-supplied buffer.
76
77 ReleaseBitmapBlock
78 Release a bitmap block back into the buffer cache.
79 */
80
81 #include "../../hfs_macos_defs.h"
82
83 #include <sys/types.h>
84 #include <sys/buf.h>
85 #include <sys/systm.h>
86
87 #include "../../hfs.h"
88 #include "../../hfs_dbg.h"
89 #include "../../hfs_format.h"
90 #include "../../hfs_endian.h"
91
92 #include "../headers/FileMgrInternal.h"
93
94
95 enum {
96 kBytesPerWord = 4,
97 kBitsPerByte = 8,
98 kBitsPerWord = 32,
99
100 kBitsWithinWordMask = kBitsPerWord-1
101 };
102
103 #define kLowBitInWordMask 0x00000001ul
104 #define kHighBitInWordMask 0x80000000ul
105 #define kAllBitsSetInWord 0xFFFFFFFFul
106
107
108 static OSErr ReadBitmapBlock(
109 ExtendedVCB *vcb,
110 UInt32 bit,
111 UInt32 **buffer,
112 UInt32 *blockRef);
113
114 static OSErr ReleaseBitmapBlock(
115 ExtendedVCB *vcb,
116 UInt32 blockRef,
117 Boolean dirty);
118
119 static OSErr BlockAllocateAny(
120 ExtendedVCB *vcb,
121 UInt32 startingBlock,
122 UInt32 endingBlock,
123 UInt32 maxBlocks,
124 UInt32 *actualStartBlock,
125 UInt32 *actualNumBlocks);
126
127 static OSErr BlockAllocateContig(
128 ExtendedVCB *vcb,
129 UInt32 startingBlock,
130 UInt32 minBlocks,
131 UInt32 maxBlocks,
132 UInt32 *actualStartBlock,
133 UInt32 *actualNumBlocks);
134
135 static OSErr BlockFindContiguous(
136 ExtendedVCB *vcb,
137 UInt32 startingBlock,
138 UInt32 endingBlock,
139 UInt32 minBlocks,
140 UInt32 maxBlocks,
141 UInt32 *actualStartBlock,
142 UInt32 *actualNumBlocks);
143
144 static OSErr BlockMarkAllocated(
145 ExtendedVCB *vcb,
146 UInt32 startingBlock,
147 UInt32 numBlocks);
148
149 static OSErr BlockMarkFree(
150 ExtendedVCB *vcb,
151 UInt32 startingBlock,
152 UInt32 numBlocks);
153
154 static OSErr BlockAllocateKnown(
155 ExtendedVCB *vcb,
156 UInt32 maxBlocks,
157 UInt32 *actualStartBlock,
158 UInt32 *actualNumBlocks);
159
160
161 /*
162 ;________________________________________________________________________________
163 ;
164 ; Routine: BlkAlloc
165 ;
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
172 ; allocated.
173 ;
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
176 ; point.
177 ;
178 ; All requests will be rounded up to the next highest clump size, as
179 ; indicated in the file's FCB.
180 ;
181 ; Input Arguments:
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.)
193 ;
194 ; Output:
195 ; (result) - Error code, zero for successful allocation
196 ; *startBlock - Actual starting allocation block
197 ; *actualBlocks - Actual number of allocation blocks allocated
198 ;
199 ; Side effects:
200 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
201 ;________________________________________________________________________________
202 */
203
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 */
214 /* bytes */
215 {
216 OSErr err;
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
220
221 //
222 // Initialize outputs in case we get an error
223 //
224 *actualStartBlock = 0;
225 *actualNumBlocks = 0;
226
227 //
228 // Compute the number of allocation blocks requested, and maximum
229 //
230 minBlocks = FileBytesToBlocks(bytesRequested, vcb->blockSize);
231 maxBlocks = FileBytesToBlocks(bytesMaximum, vcb->blockSize);
232
233 //
234 // If the disk is already full, don't bother.
235 //
236 if (hfs_freeblks(VCBTOHFS(vcb), 0) == 0) {
237 err = dskFulErr;
238 goto Exit;
239 }
240 if (forceContiguous && hfs_freeblks(VCBTOHFS(vcb), 0) < minBlocks) {
241 err = dskFulErr;
242 goto Exit;
243 }
244
245 //
246 // If caller didn't specify a starting block number, then use the volume's
247 // next block to allocate from.
248 //
249 if (startingBlock == 0) {
250 VCB_LOCK(vcb);
251 startingBlock = vcb->nextAllocation;
252 VCB_UNLOCK(vcb);
253 updateAllocPtr = true;
254 }
255
256 //
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.
259 //
260 if (forceContiguous) {
261 err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
262 /*
263 * If we allocated from a new position then
264 * also update the roving allocatior.
265 */
266 if ((err == noErr) && (*actualStartBlock > startingBlock))
267 vcb->nextAllocation = *actualStartBlock;
268 } else {
269 /*
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.
275 */
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);
281 }
282
283 if (err == noErr) {
284 //
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.
291 //
292 VCB_LOCK(vcb);
293
294 if (updateAllocPtr)
295 vcb->nextAllocation = *actualStartBlock;
296
297 //
298 // Update the number of free blocks on the volume
299 //
300 vcb->freeBlocks -= *actualNumBlocks;
301 VCB_UNLOCK(vcb);
302
303 MarkVCBDirty(vcb);
304 }
305
306 Exit:
307
308 return err;
309 }
310
311
312 /*
313 ;________________________________________________________________________________
314 ;
315 ; Routine: BlkDealloc
316 ;
317 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
318 ;
319 ; Input Arguments:
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!)
323 ;
324 ; Output:
325 ; (result) - Result code
326 ;
327 ; Side effects:
328 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
329 ;________________________________________________________________________________
330 */
331
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
336 {
337 OSErr err;
338
339 //
340 // If no blocks to deallocate, then exit early
341 //
342 if (numBlocks == 0) {
343 err = noErr;
344 goto Exit;
345 }
346
347 //
348 // Call internal routine to free the sequence of blocks
349 //
350 err = BlockMarkFree(vcb, firstBlock, numBlocks);
351 if (err)
352 goto Exit;
353
354 //
355 // Update the volume's free block count, and mark the VCB as dirty.
356 //
357 VCB_LOCK(vcb);
358 vcb->freeBlocks += numBlocks;
359 if (vcb->nextAllocation == (firstBlock + numBlocks))
360 vcb->nextAllocation -= numBlocks;
361 VCB_UNLOCK(vcb);
362 MarkVCBDirty(vcb);
363
364 Exit:
365
366 return err;
367 }
368
369
370 /*
371 ;_______________________________________________________________________
372 ;
373 ; Routine: FileBytesToBlocks
374 ;
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
379 ;
380 ; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
381 ;_______________________________________________________________________
382 */
383 UInt32 FileBytesToBlocks(
384 SInt64 numerator,
385 UInt32 denominator)
386 {
387 UInt32 quotient;
388
389 quotient = (UInt32)(numerator / denominator);
390 if (quotient * denominator != numerator)
391 quotient++;
392
393 return quotient;
394 }
395
396
397
398 /*
399 ;_______________________________________________________________________
400 ;
401 ; Routine: ReadBitmapBlock
402 ;
403 ; Function: Read in a bitmap block corresponding to a given allocation
404 ; block (bit). Return a pointer to the bitmap block.
405 ;
406 ; Inputs:
407 ; vcb -- Pointer to ExtendedVCB
408 ; bit -- Allocation block whose bitmap block is desired
409 ;
410 ; Outputs:
411 ; buffer -- Pointer to bitmap block corresonding to "block"
412 ; blockRef
413 ;_______________________________________________________________________
414 */
415 static OSErr ReadBitmapBlock(
416 ExtendedVCB *vcb,
417 UInt32 bit,
418 UInt32 **buffer,
419 UInt32 *blockRef)
420 {
421 OSErr err;
422 struct buf *bp = NULL;
423 struct vnode *vp = NULL;
424 UInt32 block;
425 UInt32 blockSize;
426
427 /*
428 * volume bitmap blocks are protected by the Extents B-tree lock
429 */
430 REQUIRE_FILE_LOCK(vcb->extentsRefNum, false);
431
432 blockSize = (UInt32)vcb->vcbVBMIOSize;
433 block = bit / (blockSize * kBitsPerByte);
434
435 if (vcb->vcbSigWord == kHFSPlusSigWord) {
436 vp = vcb->allocationsRefNum; /* use allocation file vnode */
437
438 } else /* hfs */ {
439 vp = VCBTOHFS(vcb)->hfs_devvp; /* use device I/O vnode */
440 block += vcb->vcbVBMSt; /* map to physical block */
441 }
442
443 err = meta_bread(vp, block, blockSize, NOCRED, &bp);
444
445 if (bp) {
446 if (err) {
447 brelse(bp);
448 *blockRef = NULL;
449 *buffer = NULL;
450 } else {
451 *blockRef = (UInt32)bp;
452 *buffer = (UInt32 *)bp->b_data;
453 }
454 }
455
456 return err;
457 }
458
459
460 /*
461 ;_______________________________________________________________________
462 ;
463 ; Routine: ReleaseBitmapBlock
464 ;
465 ; Function: Relase a bitmap block.
466 ;
467 ; Inputs:
468 ; vcb
469 ; blockRef
470 ; dirty
471 ;_______________________________________________________________________
472 */
473 static OSErr ReleaseBitmapBlock(
474 ExtendedVCB *vcb,
475 UInt32 blockRef,
476 Boolean dirty)
477 {
478 struct buf *bp = (struct buf *)blockRef;
479
480 if (bp) {
481 if (dirty) {
482 // XXXdbg
483 struct hfsmount *hfsmp = VCBTOHFS(vcb);
484
485 if (hfsmp->jnl) {
486 journal_modify_block_end(hfsmp->jnl, bp);
487 } else {
488 bdwrite(bp);
489 }
490 } else {
491 brelse(bp);
492 }
493 }
494
495 return (0);
496 }
497
498
499 /*
500 _______________________________________________________________________
501
502 Routine: BlockAllocateContig
503
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).
508
509 Inputs:
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
514
515 Outputs:
516 actualStartBlock First block of range allocated, or 0 if error
517 actualNumBlocks Number of blocks allocated, or 0 if error
518 _______________________________________________________________________
519 */
520 static OSErr BlockAllocateContig(
521 ExtendedVCB *vcb,
522 UInt32 startingBlock,
523 UInt32 minBlocks,
524 UInt32 maxBlocks,
525 UInt32 *actualStartBlock,
526 UInt32 *actualNumBlocks)
527 {
528 OSErr err;
529
530 //
531 // Find a contiguous group of blocks at least minBlocks long.
532 // Determine the number of contiguous blocks available (up
533 // to maxBlocks).
534 //
535
536 /*
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.
543 */
544 err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
545 actualStartBlock, actualNumBlocks);
546 if (err == dskFulErr && startingBlock != 0) {
547 /*
548 * Constrain the endingBlock so we don't bother looking for ranges
549 * that would overlap those found in the previous call.
550 */
551 err = BlockFindContiguous(vcb, 0, startingBlock, minBlocks, maxBlocks,
552 actualStartBlock, actualNumBlocks);
553 }
554 if (err != noErr) goto Exit;
555
556 //
557 // Now mark those blocks allocated.
558 //
559 err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
560
561 Exit:
562 if (err != noErr) {
563 *actualStartBlock = 0;
564 *actualNumBlocks = 0;
565 }
566
567 return err;
568 }
569
570 /*
571 _______________________________________________________________________
572
573 Routine: BlockAllocateAny
574
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
578 one free block.
579
580 Inputs:
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
585
586 Outputs:
587 actualStartBlock First block of range allocated, or 0 if error
588 actualNumBlocks Number of blocks allocated, or 0 if error
589 _______________________________________________________________________
590 */
591 static OSErr BlockAllocateAny(
592 ExtendedVCB *vcb,
593 UInt32 startingBlock,
594 register UInt32 endingBlock,
595 UInt32 maxBlocks,
596 UInt32 *actualStartBlock,
597 UInt32 *actualNumBlocks)
598 {
599 OSErr err;
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;
606 UInt32 blockRef;
607 UInt32 bitsPerBlock;
608 UInt32 wordsPerBlock;
609 Boolean dirty = false;
610 struct hfsmount *hfsmp = VCBTOHFS(vcb);
611
612 // Since this routine doesn't wrap around
613 if (maxBlocks > (endingBlock - startingBlock)) {
614 maxBlocks = endingBlock - startingBlock;
615 }
616
617 //
618 // Pre-read the first bitmap block
619 //
620 err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef);
621 if (err != noErr) goto Exit;
622 buffer = currCache;
623
624 //
625 // Set up the current position within the block
626 //
627 {
628 UInt32 wordIndexInBlock;
629
630 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
631 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
632
633 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
634 buffer += wordIndexInBlock;
635 wordsLeft = wordsPerBlock - wordIndexInBlock;
636 currentWord = SWAP_BE32 (*buffer);
637 bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask);
638 }
639
640 //
641 // Find the first unallocated block
642 //
643 block=startingBlock;
644 while (block < endingBlock) {
645 if ((currentWord & bitMask) == 0)
646 break;
647
648 // Next bit
649 ++block;
650 bitMask >>= 1;
651 if (bitMask == 0) {
652 // Next word
653 bitMask = kHighBitInWordMask;
654 ++buffer;
655
656 if (--wordsLeft == 0) {
657 // Next block
658 buffer = currCache = NULL;
659 err = ReleaseBitmapBlock(vcb, blockRef, false);
660 if (err != noErr) goto Exit;
661
662 err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
663 if (err != noErr) goto Exit;
664 buffer = currCache;
665
666 wordsLeft = wordsPerBlock;
667 }
668
669 currentWord = SWAP_BE32 (*buffer);
670 }
671 }
672
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) {
676 err = dskFulErr;
677 goto Exit;
678 }
679
680 // Return the first block in the allocated range
681 *actualStartBlock = block;
682 dirty = true;
683
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
690 }
691
692 // XXXdbg
693 if (hfsmp->jnl) {
694 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
695 }
696
697 //
698 // Allocate all of the consecutive blocks
699 //
700 while ((currentWord & bitMask) == 0) {
701 // Allocate this block
702 currentWord |= bitMask;
703
704 // Move to the next block. If no more, then exit.
705 ++block;
706 if (block == endingBlock)
707 break;
708
709 // Next bit
710 bitMask >>= 1;
711 if (bitMask == 0) {
712 *buffer = SWAP_BE32 (currentWord); // update value in bitmap
713
714 // Next word
715 bitMask = kHighBitInWordMask;
716 ++buffer;
717
718 if (--wordsLeft == 0) {
719 // Next block
720 buffer = currCache = NULL;
721 err = ReleaseBitmapBlock(vcb, blockRef, true);
722 if (err != noErr) goto Exit;
723
724 err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
725 if (err != noErr) goto Exit;
726 buffer = currCache;
727
728 // XXXdbg
729 if (hfsmp->jnl) {
730 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
731 }
732
733 wordsLeft = wordsPerBlock;
734 }
735
736 currentWord = SWAP_BE32 (*buffer);
737 }
738 }
739 *buffer = SWAP_BE32 (currentWord); // update the last change
740
741 Exit:
742 if (err == noErr) {
743 *actualNumBlocks = block - *actualStartBlock;
744 }
745 else {
746 *actualStartBlock = 0;
747 *actualNumBlocks = 0;
748 }
749
750 if (currCache)
751 (void) ReleaseBitmapBlock(vcb, blockRef, dirty);
752
753 return err;
754 }
755
756
757 /*
758 _______________________________________________________________________
759
760 Routine: BlockAllocateKnown
761
762 Function: Try to allocate space from known free space in the free
763 extent cache.
764
765 Inputs:
766 vcb Pointer to volume where space is to be allocated
767 maxBlocks Maximum number of contiguous blocks to allocate
768
769 Outputs:
770 actualStartBlock First block of range allocated, or 0 if error
771 actualNumBlocks Number of blocks allocated, or 0 if error
772
773 Returns:
774 dskFulErr Free extent cache is empty
775 _______________________________________________________________________
776 */
777 static OSErr BlockAllocateKnown(
778 ExtendedVCB *vcb,
779 UInt32 maxBlocks,
780 UInt32 *actualStartBlock,
781 UInt32 *actualNumBlocks)
782 {
783 UInt32 i;
784 UInt32 foundBlocks;
785 UInt32 newStartBlock, newBlockCount;
786
787 if (vcb->vcbFreeExtCnt == 0)
788 return dskFulErr;
789
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;
796
797 // Adjust the start and length of that extent.
798 newStartBlock = vcb->vcbFreeExt[0].startBlock + foundBlocks;
799 newBlockCount = vcb->vcbFreeExt[0].blockCount - foundBlocks;
800
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)
804 {
805 if (vcb->vcbFreeExt[i].blockCount > newBlockCount)
806 {
807 vcb->vcbFreeExt[i-1].startBlock = vcb->vcbFreeExt[i].startBlock;
808 vcb->vcbFreeExt[i-1].blockCount = vcb->vcbFreeExt[i].blockCount;
809 }
810 else
811 {
812 break;
813 }
814 }
815
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)
820 {
821 // It's now the smallest extent, so forget about it
822 --vcb->vcbFreeExtCnt;
823 }
824 else
825 {
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;
829 }
830
831 //
832 // Now mark the found extent in the bitmap
833 //
834 return BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
835 }
836
837
838
839 /*
840 _______________________________________________________________________
841
842 Routine: BlockMarkAllocated
843
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).
847
848 Inputs:
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 _______________________________________________________________________
853 */
854 static OSErr BlockMarkAllocated(
855 ExtendedVCB *vcb,
856 UInt32 startingBlock,
857 register UInt32 numBlocks)
858 {
859 OSErr err;
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;
866 UInt32 blockRef;
867 UInt32 bitsPerBlock;
868 UInt32 wordsPerBlock;
869 // XXXdbg
870 struct hfsmount *hfsmp = VCBTOHFS(vcb);
871
872 //
873 // Pre-read the bitmap block containing the first word of allocation
874 //
875
876 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
877 if (err != noErr) goto Exit;
878 //
879 // Initialize currentWord, and wordsLeft.
880 //
881 {
882 UInt32 wordIndexInBlock;
883
884 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
885 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
886
887 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
888 currentWord = buffer + wordIndexInBlock;
889 wordsLeft = wordsPerBlock - wordIndexInBlock;
890 }
891
892 // XXXdbg
893 if (hfsmp->jnl) {
894 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
895 }
896
897 //
898 // If the first block to allocate doesn't start on a word
899 // boundary in the bitmap, then treat that first word
900 // specially.
901 //
902
903 firstBit = startingBlock % kBitsPerWord;
904 if (firstBit != 0) {
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
910 }
911 #if DEBUG_BUILD
912 if ((*currentWord & SWAP_BE32 (bitMask)) != 0) {
913 panic("BlockMarkAllocated: blocks already allocated!");
914 }
915 #endif
916 *currentWord |= SWAP_BE32 (bitMask); // set the bits in the bitmap
917 numBlocks -= numBits; // adjust number of blocks left to allocate
918
919 ++currentWord; // move to next word
920 --wordsLeft; // one less word left in this block
921 }
922
923 //
924 // Allocate whole words (32 blocks) at a time.
925 //
926
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
932
933 buffer = NULL;
934 err = ReleaseBitmapBlock(vcb, blockRef, true);
935 if (err != noErr) goto Exit;
936
937 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
938 if (err != noErr) goto Exit;
939
940 // XXXdbg
941 if (hfsmp->jnl) {
942 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
943 }
944
945 // Readjust currentWord and wordsLeft
946 currentWord = buffer;
947 wordsLeft = wordsPerBlock;
948 }
949 #if DEBUG_BUILD
950 if (*currentWord != 0) {
951 panic("BlockMarkAllocated: blocks already allocated!");
952 }
953 #endif
954 *currentWord = SWAP_BE32 (bitMask);
955 numBlocks -= kBitsPerWord;
956
957 ++currentWord; // move to next word
958 --wordsLeft; // one less word left in this block
959 }
960
961 //
962 // Allocate any remaining blocks.
963 //
964
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
970
971 buffer = NULL;
972 err = ReleaseBitmapBlock(vcb, blockRef, true);
973 if (err != noErr) goto Exit;
974
975 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
976 if (err != noErr) goto Exit;
977
978 // XXXdbg
979 if (hfsmp->jnl) {
980 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
981 }
982
983 // Readjust currentWord and wordsLeft
984 currentWord = buffer;
985 wordsLeft = wordsPerBlock;
986 }
987 #if DEBUG_BUILD
988 if ((*currentWord & SWAP_BE32 (bitMask)) != 0) {
989 panic("BlockMarkAllocated: blocks already allocated!");
990 }
991 #endif
992 *currentWord |= SWAP_BE32 (bitMask); // set the bits in the bitmap
993
994 // No need to update currentWord or wordsLeft
995 }
996
997 Exit:
998
999 if (buffer)
1000 (void)ReleaseBitmapBlock(vcb, blockRef, true);
1001
1002 return err;
1003 }
1004
1005
1006 /*
1007 _______________________________________________________________________
1008
1009 Routine: BlockMarkFree
1010
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).
1014
1015 Inputs:
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 _______________________________________________________________________
1020 */
1021 static OSErr BlockMarkFree(
1022 ExtendedVCB *vcb,
1023 UInt32 startingBlock,
1024 register UInt32 numBlocks)
1025 {
1026 OSErr err;
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;
1033 UInt32 blockRef;
1034 UInt32 bitsPerBlock;
1035 UInt32 wordsPerBlock;
1036 // XXXdbg
1037 struct hfsmount *hfsmp = VCBTOHFS(vcb);
1038
1039 //
1040 // Pre-read the bitmap block containing the first word of allocation
1041 //
1042
1043 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1044 if (err != noErr) goto Exit;
1045 // XXXdbg
1046 if (hfsmp->jnl) {
1047 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1048 }
1049
1050 //
1051 // Initialize currentWord, and wordsLeft.
1052 //
1053 {
1054 UInt32 wordIndexInBlock;
1055
1056 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
1057 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
1058
1059 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
1060 currentWord = buffer + wordIndexInBlock;
1061 wordsLeft = wordsPerBlock - wordIndexInBlock;
1062 }
1063
1064 //
1065 // If the first block to free doesn't start on a word
1066 // boundary in the bitmap, then treat that first word
1067 // specially.
1068 //
1069
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
1077 }
1078 #if DEBUG_BUILD
1079 if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
1080 panic("BlockMarkFree: blocks not allocated!");
1081 }
1082 #endif
1083 *currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
1084 numBlocks -= numBits; // adjust number of blocks left to free
1085
1086 ++currentWord; // move to next word
1087 --wordsLeft; // one less word left in this block
1088 }
1089
1090 //
1091 // Free whole words (32 blocks) at a time.
1092 //
1093
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
1098
1099 buffer = NULL;
1100 err = ReleaseBitmapBlock(vcb, blockRef, true);
1101 if (err != noErr) goto Exit;
1102
1103 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1104 if (err != noErr) goto Exit;
1105
1106 // XXXdbg
1107 if (hfsmp->jnl) {
1108 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1109 }
1110
1111 // Readjust currentWord and wordsLeft
1112 currentWord = buffer;
1113 wordsLeft = wordsPerBlock;
1114 }
1115
1116 #if DEBUG_BUILD
1117 if (*currentWord != SWAP_BE32 (kAllBitsSetInWord)) {
1118 panic("BlockMarkFree: blocks not allocated!");
1119 }
1120 #endif
1121 *currentWord = 0; // clear the entire word
1122 numBlocks -= kBitsPerWord;
1123
1124 ++currentWord; // move to next word
1125 --wordsLeft; // one less word left in this block
1126 }
1127
1128 //
1129 // Free any remaining blocks.
1130 //
1131
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
1137
1138 buffer = NULL;
1139 err = ReleaseBitmapBlock(vcb, blockRef, true);
1140 if (err != noErr) goto Exit;
1141
1142 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1143 if (err != noErr) goto Exit;
1144
1145 // XXXdbg
1146 if (hfsmp->jnl) {
1147 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1148 }
1149
1150 // Readjust currentWord and wordsLeft
1151 currentWord = buffer;
1152 wordsLeft = wordsPerBlock;
1153 }
1154 #if DEBUG_BUILD
1155 if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
1156 panic("BlockMarkFree: blocks not allocated!");
1157 }
1158 #endif
1159 *currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
1160
1161 // No need to update currentWord or wordsLeft
1162 }
1163
1164 Exit:
1165
1166 if (buffer)
1167 (void)ReleaseBitmapBlock(vcb, blockRef, true);
1168
1169 return err;
1170 }
1171
1172
1173 /*
1174 _______________________________________________________________________
1175
1176 Routine: BlockFindContiguous
1177
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.
1181
1182 Inputs:
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
1188
1189 Outputs:
1190 actualStartBlock First block of range found, or 0 if error
1191 actualNumBlocks Number of blocks found, or 0 if error
1192
1193 Returns:
1194 noErr Found at least minBlocks contiguous
1195 dskFulErr No contiguous space found, or all less than minBlocks
1196 _______________________________________________________________________
1197 */
1198
1199 static OSErr BlockFindContiguous(
1200 ExtendedVCB *vcb,
1201 UInt32 startingBlock,
1202 UInt32 endingBlock,
1203 UInt32 minBlocks,
1204 UInt32 maxBlocks,
1205 UInt32 *actualStartBlock,
1206 UInt32 *actualNumBlocks)
1207 {
1208 OSErr err;
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;
1218 UInt32 blockRef;
1219 UInt32 wordsPerBlock;
1220
1221 if ((endingBlock - startingBlock) < minBlocks)
1222 {
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.
1225 goto DiskFull;
1226 }
1227
1228 stopBlock = endingBlock - minBlocks + 1;
1229 currentBlock = startingBlock;
1230 firstBlock = 0;
1231
1232 //
1233 // Pre-read the first bitmap block.
1234 //
1235 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1236 if ( err != noErr ) goto ErrorExit;
1237
1238 //
1239 // Figure out where currentBlock is within the buffer.
1240 //
1241 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
1242
1243 wordsLeft = (startingBlock / kBitsPerWord) & (wordsPerBlock-1); // Current index into buffer
1244 currentWord = buffer + wordsLeft;
1245 wordsLeft = wordsPerBlock - wordsLeft;
1246
1247 do
1248 {
1249 foundBlocks = 0;
1250
1251 //============================================================
1252 // Look for a free block, skipping over allocated blocks.
1253 //============================================================
1254
1255 //
1256 // Check an initial partial word (if any)
1257 //
1258 bitMask = currentBlock & kBitsWithinWordMask;
1259 if (bitMask)
1260 {
1261 tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
1262 bitMask = kHighBitInWordMask >> bitMask;
1263 while (tempWord & bitMask)
1264 {
1265 bitMask >>= 1;
1266 ++currentBlock;
1267 }
1268
1269 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1270 if (bitMask)
1271 goto FoundUnused;
1272
1273 // Didn't find any unused bits, so we're done with this word.
1274 ++currentWord;
1275 --wordsLeft;
1276 }
1277
1278 //
1279 // Check whole words
1280 //
1281 while (currentBlock < stopBlock)
1282 {
1283 // See if it's time to read another block.
1284 if (wordsLeft == 0)
1285 {
1286 buffer = NULL;
1287 err = ReleaseBitmapBlock(vcb, blockRef, false);
1288 if (err != noErr) goto ErrorExit;
1289
1290 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1291 if ( err != noErr ) goto ErrorExit;
1292
1293 currentWord = buffer;
1294 wordsLeft = wordsPerBlock;
1295 }
1296
1297 // See if any of the bits are clear
1298 if ((tempWord = SWAP_BE32(*currentWord)) + 1) // non-zero if any bits were clear
1299 {
1300 // Figure out which bit is clear
1301 bitMask = kHighBitInWordMask;
1302 while (tempWord & bitMask)
1303 {
1304 bitMask >>= 1;
1305 ++currentBlock;
1306 }
1307
1308 break; // Found the free bit; break out to FoundUnused.
1309 }
1310
1311 // Keep looking at the next word
1312 currentBlock += kBitsPerWord;
1313 ++currentWord;
1314 --wordsLeft;
1315 }
1316
1317 FoundUnused:
1318 // Make sure the unused bit is early enough to use
1319 if (currentBlock >= stopBlock)
1320 {
1321 break;
1322 }
1323
1324 // Remember the start of the extent
1325 firstBlock = currentBlock;
1326
1327 //============================================================
1328 // Count the number of contiguous free blocks.
1329 //============================================================
1330
1331 //
1332 // Check an initial partial word (if any)
1333 //
1334 bitMask = currentBlock & kBitsWithinWordMask;
1335 if (bitMask)
1336 {
1337 tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
1338 bitMask = kHighBitInWordMask >> bitMask;
1339 while (bitMask && !(tempWord & bitMask))
1340 {
1341 bitMask >>= 1;
1342 ++currentBlock;
1343 }
1344
1345 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1346 if (bitMask)
1347 goto FoundUsed;
1348
1349 // Didn't find any used bits, so we're done with this word.
1350 ++currentWord;
1351 --wordsLeft;
1352 }
1353
1354 //
1355 // Check whole words
1356 //
1357 while (currentBlock < endingBlock)
1358 {
1359 // See if it's time to read another block.
1360 if (wordsLeft == 0)
1361 {
1362 buffer = NULL;
1363 err = ReleaseBitmapBlock(vcb, blockRef, false);
1364 if (err != noErr) goto ErrorExit;
1365
1366 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1367 if ( err != noErr ) goto ErrorExit;
1368
1369 currentWord = buffer;
1370 wordsLeft = wordsPerBlock;
1371 }
1372
1373 // See if any of the bits are set
1374 if ((tempWord = SWAP_BE32(*currentWord)) != 0)
1375 {
1376 // Figure out which bit is set
1377 bitMask = kHighBitInWordMask;
1378 while (!(tempWord & bitMask))
1379 {
1380 bitMask >>= 1;
1381 ++currentBlock;
1382 }
1383
1384 break; // Found the used bit; break out to FoundUsed.
1385 }
1386
1387 // Keep looking at the next word
1388 currentBlock += kBitsPerWord;
1389 ++currentWord;
1390 --wordsLeft;
1391
1392 // If we found at least maxBlocks, we can quit early.
1393 if ((currentBlock - firstBlock) >= maxBlocks)
1394 break;
1395 }
1396
1397 FoundUsed:
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;
1402
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!
1410
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)
1415 --tempWord;
1416 if (tempWord < kMaxFreeExtents)
1417 {
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)
1420 {
1421 vcb->vcbFreeExt[tempWord] = vcb->vcbFreeExt[tempWord-1];
1422 --tempWord;
1423 }
1424 vcb->vcbFreeExt[tempWord].startBlock = firstBlock;
1425 vcb->vcbFreeExt[tempWord].blockCount = foundBlocks;
1426
1427 if (vcb->vcbFreeExtCnt < kMaxFreeExtents)
1428 ++vcb->vcbFreeExtCnt;
1429 }
1430 } while (currentBlock < stopBlock);
1431
1432
1433 // Return the outputs.
1434 if (foundBlocks < minBlocks)
1435 {
1436 DiskFull:
1437 err = dskFulErr;
1438 ErrorExit:
1439 *actualStartBlock = 0;
1440 *actualNumBlocks = 0;
1441 }
1442 else
1443 {
1444 err = noErr;
1445 *actualStartBlock = firstBlock;
1446 *actualNumBlocks = foundBlocks;
1447 }
1448
1449 if (buffer)
1450 (void) ReleaseBitmapBlock(vcb, blockRef, false);
1451
1452 return err;
1453 }
1454
1455