|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
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-1997 by Apple Computer, Inc., all rights reserved.
33:
34: File Ownership:
35:
36: DRI: Mark Day
37:
38: Other Contact: Greg Parks
39:
40: Technology: HFS+
41:
42: Writers:
43:
44: (djb) Don Brady
45: (DSH) Deric Horn
46: (msd) Mark Day
47:
48: Change History (most recent first):
49: <Rhap> 4/27/98 djb Remove unneccessary DebugStr in BlockVerifyAllocated.
50: <Rhap> 4/17/98 djb Add VCB locking.
51: <Rhap> 4/13/98 djb Add RequireFileLock checking to ReadBitmapBlock.
52: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file.
53:
54: <12> 1 0/31/97 DSH Modify BlockVerifyAllocated() so DFA can call without actually
55: writing to the disk.
56: <CS11> 10/20/97 msd The way BlockAllocate rounds up to a multiple of the clump size
57: is wrong. ExtendFileC should do the round-up and pass the result
58: into BlockAllocate. Removed the fcb parameter to BlockAllocate;
59: added a bytesMaximum parameter.
60: <CS10> 10/17/97 msd Conditionalize DebugStrs.
61: <CS9> 9/4/97 djb Add logging to BlockAllocate.
62: <CS8> 9/4/97 msd Add a histogram of allocation sizes. Use DEBUG_BUILD instead of
63: VSM_DEBUG to generate DebugStr messages.
64: <CS7> 8/14/97 msd Bug 1662332. Don't mark blocks dirty in UpdateFreeCount. In
65: BlockVerifyAllocated, only mark blocks dirty if they've actually
66: changed.
67: <CS6> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
68: collision
69: <CS5> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
70: <CS4> 6/12/97 msd Export BlockAllocateAny and UpdateVCBFreeBlks.
71: <3> 5/8/97 DSH Added comments and ascii diagram of new BlockFindContiguous()
72: algorithm.
73: <2> 5/7/97 DSH New faster BlockFindContiguous algorithm. It searches backwards
74: until a dirty bit is found instead of forwards.
75: <CS1> 4/25/97 djb first checked in
76:
77: <HFS21> 4/14/97 msd Fix UpdateVCBFreeBlks so free space calculation doesn't overflow
78: on volumes bigger than 4GB.
79: <HFS20> 4/4/97 djb Get in sync with volume format changes.
80: <HFS19> 1/27/97 msd Speed up BlockCheck and UpdateFreeCount. Removed DebugStr from
81: BlockCheck; there are now DebugStr's in BlockVerifyAllocated,
82: before the bitmap gets fixed (so potential problems can be
83: debugged easier). Adjusted comments about internal routines.
84: Changed names of "Fast" routines back to their original names
85: (since the originals are now removed).
86: <HFS18> 1/24/97 msd Speed up allocation and deallocation.
87: <HFS17> 1/21/97 msd Add instrumentation for function entry/exit. BlockAllocate and
88: ReadBitMapBlock use the event tag to log bytes requested and
89: block number (respectively).
90: <HFS16> 1/15/97 djb Add HFS+ supprt to BlockCheck (for MountCheck).
91: <HFS15> 1/13/97 DSH Use vcb->nextAllocation instead of vcbAllocPtr.
92: <HFS14> 1/9/97 djb UpdateVCBFreeBlks is not converting correctly.
93: <HFS13> 1/6/97 djb Use vcb's allocationsRefNum to access allocation file.
94: <HFS12> 1/2/97 DSH Added UpdateVCBFreeBlks() to update vcbFreeBks whenever we
95: update vcb->freeblocks.
96: <HFS11> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB
97: <HFS10> 12/12/96 msd DivideAndRoundUp should not be declared as static.
98: <HFS9> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
99: <HFS8> 12/4/96 DSH PrecompiledHeaders
100: <HFS7> 11/27/96 djb Added AllocateFreeSpace for HFS wrapper support.
101: <HFS6> 11/27/96 msd Changed ReadBitmapBlock to read from HFS+ allocation file.
102: Temporarily uses the vcbVBMSt field of the VCB as the allocation
103: file's refnum until extended VCB changes are checked in.
104: <HFS5> 11/26/96 msd VSM and FileExtentMapping routines use FCB instead of FCBRec.
105: <HFS4> 11/20/96 DSH Changed a parameter in GetBlock_glue, so I also changed the
106: caller.
107: <HFS3> 11/20/96 msd Include FilesInternal.h. Remove definition of MarkVCBDirty
108: (since it is now in FilesInternal.h).
109: <HFS2> 11/12/96 msd Need to bound allocations to be within the last allocation block
110: of the volume (function AllocateAt).
111: <HFS1> 11/11/96 msd first checked in
112: */
113:
114: /*
115: Public routines:
116: BlockAllocate
117: Allocate space on a volume. Can allocate space contiguously.
118: If not contiguous, then allocation may be less than what was
119: asked for. Returns the starting block number, and number of
120: blocks. (Will only do a single extent???)
121: BlockDeallocate
122: Deallocate a contiguous run of allocation blocks.
123: BlockCheck
124: Makes sure that the blocks associated with an extent record
125: are in fact allocated in the bitmap. The bits will be set
126: if needed. Returns whether any bits needed to be set.
127: UpdateFreeCount
128: Computes the number of free allocation blocks on a volume.
129: The vcb's free block count is updated.
130:
131: AllocateFreeSpace
132: Allocates all the remaining free space (used for embedding HFS+ volumes).
133:
134: BlockAllocateAny
135: Find and allocate a contiguous range of blocks up to a given size. The
136: first range of contiguous free blocks found are allocated, even if there
137: are fewer blocks than requested (and even if a contiguous range of blocks
138: of the given size exists elsewhere).
139:
140: UpdateVCBFreeBlks
141: Given an ExtenddVCB, calculate the vcbFreeBks value
142: so that vcbFreeBks*vcbAlBlkSiz == freeBlocks*blockSize.
143:
144: Internal routines:
145: BlockVerifyAllocated
146: Makes sure that a contiguous range of blocks are marked as used
147: in the bitmap. If not, those blocks will be marked as used. A
148: boolean is returned to indicate whether any unmarked blocks were
149: found (and fixed).
150: BlockMarkFree
151: Mark a contiguous range of blocks as free. The corresponding
152: bits in the volume bitmap will be cleared.
153: BlockMarkAllocated
154: Mark a contiguous range of blocks as allocated. The cor-
155: responding bits in the volume bitmap are set. Also tests to see
156: if any of the blocks were previously unallocated.
157: FindContiguous
158: Find a contiguous range of blocks of a given size. The caller
159: specifies where to begin the search (by block number). The
160: block number of the first block in the range is returned.
161: BlockAllocateContig
162: Find and allocate a contiguous range of blocks of a given size. If
163: a contiguous range of free blocks of the given size isn't found, then
164: the allocation fails (i.e. it is "all or nothing").
165: ReadBitmapBlock
166: Given an allocation block number, read the bitmap block that
167: contains that allocation block into a caller-supplied buffer.
168: */
169:
170: #include "../headers/system/ConditionalMacros.h"
171:
172: #if ( PRAGMA_LOAD_SUPPORTED )
173: #pragma load PrecompiledHeaders
174: #else
175: #if TARGET_OS_MAC
176: #include <FSM.h>
177: #else
178: #include "../headers/system/MacOSStubs.h"
179: #include <sys/types.h>
180: #include <sys/buf.h>
181: #include <sys/systm.h>
182:
183: #include "../../hfs.h"
184: #include "../../hfs_dbg.h"
185: #endif /* TARGET_OS_MAC */
186: #endif /* PRAGMA_LOAD_SUPPORTED */
187:
188:
189: #if HFSInstrumentation
190: #include "Instrumentation.h"
191: #endif
192:
193: #include "../headers/HFSVolumes.h"
194: #include "../headers/FileMgrInternal.h"
195:
196: #include "../headers/system/HFSInstrumentation.h"
197:
198: #if TARGET_OS_RHAPSODY
199: #define EXPLICIT_BUFFER_RELEASES 1
200: #endif
201:
202: enum {
203: kBitsPerByte = 8,
204: kBitsPerWord = 32,
205: kWordsPerBlock = 128,
206: kBytesPerBlock = 512,
207: kBitsPerBlock = 4096,
208:
209: kBitsWithinWordMask = kBitsPerWord-1,
210: kBitsWithinBlockMask = kBitsPerBlock-1,
211: kWordsWithinBlockMask = kWordsPerBlock-1,
212:
213: kExtentsPerRecord = 3
214: };
215:
216: #define kLowBitInWordMask 0x00000001ul
217: #define kHighBitInWordMask 0x80000000ul
218: #define kAllBitsSetInWord 0xFFFFFFFFul
219:
220:
221: static OSErr BlockVerifyAllocated(
222: ExtendedVCB *vcb,
223: UInt32 startBlock,
224: UInt32 blockCount,
225: Boolean *foundUnmarkedBlock);
226:
227: static OSErr ReadBitmapBlock(
228: ExtendedVCB *vcb,
229: UInt32 block,
230: UInt32 **buffer);
231:
232: static OSErr BlockAllocateContig(
233: ExtendedVCB *vcb,
234: UInt32 startingBlock,
235: UInt32 minBlocks,
236: UInt32 maxBlocks,
237: UInt32 *actualStartBlock,
238: UInt32 *actualNumBlocks);
239:
240: static OSErr BlockFindContiguous(
241: ExtendedVCB *vcb,
242: UInt32 startingBlock,
243: UInt32 endingBlock,
244: UInt32 minBlocks,
245: UInt32 maxBlocks,
246: UInt32 *actualStartBlock,
247: UInt32 *actualNumBlocks);
248:
249: static OSErr BlockMarkAllocated(
250: ExtendedVCB *vcb,
251: UInt32 startingBlock,
252: UInt32 numBlocks);
253:
254: static OSErr BlockMarkFree(
255: ExtendedVCB *vcb,
256: UInt32 startingBlock,
257: UInt32 numBlocks);
258:
259: #if TARGET_OS_RHAPSODY && DIAGNOSTIC
260: #if DIAGNOSTIC
261: extern void RequireFileLock(FileReference file, int shareable);
262: #else
263: #define RequireFileLock(f)
264: #endif
265: #endif
266:
267: /*
268: ;________________________________________________________________________________
269: ;
270: ; Routine: BlkAlloc
271: ;
272: ; Function: Allocate space on a volume. If contiguous allocation is requested,
273: ; at least the requested number of bytes will be allocated or an
274: ; error will be returned. If contiguous allocation is not forced,
275: ; the space will be allocated at the first free fragment following
276: ; the requested starting allocation block. If there is not enough
277: ; room there, a block of less than the requested size will be
278: ; allocated.
279: ;
280: ; If the requested starting block is 0 (for new file allocations),
281: ; the volume's allocation block pointer will be used as a starting
282: ; point.
283: ;
284: ; All requests will be rounded up to the next highest clump size, as
285: ; indicated in the file's FCB.
286: ;
287: ; Input Arguments:
288: ; vcb - Pointer to ExtendedVCB for the volume to allocate space on
289: ; fcb - Pointer to FCB for the file for which storage is being allocated
290: ; startingBlock - Preferred starting allocation block, 0 = no preference
291: ; forceContiguous - Force contiguous flag - if bit 0 set (NE), allocation is contiguous
292: ; or an error is returned
293: ; bytesRequested - Number of bytes requested. If the allocation is non-contiguous,
294: ; less than this may actually be allocated
295: ; bytesMaximum - The maximum number of bytes to allocate. If there is additional free
296: ; space after bytesRequested, then up to bytesMaximum bytes should really
297: ; be allocated. (Used by ExtendFileC to round up allocations to a multiple
298: ; of the file's clump size.)
299: ;
300: ; Output:
301: ; (result) - Error code, zero for successful allocation
302: ; *startBlock - Actual starting allocation block
303: ; *actualBlocks - Actual number of allocation blocks allocated
304: ;
305: ; Side effects:
306: ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
307: ;
308: ; Modification history:
309: ; <06Oct85> PWD Changed to check for errors after calls to ReadBM and NextWord
310: ; Relocated call to MarkBlock in allocation loop
311: ; Changed to call NextBit
312: ; <21Oct85> PWD Changed to check VCBFreeBks before attempting to allocate any block.
313: ; Speed up scan for free space by checking for all 1's.
314: ;________________________________________________________________________________
315: */
316:
317: OSErr BlockAllocate (
318: ExtendedVCB *vcb, /* which volume to allocate space on */
319: UInt32 startingBlock, /* preferred starting block, or 0 for no preference */
320: UInt32 bytesRequested, /* desired number of BYTES to allocate */
321: UInt32 bytesMaximum, /* maximum number of bytes to allocate */
322: Boolean forceContiguous, /* non-zero to force contiguous allocation and to force */
323: /* bytesRequested bytes to actually be allocated */
324: UInt32 *actualStartBlock, /* actual first block of allocation */
325: UInt32 *actualNumBlocks) /* number of blocks actually allocated; if forceContiguous */
326: /* was zero, then this may represent fewer than bytesRequested */
327: /* bytes */
328: {
329: OSErr err;
330: UInt32 minBlocks; // minimum number of allocation blocks requested
331: UInt32 maxBlocks; // number of allocation blocks requested, rounded to clump size
332: Boolean updateAllocPtr = false; // true if nextAllocation needs to be updated
333:
334: LogStartTime(kTraceBlockAllocate);
335:
336: #if HFSInstrumentation
337: InstSplitHistogramClassRef histogram;
338: InstTraceClassRef trace;
339: InstEventTag eventTag;
340:
341: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockAllocate", 'hfs+', kInstEnableClassMask, &trace);
342: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
343:
344: err = InstCreateSplitHistogramClass(kInstRootClassRef, "HFS:VSM:BlockAllocate size", 0, 512, 16384, 262144, 16384,
345: kInstEnableClassMask, &histogram);
346: if (err != noErr) DebugStr("\pError from InstCreateHistogramClass");
347:
348: eventTag = bytesRequested; // a cheap way to get bytesRequested into the log
349: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
350: InstUpdateHistogram( histogram, bytesRequested, 1);
351: #endif
352:
353: //
354: // Initialize outputs in case we get an error
355: //
356: *actualStartBlock = 0;
357: *actualNumBlocks = 0;
358:
359: //
360: // Compute the number of allocation blocks requested, and maximum
361: //
362: minBlocks = DivideAndRoundUp(bytesRequested, vcb->blockSize);
363: maxBlocks = DivideAndRoundUp(bytesMaximum, vcb->blockSize);
364:
365: //
366: // If the disk is already full, don't bother.
367: //
368: if (vcb->freeBlocks == 0) {
369: err = dskFulErr;
370: goto Exit;
371: }
372: if (forceContiguous && vcb->freeBlocks < minBlocks) {
373: err = dskFulErr;
374: goto Exit;
375: }
376:
377: //
378: // If caller didn't specify a starting block number, then use the volume's
379: // next block to allocate from.
380: //
381: if (startingBlock == 0) {
382: VCB_LOCK(vcb);
383: startingBlock = vcb->nextAllocation;
384: VCB_UNLOCK(vcb);
385: updateAllocPtr = true;
386: }
387:
388: //
389: // If the request must be contiguous, then find a sequence of free blocks
390: // that is long enough. Otherwise, find the first free block.
391: //
392: if (forceContiguous) {
393: err = BlockAllocateContig(vcb, startingBlock, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
394: } else {
395: err = BlockAllocateAny(vcb, startingBlock, vcb->totalBlocks, maxBlocks, actualStartBlock, actualNumBlocks);
396: if (err == dskFulErr) {
397: err = BlockAllocateAny(vcb, 0, startingBlock, maxBlocks, actualStartBlock, actualNumBlocks);
398: };
399: }
400:
401: if (err == noErr) {
402: //
403: // If we used the volume's roving allocation pointer, then we need to update it.
404: // Adding in the length of the current allocation might reduce the next allocate
405: // call by avoiding a re-scan of the already allocated space. However, the clump
406: // just allocated can quite conceivably end up being truncated or released when
407: // the file is closed or its EOF changed. Leaving the allocation pointer at the
408: // start of the last allocation will avoid unnecessary fragmentation in this case.
409: //
410: VCB_LOCK(vcb);
411:
412: if (updateAllocPtr)
413: vcb->nextAllocation = *actualStartBlock;
414:
415: //
416: // Update the number of free blocks on the volume
417: //
418: vcb->freeBlocks -= *actualNumBlocks;
419: VCB_UNLOCK(vcb);
420:
421: UpdateVCBFreeBlks( vcb );
422: MarkVCBDirty(vcb);
423: }
424:
425: Exit:
426:
427: #if HFSInstrumentation
428: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
429: #endif
430: LogEndTime(kTraceBlockAllocate, err);
431:
432: return err;
433: }
434:
435:
436: /*
437: ;________________________________________________________________________________
438: ;
439: ; Routine: UpdateVCBFreeBlks
440: ;
441: ; Function: Whenever the freeBlocks field in the ExtendedVCB is updated,
442: ; we must also recalculate the (UInt16) vcbFreeBks field in the
443: ; traditional HFS VCB structure.
444: ;
445: ; Input Arguments:
446: ; vcb - Pointer to ExtendedVCB for the volume to free space on
447: ;________________________________________________________________________________
448: */
449: void UpdateVCBFreeBlks( ExtendedVCB *vcb )
450: {
451: UInt32 hfsCompatabilityFreeBlocks;
452: UInt32 plusBlockSize;
453: UInt32 hfsBlockSize;
454:
455: #if DEBUG_BUILD
456: if ( vcb->vcbSigWord == kHFSSigWord && vcb->freeBlocks > 0xFFFF )
457: DebugStr("\p UpdateVCBFreeBlks: freeBlocks overflow!");
458: #endif
459:
460: //
461: //�� The following calculation will overflow on volumes 2 TB or bigger.
462: //
463: // We divide both the true allocation block size and HFS-compatible allocation block size
464: // by 512 since that reduces the magnitude of the numbers (with no overflow until
465: // 4 GB * 512 = 2 TB). Since allocation blocks for both HFS and HFS Plus must be a
466: // multiple of 512, then there will be no roundoff error.
467: //
468: plusBlockSize = vcb->blockSize >> 9; // Divide by 512
469: hfsBlockSize = ((UInt32) vcb->vcbAlBlkSiz) >> 9; // Divide by 512
470:
471: hfsCompatabilityFreeBlocks = (vcb->freeBlocks * plusBlockSize) / hfsBlockSize;
472:
473: if ( hfsCompatabilityFreeBlocks > 0xFFFF )
474: vcb->vcbFreeBks = 0xFFFF;
475: else
476: vcb->vcbFreeBks = (UInt16) hfsCompatabilityFreeBlocks;
477: }
478:
479:
480: /*
481: ;________________________________________________________________________________
482: ;
483: ; Routine: BlkDealloc
484: ;
485: ; Function: Update the bitmap to deallocate a run of disk allocation blocks
486: ;
487: ; Input Arguments:
488: ; vcb - Pointer to ExtendedVCB for the volume to free space on
489: ; firstBlock - First allocation block to be freed
490: ; numBlocks - Number of allocation blocks to free up (must be > 0!)
491: ;
492: ; Output:
493: ; (result) - Result code
494: ;
495: ; Side effects:
496: ; The volume bitmap is read and updated; the volume bitmap cache may be changed.
497: ;
498: ; Modification history:
499: ;
500: ; <06Oct85> PWD Changed to check for error after calls to ReadBM and NextWord
501: ; Now calls NextBit to read successive bits from the bitmap
502: ;________________________________________________________________________________
503: */
504:
505: OSErr BlockDeallocate (
506: ExtendedVCB *vcb, // Which volume to deallocate space on
507: UInt32 firstBlock, // First block in range to deallocate
508: UInt32 numBlocks) // Number of contiguous blocks to deallocate
509: {
510: OSErr err;
511:
512: #if HFSInstrumentation
513: InstTraceClassRef trace;
514: InstEventTag eventTag;
515:
516: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockDeallocate", 'hfs+', kInstEnableClassMask, &trace);
517: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
518:
519: eventTag = InstCreateEventTag();
520: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
521: #endif
522:
523: //
524: // If no blocks to deallocate, then exit early
525: //
526: if (numBlocks == 0) {
527: err = noErr;
528: goto Exit;
529: }
530:
531: //
532: // Call internal routine to free the sequence of blocks
533: //
534: err = BlockMarkFree(vcb, firstBlock, numBlocks);
535: if (err)
536: goto Exit;
537:
538: //
539: // Update the volume's free block count, and mark the VCB as dirty.
540: //
541: VCB_LOCK(vcb);
542: vcb->freeBlocks += numBlocks;
543: VCB_UNLOCK(vcb);
544: UpdateVCBFreeBlks( vcb );
545: MarkVCBDirty(vcb);
546:
547: Exit:
548:
549: #if HFSInstrumentation
550: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
551: #endif
552:
553: return err;
554: }
555:
556:
557:
558: /*
559: ;_______________________________________________________________________
560: ;
561: ; Routine: BlkChk
562: ;
563: ; Input Arguments:
564: ; extents -- pointer to extent record
565: ; vcb -- ExtendedVCB for volume
566: ;
567: ; Output:
568: ; (result) -- 0 if block was already allocated
569: ; -1 otherwise
570: ;
571: ; Called By: MountVol
572: ; Function: Make sure the extents in the extent record are marked as
573: ; allocated in the volume bitmap. The allocation blocks mapped
574: ; by the extent record are marked in the bitmap if they weren't
575: ; already marked (in which case D0 is set).
576: ;
577: ; Modification History:
578: ; 3-Jul-85 PWD New today.
579: ; <06Oct85> PWD Added check for errors after calls to ReadBM and NextWord
580: ;_______________________________________________________________________
581: */
582:
583: SInt32 BlockCheck (
584: ExtendedVCB *vcb, // Volume to check
585: HFSPlusExtentRecord extents) // List of extents to verify as allocated
586: {
587: OSErr err;
588: Boolean trouble = false; // Assume everything went OK
589: Boolean foundUnmarkedBlock;
590: int i, extentsPerRecord;
591:
592: #if HFSInstrumentation
593: InstTraceClassRef trace;
594: InstEventTag eventTag;
595:
596: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockCheck", 'hfs+', kInstEnableClassMask, &trace);
597: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
598:
599: eventTag = InstCreateEventTag();
600: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
601: #endif
602:
603: if (vcb->vcbSigWord == kHFSPlusSigWord)
604: extentsPerRecord = kHFSPlusExtentDensity;
605: else
606: extentsPerRecord = kHFSExtentDensity;
607:
608:
609:
610: for (i = 0; i < extentsPerRecord; i++) {
611: if (extents[i].blockCount != 0) { // if no blocks, then no extent to check
612: err = BlockVerifyAllocated(vcb, extents[i].startBlock, extents[i].blockCount, &foundUnmarkedBlock);
613: if (err)
614: return err;
615: trouble |= foundUnmarkedBlock;
616: }
617: }
618:
619: #if HFSInstrumentation
620: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
621: #endif
622:
623: if (trouble)
624: return -1;
625: else
626: return 0;
627: }
628:
629:
630:
631: /*
632: ;_______________________________________________________________________
633: ;
634: ; Routine: UpdateFree
635: ; Arguments: vcb -- ExtendedVCB for volume
636: ;
637: ; Called By: MountVol
638: ; Function: This routine is used as part of the MountVol consistency check
639: ; to figure out the number of free allocation blocks in the volume.
640: ;
641: ; Modification History:
642: ; <08Sep85> LAK New today.
643: ; <06Oct85> PWD Added explicit check for errors after calls to ReadBM, NextWord
644: ; Now calls NextBit.
645: ;_______________________________________________________________________
646: */
647:
648: OSErr UpdateFreeCount (
649: ExtendedVCB *vcb) // Volume whose free block count should be updated
650: {
651: OSErr err;
652: register UInt32 wordsLeft; // Number of words left in this bitmap block
653: register UInt32 numBlocks; // Number of blocks left to scan
654: register UInt32 freeCount; // Running count of free blocks found so far
655: register UInt32 temp;
656: UInt32 blockNum; // Block number of first block in this bitmap block
657: UInt32 *buffer = NULL; // Pointer to bitmap block
658: register UInt32 *currentWord; // Pointer to current word in bitmap block
659:
660: #if HFSInstrumentation
661: InstTraceClassRef trace;
662: InstEventTag eventTag;
663:
664: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:UpdateFreeCount", 'hfs+', kInstEnableClassMask, &trace);
665: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
666:
667: eventTag = InstCreateEventTag();
668: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
669: #endif
670:
671: //
672: // Pre-read the first bitmap block
673: //
674:
675: err = ReadBitmapBlock(vcb, 0, &buffer);
676: if (err != noErr) goto Exit;
677:
678: //
679: // Initialize buffer stuff
680: //
681: currentWord = buffer;
682: wordsLeft = kWordsPerBlock;
683: numBlocks = vcb->totalBlocks;
684: freeCount = 0;
685: blockNum = 0;
686:
687: //
688: // Scan whole words first
689: //
690:
691: while (numBlocks >= kBitsPerWord) {
692: // See if it's time to move to the next bitmap block
693: if (wordsLeft == 0) {
694: // Read in the next bitmap block
695: blockNum += kBitsPerBlock; // generate a block number in the next bitmap block
696:
697: #if EXPLICIT_BUFFER_RELEASES
698: err = RelBlock_glue((Ptr)buffer, rbDefault);
699: if (err != noErr) goto Exit;
700: buffer = NULL;
701: #endif
702: err = ReadBitmapBlock(vcb, blockNum, &buffer);
703: if (err != noErr) goto Exit;
704:
705: // Readjust currentWord, wordsLeft
706: currentWord = buffer;
707: wordsLeft = kWordsPerBlock;
708: }
709:
710: // We count free blocks by inverting the word in the bitmap and counting set bits.
711: temp = ~(*currentWord);
712: while (temp) {
713: ++freeCount;
714: temp &= temp-1; // this clears least significant bit that is currently set
715: }
716:
717: numBlocks -= kBitsPerWord;
718: ++currentWord; // move to next word
719: --wordsLeft; // one less word left in this block
720: }
721:
722: //
723: // Check any remaining blocks.
724: //
725:
726: if (numBlocks != 0) {
727: if (wordsLeft == 0) {
728: // Read in the next bitmap block
729: blockNum += kBitsPerBlock; // generate a block number in the next bitmap block
730:
731: #if EXPLICIT_BUFFER_RELEASES
732: err = RelBlock_glue((Ptr)buffer, rbDefault);
733: if (err != noErr) goto Exit;
734: buffer = NULL;
735: #endif
736: err = ReadBitmapBlock(vcb, blockNum, &buffer);
737: if (err != noErr) goto Exit;
738:
739: // Readjust currentWord, wordsLeft
740: currentWord = buffer;
741: wordsLeft = kWordsPerBlock;
742: }
743:
744: // We count free blocks by inverting the word in the bitmap and counting set bits.
745: temp = ~(*currentWord);
746: while (numBlocks != 0) {
747: if (temp & kHighBitInWordMask)
748: ++freeCount;
749: temp <<= 1;
750: --numBlocks;
751: }
752: }
753:
754: VCB_LOCK(vcb);
755: vcb->freeBlocks = freeCount;
756: VCB_UNLOCK(vcb);
757: UpdateVCBFreeBlks( vcb );
758:
759: Exit:
760:
761: #if EXPLICIT_BUFFER_RELEASES
762: if (buffer) {
763: (void)RelBlock_glue((Ptr)buffer, rbDefault); /* Ignore any additional errors */
764: };
765: #endif
766:
767: #if HFSInstrumentation
768: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
769: #endif
770:
771: return err;
772: }
773:
774:
775:
776: /*
777: ;_______________________________________________________________________
778: ;
779: ; Routine: AllocateFreeSpace
780: ; Arguments: vcb -- ExtendedVCB for volume
781: ;
782: ; Called By: HFSDiskInitComponent
783: ; Function: This routine is used as part of DiskInit to create an
784: ; embedded HFS+ volume.
785: ;
786: ; Note: Assumes that the free space is contiguous (true for a freshly erased disk)
787: ;_______________________________________________________________________
788: */
789:
790: OSErr AllocateFreeSpace (
791: ExtendedVCB *vcb, // Volume whose free space is about to be expropriated
792: UInt32 *startBlock, // return where free space starts
793: UInt32 *actualBlocks) // return the number of blocks in free space
794: {
795: OSErr err;
796:
797: err = BlockAllocateAny(vcb, 0, vcb->totalBlocks, vcb->freeBlocks, startBlock, actualBlocks);
798:
799: if (err == noErr) {
800: VCB_LOCK(vcb);
801: vcb->freeBlocks = 0; // sorry, no more blocks left!
802: vcb->vcbFreeBks = 0;
803: VCB_UNLOCK(vcb);
804: MarkVCBDirty(vcb);
805: }
806:
807: return err;
808: }
809:
810: /*
811: ;_______________________________________________________________________
812: ;
813: ; Routine: DivideAndRoundUp
814: ;
815: ; Function: Divide numerator by denominator, rounding up the result if there
816: ; was a remainder. This is frequently used for computing the number
817: ; of whole and/or partial blocks used by some count of bytes.
818: ;_______________________________________________________________________
819: */
820: UInt32 DivideAndRoundUp(
821: UInt32 numerator,
822: UInt32 denominator)
823: {
824: UInt32 quotient;
825:
826: quotient = numerator / denominator;
827: if (quotient * denominator != numerator)
828: quotient++;
829:
830: return quotient;
831: }
832:
833:
834:
835: /*
836: ;_______________________________________________________________________
837: ;
838: ; Routine: ReadBitmapBlock
839: ;
840: ; Function: Read in a bitmap block corresponding to a given allocation
841: ; block. Return a pointer to the bitmap block.
842: ;
843: ; Inputs:
844: ; vcb -- Pointer to ExtendedVCB
845: ; block -- Allocation block whose bitmap block is desired
846: ;
847: ; Outputs:
848: ; buffer -- Pointer to bitmap block corresonding to "block"
849: ;_______________________________________________________________________
850: */
851: static OSErr ReadBitmapBlock(
852: ExtendedVCB *vcb,
853: UInt32 block,
854: UInt32 **buffer)
855: {
856: OSErr err;
857:
858: #if HFSInstrumentation
859: InstTraceClassRef trace;
860: InstEventTag eventTag;
861:
862: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:ReadBitmapBlock", 'hfs+', kInstEnableClassMask, &trace);
863: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
864:
865: eventTag = block; // a cheap way to get the block number into the log
866: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
867: #endif
868:
869: err = noErr;
870:
871: #if TARGET_OS_RHAPSODY
872: RequireFileLock(vcb->extentsRefNum, false); /* bitmap blocks are covered by the Extents B-tree lock */
873: #endif
874:
875: if (vcb->vcbSigWord == kHFSSigWord) {
876: //
877: // HFS: Turn block number into physical block offset within the
878: // bitmap, and then the physical block within the volume.
879: //
880: block /= kBitsPerBlock; // block offset within bitmap
881: block += vcb->vcbVBMSt; // block within whole volume
882: }
883: else {
884: FCB *allocFile;
885: UInt32 startBlock;
886: UInt32 availableBytes;
887:
888: //
889: // HFS+: Read from allocation file. We simply convert the block number into a byte
890: // offset within the allocation file and then determine which block that byte is in.
891: //
892: allocFile = GetFileControlBlock(vcb->allocationsRefNum);
893:
894: //
895: // Find out which physical block holds byte #offset in allocation file. Note that we
896: // map only 1 byte (the one we asked for).
897: //
898: err = MapFileBlockC(vcb, allocFile, 1, block/kBitsPerByte, &startBlock, &availableBytes);
899: block = startBlock;
900: }
901:
902: if (err == noErr) {
903: #if TARGET_OS_MAC
904: err = GetBlock_glue(
905: #if EXPLICIT_BUFFER_RELEASES
906: 0, // No options
907: #else
908: gbReleaseMask, // Release block immediately. We only work on one
909: // block at a time. Call MarkBlock later if dirty.
910: #endif
911: block, // Physical block on volume
912: (Ptr *) buffer, // A place to return the buffer pointer
913: vcb->vcbVRefNum, // Which volume to read from
914: vcb); // Cache queue header for volume bitmap
915: #else
916: err = GetBlock_glue(
917: #if EXPLICIT_BUFFER_RELEASES
918: 0, // No options
919: #else
920: gbReleaseMask, // Release block immediately. We only work on one
921: // block at a time. Call MarkBlock later if dirty.
922: #endif
923: block, // Physical block on volume
924: (Ptr *) buffer, // A place to return the buffer pointer
925: kNoFileReference, // Not a file read
926: vcb); // Volume to read from
927: #endif
928: }
929:
930: #if HFSInstrumentation
931: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
932: #endif
933:
934: return err;
935: }
936:
937:
938:
939: /*
940: _______________________________________________________________________
941:
942: Routine: BlockAllocateContig
943:
944: Function: Allocate a contiguous group of allocation blocks. The
945: allocation is all-or-nothing. The caller guarantees that
946: there are enough free blocks (though they may not be
947: contiguous, in which case this call will fail).
948:
949: Inputs:
950: vcb Pointer to volume where space is to be allocated
951: startingBlock Preferred first block for allocation
952: minBlocks Minimum number of contiguous blocks to allocate
953: maxBlocks Maximum number of contiguous blocks to allocate
954:
955: Outputs:
956: actualStartBlock First block of range allocated, or 0 if error
957: actualNumBlocks Number of blocks allocated, or 0 if error
958: _______________________________________________________________________
959: */
960: static OSErr BlockAllocateContig(
961: ExtendedVCB *vcb,
962: UInt32 startingBlock,
963: UInt32 minBlocks,
964: UInt32 maxBlocks,
965: UInt32 *actualStartBlock,
966: UInt32 *actualNumBlocks)
967: {
968: OSErr err;
969:
970: //
971: // Find a contiguous group of blocks at least minBlocks long.
972: // Determine the number of contiguous blocks available (up
973: // to maxBlocks).
974: //
975: err = BlockFindContiguous(vcb, startingBlock, vcb->totalBlocks, minBlocks, maxBlocks,
976: actualStartBlock, actualNumBlocks);
977: if (err == dskFulErr) {
978: //�� Should constrain the endingBlock here, so we don't bother looking for ranges
979: //�� that start after startingBlock, since we already checked those.
980: err = BlockFindContiguous(vcb, 0, vcb->totalBlocks, minBlocks, maxBlocks,
981: actualStartBlock, actualNumBlocks);
982: }
983: if (err != noErr) goto Exit;
984:
985: //
986: // Now mark those blocks allocated.
987: //
988: err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks);
989:
990: Exit:
991: if (err != noErr) {
992: *actualStartBlock = 0;
993: *actualNumBlocks = 0;
994: }
995:
996: return err;
997: }
998:
999: extern OSErr LookupBufferMapping(caddr_t bufferAddress, struct buf **bpp, int *mappingIndexPtr);
1000:
1001: /*
1002: _______________________________________________________________________
1003:
1004: Routine: BlockAllocateAny
1005:
1006: Function: Allocate one or more allocation blocks. If there are fewer
1007: free blocks than requested, all free blocks will be
1008: allocated. The caller guarantees that there is at least
1009: one free block.
1010:
1011: Inputs:
1012: vcb Pointer to volume where space is to be allocated
1013: startingBlock Preferred first block for allocation
1014: endingBlock Last block to check + 1
1015: maxBlocks Maximum number of contiguous blocks to allocate
1016:
1017: Outputs:
1018: actualStartBlock First block of range allocated, or 0 if error
1019: actualNumBlocks Number of blocks allocated, or 0 if error
1020: _______________________________________________________________________
1021: */
1022: OSErr BlockAllocateAny(
1023: ExtendedVCB *vcb,
1024: UInt32 startingBlock,
1025: register UInt32 endingBlock,
1026: UInt32 maxBlocks,
1027: UInt32 *actualStartBlock,
1028: UInt32 *actualNumBlocks)
1029: {
1030: OSErr err;
1031: register UInt32 block; // current block number
1032: register UInt32 currentWord; // Pointer to current word within bitmap block
1033: register UInt32 bitMask; // Word with given bits already set (ready to OR in)
1034: register UInt32 wordsLeft; // Number of words left in this bitmap block
1035: UInt32 *buffer = NULL;
1036: UInt32 *currCache = NULL;
1037:
1038: #if DIAGNOSTIC
1039: struct buf *bp = NULL;
1040: int mappingEntry;
1041: #endif
1042:
1043: // Since this routine doesn't wrap around
1044: if (maxBlocks > (endingBlock - startingBlock)) {
1045: maxBlocks = endingBlock - startingBlock;
1046: }
1047:
1048: DBG_TREE (("\nAllocating starting at %ld, maxblocks %ld\n", startingBlock, maxBlocks));
1049: //
1050: // Pre-read the first bitmap block
1051: //
1052: err = ReadBitmapBlock(vcb, startingBlock, &currCache);
1053: DBG_TREE (("\n1. Read bit map at %ld, buffer is 0x%x\n", startingBlock, (int)currCache));
1054: if (err != noErr) goto Exit;
1055: buffer = currCache;
1056: MarkBlock_glue((Ptr) currCache); // this block will be dirty
1057: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1058:
1059: //
1060: // Set up the current position within the block
1061: //
1062: {
1063: UInt32 wordIndexInBlock;
1064:
1065: wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
1066: buffer += wordIndexInBlock;
1067: wordsLeft = kWordsPerBlock - wordIndexInBlock;
1068: currentWord = *buffer;
1069: bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask);
1070: }
1071:
1072: //
1073: // Find the first unallocated block
1074: //
1075: block=startingBlock;
1076: while (block < endingBlock) {
1077: if ((currentWord & bitMask) == 0)
1078: break;
1079:
1080: // Next bit
1081: ++block;
1082: bitMask >>= 1;
1083: if (bitMask == 0) {
1084: // Next word
1085: bitMask = kHighBitInWordMask;
1086: ++buffer;
1087:
1088: if (--wordsLeft == 0) {
1089: // Next block
1090: #if EXPLICIT_BUFFER_RELEASES
1091: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1092: err = RelBlock_glue((Ptr)currCache, rbDefault);
1093: if (err != noErr) goto Exit;
1094: buffer = currCache = NULL;
1095: #endif
1096: err = ReadBitmapBlock(vcb, block, &currCache);
1097: if (err != noErr) goto Exit;
1098: buffer = currCache;
1099: DBG_TREE (("\n2. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));
1100: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1101: MarkBlock_glue((Ptr) currCache); // this block will be dirty
1102:
1103: wordsLeft = kWordsPerBlock;
1104: }
1105:
1106: currentWord = *buffer;
1107: }
1108: }
1109:
1110: // Did we get to the end of the bitmap before finding a free block?
1111: // If so, then couldn't allocate anything.
1112: if (block == endingBlock) {
1113: err = dskFulErr;
1114: goto Exit;
1115: }
1116:
1117: // Return the first block in the allocated range
1118: *actualStartBlock = block;
1119:
1120: // If we could get the desired number of blocks before hitting endingBlock,
1121: // then adjust endingBlock so we won't keep looking. Ideally, the comparison
1122: // would be (block + maxBlocks) < endingBlock, but that could overflow. The
1123: // comparison below yields identical results, but without overflow.
1124: if (block < (endingBlock-maxBlocks)) {
1125: endingBlock = block + maxBlocks; // if we get this far, we've found enough
1126: }
1127:
1128: //
1129: // Allocate all of the consecutive blocks
1130: //
1131: while ((currentWord & bitMask) == 0) {
1132: // Allocate this block
1133: currentWord |= bitMask;
1134:
1135: // Move to the next block. If no more, then exit.
1136: ++block;
1137: if (block == endingBlock)
1138: break;
1139:
1140: // Next bit
1141: bitMask >>= 1;
1142: if (bitMask == 0) {
1143: *buffer = currentWord; // update value in bitmap
1144:
1145: // Next word
1146: bitMask = kHighBitInWordMask;
1147: ++buffer;
1148:
1149: if (--wordsLeft == 0) {
1150: // Next block
1151: #if EXPLICIT_BUFFER_RELEASES
1152: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1153: err = RelBlock_glue((Ptr)currCache, rbDefault);
1154: if (err != noErr) goto Exit;
1155: buffer = currCache = NULL;
1156: #endif
1157: err = ReadBitmapBlock(vcb, block, &currCache);
1158: if (err != noErr) goto Exit;
1159: buffer = currCache;
1160: DBG_TREE (("\n3. Read bit map at %ld, buffer is 0x%x\n", block, (int)currCache));
1161: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1162: MarkBlock_glue((Ptr) currCache); // this block will be dirty
1163:
1164: wordsLeft = kWordsPerBlock;
1165: }
1166:
1167: currentWord = *buffer;
1168: }
1169: }
1170: *buffer = currentWord; // update the last change
1171:
1172: Exit:
1173: if (err == noErr) {
1174: *actualNumBlocks = block - *actualStartBlock;
1175: }
1176: else {
1177: *actualStartBlock = 0;
1178: *actualNumBlocks = 0;
1179: }
1180:
1181: #if EXPLICIT_BUFFER_RELEASES
1182: if (currCache) {
1183: DBG_ASSERT(! LookupBufferMapping((caddr_t)currCache, &bp, &mappingEntry));
1184: (void)RelBlock_glue((Ptr)currCache, rbDefault); /* Ignore any additional errors */
1185: };
1186: #endif
1187:
1188: return err;
1189: }
1190:
1191:
1192:
1193: /*
1194: _______________________________________________________________________
1195:
1196: Routine: BlockMarkAllocated
1197:
1198: Function: Mark a contiguous group of blocks as allocated (set in the
1199: bitmap). It assumes those bits are currently marked
1200: deallocated (clear in the bitmap).
1201:
1202: Inputs:
1203: vcb Pointer to volume where space is to be allocated
1204: startingBlock First block number to mark as allocated
1205: numBlocks Number of blocks to mark as allocated
1206: _______________________________________________________________________
1207: */
1208: static OSErr BlockMarkAllocated(
1209: ExtendedVCB *vcb,
1210: UInt32 startingBlock,
1211: register UInt32 numBlocks)
1212: {
1213: OSErr err;
1214: register UInt32 *currentWord; // Pointer to current word within bitmap block
1215: register UInt32 wordsLeft; // Number of words left in this bitmap block
1216: register UInt32 bitMask; // Word with given bits already set (ready to OR in)
1217: UInt32 firstBit; // Bit index within word of first bit to allocate
1218: UInt32 numBits; // Number of bits in word to allocate
1219: UInt32 *buffer = NULL;
1220:
1221: #if HFSInstrumentation
1222: InstTraceClassRef trace;
1223: InstEventTag eventTag;
1224:
1225: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkAllocated", 'hfs+', kInstEnableClassMask, &trace);
1226: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1227:
1228: eventTag = InstCreateEventTag();
1229: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1230: #endif
1231:
1232: //
1233: // Pre-read the bitmap block containing the first word of allocation
1234: //
1235:
1236: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1237: if (err != noErr) goto Exit;
1238: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1239:
1240: //
1241: // Initialize currentWord, and wordsLeft.
1242: //
1243: {
1244: UInt32 wordIndexInBlock;
1245:
1246: wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
1247: currentWord = buffer + wordIndexInBlock;
1248: wordsLeft = kWordsPerBlock - wordIndexInBlock;
1249: }
1250:
1251: //
1252: // If the first block to allocate doesn't start on a word
1253: // boundary in the bitmap, then treat that first word
1254: // specially.
1255: //
1256:
1257: firstBit = startingBlock % kBitsPerWord;
1258: if (firstBit != 0) {
1259: bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit
1260: numBits = kBitsPerWord - firstBit; // number of remaining bits in this word
1261: if (numBits > numBlocks) {
1262: numBits = numBlocks; // entire allocation is inside this one word
1263: bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
1264: }
1265: #if DEBUG_BUILD
1266: if ((*currentWord & bitMask) != 0) {
1267: DebugStr("\pFATAL: blocks already allocated!");
1268: //err = fsDSIntErr;
1269: //goto Exit;
1270: }
1271: #endif
1272: *currentWord |= bitMask; // set the bits in the bitmap
1273: numBlocks -= numBits; // adjust number of blocks left to allocate
1274:
1275: ++currentWord; // move to next word
1276: --wordsLeft; // one less word left in this block
1277: }
1278:
1279: //
1280: // Allocate whole words (32 blocks) at a time.
1281: //
1282:
1283: bitMask = kAllBitsSetInWord; // put this in a register for 68K
1284: while (numBlocks >= kBitsPerWord) {
1285: if (wordsLeft == 0) {
1286: // Read in the next bitmap block
1287: startingBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1288:
1289: #if EXPLICIT_BUFFER_RELEASES
1290: err = RelBlock_glue((Ptr)buffer, rbDefault);
1291: if (err != noErr) goto Exit;
1292: buffer = NULL;
1293: #endif
1294: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1295: if (err != noErr) goto Exit;
1296: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1297:
1298: // Readjust currentWord and wordsLeft
1299: currentWord = buffer;
1300: wordsLeft = kWordsPerBlock;
1301: }
1302: #if DEBUG_BUILD
1303: if (*currentWord != 0) {
1304: DebugStr("\pFATAL: blocks already allocated!");
1305: //err = fsDSIntErr;
1306: //goto Exit;
1307: }
1308: #endif
1309: *currentWord = bitMask;
1310: numBlocks -= kBitsPerWord;
1311:
1312: ++currentWord; // move to next word
1313: --wordsLeft; // one less word left in this block
1314: }
1315:
1316: //
1317: // Allocate any remaining blocks.
1318: //
1319:
1320: if (numBlocks != 0) {
1321: bitMask = ~(kAllBitsSetInWord >> numBlocks); // set first numBlocks bits
1322: if (wordsLeft == 0) {
1323: // Read in the next bitmap block
1324: startingBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1325:
1326: #if EXPLICIT_BUFFER_RELEASES
1327: err = RelBlock_glue((Ptr)buffer, rbDefault);
1328: if (err != noErr) goto Exit;
1329: buffer = NULL;
1330: #endif
1331: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1332: if (err != noErr) goto Exit;
1333: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1334:
1335: // Readjust currentWord and wordsLeft
1336: currentWord = buffer;
1337: wordsLeft = kWordsPerBlock;
1338: }
1339: #if DEBUG_BUILD
1340: if ((*currentWord & bitMask) != 0) {
1341: DebugStr("\pFATAL: blocks already allocated!");
1342: //err = fsDSIntErr;
1343: //goto Exit;
1344: }
1345: #endif
1346: *currentWord |= bitMask; // set the bits in the bitmap
1347:
1348: // No need to update currentWord or wordsLeft
1349: }
1350:
1351: Exit:
1352:
1353: #if EXPLICIT_BUFFER_RELEASES
1354: if (buffer) {
1355: (void)RelBlock_glue((Ptr)buffer, rbDefault); /* Ignore any additional errors */
1356: };
1357: #endif
1358:
1359: #if HFSInstrumentation
1360: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1361: #endif
1362:
1363: return err;
1364: }
1365:
1366:
1367:
1368: /*
1369: _______________________________________________________________________
1370:
1371: Routine: BlockMarkFree
1372:
1373: Function: Mark a contiguous group of blocks as free (clear in the
1374: bitmap). It assumes those bits are currently marked
1375: allocated (set in the bitmap).
1376:
1377: Inputs:
1378: vcb Pointer to volume where space is to be freed
1379: startingBlock First block number to mark as freed
1380: numBlocks Number of blocks to mark as freed
1381: _______________________________________________________________________
1382: */
1383: static OSErr BlockMarkFree(
1384: ExtendedVCB *vcb,
1385: UInt32 startingBlock,
1386: register UInt32 numBlocks)
1387: {
1388: OSErr err;
1389: register UInt32 *currentWord; // Pointer to current word within bitmap block
1390: register UInt32 wordsLeft; // Number of words left in this bitmap block
1391: register UInt32 bitMask; // Word with given bits already set (ready to OR in)
1392: UInt32 firstBit; // Bit index within word of first bit to allocate
1393: UInt32 numBits; // Number of bits in word to allocate
1394: UInt32 *buffer = NULL;
1395:
1396: #if HFSInstrumentation
1397: InstTraceClassRef trace;
1398: InstEventTag eventTag;
1399:
1400: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockMarkFree", 'hfs+', kInstEnableClassMask, &trace);
1401: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1402:
1403: eventTag = InstCreateEventTag();
1404: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1405: #endif
1406:
1407: //
1408: // Pre-read the bitmap block containing the first word of allocation
1409: //
1410:
1411: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1412: if (err != noErr) goto Exit;
1413: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1414:
1415: //
1416: // Initialize currentWord, and wordsLeft.
1417: //
1418: {
1419: UInt32 wordIndexInBlock;
1420:
1421: wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord;
1422: currentWord = buffer + wordIndexInBlock;
1423: wordsLeft = kWordsPerBlock - wordIndexInBlock;
1424: }
1425:
1426: //
1427: // If the first block to free doesn't start on a word
1428: // boundary in the bitmap, then treat that first word
1429: // specially.
1430: //
1431:
1432: firstBit = startingBlock % kBitsPerWord;
1433: if (firstBit != 0) {
1434: bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit
1435: numBits = kBitsPerWord - firstBit; // number of remaining bits in this word
1436: if (numBits > numBlocks) {
1437: numBits = numBlocks; // entire allocation is inside this one word
1438: bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
1439: }
1440: #if DEBUG_BUILD
1441: if ((*currentWord & bitMask) != bitMask) {
1442: DebugStr("\pFATAL: blocks not allocated!");
1443: //err = fsDSIntErr;
1444: //goto Exit;
1445: }
1446: #endif
1447: *currentWord &= ~bitMask; // clear the bits in the bitmap
1448: numBlocks -= numBits; // adjust number of blocks left to free
1449:
1450: ++currentWord; // move to next word
1451: --wordsLeft; // one less word left in this block
1452: }
1453:
1454: //
1455: // Allocate whole words (32 blocks) at a time.
1456: //
1457:
1458: while (numBlocks >= kBitsPerWord) {
1459: if (wordsLeft == 0) {
1460: // Read in the next bitmap block
1461: startingBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1462:
1463: #if EXPLICIT_BUFFER_RELEASES
1464: err = RelBlock_glue((Ptr)buffer, rbDefault);
1465: if (err != noErr) goto Exit;
1466: buffer = NULL;
1467: #endif
1468: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1469: if (err != noErr) goto Exit;
1470: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1471:
1472: // Readjust currentWord and wordsLeft
1473: currentWord = buffer;
1474: wordsLeft = kWordsPerBlock;
1475: }
1476:
1477: #if DEBUG_BUILD
1478: if (*currentWord != kAllBitsSetInWord) {
1479: DebugStr("\pFATAL: blocks not allocated!");
1480: //err = fsDSIntErr;
1481: //goto Exit;
1482: }
1483: #endif
1484: *currentWord = 0; // clear the entire word
1485: numBlocks -= kBitsPerWord;
1486:
1487: ++currentWord; // move to next word
1488: --wordsLeft; // one less word left in this block
1489: }
1490:
1491: //
1492: // Allocate any remaining blocks.
1493: //
1494:
1495: if (numBlocks != 0) {
1496: bitMask = ~(kAllBitsSetInWord >> numBlocks); // set first numBlocks bits
1497: if (wordsLeft == 0) {
1498: // Read in the next bitmap block
1499: startingBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1500:
1501: #if EXPLICIT_BUFFER_RELEASES
1502: err = RelBlock_glue((Ptr)buffer, rbDefault);
1503: if (err != noErr) goto Exit;
1504: buffer = NULL;
1505: #endif
1506: err = ReadBitmapBlock(vcb, startingBlock, &buffer);
1507: if (err != noErr) goto Exit;
1508: MarkBlock_glue((Ptr) buffer); // this block will be dirty
1509:
1510: // Readjust currentWord and wordsLeft
1511: currentWord = buffer;
1512: wordsLeft = kWordsPerBlock;
1513: }
1514: #if DEBUG_BUILD
1515: if ((*currentWord & bitMask) != bitMask) {
1516: DebugStr("\pFATAL: blocks not allocated!");
1517: //err = fsDSIntErr;
1518: //goto Exit;
1519: }
1520: #endif
1521: *currentWord &= ~bitMask; // clear the bits in the bitmap
1522:
1523: // No need to update currentWord or wordsLeft
1524: }
1525:
1526: Exit:
1527:
1528: #if EXPLICIT_BUFFER_RELEASES
1529: if (buffer) {
1530: (void)RelBlock_glue((Ptr)buffer, rbDefault); /* Ignore any additional errors */
1531: };
1532: #endif
1533:
1534: #if HFSInstrumentation
1535: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1536: #endif
1537:
1538: return err;
1539: }
1540:
1541:
1542:
1543: static OSErr BlockVerifyAllocated(
1544: ExtendedVCB *vcb,
1545: UInt32 startBlock,
1546: register UInt32 numBlocks,
1547: Boolean *foundUnmarkedBlock)
1548: {
1549: OSErr err;
1550: register UInt32 wordsLeft; // Number of words left in this bitmap block
1551: register UInt32 bitMask; // Word with given bits already set (ready to OR in)
1552: UInt32 firstBit; // Bit index within word of first bit to allocate
1553: UInt32 numBits; // Number of bits in word to allocate
1554: UInt32 *buffer = NULL; // Pointer to bitmap block
1555: register UInt32 *currentWord; // Pointer to current word in bitmap block
1556:
1557: #if HFSInstrumentation
1558: InstTraceClassRef trace;
1559: InstEventTag eventTag;
1560:
1561: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockVerifyAllocated", 'hfs+', kInstEnableClassMask, &trace);
1562: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1563:
1564: eventTag = startBlock;
1565: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1566: #endif
1567:
1568: //
1569: // Assume everything's OK
1570: //
1571: *foundUnmarkedBlock = false;
1572:
1573: //
1574: // Pre-read the bitmap block containing the first word to check
1575: //
1576:
1577: err = ReadBitmapBlock(vcb, startBlock, &buffer);
1578: if (err != noErr) goto Exit;
1579:
1580: //
1581: // Initialize buffer stuff
1582: //
1583: {
1584: UInt32 wordIndexInBlock;
1585:
1586: wordIndexInBlock = (startBlock & kBitsWithinBlockMask) / kBitsPerWord;
1587: currentWord = buffer + wordIndexInBlock;
1588: wordsLeft = kWordsPerBlock - wordIndexInBlock;
1589: }
1590:
1591: //
1592: // If the first block to check doesn't start on a word
1593: // boundary in the bitmap, then treat that first word
1594: // specially.
1595: //
1596:
1597: firstBit = startBlock % kBitsPerWord;
1598: if (firstBit != 0) {
1599: bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit
1600: numBits = kBitsPerWord - firstBit; // number of remaining bits in this word
1601: if (numBits > numBlocks) {
1602: numBits = numBlocks; // entire allocation is inside this one word
1603: bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last
1604: }
1605:
1606: // Make sure all the bits are set
1607: if ((*currentWord & bitMask) != bitMask) {
1608: *foundUnmarkedBlock = true; // found an error
1609: if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
1610: {
1611: *currentWord |= bitMask; // set the bits in the bitmap
1612: MarkBlock_glue((Ptr) buffer); // this block is now dirty
1613: }
1614: }
1615:
1616: numBlocks -= numBits; // adjust number of blocks left to check
1617: ++currentWord; // move to next word
1618: --wordsLeft; // one less word left in this block
1619: }
1620:
1621: //
1622: // Check whole words (32 blocks) at a time.
1623: //
1624:
1625: bitMask = kAllBitsSetInWord; // put this in a register for 68K
1626: while (numBlocks >= kBitsPerWord) {
1627: // See if it's time to move to the next bitmap block
1628: if (wordsLeft == 0) {
1629: // Read in the next bitmap block
1630: startBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1631:
1632: #if EXPLICIT_BUFFER_RELEASES
1633: err = RelBlock_glue((Ptr)buffer, rbDefault);
1634: if (err != noErr) goto Exit;
1635: buffer = NULL;
1636: #endif
1637: err = ReadBitmapBlock(vcb, startBlock, &buffer);
1638: if (err != noErr) goto Exit;
1639:
1640: // Readjust currentWord, wordsLeft
1641: currentWord = buffer;
1642: wordsLeft = kWordsPerBlock;
1643: }
1644:
1645: // Make sure all the blocks are allocated
1646: if (*currentWord != bitMask) {
1647: *foundUnmarkedBlock = true; // found an error
1648: if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
1649: {
1650: *currentWord = bitMask; // update the bitmap
1651: MarkBlock_glue((Ptr) buffer); // this block is now dirty
1652: }
1653: }
1654:
1655: numBlocks -= kBitsPerWord;
1656: ++currentWord; // move to next word
1657: --wordsLeft; // one less word left in this block
1658: }
1659:
1660: //
1661: // Check any remaining blocks.
1662: //
1663:
1664: if (numBlocks != 0) {
1665: bitMask = ~(kAllBitsSetInWord >> numBlocks); // set first numBlocks bits
1666: if (wordsLeft == 0) {
1667: // Read in the next bitmap block
1668: startBlock += kBitsPerBlock; // generate a block number in the next bitmap block
1669:
1670: #if EXPLICIT_BUFFER_RELEASES
1671: err = RelBlock_glue((Ptr)buffer, rbDefault);
1672: if (err != noErr) goto Exit;
1673: buffer = NULL;
1674: #endif
1675: err = ReadBitmapBlock(vcb, startBlock, &buffer);
1676: if (err != noErr) goto Exit;
1677:
1678: // Readjust currentWord, wordsLeft
1679: currentWord = buffer;
1680: wordsLeft = kWordsPerBlock;
1681: }
1682:
1683: // Make sure all the bits are set
1684: if ((*currentWord & bitMask) != bitMask) {
1685: *foundUnmarkedBlock = true; // found an error
1686: if ( (!FORDISKFIRSTAID) || (GetDFAStage() == kRepairStage) )
1687: {
1688: *currentWord |= bitMask; // set the bits in the bitmap
1689: MarkBlock_glue((Ptr) buffer); // this block is now dirty
1690: }
1691: }
1692:
1693: // No need to update buffer pointer, etc.
1694: }
1695:
1696: Exit:
1697:
1698: #if EXPLICIT_BUFFER_RELEASES
1699: if (buffer) {
1700: (void)RelBlock_glue((Ptr)buffer, rbDefault); /* Ignore any additional errors */
1701: };
1702: #endif
1703:
1704: #if HFSInstrumentation
1705: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
1706: #endif
1707:
1708: return err;
1709: }
1710:
1711:
1712:
1713: /*
1714: _______________________________________________________________________
1715:
1716: Routine: BlockFindContiguous
1717:
1718: Function: Find a contiguous range of blocks that are free (bits
1719: clear in the bitmap). If a contiguous range of the
1720: minimum size can't be found, an error will be returned.
1721:
1722: �� It would be nice if we could skip over whole words
1723: �� with all bits set.
1724:
1725: �� When we find a bit set, and are about to set freeBlocks
1726: �� to 0, we should check to see whether there are still
1727: �� minBlocks bits left in the bitmap.
1728:
1729: Inputs:
1730: vcb Pointer to volume where space is to be allocated
1731: startingBlock Preferred first block of range
1732: endingBlock Last possible block in range + 1
1733: minBlocks Minimum number of blocks needed. Must be > 0.
1734: maxBlocks Maximum (ideal) number of blocks desired
1735:
1736: Outputs:
1737: actualStartBlock First block of range found, or 0 if error
1738: actualNumBlocks Number of blocks found, or 0 if error
1739: _______________________________________________________________________
1740: */
1741: /*
1742: _________________________________________________________________________________________
1743: (DSH) 5/8/97 Description of BlockFindContiguous() algorithm
1744: Finds a contiguous range of free blocks by searching back to front. This
1745: allows us to skip ranges of bits knowing that they are not candidates for
1746: a match because they are too small. The below ascii diagrams illustrate
1747: the algorithm in action.
1748:
1749: Representation of a piece of a volume bitmap file
1750: If BlockFindContiguous() is called with minBlocks == 10, maxBlocks == 20
1751:
1752:
1753: Fig. 1 initialization of variables, "<--" represents direction of travel
1754:
1755: startingBlock (passed in)
1756: |
1757: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1758: | <--|
1759: stopBlock currentBlock freeBlocks == 0
1760: countedFreeBlocks == 0
1761:
1762: Fig. 2 dirty bit found
1763:
1764: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1765: | |
1766: stopBlock currentBlock freeBlocks == 3
1767: countedFreeBlocks == 0
1768:
1769: Fig. 3 reset variables to search for remainder of minBlocks
1770:
1771: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1772: |_________________| | |
1773: Unsearched stopBlock currentBlock freeBlocks == 0
1774: countedFreeBlocks == 3
1775:
1776: Fig. 4 minBlocks contiguous blocks found, *actualStartBlock is set
1777:
1778: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1779: |_________________| |
1780: Unsearched stopBlock freeBlocks == 7
1781: currentBlock countedFreeBlocks == 3
1782:
1783: Fig. 5 Now run it forwards trying to accumalate up to maxBlocks if possible
1784:
1785: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1786: |_________________| | -->
1787: Unsearched currentBlock
1788: *actualNumBlocks == 10
1789:
1790: Fig. 6 Dirty bit is found, return actual number of contiguous blocks found
1791:
1792: 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1793: |_________________| |
1794: Unsearched currentBlock
1795: *actualNumBlocks == 16
1796: _________________________________________________________________________________________
1797: */
1798:
1799: static OSErr BlockFindContiguous(
1800: ExtendedVCB *vcb,
1801: UInt32 startingBlock,
1802: register UInt32 endingBlock,
1803: UInt32 minBlocks,
1804: UInt32 maxBlocks,
1805: UInt32 *actualStartBlock,
1806: UInt32 *actualNumBlocks)
1807: {
1808: OSErr err;
1809: register UInt32 bitMask; // mask of bit within word for currentBlock
1810: register UInt32 tempWord; // bitmap word currently being examined
1811: register UInt32 freeBlocks; // number of contiguous free blocks so far
1812: register UInt32 currentBlock; // block number we're currently examining
1813: UInt32 wordsLeft; // words remaining in bitmap block
1814: UInt32 *buffer = NULL;
1815: register UInt32 *currentWord;
1816:
1817: UInt32 stopBlock; // when all blocks until stopBlock are free, we found enough
1818: UInt32 countedFreeBlocks; // how many contiguous free block behind stopBlock
1819: UInt32 currentSector; // which allocations file sector
1820:
1821: #if HFSInstrumentation
1822: InstTraceClassRef trace;
1823: InstEventTag eventTag;
1824:
1825: err = InstCreateTraceClass(kInstRootClassRef, "HFS:VSM:BlockFindContiguous", 'hfs+', kInstEnableClassMask, &trace);
1826: if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
1827:
1828: eventTag = InstCreateEventTag();
1829: InstLogTraceEvent( trace, eventTag, kInstStartEvent);
1830: #endif
1831:
1832: if ((endingBlock - startingBlock) < minBlocks) {
1833: // The set of blocks we're checking is smaller than the minimum number
1834: // of blocks, so we couldn't possibly find a good range.
1835: err = dskFulErr;
1836: goto Exit;
1837: }
1838:
1839: // Search for min blocks from back to front.
1840: // If min blocks is found, advance the allocation pointer up to max blocks
1841:
1842: //
1843: // Pre-read the bitmap block containing currentBlock
1844: //
1845: stopBlock = startingBlock;
1846: currentBlock = startingBlock + minBlocks - 1; // (-1) to include startingBlock
1847:
1848: err = ReadBitmapBlock( vcb, currentBlock, &buffer );
1849: if ( err != noErr ) goto Exit;
1850:
1851: //
1852: // Init buffer, currentWord, wordsLeft, and bitMask
1853: //
1854: {
1855: UInt32 wordIndexInBlock;
1856:
1857: wordIndexInBlock = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
1858: currentWord = buffer + wordIndexInBlock;
1859:
1860: wordsLeft = wordIndexInBlock;
1861: tempWord = *currentWord;
1862: bitMask = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
1863: currentSector = currentBlock / kBitsPerBlock;
1864: }
1865:
1866: //
1867: // Look for maxBlocks free blocks. If we find an allocated block,
1868: // see if we've found minBlocks.
1869: //
1870: freeBlocks = 0;
1871: countedFreeBlocks = 0;
1872:
1873: while ( currentBlock >= stopBlock )
1874: {
1875: // Check current bit
1876: if ((tempWord & bitMask) == 0)
1877: {
1878: ++freeBlocks;
1879: }
1880: else // Used bitmap block found
1881: {
1882: if ( ( freeBlocks + countedFreeBlocks ) >= minBlocks )
1883: {
1884: break; // Found enough
1885: }
1886: else
1887: {
1888: // We found a dirty bit, so we want to check if the next (minBlocks-freeBlocks) blocks
1889: // are free beyond what we have already checked. At Fig.2 setting up for Fig.3
1890:
1891: stopBlock = currentBlock + 1 + freeBlocks; // Advance stop condition
1892: currentBlock += minBlocks;
1893: if ( currentBlock >= endingBlock ) break;
1894: countedFreeBlocks = freeBlocks;
1895: freeBlocks = 0; // Not enough; look for another range
1896:
1897: if ( currentSector != currentBlock / kBitsPerBlock )
1898: {
1899: #if EXPLICIT_BUFFER_RELEASES
1900: err = RelBlock_glue((Ptr)buffer, rbDefault);
1901: if (err != noErr) goto Exit;
1902: buffer = NULL;
1903: #endif
1904: err = ReadBitmapBlock( vcb, currentBlock, &buffer );
1905: if (err != noErr) goto Exit;
1906: currentSector = currentBlock / kBitsPerBlock;
1907: }
1908:
1909: wordsLeft = ( currentBlock & kBitsWithinBlockMask ) / kBitsPerWord;
1910: currentWord = buffer + wordsLeft;
1911: tempWord = *currentWord;
1912: bitMask = kHighBitInWordMask >> ( currentBlock & kBitsWithinWordMask );
1913:
1914: continue; // Back to the while loop
1915: }
1916: }
1917:
1918: // Move to next bit
1919: --currentBlock;
1920: bitMask <<= 1;
1921: if (bitMask == 0) // On a word boundry, start masking words
1922: {
1923: bitMask = kLowBitInWordMask;
1924:
1925: // Move to next word
1926: NextWord:
1927: if ( wordsLeft != 0 )
1928: {
1929: --currentWord;
1930: --wordsLeft;
1931: }
1932: else
1933: {
1934: // Read in the next bitmap block
1935: #if EXPLICIT_BUFFER_RELEASES
1936: err = RelBlock_glue((Ptr)buffer, rbDefault);
1937: if (err != noErr) goto Exit;
1938: buffer = NULL;
1939: #endif
1940: err = ReadBitmapBlock( vcb, currentBlock, &buffer );
1941: if (err != noErr) goto Exit;
1942:
1943: // Adjust currentWord, wordsLeft, currentSector
1944: currentSector = currentBlock / kBitsPerBlock;
1945: currentWord = buffer + kWordsPerBlock - 1; // Last word in buffer
1946: wordsLeft = kWordsPerBlock - 1;
1947: }
1948:
1949: tempWord = *currentWord; // Grab the current word
1950:
1951: //
1952: // If we found a whole word of free blocks, quickly skip over it.
1953: // NOTE: we could actually go beyond the end of the bitmap if the
1954: // number of allocation blocks on the volume is not a multiple of
1955: // 32. If this happens, we'll adjust currentBlock and freeBlocks
1956: // after the loop.
1957: //
1958: if ( tempWord == 0 )
1959: {
1960: freeBlocks += kBitsPerWord;
1961: currentBlock -= kBitsPerWord;
1962: if ( freeBlocks + countedFreeBlocks >= minBlocks )
1963: break; // Found enough
1964: goto NextWord;
1965: }
1966: }
1967: }
1968:
1969: if ( freeBlocks + countedFreeBlocks < minBlocks )
1970: {
1971: *actualStartBlock = 0;
1972: *actualNumBlocks = 0;
1973: err = dskFulErr;
1974: goto Exit;
1975: }
1976:
1977: //
1978: // When we get here, we know we've found minBlocks continuous space.
1979: // At Fig.4, setting up for Fig.5
1980: // From here we do a forward search accumalating additional free blocks.
1981: //
1982:
1983: *actualNumBlocks = minBlocks;
1984: *actualStartBlock = stopBlock - countedFreeBlocks; // ActualStartBlock is set to return to the user
1985: currentBlock = *actualStartBlock + minBlocks; // Right after found free space
1986:
1987: // Now lets see if we can run the actualNumBlocks number all the way up to maxBlocks
1988: if ( currentSector != currentBlock / kBitsPerBlock )
1989: {
1990: #if EXPLICIT_BUFFER_RELEASES
1991: err = RelBlock_glue((Ptr)buffer, rbDefault);
1992: if (err != noErr) goto Exit;
1993: buffer = NULL;
1994: #endif
1995: err = ReadBitmapBlock( vcb, currentBlock, &buffer );
1996: if (err != noErr)
1997: {
1998: err = noErr; // We already found the space
1999: goto Exit;
2000: }
2001:
2002: currentSector = currentBlock / kBitsPerBlock;
2003: }
2004:
2005: //
2006: // Init buffer, currentWord, wordsLeft, and bitMask
2007: //
2008: {
2009: UInt32 wordIndexInBlock;
2010:
2011: wordIndexInBlock = (currentBlock & kBitsWithinBlockMask) / kBitsPerWord;
2012: currentWord = buffer + wordIndexInBlock;
2013: tempWord = *currentWord;
2014: wordsLeft = kWordsPerBlock - wordIndexInBlock;
2015: bitMask = kHighBitInWordMask >> (currentBlock & kBitsWithinWordMask);
2016: }
2017:
2018: if ( *actualNumBlocks < maxBlocks )
2019: {
2020: while ( currentBlock < endingBlock )
2021: {
2022:
2023: if ( (tempWord & bitMask) == 0 )
2024: {
2025: *actualNumBlocks += 1;
2026:
2027: if ( *actualNumBlocks == maxBlocks )
2028: break;
2029: }
2030: else
2031: {
2032: break;
2033: }
2034:
2035: // Move to next bit
2036: ++currentBlock;
2037: bitMask >>= 1;
2038: if (bitMask == 0)
2039: {
2040: bitMask = kHighBitInWordMask;
2041: ++currentWord;
2042:
2043: if ( --wordsLeft == 0)
2044: {
2045: #if EXPLICIT_BUFFER_RELEASES
2046: err = RelBlock_glue((Ptr)buffer, rbDefault);
2047: if (err != noErr) goto Exit;
2048: buffer = NULL;
2049: #endif
2050: err = ReadBitmapBlock(vcb, currentBlock, &buffer);
2051: if (err != noErr) break;
2052:
2053: // Adjust currentWord, wordsLeft
2054: currentWord = buffer;
2055: wordsLeft = kWordsPerBlock;
2056: }
2057: tempWord = *currentWord; // grab the current word
2058: }
2059: }
2060: }
2061:
2062: Exit:
2063:
2064: #if EXPLICIT_BUFFER_RELEASES
2065: if (buffer) {
2066: (void)RelBlock_glue((Ptr)buffer, rbDefault); /* Ignore any additional errors */
2067: };
2068: #endif
2069:
2070: #if HFSInstrumentation
2071: InstLogTraceEvent( trace, eventTag, kInstEndEvent);
2072: #endif
2073:
2074: return err;
2075: }
2076:
2077:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.