]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/VolumeAllocation.c
4fe6499214d2987b85693abafd71ddf6e88b18c8
[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 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 File: VolumeAllocation.c
24
25 Contains: Routines for accessing and modifying the volume bitmap.
26
27 Version: HFS Plus 1.0
28
29 Copyright: © 1996-2001 by Apple Computer, Inc., all rights reserved.
30
31 */
32
33 /*
34 Public routines:
35 BlockAllocate
36 Allocate space on a volume. Can allocate space contiguously.
37 If not contiguous, then allocation may be less than what was
38 asked for. Returns the starting block number, and number of
39 blocks. (Will only do a single extent???)
40 BlockDeallocate
41 Deallocate a contiguous run of allocation blocks.
42
43
44 Internal routines:
45 BlockMarkFree
46 Mark a contiguous range of blocks as free. The corresponding
47 bits in the volume bitmap will be cleared.
48 BlockMarkAllocated
49 Mark a contiguous range of blocks as allocated. The cor-
50 responding bits in the volume bitmap are set. Also tests to see
51 if any of the blocks were previously unallocated.
52 FindContiguous
53 Find a contiguous range of blocks of a given size. The caller
54 specifies where to begin the search (by block number). The
55 block number of the first block in the range is returned.
56 BlockAllocateAny
57 Find and allocate a contiguous range of blocks up to a given size. The
58 first range of contiguous free blocks found are allocated, even if there
59 are fewer blocks than requested (and even if a contiguous range of blocks
60 of the given size exists elsewhere).
61 BlockAllocateContig
62 Find and allocate a contiguous range of blocks of a given size. If
63 a contiguous range of free blocks of the given size isn't found, then
64 the allocation fails (i.e. it is "all or nothing").
65
66 BlockAllocateKnown
67 Try to allocate space from known free space in the volume's
68 free extent cache.
69
70 ReadBitmapBlock
71 Given an allocation block number, read the bitmap block that
72 contains that allocation block into a caller-supplied buffer.
73
74 ReleaseBitmapBlock
75 Release a bitmap block back into the buffer cache.
76 */
77
78 #include "../../hfs_macos_defs.h"
79
80 #include <sys/types.h>
81 #include <sys/buf.h>
82 #include <sys/systm.h>
83
84 #include "../../hfs.h"
85 #include "../../hfs_dbg.h"
86 #include "../../hfs_format.h"
87 #include "../../hfs_endian.h"
88
89 #include "../headers/FileMgrInternal.h"
90
91
92 enum {
93 kBytesPerWord = 4,
94 kBitsPerByte = 8,
95 kBitsPerWord = 32,
96
97 kBitsWithinWordMask = kBitsPerWord-1
98 };
99
100 #define kLowBitInWordMask 0x00000001ul
101 #define kHighBitInWordMask 0x80000000ul
102 #define kAllBitsSetInWord 0xFFFFFFFFul
103
104
105 static OSErr ReadBitmapBlock(
106 ExtendedVCB *vcb,
107 UInt32 bit,
108 UInt32 **buffer,
109 UInt32 *blockRef);
110
111 static OSErr ReleaseBitmapBlock(
112 ExtendedVCB *vcb,
113 UInt32 blockRef,
114 Boolean dirty);
115
116 static OSErr BlockAllocateAny(
117 ExtendedVCB *vcb,
118 UInt32 startingBlock,
119 UInt32 endingBlock,
120 UInt32 maxBlocks,
121 UInt32 *actualStartBlock,
122 UInt32 *actualNumBlocks);
123
124 static OSErr BlockAllocateContig(
125 ExtendedVCB *vcb,
126 UInt32 startingBlock,
127 UInt32 minBlocks,
128 UInt32 maxBlocks,
129 UInt32 *actualStartBlock,
130 UInt32 *actualNumBlocks);
131
132 static OSErr BlockFindContiguous(
133 ExtendedVCB *vcb,
134 UInt32 startingBlock,
135 UInt32 endingBlock,
136 UInt32 minBlocks,
137 UInt32 maxBlocks,
138 UInt32 *actualStartBlock,
139 UInt32 *actualNumBlocks);
140
141 static OSErr BlockMarkAllocated(
142 ExtendedVCB *vcb,
143 UInt32 startingBlock,
144 UInt32 numBlocks);
145
146 static OSErr BlockMarkFree(
147 ExtendedVCB *vcb,
148 UInt32 startingBlock,
149 UInt32 numBlocks);
150
151 static OSErr BlockAllocateKnown(
152 ExtendedVCB *vcb,
153 UInt32 maxBlocks,
154 UInt32 *actualStartBlock,
155 UInt32 *actualNumBlocks);
156
157
158 /*
159 ;________________________________________________________________________________
160 ;
161 ; Routine: BlkAlloc
162 ;
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
169 ; allocated.
170 ;
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
173 ; point.
174 ;
175 ; All requests will be rounded up to the next highest clump size, as
176 ; indicated in the file's FCB.
177 ;
178 ; Input Arguments:
179 ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
180 ; fcb - Pointer to FCB for the file for which storage is being allocated
181 ; startingBlock - Preferred starting allocation block, 0 = no preference
182 ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
183 ; or an error is returned
184 ; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
185 ; less than this may actually be allocated
186 ; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
187 ; space after bytesRequested, then up to bytesMaximum bytes should really
188 ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
189 ; of the file's clump size.)
190 ;
191 ; Output:
192 ; (result) - Error code, zero for successful allocation
193 ; *startBlock - Actual starting allocation block
194 ; *actualBlocks - Actual number of allocation blocks allocated
195 ;
196 ; Side effects:
197 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
198 ;________________________________________________________________________________
199 */
200
201 OSErr BlockAllocate (
202 ExtendedVCB *vcb, /* which volume to allocate space on */
203 UInt32 startingBlock, /* preferred starting block, or 0 for no preference */
204 SInt64 bytesRequested, /* desired number of BYTES to allocate */
205 SInt64 bytesMaximum, /* maximum number of bytes to allocate */
206 Boolean forceContiguous, /* non-zero to force contiguous allocation and to force */
207 /* bytesRequested bytes to actually be allocated */
208 UInt32 *actualStartBlock, /* actual first block of allocation */
209 UInt32 *actualNumBlocks) /* number of blocks actually allocated; if forceContiguous */
210 /* was zero, then this may represent fewer than bytesRequested */
211 /* bytes */
212 {
213 OSErr err;
214 UInt32 minBlocks; // minimum number of allocation blocks requested
215 UInt32 maxBlocks; // number of allocation blocks requested, rounded to clump size
216 Boolean updateAllocPtr = false; // true if nextAllocation needs to be updated
217
218 //
219 // Initialize outputs in case we get an error
220 //
221 *actualStartBlock = 0;
222 *actualNumBlocks = 0;
223
224 //
225 // Compute the number of allocation blocks requested, and maximum
226 //
227 minBlocks = FileBytesToBlocks(bytesRequested, vcb->blockSize);
228 maxBlocks = FileBytesToBlocks(bytesMaximum, vcb->blockSize);
229
230 //
231 // If the disk is already full, don't bother.
232 //
233 if (hfs_freeblks(VCBTOHFS(vcb), 0) == 0) {
234 err = dskFulErr;
235 goto Exit;
236 }
237 if (forceContiguous && hfs_freeblks(VCBTOHFS(vcb), 0) < minBlocks) {
238 err = dskFulErr;
239 goto Exit;
240 }
241
242 //
243 // If caller didn't specify a starting block number, then use the volume's
244 // next block to allocate from.
245 //
246 if (startingBlock == 0) {
247 VCB_LOCK(vcb);
248 startingBlock = vcb->nextAllocation;
249 VCB_UNLOCK(vcb);
250 updateAllocPtr = true;
251 }
252
253 //
254 // If the request must be contiguous, then find a sequence of free blocks
255 // that is long enough. Otherwise, find the first free block.
256 //
257 if (forceContiguous) {
258 err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
259 /*
260 * If we allocated from a new position then
261 * also update the roving allocatior.
262 */
263 if ((err == noErr) && (*actualStartBlock > startingBlock))
264 vcb->nextAllocation = *actualStartBlock;
265 } else {
266 /*
267 * Scan the bitmap once, gather the N largest free extents, then
268 * allocate from these largest extents. Repeat as needed until
269 * we get all the space we needed. We could probably build up
270 * that list when the higher level caller tried (and failed) a
271 * contiguous allocation first.
272 */
273 err = BlockAllocateKnown(vcb, maxBlocks, actualStartBlock, actualNumBlocks);
274 if (err == dskFulErr)
275 err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
276 if (err == dskFulErr)
277 err = BlockAllocateAny(vcb, 0, startingBlock, maxBlocks, actualStartBlock, actualNumBlocks);
278 }
279
280 if (err == noErr) {
281 //
282 // If we used the volume's roving allocation pointer, then we need to update it.
283 // Adding in the length of the current allocation might reduce the next allocate
284 // call by avoiding a re-scan of the already allocated space. However, the clump
285 // just allocated can quite conceivably end up being truncated or released when
286 // the file is closed or its EOF changed. Leaving the allocation pointer at the
287 // start of the last allocation will avoid unnecessary fragmentation in this case.
288 //
289 VCB_LOCK(vcb);
290
291 if (updateAllocPtr)
292 vcb->nextAllocation = *actualStartBlock;
293
294 //
295 // Update the number of free blocks on the volume
296 //
297 vcb->freeBlocks -= *actualNumBlocks;
298 VCB_UNLOCK(vcb);
299
300 MarkVCBDirty(vcb);
301 }
302
303 Exit:
304
305 return err;
306 }
307
308
309 /*
310 ;________________________________________________________________________________
311 ;
312 ; Routine: BlkDealloc
313 ;
314 ; Function: Update the bitmap to deallocate a run of disk allocation blocks
315 ;
316 ; Input Arguments:
317 ; vcb - Pointer to ExtendedVCB for the volume to free space on
318 ; firstBlock - First allocation block to be freed
319 ; numBlocks - Number of allocation blocks to free up (must be > 0!)
320 ;
321 ; Output:
322 ; (result) - Result code
323 ;
324 ; Side effects:
325 ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
326 ;________________________________________________________________________________
327 */
328
329 OSErr BlockDeallocate (
330 ExtendedVCB *vcb, // Which volume to deallocate space on
331 UInt32 firstBlock, // First block in range to deallocate
332 UInt32 numBlocks) // Number of contiguous blocks to deallocate
333 {
334 OSErr err;
335
336 //
337 // If no blocks to deallocate, then exit early
338 //
339 if (numBlocks == 0) {
340 err = noErr;
341 goto Exit;
342 }
343
344 //
345 // Call internal routine to free the sequence of blocks
346 //
347 err = BlockMarkFree(vcb, firstBlock, numBlocks);
348 if (err)
349 goto Exit;
350
351 //
352 // Update the volume's free block count, and mark the VCB as dirty.
353 //
354 VCB_LOCK(vcb);
355 vcb->freeBlocks += numBlocks;
356 if (vcb->nextAllocation == (firstBlock + numBlocks))
357 vcb->nextAllocation -= numBlocks;
358 VCB_UNLOCK(vcb);
359 MarkVCBDirty(vcb);
360
361 Exit:
362
363 return err;
364 }
365
366
367 /*
368 ;_______________________________________________________________________
369 ;
370 ; Routine: FileBytesToBlocks
371 ;
372 ; Function: Divide numerator by denominator, rounding up the result if there
373 ; was a remainder. This is frequently used for computing the number
374 ; of whole and/or partial blocks used by some count of bytes.
375 ; Actuall divides a 64 bit by a 32 bit into a 32bit result
376 ;
377 ; CAREFULL!!! THIS CAN CAUSE OVERFLOW....USER BEWARE!!!
378 ;_______________________________________________________________________
379 */
380 UInt32 FileBytesToBlocks(
381 SInt64 numerator,
382 UInt32 denominator)
383 {
384 UInt32 quotient;
385
386 quotient = (UInt32)(numerator / denominator);
387 if (quotient * denominator != numerator)
388 quotient++;
389
390 return quotient;
391 }
392
393
394
395 /*
396 ;_______________________________________________________________________
397 ;
398 ; Routine: ReadBitmapBlock
399 ;
400 ; Function: Read in a bitmap block corresponding to a given allocation
401 ; block (bit). Return a pointer to the bitmap block.
402 ;
403 ; Inputs:
404 ; vcb -- Pointer to ExtendedVCB
405 ; bit -- Allocation block whose bitmap block is desired
406 ;
407 ; Outputs:
408 ; buffer -- Pointer to bitmap block corresonding to "block"
409 ; blockRef
410 ;_______________________________________________________________________
411 */
412 static OSErr ReadBitmapBlock(
413 ExtendedVCB *vcb,
414 UInt32 bit,
415 UInt32 **buffer,
416 UInt32 *blockRef)
417 {
418 OSErr err;
419 struct buf *bp = NULL;
420 struct vnode *vp = NULL;
421 UInt32 block;
422 UInt32 blockSize;
423
424 /*
425 * volume bitmap blocks are protected by the Extents B-tree lock
426 */
427 REQUIRE_FILE_LOCK(vcb->extentsRefNum, false);
428
429 blockSize = (UInt32)vcb->vcbVBMIOSize;
430 block = bit / (blockSize * kBitsPerByte);
431
432 if (vcb->vcbSigWord == kHFSPlusSigWord) {
433 vp = vcb->allocationsRefNum; /* use allocation file vnode */
434
435 } else /* hfs */ {
436 vp = VCBTOHFS(vcb)->hfs_devvp; /* use device I/O vnode */
437 block += vcb->vcbVBMSt; /* map to physical block */
438 }
439
440 err = meta_bread(vp, block, blockSize, NOCRED, &bp);
441
442 if (bp) {
443 if (err) {
444 brelse(bp);
445 *blockRef = NULL;
446 *buffer = NULL;
447 } else {
448 *blockRef = (UInt32)bp;
449 *buffer = (UInt32 *)bp->b_data;
450 }
451 }
452
453 return err;
454 }
455
456
457 /*
458 ;_______________________________________________________________________
459 ;
460 ; Routine: ReleaseBitmapBlock
461 ;
462 ; Function: Relase a bitmap block.
463 ;
464 ; Inputs:
465 ; vcb
466 ; blockRef
467 ; dirty
468 ;_______________________________________________________________________
469 */
470 static OSErr ReleaseBitmapBlock(
471 ExtendedVCB *vcb,
472 UInt32 blockRef,
473 Boolean dirty)
474 {
475 struct buf *bp = (struct buf *)blockRef;
476
477 if (bp) {
478 if (dirty) {
479 // XXXdbg
480 struct hfsmount *hfsmp = VCBTOHFS(vcb);
481
482 if (hfsmp->jnl) {
483 journal_modify_block_end(hfsmp->jnl, bp);
484 } else {
485 bdwrite(bp);
486 }
487 } else {
488 brelse(bp);
489 }
490 }
491
492 return (0);
493 }
494
495
496 /*
497 _______________________________________________________________________
498
499 Routine: BlockAllocateContig
500
501 Function: Allocate a contiguous group of allocation blocks. The
502 allocation is all-or-nothing. The caller guarantees that
503 there are enough free blocks (though they may not be
504 contiguous, in which case this call will fail).
505
506 Inputs:
507 vcb Pointer to volume where space is to be allocated
508 startingBlock Preferred first block for allocation
509 minBlocks Minimum number of contiguous blocks to allocate
510 maxBlocks Maximum number of contiguous blocks to allocate
511
512 Outputs:
513 actualStartBlock First block of range allocated, or 0 if error
514 actualNumBlocks Number of blocks allocated, or 0 if error
515 _______________________________________________________________________
516 */
517 static OSErr BlockAllocateContig(
518 ExtendedVCB *vcb,
519 UInt32 startingBlock,
520 UInt32 minBlocks,
521 UInt32 maxBlocks,
522 UInt32 *actualStartBlock,
523 UInt32 *actualNumBlocks)
524 {
525 OSErr err;
526
527 //
528 // Find a contiguous group of blocks at least minBlocks long.
529 // Determine the number of contiguous blocks available (up
530 // to maxBlocks).
531 //
532
533 /*
534 * NOTE: If the only contiguous free extent of at least minBlocks
535 * crosses startingBlock (i.e. starts before, ends after), then we
536 * won't find it. Earlier versions *did* find this case by letting
537 * the second search look past startingBlock by minBlocks. But
538 * with the free extent cache, this can lead to duplicate entries
539 * in the cache, causing the same blocks to be allocated twice.
540 */
541 err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
542 actualStartBlock, actualNumBlocks);
543 if (err == dskFulErr && startingBlock != 0) {
544 /*
545 * Constrain the endingBlock so we don't bother looking for ranges
546 * that would overlap those found in the previous call.
547 */
548 err = BlockFindContiguous(vcb, 0, startingBlock, minBlocks, maxBlocks,
549 actualStartBlock, actualNumBlocks);
550 }
551 if (err != noErr) goto Exit;
552
553 //
554 // Now mark those blocks allocated.
555 //
556 err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
557
558 Exit:
559 if (err != noErr) {
560 *actualStartBlock = 0;
561 *actualNumBlocks = 0;
562 }
563
564 return err;
565 }
566
567 /*
568 _______________________________________________________________________
569
570 Routine: BlockAllocateAny
571
572 Function: Allocate one or more allocation blocks. If there are fewer
573 free blocks than requested, all free blocks will be
574 allocated. The caller guarantees that there is at least
575 one free block.
576
577 Inputs:
578 vcb Pointer to volume where space is to be allocated
579 startingBlock Preferred first block for allocation
580 endingBlock Last block to check + 1
581 maxBlocks Maximum number of contiguous blocks to allocate
582
583 Outputs:
584 actualStartBlock First block of range allocated, or 0 if error
585 actualNumBlocks Number of blocks allocated, or 0 if error
586 _______________________________________________________________________
587 */
588 static OSErr BlockAllocateAny(
589 ExtendedVCB *vcb,
590 UInt32 startingBlock,
591 register UInt32 endingBlock,
592 UInt32 maxBlocks,
593 UInt32 *actualStartBlock,
594 UInt32 *actualNumBlocks)
595 {
596 OSErr err;
597 register UInt32 block; // current block number
598 register UInt32 currentWord; // Pointer to current word within bitmap block
599 register UInt32 bitMask; // Word with given bits already set (ready to OR in)
600 register UInt32 wordsLeft; // Number of words left in this bitmap block
601 UInt32 *buffer = NULL;
602 UInt32 *currCache = NULL;
603 UInt32 blockRef;
604 UInt32 bitsPerBlock;
605 UInt32 wordsPerBlock;
606 Boolean dirty = false;
607 struct hfsmount *hfsmp = VCBTOHFS(vcb);
608
609 // Since this routine doesn't wrap around
610 if (maxBlocks > (endingBlock - startingBlock)) {
611 maxBlocks = endingBlock - startingBlock;
612 }
613
614 //
615 // Pre-read the first bitmap block
616 //
617 err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef);
618 if (err != noErr) goto Exit;
619 buffer = currCache;
620
621 //
622 // Set up the current position within the block
623 //
624 {
625 UInt32 wordIndexInBlock;
626
627 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
628 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
629
630 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
631 buffer += wordIndexInBlock;
632 wordsLeft = wordsPerBlock - wordIndexInBlock;
633 currentWord = SWAP_BE32 (*buffer);
634 bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask);
635 }
636
637 //
638 // Find the first unallocated block
639 //
640 block=startingBlock;
641 while (block < endingBlock) {
642 if ((currentWord & bitMask) == 0)
643 break;
644
645 // Next bit
646 ++block;
647 bitMask >>= 1;
648 if (bitMask == 0) {
649 // Next word
650 bitMask = kHighBitInWordMask;
651 ++buffer;
652
653 if (--wordsLeft == 0) {
654 // Next block
655 buffer = currCache = NULL;
656 err = ReleaseBitmapBlock(vcb, blockRef, false);
657 if (err != noErr) goto Exit;
658
659 err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
660 if (err != noErr) goto Exit;
661 buffer = currCache;
662
663 wordsLeft = wordsPerBlock;
664 }
665
666 currentWord = SWAP_BE32 (*buffer);
667 }
668 }
669
670 // Did we get to the end of the bitmap before finding a free block?
671 // If so, then couldn't allocate anything.
672 if (block == endingBlock) {
673 err = dskFulErr;
674 goto Exit;
675 }
676
677 // Return the first block in the allocated range
678 *actualStartBlock = block;
679 dirty = true;
680
681 // If we could get the desired number of blocks before hitting endingBlock,
682 // then adjust endingBlock so we won't keep looking. Ideally, the comparison
683 // would be (block + maxBlocks) < endingBlock, but that could overflow. The
684 // comparison below yields identical results, but without overflow.
685 if (block < (endingBlock-maxBlocks)) {
686 endingBlock = block + maxBlocks; // if we get this far, we've found enough
687 }
688
689 // XXXdbg
690 if (hfsmp->jnl) {
691 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
692 }
693
694 //
695 // Allocate all of the consecutive blocks
696 //
697 while ((currentWord & bitMask) == 0) {
698 // Allocate this block
699 currentWord |= bitMask;
700
701 // Move to the next block. If no more, then exit.
702 ++block;
703 if (block == endingBlock)
704 break;
705
706 // Next bit
707 bitMask >>= 1;
708 if (bitMask == 0) {
709 *buffer = SWAP_BE32 (currentWord); // update value in bitmap
710
711 // Next word
712 bitMask = kHighBitInWordMask;
713 ++buffer;
714
715 if (--wordsLeft == 0) {
716 // Next block
717 buffer = currCache = NULL;
718 err = ReleaseBitmapBlock(vcb, blockRef, true);
719 if (err != noErr) goto Exit;
720
721 err = ReadBitmapBlock(vcb, block, &currCache, &blockRef);
722 if (err != noErr) goto Exit;
723 buffer = currCache;
724
725 // XXXdbg
726 if (hfsmp->jnl) {
727 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
728 }
729
730 wordsLeft = wordsPerBlock;
731 }
732
733 currentWord = SWAP_BE32 (*buffer);
734 }
735 }
736 *buffer = SWAP_BE32 (currentWord); // update the last change
737
738 Exit:
739 if (err == noErr) {
740 *actualNumBlocks = block - *actualStartBlock;
741 }
742 else {
743 *actualStartBlock = 0;
744 *actualNumBlocks = 0;
745 }
746
747 if (currCache)
748 (void) ReleaseBitmapBlock(vcb, blockRef, dirty);
749
750 return err;
751 }
752
753
754 /*
755 _______________________________________________________________________
756
757 Routine: BlockAllocateKnown
758
759 Function: Try to allocate space from known free space in the free
760 extent cache.
761
762 Inputs:
763 vcb Pointer to volume where space is to be allocated
764 maxBlocks Maximum number of contiguous blocks to allocate
765
766 Outputs:
767 actualStartBlock First block of range allocated, or 0 if error
768 actualNumBlocks Number of blocks allocated, or 0 if error
769
770 Returns:
771 dskFulErr Free extent cache is empty
772 _______________________________________________________________________
773 */
774 static OSErr BlockAllocateKnown(
775 ExtendedVCB *vcb,
776 UInt32 maxBlocks,
777 UInt32 *actualStartBlock,
778 UInt32 *actualNumBlocks)
779 {
780 UInt32 i;
781 UInt32 foundBlocks;
782 UInt32 newStartBlock, newBlockCount;
783
784 if (vcb->vcbFreeExtCnt == 0)
785 return dskFulErr;
786
787 // Just grab up to maxBlocks of the first (largest) free exent.
788 *actualStartBlock = vcb->vcbFreeExt[0].startBlock;
789 foundBlocks = vcb->vcbFreeExt[0].blockCount;
790 if (foundBlocks > maxBlocks)
791 foundBlocks = maxBlocks;
792 *actualNumBlocks = foundBlocks;
793
794 // Adjust the start and length of that extent.
795 newStartBlock = vcb->vcbFreeExt[0].startBlock + foundBlocks;
796 newBlockCount = vcb->vcbFreeExt[0].blockCount - foundBlocks;
797
798 // The first extent might not be the largest anymore. Bubble up any
799 // (now larger) extents to the top of the list.
800 for (i=1; i<vcb->vcbFreeExtCnt; ++i)
801 {
802 if (vcb->vcbFreeExt[i].blockCount > newBlockCount)
803 {
804 vcb->vcbFreeExt[i-1].startBlock = vcb->vcbFreeExt[i].startBlock;
805 vcb->vcbFreeExt[i-1].blockCount = vcb->vcbFreeExt[i].blockCount;
806 }
807 else
808 {
809 break;
810 }
811 }
812
813 // If this is now the smallest known free extent, then it might be smaller than
814 // other extents we didn't keep track of. So, just forget about this extent.
815 // After the previous loop, (i-1) is the index of the extent we just allocated from.
816 if (i == vcb->vcbFreeExtCnt)
817 {
818 // It's now the smallest extent, so forget about it
819 --vcb->vcbFreeExtCnt;
820 }
821 else
822 {
823 // It's not the smallest, so store it in its proper place
824 vcb->vcbFreeExt[i-1].startBlock = newStartBlock;
825 vcb->vcbFreeExt[i-1].blockCount = newBlockCount;
826 }
827
828 //
829 // Now mark the found extent in the bitmap
830 //
831 return BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
832 }
833
834
835
836 /*
837 _______________________________________________________________________
838
839 Routine: BlockMarkAllocated
840
841 Function: Mark a contiguous group of blocks as allocated (set in the
842 bitmap). It assumes those bits are currently marked
843 deallocated (clear in the bitmap).
844
845 Inputs:
846 vcb Pointer to volume where space is to be allocated
847 startingBlock First block number to mark as allocated
848 numBlocks Number of blocks to mark as allocated
849 _______________________________________________________________________
850 */
851 static OSErr BlockMarkAllocated(
852 ExtendedVCB *vcb,
853 UInt32 startingBlock,
854 register UInt32 numBlocks)
855 {
856 OSErr err;
857 register UInt32 *currentWord; // Pointer to current word within bitmap block
858 register UInt32 wordsLeft; // Number of words left in this bitmap block
859 register UInt32 bitMask; // Word with given bits already set (ready to OR in)
860 UInt32 firstBit; // Bit index within word of first bit to allocate
861 UInt32 numBits; // Number of bits in word to allocate
862 UInt32 *buffer = NULL;
863 UInt32 blockRef;
864 UInt32 bitsPerBlock;
865 UInt32 wordsPerBlock;
866 // XXXdbg
867 struct hfsmount *hfsmp = VCBTOHFS(vcb);
868
869 //
870 // Pre-read the bitmap block containing the first word of allocation
871 //
872
873 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
874 if (err != noErr) goto Exit;
875 //
876 // Initialize currentWord, and wordsLeft.
877 //
878 {
879 UInt32 wordIndexInBlock;
880
881 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
882 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
883
884 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
885 currentWord = buffer + wordIndexInBlock;
886 wordsLeft = wordsPerBlock - wordIndexInBlock;
887 }
888
889 // XXXdbg
890 if (hfsmp->jnl) {
891 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
892 }
893
894 //
895 // If the first block to allocate doesn't start on a word
896 // boundary in the bitmap, then treat that first word
897 // specially.
898 //
899
900 firstBit = startingBlock % kBitsPerWord;
901 if (firstBit != 0) {
902 bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit
903 numBits = kBitsPerWord - firstBit; // number of remaining bits in this word
904 if (numBits > numBlocks) {
905 numBits = numBlocks; // entire allocation is inside this one word
906 bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
907 }
908 #if DEBUG_BUILD
909 if ((*currentWord & SWAP_BE32 (bitMask)) != 0) {
910 panic("BlockMarkAllocated: blocks already allocated!");
911 }
912 #endif
913 *currentWord |= SWAP_BE32 (bitMask); // set the bits in the bitmap
914 numBlocks -= numBits; // adjust number of blocks left to allocate
915
916 ++currentWord; // move to next word
917 --wordsLeft; // one less word left in this block
918 }
919
920 //
921 // Allocate whole words (32 blocks) at a time.
922 //
923
924 bitMask = kAllBitsSetInWord; // put this in a register for 68K
925 while (numBlocks >= kBitsPerWord) {
926 if (wordsLeft == 0) {
927 // Read in the next bitmap block
928 startingBlock += bitsPerBlock; // generate a block number in the next bitmap block
929
930 buffer = NULL;
931 err = ReleaseBitmapBlock(vcb, blockRef, true);
932 if (err != noErr) goto Exit;
933
934 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
935 if (err != noErr) goto Exit;
936
937 // XXXdbg
938 if (hfsmp->jnl) {
939 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
940 }
941
942 // Readjust currentWord and wordsLeft
943 currentWord = buffer;
944 wordsLeft = wordsPerBlock;
945 }
946 #if DEBUG_BUILD
947 if (*currentWord != 0) {
948 panic("BlockMarkAllocated: blocks already allocated!");
949 }
950 #endif
951 *currentWord = SWAP_BE32 (bitMask);
952 numBlocks -= kBitsPerWord;
953
954 ++currentWord; // move to next word
955 --wordsLeft; // one less word left in this block
956 }
957
958 //
959 // Allocate any remaining blocks.
960 //
961
962 if (numBlocks != 0) {
963 bitMask = ~(kAllBitsSetInWord >> numBlocks); // set first numBlocks bits
964 if (wordsLeft == 0) {
965 // Read in the next bitmap block
966 startingBlock += bitsPerBlock; // generate a block number in the next bitmap block
967
968 buffer = NULL;
969 err = ReleaseBitmapBlock(vcb, blockRef, true);
970 if (err != noErr) goto Exit;
971
972 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
973 if (err != noErr) goto Exit;
974
975 // XXXdbg
976 if (hfsmp->jnl) {
977 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
978 }
979
980 // Readjust currentWord and wordsLeft
981 currentWord = buffer;
982 wordsLeft = wordsPerBlock;
983 }
984 #if DEBUG_BUILD
985 if ((*currentWord & SWAP_BE32 (bitMask)) != 0) {
986 panic("BlockMarkAllocated: blocks already allocated!");
987 }
988 #endif
989 *currentWord |= SWAP_BE32 (bitMask); // set the bits in the bitmap
990
991 // No need to update currentWord or wordsLeft
992 }
993
994 Exit:
995
996 if (buffer)
997 (void)ReleaseBitmapBlock(vcb, blockRef, true);
998
999 return err;
1000 }
1001
1002
1003 /*
1004 _______________________________________________________________________
1005
1006 Routine: BlockMarkFree
1007
1008 Function: Mark a contiguous group of blocks as free (clear in the
1009 bitmap). It assumes those bits are currently marked
1010 allocated (set in the bitmap).
1011
1012 Inputs:
1013 vcb Pointer to volume where space is to be freed
1014 startingBlock First block number to mark as freed
1015 numBlocks Number of blocks to mark as freed
1016 _______________________________________________________________________
1017 */
1018 static OSErr BlockMarkFree(
1019 ExtendedVCB *vcb,
1020 UInt32 startingBlock,
1021 register UInt32 numBlocks)
1022 {
1023 OSErr err;
1024 register UInt32 *currentWord; // Pointer to current word within bitmap block
1025 register UInt32 wordsLeft; // Number of words left in this bitmap block
1026 register UInt32 bitMask; // Word with given bits already set (ready to OR in)
1027 UInt32 firstBit; // Bit index within word of first bit to allocate
1028 UInt32 numBits; // Number of bits in word to allocate
1029 UInt32 *buffer = NULL;
1030 UInt32 blockRef;
1031 UInt32 bitsPerBlock;
1032 UInt32 wordsPerBlock;
1033 // XXXdbg
1034 struct hfsmount *hfsmp = VCBTOHFS(vcb);
1035
1036 //
1037 // Pre-read the bitmap block containing the first word of allocation
1038 //
1039
1040 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1041 if (err != noErr) goto Exit;
1042 // XXXdbg
1043 if (hfsmp->jnl) {
1044 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1045 }
1046
1047 //
1048 // Initialize currentWord, and wordsLeft.
1049 //
1050 {
1051 UInt32 wordIndexInBlock;
1052
1053 bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte;
1054 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
1055
1056 wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord;
1057 currentWord = buffer + wordIndexInBlock;
1058 wordsLeft = wordsPerBlock - wordIndexInBlock;
1059 }
1060
1061 //
1062 // If the first block to free doesn't start on a word
1063 // boundary in the bitmap, then treat that first word
1064 // specially.
1065 //
1066
1067 firstBit = startingBlock % kBitsPerWord;
1068 if (firstBit != 0) {
1069 bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit
1070 numBits = kBitsPerWord - firstBit; // number of remaining bits in this word
1071 if (numBits > numBlocks) {
1072 numBits = numBlocks; // entire allocation is inside this one word
1073 bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
1074 }
1075 #if DEBUG_BUILD
1076 if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
1077 panic("BlockMarkFree: blocks not allocated!");
1078 }
1079 #endif
1080 *currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
1081 numBlocks -= numBits; // adjust number of blocks left to free
1082
1083 ++currentWord; // move to next word
1084 --wordsLeft; // one less word left in this block
1085 }
1086
1087 //
1088 // Free whole words (32 blocks) at a time.
1089 //
1090
1091 while (numBlocks >= kBitsPerWord) {
1092 if (wordsLeft == 0) {
1093 // Read in the next bitmap block
1094 startingBlock += bitsPerBlock; // generate a block number in the next bitmap block
1095
1096 buffer = NULL;
1097 err = ReleaseBitmapBlock(vcb, blockRef, true);
1098 if (err != noErr) goto Exit;
1099
1100 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1101 if (err != noErr) goto Exit;
1102
1103 // XXXdbg
1104 if (hfsmp->jnl) {
1105 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1106 }
1107
1108 // Readjust currentWord and wordsLeft
1109 currentWord = buffer;
1110 wordsLeft = wordsPerBlock;
1111 }
1112
1113 #if DEBUG_BUILD
1114 if (*currentWord != SWAP_BE32 (kAllBitsSetInWord)) {
1115 panic("BlockMarkFree: blocks not allocated!");
1116 }
1117 #endif
1118 *currentWord = 0; // clear the entire word
1119 numBlocks -= kBitsPerWord;
1120
1121 ++currentWord; // move to next word
1122 --wordsLeft; // one less word left in this block
1123 }
1124
1125 //
1126 // Free any remaining blocks.
1127 //
1128
1129 if (numBlocks != 0) {
1130 bitMask = ~(kAllBitsSetInWord >> numBlocks); // set first numBlocks bits
1131 if (wordsLeft == 0) {
1132 // Read in the next bitmap block
1133 startingBlock += bitsPerBlock; // generate a block number in the next bitmap block
1134
1135 buffer = NULL;
1136 err = ReleaseBitmapBlock(vcb, blockRef, true);
1137 if (err != noErr) goto Exit;
1138
1139 err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef);
1140 if (err != noErr) goto Exit;
1141
1142 // XXXdbg
1143 if (hfsmp->jnl) {
1144 journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef);
1145 }
1146
1147 // Readjust currentWord and wordsLeft
1148 currentWord = buffer;
1149 wordsLeft = wordsPerBlock;
1150 }
1151 #if DEBUG_BUILD
1152 if ((*currentWord & SWAP_BE32 (bitMask)) != SWAP_BE32 (bitMask)) {
1153 panic("BlockMarkFree: blocks not allocated!");
1154 }
1155 #endif
1156 *currentWord &= SWAP_BE32 (~bitMask); // clear the bits in the bitmap
1157
1158 // No need to update currentWord or wordsLeft
1159 }
1160
1161 Exit:
1162
1163 if (buffer)
1164 (void)ReleaseBitmapBlock(vcb, blockRef, true);
1165
1166 return err;
1167 }
1168
1169
1170 /*
1171 _______________________________________________________________________
1172
1173 Routine: BlockFindContiguous
1174
1175 Function: Find a contiguous range of blocks that are free (bits
1176 clear in the bitmap). If a contiguous range of the
1177 minimum size can't be found, an error will be returned.
1178
1179 Inputs:
1180 vcb Pointer to volume where space is to be allocated
1181 startingBlock Preferred first block of range
1182 endingBlock Last possible block in range + 1
1183 minBlocks Minimum number of blocks needed. Must be > 0.
1184 maxBlocks Maximum (ideal) number of blocks desired
1185
1186 Outputs:
1187 actualStartBlock First block of range found, or 0 if error
1188 actualNumBlocks Number of blocks found, or 0 if error
1189
1190 Returns:
1191 noErr Found at least minBlocks contiguous
1192 dskFulErr No contiguous space found, or all less than minBlocks
1193 _______________________________________________________________________
1194 */
1195
1196 static OSErr BlockFindContiguous(
1197 ExtendedVCB *vcb,
1198 UInt32 startingBlock,
1199 UInt32 endingBlock,
1200 UInt32 minBlocks,
1201 UInt32 maxBlocks,
1202 UInt32 *actualStartBlock,
1203 UInt32 *actualNumBlocks)
1204 {
1205 OSErr err;
1206 register UInt32 currentBlock; // Block we're currently looking at.
1207 UInt32 firstBlock; // First free block in current extent.
1208 UInt32 stopBlock; // If we get to this block, stop searching for first free block.
1209 UInt32 foundBlocks; // Number of contiguous free blocks in current extent.
1210 UInt32 *buffer = NULL;
1211 register UInt32 *currentWord;
1212 register UInt32 bitMask;
1213 register UInt32 wordsLeft;
1214 register UInt32 tempWord;
1215 UInt32 blockRef;
1216 UInt32 wordsPerBlock;
1217
1218 if ((endingBlock - startingBlock) < minBlocks)
1219 {
1220 // The set of blocks we're checking is smaller than the minimum number
1221 // of blocks, so we couldn't possibly find a good range.
1222 goto DiskFull;
1223 }
1224
1225 stopBlock = endingBlock - minBlocks + 1;
1226 currentBlock = startingBlock;
1227 firstBlock = 0;
1228
1229 //
1230 // Pre-read the first bitmap block.
1231 //
1232 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1233 if ( err != noErr ) goto ErrorExit;
1234
1235 //
1236 // Figure out where currentBlock is within the buffer.
1237 //
1238 wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord;
1239
1240 wordsLeft = (startingBlock / kBitsPerWord) & (wordsPerBlock-1); // Current index into buffer
1241 currentWord = buffer + wordsLeft;
1242 wordsLeft = wordsPerBlock - wordsLeft;
1243
1244 do
1245 {
1246 foundBlocks = 0;
1247
1248 //============================================================
1249 // Look for a free block, skipping over allocated blocks.
1250 //============================================================
1251
1252 //
1253 // Check an initial partial word (if any)
1254 //
1255 bitMask = currentBlock & kBitsWithinWordMask;
1256 if (bitMask)
1257 {
1258 tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
1259 bitMask = kHighBitInWordMask >> bitMask;
1260 while (tempWord & bitMask)
1261 {
1262 bitMask >>= 1;
1263 ++currentBlock;
1264 }
1265
1266 // Did we find an unused bit (bitMask != 0), or run out of bits (bitMask == 0)?
1267 if (bitMask)
1268 goto FoundUnused;
1269
1270 // Didn't find any unused bits, so we're done with this word.
1271 ++currentWord;
1272 --wordsLeft;
1273 }
1274
1275 //
1276 // Check whole words
1277 //
1278 while (currentBlock < stopBlock)
1279 {
1280 // See if it's time to read another block.
1281 if (wordsLeft == 0)
1282 {
1283 buffer = NULL;
1284 err = ReleaseBitmapBlock(vcb, blockRef, false);
1285 if (err != noErr) goto ErrorExit;
1286
1287 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1288 if ( err != noErr ) goto ErrorExit;
1289
1290 currentWord = buffer;
1291 wordsLeft = wordsPerBlock;
1292 }
1293
1294 // See if any of the bits are clear
1295 if ((tempWord = SWAP_BE32(*currentWord)) + 1) // non-zero if any bits were clear
1296 {
1297 // Figure out which bit is clear
1298 bitMask = kHighBitInWordMask;
1299 while (tempWord & bitMask)
1300 {
1301 bitMask >>= 1;
1302 ++currentBlock;
1303 }
1304
1305 break; // Found the free bit; break out to FoundUnused.
1306 }
1307
1308 // Keep looking at the next word
1309 currentBlock += kBitsPerWord;
1310 ++currentWord;
1311 --wordsLeft;
1312 }
1313
1314 FoundUnused:
1315 // Make sure the unused bit is early enough to use
1316 if (currentBlock >= stopBlock)
1317 {
1318 break;
1319 }
1320
1321 // Remember the start of the extent
1322 firstBlock = currentBlock;
1323
1324 //============================================================
1325 // Count the number of contiguous free blocks.
1326 //============================================================
1327
1328 //
1329 // Check an initial partial word (if any)
1330 //
1331 bitMask = currentBlock & kBitsWithinWordMask;
1332 if (bitMask)
1333 {
1334 tempWord = SWAP_BE32(*currentWord); // Fetch the current word only once
1335 bitMask = kHighBitInWordMask >> bitMask;
1336 while (bitMask && !(tempWord & bitMask))
1337 {
1338 bitMask >>= 1;
1339 ++currentBlock;
1340 }
1341
1342 // Did we find a used bit (bitMask != 0), or run out of bits (bitMask == 0)?
1343 if (bitMask)
1344 goto FoundUsed;
1345
1346 // Didn't find any used bits, so we're done with this word.
1347 ++currentWord;
1348 --wordsLeft;
1349 }
1350
1351 //
1352 // Check whole words
1353 //
1354 while (currentBlock < endingBlock)
1355 {
1356 // See if it's time to read another block.
1357 if (wordsLeft == 0)
1358 {
1359 buffer = NULL;
1360 err = ReleaseBitmapBlock(vcb, blockRef, false);
1361 if (err != noErr) goto ErrorExit;
1362
1363 err = ReadBitmapBlock(vcb, currentBlock, &buffer, &blockRef);
1364 if ( err != noErr ) goto ErrorExit;
1365
1366 currentWord = buffer;
1367 wordsLeft = wordsPerBlock;
1368 }
1369
1370 // See if any of the bits are set
1371 if ((tempWord = SWAP_BE32(*currentWord)) != 0)
1372 {
1373 // Figure out which bit is set
1374 bitMask = kHighBitInWordMask;
1375 while (!(tempWord & bitMask))
1376 {
1377 bitMask >>= 1;
1378 ++currentBlock;
1379 }
1380
1381 break; // Found the used bit; break out to FoundUsed.
1382 }
1383
1384 // Keep looking at the next word
1385 currentBlock += kBitsPerWord;
1386 ++currentWord;
1387 --wordsLeft;
1388
1389 // If we found at least maxBlocks, we can quit early.
1390 if ((currentBlock - firstBlock) >= maxBlocks)
1391 break;
1392 }
1393
1394 FoundUsed:
1395 // Make sure we didn't run out of bitmap looking for a used block.
1396 // If so, pin to the end of the bitmap.
1397 if (currentBlock > endingBlock)
1398 currentBlock = endingBlock;
1399
1400 // Figure out how many contiguous free blocks there were.
1401 // Pin the answer to maxBlocks.
1402 foundBlocks = currentBlock - firstBlock;
1403 if (foundBlocks > maxBlocks)
1404 foundBlocks = maxBlocks;
1405 if (foundBlocks >= minBlocks)
1406 break; // Found what we needed!
1407
1408 // This free chunk wasn't big enough. Try inserting it into the free extent cache in case
1409 // the allocation wasn't forced contiguous.
1410 tempWord = vcb->vcbFreeExtCnt;
1411 if (tempWord == kMaxFreeExtents && vcb->vcbFreeExt[kMaxFreeExtents-1].blockCount < foundBlocks)
1412 --tempWord;
1413 if (tempWord < kMaxFreeExtents)
1414 {
1415 // We're going to add this extent. Bubble any smaller extents down in the list.
1416 while (tempWord && vcb->vcbFreeExt[tempWord-1].blockCount < foundBlocks)
1417 {
1418 vcb->vcbFreeExt[tempWord] = vcb->vcbFreeExt[tempWord-1];
1419 --tempWord;
1420 }
1421 vcb->vcbFreeExt[tempWord].startBlock = firstBlock;
1422 vcb->vcbFreeExt[tempWord].blockCount = foundBlocks;
1423
1424 if (vcb->vcbFreeExtCnt < kMaxFreeExtents)
1425 ++vcb->vcbFreeExtCnt;
1426 }
1427 } while (currentBlock < stopBlock);
1428
1429
1430 // Return the outputs.
1431 if (foundBlocks < minBlocks)
1432 {
1433 DiskFull:
1434 err = dskFulErr;
1435 ErrorExit:
1436 *actualStartBlock = 0;
1437 *actualNumBlocks = 0;
1438 }
1439 else
1440 {
1441 err = noErr;
1442 *actualStartBlock = firstBlock;
1443 *actualNumBlocks = foundBlocks;
1444 }
1445
1446 if (buffer)
1447 (void) ReleaseBitmapBlock(vcb, blockRef, false);
1448
1449 return err;
1450 }
1451
1452