2 * Copyright (c) 2000-2002, 2004-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /* Summary for in-memory volume bitmap:
25 * A binary search tree is used to store bitmap segments that are
26 * partially full. If a segment does not exist in the tree, it
27 * can be assumed to be in the following state:
28 * 1. Full if the coresponding segment map bit is set
32 #include "Scavenger.h"
36 #include <bitstring.h>
38 #define bit_dealloc(p) free(p)
45 kBitsPerSegment
= 1024,
46 kBytesPerSegment
= kBitsPerSegment
/ kBitsPerByte
,
47 kWordsPerSegment
= kBitsPerSegment
/ kBitsPerWord
,
49 kBitsWithinWordMask
= kBitsPerWord
-1,
50 kBitsWithinSegmentMask
= kBitsPerSegment
-1,
52 kBMS_NodesPerPool
= 450,
57 #define kAllBitsSetInWord 0xFFFFFFFFu
58 #define kMSBBitSetInWord 0x80000000u
66 #define kEmptySegment 0
67 #define kFullSegment 1
69 int gBitMapInited
= 0;
72 * Bitmap segments that are full are marked in
73 * the gFullSegmentList (a bit string).
75 bitstr_t
* gFullSegmentList
;
78 UInt32 gTotalSegments
;
79 UInt32
* gFullBitmapSegment
; /* points to a FULL bitmap segment*/
80 UInt32
* gEmptyBitmapSegment
; /* points to an EMPTY bitmap segment*/
83 * Bitmap Segment (BMS) Tree node
84 * Bitmap segments that are partially full are
85 * saved in the BMS Tree.
87 typedef struct BMS_Node
{
88 struct BMS_Node
*left
;
89 struct BMS_Node
*right
;
91 UInt32 bitmap
[kWordsPerSegment
];
94 BMS_Node
*gBMS_Root
; /* root of BMS tree */
95 BMS_Node
*gBMS_FreeNodes
; /* list of free BMS nodes */
96 BMS_Node
*gBMS_PoolList
[kBMS_PoolMax
]; /* list of BMS node pools */
97 int gBMS_PoolCount
; /* count of pools allocated */
99 /* Bitmap operations routines */
100 static int FindContigClearedBitmapBits (SVCB
*vcb
, UInt32 numBlocks
, UInt32
*actualStartBlock
);
102 /* Segment Tree routines (binary search tree) */
103 static int BMS_InitTree(void);
104 static int BMS_DisposeTree(void);
105 static BMS_Node
* BMS_Lookup(UInt32 segment
);
106 static BMS_Node
* BMS_Insert(UInt32 segment
, int segmentType
);
107 static BMS_Node
* BMS_Delete(UInt32 segment
);
108 static void BMS_GrowNodePool(void);
111 static void BMS_PrintTree(BMS_Node
* root
);
112 static void BMS_MaxDepth(BMS_Node
* root
, int depth
, int *maxdepth
);
116 * Initialize our volume bitmap data structures
118 int BitMapCheckBegin(SGlobPtr g
)
125 isHFSPlus
= VolumeObjectIsHFSPlus( );
127 gFullBitmapSegment
= (UInt32
*)malloc(kBytesPerSegment
);
128 memset((void *)gFullBitmapSegment
, 0xff, kBytesPerSegment
);
130 gEmptyBitmapSegment
= (UInt32
*)malloc(kBytesPerSegment
);
131 memset((void *)gEmptyBitmapSegment
, 0x00, kBytesPerSegment
);
133 gTotalBits
= g
->calculatedVCB
->vcbTotalBlocks
;
134 gTotalSegments
= (gTotalBits
/ kBitsPerSegment
);
135 if (gTotalBits
% kBitsPerSegment
)
138 gFullSegmentList
= bit_alloc(gTotalSegments
);
139 bit_nclear(gFullSegmentList
, 0, gTotalSegments
- 1);
149 * Allocate the VolumeHeader in the volume bitmap.
150 * Since the VH is the 3rd sector in we may need to
151 * add some alignment allocation blocks before it.
153 if (g
->calculatedVCB
->vcbBlockSize
== 512)
155 else if (g
->calculatedVCB
->vcbBlockSize
== 1024)
160 (void) CaptureBitmapBits(0, 1 + alignBits
);
162 if (g
->calculatedVCB
->vcbBlockSize
== 512)
167 (void) CaptureBitmapBits(gTotalBits
- 1 - alignBits
, 1 + alignBits
);
173 /* debugging stats */
174 int gFullSegments
= 0;
175 int gSegmentNodes
= 0;
177 int BitMapCheckEnd(void)
183 BMS_MaxDepth(gBMS_Root
, 0, &maxdepth
);
184 plog(" %d full segments, %d segment nodes (max depth was %d nodes)\n",
185 gFullSegments
, gSegmentNodes
, maxdepth
);
187 free(gFullBitmapSegment
);
188 gFullBitmapSegment
= NULL
;
190 free(gEmptyBitmapSegment
);
191 gEmptyBitmapSegment
= NULL
;
193 bit_dealloc(gFullSegmentList
);
194 gFullSegmentList
= NULL
;
202 /* Function: GetSegmentBitmap
204 * Description: Return bitmap segment corresponding to given startBit.
206 * 1. Calculate the segment number for given bit.
207 * 2. If the segment exists in full segment list,
208 * If bitOperation is to clear bits,
209 * a. Remove segment from full segment list.
210 * b. Insert a full segment in the bitmap tree.
211 * Else return pointer to dummy full segment
212 * 3. If segment found in tree, it is partially full. Return it.
213 * 4. If (2) and (3) are not true, it is a empty segment.
214 * If bitOperation is to set bits,
215 * a. Insert empty segment in the bitmap tree.
216 * Else return pointer to dummy empty segment.
219 * 1. startBit - bit number (block number) to lookup
220 * 2. buffer - pointer to return pointer to bitmap segment
221 * 3. bitOperation - intent for new segment
222 * kSettingBits - caller wants to set bits
223 * kClearingBits - caller wants to clear bits
224 * kTestingBits - caller wants to test bits.
227 * 1. buffer - pointer to desired segment
228 * returns zero on success, -1 on failure.
230 static int GetSegmentBitmap(UInt32 startBit
, UInt32
**buffer
, int bitOperation
)
233 BMS_Node
*segNode
= NULL
;
236 segment
= startBit
/ kBitsPerSegment
;
238 // for a full seqment...
239 if (bit_test(gFullSegmentList
, segment
)) {
240 if (bitOperation
== kClearingBits
) {
241 bit_clear(gFullSegmentList
, segment
);
243 if ((segNode
= BMS_Insert(segment
, kFullSegment
)) != NULL
)
244 *buffer
= &segNode
->bitmap
[0];
246 *buffer
= gFullBitmapSegment
;
248 // for a partially full segment..
249 } else if ((segNode
= BMS_Lookup(segment
)) != NULL
) {
250 *buffer
= &segNode
->bitmap
[0];
252 // for an empty segment...
254 if (bitOperation
== kSettingBits
) {
255 if ((segNode
= BMS_Insert(segment
, kEmptySegment
)) != NULL
)
256 *buffer
= &segNode
->bitmap
[0];
258 *buffer
= gEmptyBitmapSegment
;
261 if (*buffer
== NULL
) {
263 plog("GetSegmentBitmap: couldn't get a node for block %d, segment %d\n", startBit
, segment
);
265 return (-1); /* oops */
271 plog(" segment %d: L=0x%08x, R=0x%08x \n< ",
272 (int)segNode
->segment
, (int)segNode
->left
, segNode
->right
);
273 for (i
= 0; i
< kWordsPerSegment
; ++i
) {
274 plog("0x%08x ", segNode
->bitmap
[i
]);
275 if ((i
& 0x3) == 0x3)
281 if (bitOperation
== kSettingBits
&& *buffer
&& bcmp(*buffer
, gFullBitmapSegment
, kBytesPerSegment
) == 0) {
282 plog("*** segment %d (start blk %d) is already full!\n", segment
, startBit
);
285 if (bitOperation
== kClearingBits
&& *buffer
&& bcmp(*buffer
, gEmptyBitmapSegment
, kBytesPerSegment
) == 0) {
286 plog("*** segment %d (start blk %d) is already empty!\n", segment
, startBit
);
294 /* Function: TestSegmentBitmap
296 * Description: Test if the current bitmap segment is a full
297 * segment or empty segment.
298 * If full segment, delete the segment, set corresponding full segment
299 * bit in gFullSegmentList, and update counters.
300 * If empty list, delete the segment from list. Note that we update
301 * the counter only for debugging purposes.
304 * startBit - startBit of segment to test
309 void TestSegmentBitmap(UInt32 startBit
)
312 BMS_Node
*segNode
= NULL
;
314 segment
= startBit
/ kBitsPerSegment
;
316 if (bit_test(gFullSegmentList
, segment
))
319 if ((segNode
= BMS_Lookup(segment
)) != NULL
) {
323 for (i
= 0; i
< kWordsPerSegment
; ++i
) {
324 plog("0x%08x ", segNode
->bitmap
[i
]);
325 if ((i
& 0x3) == 0x3)
330 if (segment
!= 0 && bcmp(&segNode
->bitmap
[0], gFullBitmapSegment
, kBytesPerSegment
) == 0) {
331 if (BMS_Delete(segment
) != NULL
) {
332 bit_set(gFullSegmentList
, segment
);
333 /* debugging stats */
339 if (segment
!= 0 && bcmp(&segNode
->bitmap
[0], gEmptyBitmapSegment
, kBytesPerSegment
) == 0) {
340 if (BMS_Delete(segment
) != NULL
) {
341 /* debugging stats */
349 /* Function: CaptureBitmapBits
351 * Description: Set bits in the segmented bitmap from startBit upto
354 * Note: This function is independent of the previous state of the bit
355 * to be set. Therefore single bit can be set multiple times. Setting a
356 * bit multiple times might result in incorrect total number of blocks used
357 * (which can be corrected using UpdateFreeBlockCount function).
359 * 1. Increment gBitsMarked with bitCount.
360 * 2. If first bit does not start on word boundary, special case it.
361 * 3. Set all whole words.
362 * 4. If not all bits in last word need to be set, special case it.
363 * 5. For 2, 3, and 4, call TestSegmentBitmap after writing one segment or
364 * setting all bits to optimize full and empty segment list.
367 * startBit - bit number in segment bitmap to start set operation.
368 * bitCount - total number of bits to set.
371 * zero on success, non-zero on failure.
372 * This function also returns E_OvlExt if any overlapping extent is found.
374 int CaptureBitmapBits(UInt32 startBit
, UInt32 bitCount
)
389 if ((startBit
+ bitCount
) > gTotalBits
) {
390 err
= vcInvalidExtentErr
;
394 /* count allocated bits */
395 gBitsMarked
+= bitCount
;
398 * Get the bitmap segment containing the first word to check
400 err
= GetSegmentBitmap(startBit
, &buffer
, kSettingBits
);
401 if (err
!= noErr
) goto Exit
;
403 /* Initialize buffer stuff */
405 UInt32 wordIndexInSegment
;
407 wordIndexInSegment
= (startBit
& kBitsWithinSegmentMask
) / kBitsPerWord
;
408 currentWord
= buffer
+ wordIndexInSegment
;
409 wordsLeft
= kWordsPerSegment
- wordIndexInSegment
;
413 * If the first bit to check doesn't start on a word
414 * boundary in the bitmap, then treat that first word
417 firstBit
= startBit
% kBitsPerWord
;
419 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
420 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
421 if (numBits
> bitCount
) {
422 numBits
= bitCount
; // entire allocation is inside this one word
423 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
426 if (SWAP_BE32(*currentWord
) & bitMask
) {
429 //plog("(1) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
432 *currentWord
|= SWAP_BE32(bitMask
); /* set the bits in the bitmap */
437 if (wordsLeft
== 0 || bitCount
== 0)
438 TestSegmentBitmap(startBit
);
442 * Set whole words (32 bits) at a time.
444 bitMask
= kAllBitsSetInWord
;
445 while (bitCount
>= kBitsPerWord
) {
446 /* See if it's time to move to the next bitmap segment */
447 if (wordsLeft
== 0) {
448 startBit
+= kBitsPerSegment
; // generate a bit in the next bitmap segment
450 err
= GetSegmentBitmap(startBit
, &buffer
, kSettingBits
);
451 if (err
!= noErr
) goto Exit
;
453 // Readjust currentWord, wordsLeft
454 currentWord
= buffer
;
455 wordsLeft
= kWordsPerSegment
;
458 if (SWAP_BE32(*currentWord
) & bitMask
) {
461 //plog("(2) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
464 *currentWord
|= SWAP_BE32(bitMask
); /* set the bits in the bitmap */
466 bitCount
-= kBitsPerWord
;
469 if (wordsLeft
== 0 || bitCount
== 0)
470 TestSegmentBitmap(startBit
);
474 * Check any remaining bits.
477 bitMask
= ~(kAllBitsSetInWord
>> bitCount
); // set first bitCount bits
478 if (wordsLeft
== 0) {
479 startBit
+= kBitsPerSegment
;
481 err
= GetSegmentBitmap(startBit
, &buffer
, kSettingBits
);
482 if (err
!= noErr
) goto Exit
;
484 currentWord
= buffer
;
485 wordsLeft
= kWordsPerSegment
;
488 if (SWAP_BE32(*currentWord
) & bitMask
) {
491 //plog("(3) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
494 *currentWord
|= SWAP_BE32(bitMask
); /* set the bits in the bitmap */
496 TestSegmentBitmap(startBit
);
499 return (overlap
? E_OvlExt
: err
);
503 /* Function: ReleaseBitMapBits
505 * Description: Clear bits in the segmented bitmap from startBit upto
508 * Note: This function is independent of the previous state of the bit
509 * to clear. Therefore single bit can be cleared multiple times. Clearing a
510 * bit multiple times might result in incorrect total number of blocks used
511 * (which can be corrected using UpdateFreeBlockCount function).
513 * 1. Decrement gBitsMarked with bitCount.
514 * 2. If first bit does not start on word boundary, special case it.
515 * 3. Clear all whole words.
516 * 4. If partial bits in last word needs to be cleared, special case it.
517 * 5. For 2, 3, and 4, call TestSegmentBitmap after writing one segment or
518 * clearing all bits to optimize full and empty segment list.
521 * startBit - bit number in segment bitmap to start clear operation.
522 * bitCount - total number of bits to clear.
525 * zero on success, non-zero on failure.
526 * This function also returns E_OvlExt if any overlapping extent is found.
528 int ReleaseBitmapBits(UInt32 startBit
, UInt32 bitCount
)
543 if ((startBit
+ bitCount
) > gTotalBits
) {
544 err
= vcInvalidExtentErr
;
548 /* decrment allocated bits */
549 gBitsMarked
-= bitCount
;
552 * Get the bitmap segment containing the first word to check
554 err
= GetSegmentBitmap(startBit
, &buffer
, kClearingBits
);
555 if (err
!= noErr
) goto Exit
;
557 /* Initialize buffer stuff */
559 UInt32 wordIndexInSegment
;
561 wordIndexInSegment
= (startBit
& kBitsWithinSegmentMask
) / kBitsPerWord
;
562 currentWord
= buffer
+ wordIndexInSegment
;
563 wordsLeft
= kWordsPerSegment
- wordIndexInSegment
;
567 * If the first bit to check doesn't start on a word
568 * boundary in the bitmap, then treat that first word
571 firstBit
= startBit
% kBitsPerWord
;
573 bitMask
= kAllBitsSetInWord
>> firstBit
; // turn off all bits before firstBit
574 numBits
= kBitsPerWord
- firstBit
; // number of remaining bits in this word
575 if (numBits
> bitCount
) {
576 numBits
= bitCount
; // entire deallocation is inside this one word
577 bitMask
&= ~(kAllBitsSetInWord
>> (firstBit
+ numBits
)); // turn off bits after last
580 if ((SWAP_BE32(*currentWord
) & bitMask
) != bitMask
) {
583 //plog("(1) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
586 *currentWord
&= SWAP_BE32(~bitMask
); /* clear the bits in the bitmap */
591 if (wordsLeft
== 0 || bitCount
== 0)
592 TestSegmentBitmap(startBit
);
596 * Clear whole words (32 bits) at a time.
598 bitMask
= kAllBitsSetInWord
;
599 while (bitCount
>= kBitsPerWord
) {
600 /* See if it's time to move to the next bitmap segment */
601 if (wordsLeft
== 0) {
602 startBit
+= kBitsPerSegment
; // generate a bit in the next bitmap segment
604 err
= GetSegmentBitmap(startBit
, &buffer
, kClearingBits
);
605 if (err
!= noErr
) goto Exit
;
607 // Readjust currentWord, wordsLeft
608 currentWord
= buffer
;
609 wordsLeft
= kWordsPerSegment
;
612 if ((SWAP_BE32(*currentWord
) & bitMask
) != bitMask
) {
615 //plog("(2) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
618 *currentWord
&= SWAP_BE32(~bitMask
); /* clear the bits in the bitmap */
620 bitCount
-= kBitsPerWord
;
623 if (wordsLeft
== 0 || bitCount
== 0)
624 TestSegmentBitmap(startBit
);
628 * Check any remaining bits.
631 bitMask
= ~(kAllBitsSetInWord
>> bitCount
); // set first bitCount bits
632 if (wordsLeft
== 0) {
633 startBit
+= kBitsPerSegment
;
635 err
= GetSegmentBitmap(startBit
, &buffer
, kClearingBits
);
636 if (err
!= noErr
) goto Exit
;
638 currentWord
= buffer
;
639 wordsLeft
= kWordsPerSegment
;
642 if ((SWAP_BE32(*currentWord
) & bitMask
) != bitMask
) {
645 //plog("(3) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
648 *currentWord
&= SWAP_BE32(~bitMask
); /* set the bits in the bitmap */
650 TestSegmentBitmap(startBit
);
653 return (overlap
? E_OvlExt
: err
);
656 /* Function: CheckVolumeBitMap
658 * Description: Compares the in-memory volume bitmap with the on-disk
660 * If repair is true, update the on-disk bitmap with the in-memory bitmap.
661 * If repair is false and the bitmaps don't match, an error message is
662 * printed and check stops.
665 * 1. g - global scavenger structure
666 * 2. repair - indicate if a repair operation is requested or not.
669 * zero on success, non-zero on failure.
671 int CheckVolumeBitMap(SGlobPtr g
, Boolean repair
)
675 UInt64 bit
; /* 64-bit to avoid wrap around on volumes with 2^32 - 1 blocks */
676 UInt32 bitsWithinFileBlkMask
;
678 BlockDescriptor block
;
679 ReleaseBlockOptions relOpt
;
683 Boolean foundOverAlloc
= false;
686 vcb
= g
->calculatedVCB
;
687 fcb
= g
->calculatedAllocationsFCB
;
688 isHFSPlus
= VolumeObjectIsHFSPlus( );
690 if ( vcb
->vcbFreeBlocks
!= (vcb
->vcbTotalBlocks
- gBitsMarked
) ) {
691 vcb
->vcbFreeBlocks
= vcb
->vcbTotalBlocks
- gBitsMarked
;
695 vbmBlockP
= (UInt8
*)NULL
;
696 block
.buffer
= (void *)NULL
;
697 relOpt
= kReleaseBlock
;
699 bitsWithinFileBlkMask
= (fcb
->fcbBlockSize
* 8) - 1;
701 bitsWithinFileBlkMask
= (kHFSBlockSize
* 8) - 1;
702 fileBlk
= (isHFSPlus
? 0 : vcb
->vcbVBMSt
);
705 * Loop through all the bitmap segments and compare
706 * them against the on-disk bitmap.
708 for (bit
= 0; bit
< gTotalBits
; bit
+= kBitsPerSegment
) {
709 (void) GetSegmentBitmap((UInt32
)bit
, &buffer
, kTestingBits
);
712 * When we cross file block boundries read a new block from disk.
714 if ((bit
& bitsWithinFileBlkMask
) == 0) {
717 err
= ReleaseFileBlock(fcb
, &block
, relOpt
);
720 err
= GetFileBlock(fcb
, fileBlk
, kGetBlock
, &block
);
721 } else /* plain HFS */ {
723 err
= ReleaseVolumeBlock(vcb
, &block
, relOpt
| kSkipEndianSwap
);
726 err
= GetVolumeBlock(vcb
, fileBlk
, kGetBlock
| kSkipEndianSwap
, &block
);
730 vbmBlockP
= (UInt8
*) block
.buffer
;
731 relOpt
= kReleaseBlock
;
732 g
->TarBlock
= fileBlk
;
735 if (memcmp(buffer
, vbmBlockP
+ (bit
& bitsWithinFileBlkMask
)/8, kBytesPerSegment
) == 0)
739 bcopy(buffer
, vbmBlockP
+ (bit
& bitsWithinFileBlkMask
)/8, kBytesPerSegment
);
740 relOpt
= kForceWriteBlock
;
747 UInt32 dummy
, block_num
;
749 plog(" disk buffer + %d\n", (bit
& bitsWithinFileBlkMask
)/8);
750 plog("start block number for segment = %qu\n", bit
);
751 plog("segment %qd\n", bit
/ kBitsPerSegment
);
754 for (i
= 0; i
< kWordsPerSegment
; ++i
) {
755 plog("0x%08x ", buffer
[i
]);
756 if ((i
& 0x7) == 0x7)
760 disk_buffer
= (UInt32
*) (vbmBlockP
+ (bit
& bitsWithinFileBlkMask
)/8);
762 for (i
= 0; i
< kWordsPerSegment
; ++i
) {
763 plog("0x%08x ", disk_buffer
[i
]);
764 if ((i
& 0x7) == 0x7)
769 for (i
= 0; i
< kWordsPerSegment
; ++i
) {
770 /* Compare each word in the segment */
771 if (buffer
[i
] != disk_buffer
[i
]) {
773 /* If two words are different, compare each bit in the word */
774 for (j
= 0; j
< kBitsPerWord
; ++j
) {
775 /* If two bits are different, calculate allocation block number */
776 if ((buffer
[i
] & dummy
) != (disk_buffer
[i
] & dummy
)) {
777 block_num
= bit
+ (i
* kBitsPerWord
) + j
;
778 if (buffer
[i
] & dummy
) {
779 plog ("Allocation block %u should be marked used on disk.\n", block_num
);
781 plog ("Allocation block %u should be marked free on disk.\n", block_num
);
790 * We have at least one difference. If we have over-allocated (that is, the
791 * volume bitmap says a block is allocated, but our counts say it isn't), then
792 * this is a lessor error. If we've under-allocated (that is, the volume bitmap
793 * says a block is available, but our counts say it is in use), then this is a
794 * bigger problem -- it can lead to overlapping extents.
796 * Once we determine we have under-allocated, we can just stop and print out
799 for (indx
= 0; indx
< kBytesPerSegment
; indx
++) {
800 uint8_t *bufp
, *diskp
;
801 bufp
= (uint8_t *)buffer
;
802 diskp
= vbmBlockP
+ (bit
& bitsWithinFileBlkMask
)/8;
803 if (bufp
[indx
] & ~diskp
[indx
]) {
808 g
->VIStat
= g
->VIStat
| S_VBM
;
810 fsckPrint(g
->context
, E_VBMDamaged
);
811 break; /* stop checking after first miss */
812 } else if (!foundOverAlloc
) {
813 /* Only print out a message on the first find */
814 fsckPrint(g
->context
, E_VBMDamagedOverAlloc
);
815 foundOverAlloc
= true;
823 (void) ReleaseFileBlock(fcb
, &block
, relOpt
);
825 (void) ReleaseVolumeBlock(vcb
, &block
, relOpt
| kSkipEndianSwap
);
831 /* Function: UpdateFreeBlockCount
833 * Description: Re-calculate the total bits marked in in-memory bitmap
834 * by traversing the entire bitmap. Update the total number of bits set in
835 * the in-memory volume bitmap and the volume free block count.
837 * All the bits representing the blocks that are beyond total allocation
838 * blocks of the volume are intialized to zero in the last bitmap segment.
839 * This function checks for bits marked, therefore we do not special case
840 * the last bitmap segment.
843 * g - global scavenger structure pointer.
848 void UpdateFreeBlockCount(SGlobPtr g
)
851 UInt32 newBitsMarked
= 0;
855 SVCB
* vcb
= g
->calculatedVCB
;
857 /* Loop through all the bitmap segments */
858 for (bit
= 0; bit
< gTotalBits
; bit
+= kBitsPerSegment
) {
859 (void) GetSegmentBitmap(bit
, &buffer
, kTestingBits
);
861 /* All bits in segment are set */
862 if (buffer
== gFullBitmapSegment
) {
863 newBitsMarked
+= kBitsPerSegment
;
867 /* All bits in segment are clear */
868 if (buffer
== gEmptyBitmapSegment
) {
872 /* Segment is partially full */
873 for (i
= 0; i
< kWordsPerSegment
; i
++) {
874 if (buffer
[i
] == kAllBitsSetInWord
) {
875 newBitsMarked
+= kBitsPerWord
;
877 curWord
= SWAP_BE32(buffer
[i
]);
879 newBitsMarked
+= curWord
& 1;
886 /* Update total bits marked count for in-memory bitmap */
887 if (gBitsMarked
!= newBitsMarked
) {
888 gBitsMarked
= newBitsMarked
;
891 /* Update volume free block count */
892 if (vcb
->vcbFreeBlocks
!= (vcb
->vcbTotalBlocks
- gBitsMarked
)) {
893 vcb
->vcbFreeBlocks
= vcb
->vcbTotalBlocks
- gBitsMarked
;
898 /* Function: FindContigClearedBitmapBits
900 * Description: Find contigous free bitmap bits (allocation blocks) from
901 * the in-memory volume bitmap. If found, the bits are not marked as
904 * The function traverses the entire in-memory volume bitmap. It keeps
905 * a count of contigous cleared bits and the first cleared bit seen in
906 * the current sequence.
907 * If it sees a set bit, it re-intializes the count to the number of
908 * blocks to be found and first cleared bit as zero.
909 * If it sees a cleared bit, it decrements the count of number of blocks
910 * to be found cleared. If the first cleared bit was set to zero,
911 * it initializes it with the current bit. If the count of number
912 * of blocks becomes zero, the function returns.
914 * The function takes care if the last bitmap segment is paritally used
915 * to represented the total number of allocation blocks.
918 * 1. vcb - pointer to volume information
919 * 2. numBlocks - number of free contigous blocks
920 * 3. actualStartBlock - pointer to return the start block, if contigous
924 * 1. actualStartBlock - pointer to return the start block, if contigous
926 * On success, returns zero.
927 * On failure, non-zero value
928 * ENOSPC - No contigous free blocks were found of given length
930 static int FindContigClearedBitmapBits (SVCB
*vcb
, UInt32 numBlocks
, UInt32
*actualStartBlock
)
937 UInt32 validBitsInSegment
; /* valid bits remaining (considering totalBits) in segment */
938 UInt32 validBitsInWord
; /* valid bits remaining (considering totalBits) in word */
939 UInt32 bitsRemain
= numBlocks
; /* total free bits more to search */
940 UInt32 startBlock
= 0; /* start bit for free bits sequence */
942 /* For all segments except the last segments, number of valid bits
943 * is always total number of bits represented by the segment
945 validBitsInSegment
= kBitsPerSegment
;
947 /* For all words except the last word, the number of valid bits
948 * is always total number of bits represented by the word
950 validBitsInWord
= kBitsPerWord
;
952 /* Loop through all the bitmap segments */
953 for (bit
= 0; bit
< gTotalBits
; bit
+= kBitsPerSegment
) {
954 (void) GetSegmentBitmap(bit
, &buffer
, kTestingBits
);
956 /* If this is last segment, calculate valid bits remaining */
957 if ((gTotalBits
- bit
) < kBitsPerSegment
) {
958 validBitsInSegment
= gTotalBits
- bit
;
961 /* All bits in segment are set */
962 if (buffer
== gFullBitmapSegment
) {
963 /* Reset our counters */
965 bitsRemain
= numBlocks
;
969 /* All bits in segment are clear */
970 if (buffer
== gEmptyBitmapSegment
) {
971 /* If startBlock is not initialized, initialize it */
972 if (bitsRemain
== numBlocks
) {
975 /* If the total number of required free blocks is greater than
976 * total number of blocks represented in one free segment, include
977 * entire segment in our count
978 * If the total number of required free blocks is less than the
979 * total number of blocks represented in one free segment, include
980 * only the remaining free blocks in the count and break out.
982 if (bitsRemain
> validBitsInSegment
) {
983 bitsRemain
-= validBitsInSegment
;
991 /* Segment is partially full */
992 for (i
= 0; i
< kWordsPerSegment
; i
++) {
993 /* All bits in a word are set */
994 if (buffer
[i
] == kAllBitsSetInWord
) {
995 /* Reset our counters */
997 bitsRemain
= numBlocks
;
999 /* Not all bits in a word are set */
1001 /* If this is the last segment, check if the current word
1002 * is the last word containing valid bits.
1004 if (validBitsInSegment
!= kBitsPerSegment
) {
1005 if ((validBitsInSegment
- (i
* kBitsPerWord
)) < kBitsPerWord
) {
1006 /* Calculate the total valid bits in last word */
1007 validBitsInWord
= validBitsInSegment
- (i
* kBitsPerWord
);
1011 curWord
= SWAP_BE32(buffer
[i
]);
1012 /* Check every bit in the word */
1013 for (j
= 0; j
< validBitsInWord
; j
++) {
1014 if (curWord
& kMSBBitSetInWord
) {
1015 /* The bit is set, reset our counters */
1017 bitsRemain
= numBlocks
;
1019 /* The bit is clear */
1020 if (bitsRemain
== numBlocks
) {
1021 startBlock
= bit
+ (i
* kBitsPerWord
) + j
;
1024 if (bitsRemain
== 0) {
1029 } /* for - checking bits set in word */
1031 /* If this is last valid word, stop the search */
1032 if (validBitsInWord
!= kBitsPerWord
) {
1035 } /* else - not all bits set in a word */
1036 } /* for - segment is partially full */
1037 } /* for - loop over all segments */
1040 if (bitsRemain
== 0) {
1041 /* Return the new start block found */
1042 *actualStartBlock
= startBlock
;
1045 *actualStartBlock
= 0;
1051 /* Function: AllocateContigBitmapBits
1053 * Description: Find contigous free bitmap bits (allocation blocks) from
1054 * the in-memory volume bitmap. If found, also mark the bits as used.
1057 * 1. vcb - pointer to volume information
1058 * 2. numBlocks - number of free contigous blocks
1059 * 3. actualStartBlock - pointer to return the start block, if contigous
1060 * free blocks found.
1063 * 1. actualStartBlock - pointer to return the start block, if contigous
1064 * free blocks found.
1065 * On success, returns zero.
1066 * On failure, non-zero value
1067 * ENOENT - No contigous free blocks were found of given length
1068 * E_OvlExt - Free blocks found are already allocated (overlapping
1071 int AllocateContigBitmapBits (SVCB
*vcb
, UInt32 numBlocks
, UInt32
*actualStartBlock
)
1075 error
= FindContigClearedBitmapBits (vcb
, numBlocks
, actualStartBlock
);
1076 if (error
== noErr
) {
1077 error
= CaptureBitmapBits (*actualStartBlock
, numBlocks
);
1083 enum { kMaxTrimExtents
= 256 };
1084 dk_extent_t gTrimExtents
[kMaxTrimExtents
];
1085 dk_unmap_t gTrimData
;
1087 static void TrimInit(void)
1089 bzero(&gTrimData
, sizeof(gTrimData
));
1090 gTrimData
.extents
= gTrimExtents
;
1093 static void TrimFlush(void)
1097 if (gTrimData
.extentsCount
== 0)
1099 DPRINTF(d_info
|d_trim
, "TrimFlush: nothing to flush\n");
1103 err
= ioctl(fsreadfd
, DKIOCUNMAP
, &gTrimData
);
1106 DPRINTF(d_error
|d_trim
, "TrimFlush: error %d\n", errno
);
1108 gTrimData
.extentsCount
= 0;
1111 static void TrimExtent(SGlobPtr g
, UInt32 startBlock
, UInt32 blockCount
)
1116 DPRINTF(d_info
|d_trim
, "Trimming: startBlock=%10u, blockCount=%10u\n", startBlock
, blockCount
);
1118 offset
= (UInt64
) startBlock
* g
->calculatedVCB
->vcbBlockSize
;
1119 if (VolumeObjectIsHFSPlus())
1120 offset
+= g
->calculatedVCB
->vcbEmbeddedOffset
;
1122 offset
+= g
->calculatedVCB
->vcbAlBlSt
* 512ULL;
1123 length
= (UInt64
) blockCount
* g
->calculatedVCB
->vcbBlockSize
;
1125 gTrimExtents
[gTrimData
.extentsCount
].offset
= offset
;
1126 gTrimExtents
[gTrimData
.extentsCount
].length
= length
;
1127 if (++gTrimData
.extentsCount
== kMaxTrimExtents
)
1131 /* Function: TrimFreeBlocks
1133 * Description: Find contiguous ranges of free allocation blocks (cleared bits
1134 * in the bitmap) and issue DKIOCUNMAP requests to tell the underlying device
1135 * that those blocks are not in use. This allows the device to reclaim that
1139 * g - global scavenger structure pointer
1141 void TrimFreeBlocks(SGlobPtr g
)
1145 UInt32 wordWithinSegment
;
1146 UInt32 bitWithinWordMask
;
1150 UInt32 totalTrimmed
= 0;
1154 /* We haven't seen any free blocks yet. */
1158 /* Loop through bitmap segments */
1159 for (bit
= 0; bit
< gTotalBits
; /* bit incremented below */) {
1160 assert((bit
% kBitsPerSegment
) == 0);
1162 (void) GetSegmentBitmap(bit
, &buffer
, kTestingBits
);
1164 if (buffer
== gFullBitmapSegment
) {
1166 * There are no free blocks in this segment, so trim any previous
1167 * extent (that ended at the end of the previous segment).
1169 if (blockCount
!= 0) {
1170 TrimExtent(g
, startBlock
, blockCount
);
1171 totalTrimmed
+= blockCount
;
1174 bit
+= kBitsPerSegment
;
1178 if (buffer
== gEmptyBitmapSegment
) {
1180 * This entire segment is free. Add it to a previous extent, or
1183 if (blockCount
== 0) {
1186 if (gTotalBits
- bit
< kBitsPerSegment
) {
1187 blockCount
+= gTotalBits
- bit
;
1189 blockCount
+= kBitsPerSegment
;
1191 bit
+= kBitsPerSegment
;
1196 * If we get here, the current segment has some free and some used
1197 * blocks, so we have to iterate over them.
1199 for (wordWithinSegment
= 0;
1200 wordWithinSegment
< kWordsPerSegment
&& bit
< gTotalBits
;
1201 ++wordWithinSegment
)
1203 assert((bit
% kBitsPerWord
) == 0);
1205 currentWord
= SWAP_BE32(buffer
[wordWithinSegment
]);
1207 /* Iterate over all the bits in the current word. */
1208 for (bitWithinWordMask
= kMSBBitSetInWord
;
1209 bitWithinWordMask
!= 0 && bit
< gTotalBits
;
1210 ++bit
, bitWithinWordMask
>>= 1)
1212 if (currentWord
& bitWithinWordMask
) {
1213 /* Found a used block. */
1214 if (blockCount
!= 0) {
1215 TrimExtent(g
, startBlock
, blockCount
);
1216 totalTrimmed
+= blockCount
;
1221 * Found an unused block. Add it to the current extent,
1222 * or start a new one.
1224 if (blockCount
== 0) {
1232 if (blockCount
!= 0) {
1233 TrimExtent(g
, startBlock
, blockCount
);
1234 totalTrimmed
+= blockCount
;
1239 DPRINTF(d_info
|d_trim
, "Trimmed %u allocation blocks.\n", totalTrimmed
);
1242 /* Function: IsTrimSupported
1244 * Description: Determine whether the device we're verifying/repairing suppports
1245 * trimming (i.e., whether it supports DKIOCUNMAP).
1248 * non-zero Trim supported
1249 * zero Trim not supported
1251 int IsTrimSupported(void)
1254 uint32_t features
= 0;
1256 err
= ioctl(fsreadfd
, DKIOCGETFEATURES
, &features
);
1259 /* Can't tell if UNMAP is supported. Assume no. */
1263 return features
& DK_FEATURE_UNMAP
;
1267 * BITMAP SEGMENT TREE
1269 * A binary search tree is used to store bitmap segments that are
1270 * partially full. If a segment does not exist in the tree, it
1271 * can be assumed to be in the following state:
1272 * 1. Full if the coresponding segment map bit is set
1273 * 2. Empty (implied)
1282 gBMS_Root
= gBMS_FreeNodes
;
1283 gBMS_FreeNodes
= gBMS_FreeNodes
->right
;
1284 gBMS_Root
->right
= NULL
;
1291 BMS_DisposeTree(void)
1293 while(gBMS_PoolCount
> 0)
1294 free(gBMS_PoolList
[--gBMS_PoolCount
]);
1296 gBMS_Root
= gBMS_FreeNodes
= 0;
1302 BMS_Lookup(UInt32 segment
)
1304 BMS_Node
*ptree
= gBMS_Root
;
1306 while (ptree
&& ptree
->segment
!= segment
) {
1308 if (segment
> ptree
->segment
)
1309 ptree
= ptree
->right
;
1311 ptree
= ptree
->left
;
1314 return ((BMS_Node
*)ptree
);
1319 BMS_InsertTree(BMS_Node
*NewEntry
)
1322 register UInt32 segment
;
1324 segment
= NewEntry
->segment
;
1326 if (ptree
== (BMS_Node
*)NULL
) {
1327 gBMS_Root
= NewEntry
;
1332 if (segment
> ptree
->segment
) { /* walk the right sub-tree */
1334 ptree
= ptree
->right
;
1336 ptree
->right
= NewEntry
;
1340 else { /* walk the left sub-tree */
1342 ptree
= ptree
->left
;
1344 ptree
->left
= NewEntry
;
1350 return ((BMS_Node
*)NULL
);
1354 /* insert a new segment into the tree */
1356 BMS_Insert(UInt32 segment
, int segmentType
)
1360 if ((new = gBMS_FreeNodes
) == NULL
) {
1362 if ((new = gBMS_FreeNodes
) == NULL
)
1363 return ((BMS_Node
*)NULL
);
1366 gBMS_FreeNodes
= gBMS_FreeNodes
->right
;
1368 ++gSegmentNodes
; /* debugging stats */
1371 new->segment
= segment
;
1372 if (segmentType
== kFullSegment
)
1373 bcopy(gFullBitmapSegment
, new->bitmap
, kBytesPerSegment
);
1375 bzero(new->bitmap
, sizeof(new->bitmap
));
1377 if (BMS_InsertTree(new) != NULL
)
1380 return ((BMS_Node
*)NULL
);
1385 BMS_Delete(UInt32 segment
)
1387 BMS_Node
*seg_found
, *pprevious
, *pnext
, *pnextl
, *psub
;
1390 seg_found
= gBMS_Root
;
1392 /* don't allow the root to be deleted! */
1393 if (seg_found
->segment
== segment
)
1394 return ((BMS_Node
*)NULL
);
1396 while (seg_found
&& seg_found
->segment
!= segment
) {
1397 pprevious
= seg_found
;
1398 if (segment
> seg_found
->segment
)
1399 seg_found
= seg_found
->right
;
1401 seg_found
= seg_found
->left
;
1406 * we found the entry, now reorg the sub-trees
1407 * spanning from our node.
1409 if ((pnext
= seg_found
->right
)) {
1411 * Tree pruning: take the left branch of the
1412 * current node and place it at the lowest
1413 * left branch of the current right branch
1417 /* walk the Right/Left sub tree from current node */
1418 while ((pnextl
= psub
->left
))
1421 /* plug the old left tree to the new ->Right leftmost node */
1422 psub
->left
= seg_found
->left
;
1423 } else { /* only left sub-tree, simple case */
1424 pnext
= seg_found
->left
;
1427 * Now, plug the current node sub tree to
1428 * the good pointer of our parent node.
1430 if (pprevious
->left
== seg_found
)
1431 pprevious
->left
= pnext
;
1433 pprevious
->right
= pnext
;
1435 /* add node back to the free-list */
1436 bzero(seg_found
, sizeof(BMS_Node
));
1437 seg_found
->right
= gBMS_FreeNodes
;
1438 gBMS_FreeNodes
= seg_found
;
1446 BMS_GrowNodePool(void)
1451 if (gBMS_PoolCount
>= kBMS_PoolMax
)
1454 nodePool
= (BMS_Node
*)malloc(sizeof(BMS_Node
) * kBMS_NodesPerPool
);
1455 if (nodePool
!= NULL
) {
1456 bzero(&nodePool
[0], sizeof(BMS_Node
) * kBMS_NodesPerPool
);
1457 for (i
= 1 ; i
< kBMS_NodesPerPool
; i
++) {
1458 (&nodePool
[i
-1])->right
= &nodePool
[i
];
1461 gBMS_FreeNodes
= &nodePool
[0];
1462 gBMS_PoolList
[gBMS_PoolCount
++] = nodePool
;
1469 BMS_MaxDepth(BMS_Node
* root
, int depth
, int *maxdepth
)
1473 if (depth
> *maxdepth
)
1475 BMS_MaxDepth(root
->left
, depth
, maxdepth
);
1476 BMS_MaxDepth(root
->right
, depth
, maxdepth
);
1481 BMS_PrintTree(BMS_Node
* root
)
1484 BMS_PrintTree(root
->left
);
1485 plog("seg %d\n", root
->segment
);
1486 BMS_PrintTree(root
->right
);