]> git.saurik.com Git - apple/hfs.git/blame - fsck_hfs/dfalib/VolumeBitmapCheck.c
hfs-366.1.1.tar.gz
[apple/hfs.git] / fsck_hfs / dfalib / VolumeBitmapCheck.c
CommitLineData
51e135ce
A
1/*
2 * Copyright (c) 2000-2002, 2004-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
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
29 * 2. Empty (implied)
30 */
31
32#include "Scavenger.h"
33
34#include <sys/disk.h>
35
36#include <bitstring.h>
37
38#define bit_dealloc(p) free(p)
39
40#define _VBC_DEBUG_ 0
41
42enum {
43 kBitsPerByte = 8,
44 kBitsPerWord = 32,
45 kBitsPerSegment = 1024,
46 kBytesPerSegment = kBitsPerSegment / kBitsPerByte,
47 kWordsPerSegment = kBitsPerSegment / kBitsPerWord,
48
49 kBitsWithinWordMask = kBitsPerWord-1,
50 kBitsWithinSegmentMask = kBitsPerSegment-1,
51
52 kBMS_NodesPerPool = 450,
53 kBMS_PoolMax = 2000
54};
55
56
57#define kAllBitsSetInWord 0xFFFFFFFFu
58#define kMSBBitSetInWord 0x80000000u
59
60enum {
61 kSettingBits = 1,
62 kClearingBits = 2,
63 kTestingBits = 3
64};
65
66#define kEmptySegment 0
67#define kFullSegment 1
68
69int gBitMapInited = 0;
70
71/*
72 * Bitmap segments that are full are marked in
73 * the gFullSegmentList (a bit string).
74 */
75bitstr_t* gFullSegmentList;
76UInt32 gBitsMarked;
77UInt32 gTotalBits;
78UInt32 gTotalSegments;
79UInt32* gFullBitmapSegment; /* points to a FULL bitmap segment*/
80UInt32* gEmptyBitmapSegment; /* points to an EMPTY bitmap segment*/
81
82/*
83 * Bitmap Segment (BMS) Tree node
84 * Bitmap segments that are partially full are
85 * saved in the BMS Tree.
86 */
87typedef struct BMS_Node {
88 struct BMS_Node *left;
89 struct BMS_Node *right;
90 UInt32 segment;
91 UInt32 bitmap[kWordsPerSegment];
92} BMS_Node;
93
94BMS_Node *gBMS_Root; /* root of BMS tree */
95BMS_Node *gBMS_FreeNodes; /* list of free BMS nodes */
96BMS_Node *gBMS_PoolList[kBMS_PoolMax]; /* list of BMS node pools */
97int gBMS_PoolCount; /* count of pools allocated */
98
99/* Bitmap operations routines */
100static int FindContigClearedBitmapBits (SVCB *vcb, UInt32 numBlocks, UInt32 *actualStartBlock);
101
102/* Segment Tree routines (binary search tree) */
103static int BMS_InitTree(void);
104static int BMS_DisposeTree(void);
105static BMS_Node * BMS_Lookup(UInt32 segment);
106static BMS_Node * BMS_Insert(UInt32 segment, int segmentType);
107static BMS_Node * BMS_Delete(UInt32 segment);
108static void BMS_GrowNodePool(void);
109
110#if _VBC_DEBUG_
111static void BMS_PrintTree(BMS_Node * root);
112static void BMS_MaxDepth(BMS_Node * root, int depth, int *maxdepth);
113#endif
114
115/*
116 * Initialize our volume bitmap data structures
117 */
118int BitMapCheckBegin(SGlobPtr g)
119{
120 Boolean isHFSPlus;
121
122 if (gBitMapInited)
123 return (0);
124
125 isHFSPlus = VolumeObjectIsHFSPlus( );
126
127 gFullBitmapSegment = (UInt32 *)malloc(kBytesPerSegment);
128 memset((void *)gFullBitmapSegment, 0xff, kBytesPerSegment);
129
130 gEmptyBitmapSegment = (UInt32 *)malloc(kBytesPerSegment);
131 memset((void *)gEmptyBitmapSegment, 0x00, kBytesPerSegment);
132
133 gTotalBits = g->calculatedVCB->vcbTotalBlocks;
134 gTotalSegments = (gTotalBits / kBitsPerSegment);
135 if (gTotalBits % kBitsPerSegment)
136 ++gTotalSegments;
137
138 gFullSegmentList = bit_alloc(gTotalSegments);
139 bit_nclear(gFullSegmentList, 0, gTotalSegments - 1);
140
141 BMS_InitTree();
142 gBitMapInited = 1;
143 gBitsMarked = 0;
144
145 if (isHFSPlus) {
146 UInt16 alignBits;
147
148 /*
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.
152 */
153 if (g->calculatedVCB->vcbBlockSize == 512)
154 alignBits = 2;
155 else if (g->calculatedVCB->vcbBlockSize == 1024)
156 alignBits = 1;
157 else
158 alignBits = 0;
159
160 (void) CaptureBitmapBits(0, 1 + alignBits);
161
162 if (g->calculatedVCB->vcbBlockSize == 512)
163 alignBits = 1;
164 else
165 alignBits = 0;
166
167 (void) CaptureBitmapBits(gTotalBits - 1 - alignBits, 1 + alignBits);
168 }
169
170 return (0);
171}
172
173/* debugging stats */
174int gFullSegments = 0;
175int gSegmentNodes = 0;
176
177int BitMapCheckEnd(void)
178{
179 if (gBitMapInited) {
180#if _VBC_DEBUG_
181 int maxdepth = 0;
182
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);
186#endif
187 free(gFullBitmapSegment);
188 gFullBitmapSegment = NULL;
189
190 free(gEmptyBitmapSegment);
191 gEmptyBitmapSegment = NULL;
192
193 bit_dealloc(gFullSegmentList);
194 gFullSegmentList = NULL;
195
196 BMS_DisposeTree();
197 gBitMapInited = 0;
198 }
199 return (0);
200}
201
202/* Function: GetSegmentBitmap
203 *
204 * Description: Return bitmap segment corresponding to given startBit.
205 *
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.
217 *
218 * Input:
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.
225 *
226 * Output:
227 * 1. buffer - pointer to desired segment
228 * returns zero on success, -1 on failure.
229 */
230static int GetSegmentBitmap(UInt32 startBit, UInt32 **buffer, int bitOperation)
231{
232 UInt32 segment;
233 BMS_Node *segNode = NULL;
234
235 *buffer = NULL;
236 segment = startBit / kBitsPerSegment;
237
238 // for a full seqment...
239 if (bit_test(gFullSegmentList, segment)) {
240 if (bitOperation == kClearingBits) {
241 bit_clear(gFullSegmentList, segment);
242 --gFullSegments;
243 if ((segNode = BMS_Insert(segment, kFullSegment)) != NULL)
244 *buffer = &segNode->bitmap[0];
245 } else
246 *buffer = gFullBitmapSegment;
247
248 // for a partially full segment..
249 } else if ((segNode = BMS_Lookup(segment)) != NULL) {
250 *buffer = &segNode->bitmap[0];
251
252 // for an empty segment...
253 } else {
254 if (bitOperation == kSettingBits) {
255 if ((segNode = BMS_Insert(segment, kEmptySegment)) != NULL)
256 *buffer = &segNode->bitmap[0];
257 } else
258 *buffer = gEmptyBitmapSegment;
259 }
260
261 if (*buffer == NULL) {
262#if _VBC_DEBUG_
263 plog("GetSegmentBitmap: couldn't get a node for block %d, segment %d\n", startBit, segment);
264#endif
265 return (-1); /* oops */
266 }
267
268#if 0
269 if (segNode) {
270 int i;
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)
276 plog("\n ");
277 }
278 plog("\n");
279 }
280
281 if (bitOperation == kSettingBits && *buffer && bcmp(*buffer, gFullBitmapSegment, kBytesPerSegment) == 0) {
282 plog("*** segment %d (start blk %d) is already full!\n", segment, startBit);
283 exit(5);
284 }
285 if (bitOperation == kClearingBits && *buffer && bcmp(*buffer, gEmptyBitmapSegment, kBytesPerSegment) == 0) {
286 plog("*** segment %d (start blk %d) is already empty!\n", segment, startBit);
287 exit(5);
288 }
289#endif
290
291 return (0);
292}
293
294/* Function: TestSegmentBitmap
295 *
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.
302 *
303 * Input:
304 * startBit - startBit of segment to test
305 *
306 * Output:
307 * nothing (void).
308 */
309void TestSegmentBitmap(UInt32 startBit)
310{
311 UInt32 segment;
312 BMS_Node *segNode = NULL;
313
314 segment = startBit / kBitsPerSegment;
315
316 if (bit_test(gFullSegmentList, segment))
317 return;
318
319 if ((segNode = BMS_Lookup(segment)) != NULL) {
320#if 0
321 int i;
322 plog("> ");
323 for (i = 0; i < kWordsPerSegment; ++i) {
324 plog("0x%08x ", segNode->bitmap[i]);
325 if ((i & 0x3) == 0x3)
326 plog("\n ");
327 }
328 plog("\n");
329#endif
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 */
334 ++gFullSegments;
335 --gSegmentNodes;
336 }
337 }
338
339 if (segment != 0 && bcmp(&segNode->bitmap[0], gEmptyBitmapSegment, kBytesPerSegment) == 0) {
340 if (BMS_Delete(segment) != NULL) {
341 /* debugging stats */
342 --gSegmentNodes;
343 }
344 }
345 }
346}
347
348
349/* Function: CaptureBitmapBits
350 *
351 * Description: Set bits in the segmented bitmap from startBit upto
352 * bitCount bits.
353 *
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).
358 *
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.
365 *
366 * Input:
367 * startBit - bit number in segment bitmap to start set operation.
368 * bitCount - total number of bits to set.
369 *
370 * Output:
371 * zero on success, non-zero on failure.
372 * This function also returns E_OvlExt if any overlapping extent is found.
373 */
374int CaptureBitmapBits(UInt32 startBit, UInt32 bitCount)
375{
376 Boolean overlap;
377 OSErr err;
378 UInt32 wordsLeft;
379 UInt32 bitMask;
380 UInt32 firstBit;
381 UInt32 numBits;
382 UInt32 *buffer;
383 UInt32 *currentWord;
384
385 overlap = false;
386 if (bitCount == 0)
387 return (0);
388
389 if ((startBit + bitCount) > gTotalBits) {
390 err = vcInvalidExtentErr;
391 goto Exit;
392 }
393
394 /* count allocated bits */
395 gBitsMarked += bitCount;
396
397 /*
398 * Get the bitmap segment containing the first word to check
399 */
400 err = GetSegmentBitmap(startBit, &buffer, kSettingBits);
401 if (err != noErr) goto Exit;
402
403 /* Initialize buffer stuff */
404 {
405 UInt32 wordIndexInSegment;
406
407 wordIndexInSegment = (startBit & kBitsWithinSegmentMask) / kBitsPerWord;
408 currentWord = buffer + wordIndexInSegment;
409 wordsLeft = kWordsPerSegment - wordIndexInSegment;
410 }
411
412 /*
413 * If the first bit to check doesn't start on a word
414 * boundary in the bitmap, then treat that first word
415 * specially.
416 */
417 firstBit = startBit % kBitsPerWord;
418 if (firstBit != 0) {
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
424 }
425
426 if (SWAP_BE32(*currentWord) & bitMask) {
427 overlap = true;
428
429 //plog("(1) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
430 }
431
432 *currentWord |= SWAP_BE32(bitMask); /* set the bits in the bitmap */
433
434 bitCount -= numBits;
435 ++currentWord;
436 --wordsLeft;
437 if (wordsLeft == 0 || bitCount == 0)
438 TestSegmentBitmap(startBit);
439 }
440
441 /*
442 * Set whole words (32 bits) at a time.
443 */
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
449
450 err = GetSegmentBitmap(startBit, &buffer, kSettingBits);
451 if (err != noErr) goto Exit;
452
453 // Readjust currentWord, wordsLeft
454 currentWord = buffer;
455 wordsLeft = kWordsPerSegment;
456 }
457
458 if (SWAP_BE32(*currentWord) & bitMask) {
459 overlap = true;
460
461 //plog("(2) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
462 }
463
464 *currentWord |= SWAP_BE32(bitMask); /* set the bits in the bitmap */
465
466 bitCount -= kBitsPerWord;
467 ++currentWord;
468 --wordsLeft;
469 if (wordsLeft == 0 || bitCount == 0)
470 TestSegmentBitmap(startBit);
471 }
472
473 /*
474 * Check any remaining bits.
475 */
476 if (bitCount != 0) {
477 bitMask = ~(kAllBitsSetInWord >> bitCount); // set first bitCount bits
478 if (wordsLeft == 0) {
479 startBit += kBitsPerSegment;
480
481 err = GetSegmentBitmap(startBit, &buffer, kSettingBits);
482 if (err != noErr) goto Exit;
483
484 currentWord = buffer;
485 wordsLeft = kWordsPerSegment;
486 }
487
488 if (SWAP_BE32(*currentWord) & bitMask) {
489 overlap = true;
490
491 //plog("(3) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
492 }
493
494 *currentWord |= SWAP_BE32(bitMask); /* set the bits in the bitmap */
495
496 TestSegmentBitmap(startBit);
497 }
498Exit:
499 return (overlap ? E_OvlExt : err);
500}
501
502
503/* Function: ReleaseBitMapBits
504 *
505 * Description: Clear bits in the segmented bitmap from startBit upto
506 * bitCount bits.
507 *
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).
512 *
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.
519 *
520 * Input:
521 * startBit - bit number in segment bitmap to start clear operation.
522 * bitCount - total number of bits to clear.
523 *
524 * Output:
525 * zero on success, non-zero on failure.
526 * This function also returns E_OvlExt if any overlapping extent is found.
527 */
528int ReleaseBitmapBits(UInt32 startBit, UInt32 bitCount)
529{
530 Boolean overlap;
531 OSErr err;
532 UInt32 wordsLeft;
533 UInt32 bitMask;
534 UInt32 firstBit;
535 UInt32 numBits;
536 UInt32 *buffer;
537 UInt32 *currentWord;
538
539 overlap = false;
540 if (bitCount == 0)
541 return (0);
542
543 if ((startBit + bitCount) > gTotalBits) {
544 err = vcInvalidExtentErr;
545 goto Exit;
546 }
547
548 /* decrment allocated bits */
549 gBitsMarked -= bitCount;
550
551 /*
552 * Get the bitmap segment containing the first word to check
553 */
554 err = GetSegmentBitmap(startBit, &buffer, kClearingBits);
555 if (err != noErr) goto Exit;
556
557 /* Initialize buffer stuff */
558 {
559 UInt32 wordIndexInSegment;
560
561 wordIndexInSegment = (startBit & kBitsWithinSegmentMask) / kBitsPerWord;
562 currentWord = buffer + wordIndexInSegment;
563 wordsLeft = kWordsPerSegment - wordIndexInSegment;
564 }
565
566 /*
567 * If the first bit to check doesn't start on a word
568 * boundary in the bitmap, then treat that first word
569 * specially.
570 */
571 firstBit = startBit % kBitsPerWord;
572 if (firstBit != 0) {
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
578 }
579
580 if ((SWAP_BE32(*currentWord) & bitMask) != bitMask) {
581 overlap = true;
582
583 //plog("(1) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
584 }
585
586 *currentWord &= SWAP_BE32(~bitMask); /* clear the bits in the bitmap */
587
588 bitCount -= numBits;
589 ++currentWord;
590 --wordsLeft;
591 if (wordsLeft == 0 || bitCount == 0)
592 TestSegmentBitmap(startBit);
593 }
594
595 /*
596 * Clear whole words (32 bits) at a time.
597 */
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
603
604 err = GetSegmentBitmap(startBit, &buffer, kClearingBits);
605 if (err != noErr) goto Exit;
606
607 // Readjust currentWord, wordsLeft
608 currentWord = buffer;
609 wordsLeft = kWordsPerSegment;
610 }
611
612 if ((SWAP_BE32(*currentWord) & bitMask) != bitMask) {
613 overlap = true;
614
615 //plog("(2) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
616 }
617
618 *currentWord &= SWAP_BE32(~bitMask); /* clear the bits in the bitmap */
619
620 bitCount -= kBitsPerWord;
621 ++currentWord;
622 --wordsLeft;
623 if (wordsLeft == 0 || bitCount == 0)
624 TestSegmentBitmap(startBit);
625 }
626
627 /*
628 * Check any remaining bits.
629 */
630 if (bitCount != 0) {
631 bitMask = ~(kAllBitsSetInWord >> bitCount); // set first bitCount bits
632 if (wordsLeft == 0) {
633 startBit += kBitsPerSegment;
634
635 err = GetSegmentBitmap(startBit, &buffer, kClearingBits);
636 if (err != noErr) goto Exit;
637
638 currentWord = buffer;
639 wordsLeft = kWordsPerSegment;
640 }
641
642 if ((SWAP_BE32(*currentWord) & bitMask) != bitMask) {
643 overlap = true;
644
645 //plog("(3) overlapping file blocks! word: 0x%08x, mask: 0x%08x\n", *currentWord, bitMask);
646 }
647
648 *currentWord &= SWAP_BE32(~bitMask); /* set the bits in the bitmap */
649
650 TestSegmentBitmap(startBit);
651 }
652Exit:
653 return (overlap ? E_OvlExt : err);
654}
655
656/* Function: CheckVolumeBitMap
657 *
658 * Description: Compares the in-memory volume bitmap with the on-disk
659 * volume bitmap.
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.
663 *
664 * Input:
665 * 1. g - global scavenger structure
666 * 2. repair - indicate if a repair operation is requested or not.
667 *
668 * Output:
669 * zero on success, non-zero on failure.
670 */
671int CheckVolumeBitMap(SGlobPtr g, Boolean repair)
672{
673 UInt8 *vbmBlockP;
674 UInt32 *buffer;
675 UInt64 bit; /* 64-bit to avoid wrap around on volumes with 2^32 - 1 blocks */
676 UInt32 bitsWithinFileBlkMask;
677 UInt32 fileBlk;
678 BlockDescriptor block;
679 ReleaseBlockOptions relOpt;
680 SFCB * fcb;
681 SVCB * vcb;
682 Boolean isHFSPlus;
683 Boolean foundOverAlloc = false;
684 int err = 0;
685
686 vcb = g->calculatedVCB;
687 fcb = g->calculatedAllocationsFCB;
688 isHFSPlus = VolumeObjectIsHFSPlus( );
689
690 if ( vcb->vcbFreeBlocks != (vcb->vcbTotalBlocks - gBitsMarked) ) {
691 vcb->vcbFreeBlocks = vcb->vcbTotalBlocks - gBitsMarked;
692 MarkVCBDirty(vcb);
693 }
694
695 vbmBlockP = (UInt8 *)NULL;
696 block.buffer = (void *)NULL;
697 relOpt = kReleaseBlock;
698 if ( isHFSPlus )
699 bitsWithinFileBlkMask = (fcb->fcbBlockSize * 8) - 1;
700 else
701 bitsWithinFileBlkMask = (kHFSBlockSize * 8) - 1;
702 fileBlk = (isHFSPlus ? 0 : vcb->vcbVBMSt);
703
704 /*
705 * Loop through all the bitmap segments and compare
706 * them against the on-disk bitmap.
707 */
708 for (bit = 0; bit < gTotalBits; bit += kBitsPerSegment) {
709 (void) GetSegmentBitmap(bit, &buffer, kTestingBits);
710
711 /*
712 * When we cross file block boundries read a new block from disk.
713 */
714 if ((bit & bitsWithinFileBlkMask) == 0) {
715 if (isHFSPlus) {
716 if (block.buffer) {
717 err = ReleaseFileBlock(fcb, &block, relOpt);
718 ReturnIfError(err);
719 }
720 err = GetFileBlock(fcb, fileBlk, kGetBlock, &block);
721 } else /* plain HFS */ {
722 if (block.buffer) {
723 err = ReleaseVolumeBlock(vcb, &block, relOpt | kSkipEndianSwap);
724 ReturnIfError(err);
725 }
726 err = GetVolumeBlock(vcb, fileBlk, kGetBlock | kSkipEndianSwap, &block);
727 }
728 ReturnIfError(err);
729
730 vbmBlockP = (UInt8 *) block.buffer;
731 relOpt = kReleaseBlock;
732 g->TarBlock = fileBlk;
733 ++fileBlk;
734 }
735 if (memcmp(buffer, vbmBlockP + (bit & bitsWithinFileBlkMask)/8, kBytesPerSegment) == 0)
736 continue;
737
738 if (repair) {
739 bcopy(buffer, vbmBlockP + (bit & bitsWithinFileBlkMask)/8, kBytesPerSegment);
740 relOpt = kForceWriteBlock;
741 } else {
742 int underalloc = 0;
743 int indx;
744#if _VBC_DEBUG_
745 int i, j;
746 UInt32 *disk_buffer;
747 UInt32 dummy, block_num;
748
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);
752
753 plog("Memory:\n");
754 for (i = 0; i < kWordsPerSegment; ++i) {
755 plog("0x%08x ", buffer[i]);
756 if ((i & 0x7) == 0x7)
757 plog("\n");
758 }
759
760 disk_buffer = (UInt32*) (vbmBlockP + (bit & bitsWithinFileBlkMask)/8);
761 plog("Disk:\n");
762 for (i = 0; i < kWordsPerSegment; ++i) {
763 plog("0x%08x ", disk_buffer[i]);
764 if ((i & 0x7) == 0x7)
765 plog("\n");
766 }
767
768 plog ("\n");
769 for (i = 0; i < kWordsPerSegment; ++i) {
770 /* Compare each word in the segment */
771 if (buffer[i] != disk_buffer[i]) {
772 dummy = 0x80000000;
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);
780 } else {
781 plog ("Allocation block %u should be marked free on disk.\n", block_num);
782 }
783 }
784 dummy = dummy >> 1;
785 }
786 }
787 }
788#endif
789 /*
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.
795 *
796 * Once we determine we have under-allocated, we can just stop and print out
797 * the message.
798 */
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]) {
804 underalloc++;
805 break;
806 }
807 }
808 g->VIStat = g->VIStat | S_VBM;
809 if (underalloc) {
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;
816 }
817 }
818 ++g->itemsProcessed;
819 }
820
821 if (block.buffer) {
822 if (isHFSPlus)
823 (void) ReleaseFileBlock(fcb, &block, relOpt);
824 else
825 (void) ReleaseVolumeBlock(vcb, &block, relOpt | kSkipEndianSwap);
826 }
827
828 return (0);
829}
830
831/* Function: UpdateFreeBlockCount
832 *
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.
836 *
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.
841 *
842 * Input:
843 * g - global scavenger structure pointer.
844 *
845 * Output:
846 * nothing (void)
847 */
848void UpdateFreeBlockCount(SGlobPtr g)
849{
850 int i;
851 UInt32 newBitsMarked = 0;
852 UInt32 bit;
853 UInt32 *buffer;
854 UInt32 curWord;
855 SVCB * vcb = g->calculatedVCB;
856
857 /* Loop through all the bitmap segments */
858 for (bit = 0; bit < gTotalBits; bit += kBitsPerSegment) {
859 (void) GetSegmentBitmap(bit, &buffer, kTestingBits);
860
861 /* All bits in segment are set */
862 if (buffer == gFullBitmapSegment) {
863 newBitsMarked += kBitsPerSegment;
864 continue;
865 }
866
867 /* All bits in segment are clear */
868 if (buffer == gEmptyBitmapSegment) {
869 continue;
870 }
871
872 /* Segment is partially full */
873 for (i = 0; i < kWordsPerSegment; i++) {
874 if (buffer[i] == kAllBitsSetInWord) {
875 newBitsMarked += kBitsPerWord;
876 } else {
877 curWord = SWAP_BE32(buffer[i]);
878 while (curWord) {
879 newBitsMarked += curWord & 1;
880 curWord >>= 1;
881 }
882 }
883 }
884 }
885
886 /* Update total bits marked count for in-memory bitmap */
887 if (gBitsMarked != newBitsMarked) {
888 gBitsMarked = newBitsMarked;
889 }
890
891 /* Update volume free block count */
892 if (vcb->vcbFreeBlocks != (vcb->vcbTotalBlocks - gBitsMarked)) {
893 vcb->vcbFreeBlocks = vcb->vcbTotalBlocks - gBitsMarked;
894 MarkVCBDirty(vcb);
895 }
896}
897
898/* Function: FindContigClearedBitmapBits
899 *
900 * Description: Find contigous free bitmap bits (allocation blocks) from
901 * the in-memory volume bitmap. If found, the bits are not marked as
902 * used.
903 *
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.
913 *
914 * The function takes care if the last bitmap segment is paritally used
915 * to represented the total number of allocation blocks.
916 *
917 * Input:
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
921 * free blocks found.
922 *
923 * Output:
924 * 1. actualStartBlock - pointer to return the start block, if contigous
925 * free blocks found.
926 * On success, returns zero.
927 * On failure, non-zero value
928 * ENOSPC - No contigous free blocks were found of given length
929 */
930static int FindContigClearedBitmapBits (SVCB *vcb, UInt32 numBlocks, UInt32 *actualStartBlock)
931{
932 int i, j;
933 int retval = ENOSPC;
934 UInt32 bit;
935 UInt32 *buffer;
936 UInt32 curWord;
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 */
941
942 /* For all segments except the last segments, number of valid bits
943 * is always total number of bits represented by the segment
944 */
945 validBitsInSegment = kBitsPerSegment;
946
947 /* For all words except the last word, the number of valid bits
948 * is always total number of bits represented by the word
949 */
950 validBitsInWord = kBitsPerWord;
951
952 /* Loop through all the bitmap segments */
953 for (bit = 0; bit < gTotalBits; bit += kBitsPerSegment) {
954 (void) GetSegmentBitmap(bit, &buffer, kTestingBits);
955
956 /* If this is last segment, calculate valid bits remaining */
957 if ((gTotalBits - bit) < kBitsPerSegment) {
958 validBitsInSegment = gTotalBits - bit;
959 }
960
961 /* All bits in segment are set */
962 if (buffer == gFullBitmapSegment) {
963 /* Reset our counters */
964 startBlock = 0;
965 bitsRemain = numBlocks;
966 continue;
967 }
968
969 /* All bits in segment are clear */
970 if (buffer == gEmptyBitmapSegment) {
971 /* If startBlock is not initialized, initialize it */
972 if (bitsRemain == numBlocks) {
973 startBlock = bit;
974 }
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.
981 */
982 if (bitsRemain > validBitsInSegment) {
983 bitsRemain -= validBitsInSegment;
984 continue;
985 } else {
986 bitsRemain = 0;
987 break;
988 }
989 }
990
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 */
996 startBlock = 0;
997 bitsRemain = numBlocks;
998 } else {
999 /* Not all bits in a word are set */
1000
1001 /* If this is the last segment, check if the current word
1002 * is the last word containing valid bits.
1003 */
1004 if (validBitsInSegment != kBitsPerSegment) {
1005 if ((validBitsInSegment - (i * kBitsPerWord)) < kBitsPerWord) {
1006 /* Calculate the total valid bits in last word */
1007 validBitsInWord = validBitsInSegment - (i * kBitsPerWord);
1008 }
1009 }
1010
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 */
1016 startBlock = 0;
1017 bitsRemain = numBlocks;
1018 } else {
1019 /* The bit is clear */
1020 if (bitsRemain == numBlocks) {
1021 startBlock = bit + (i * kBitsPerWord) + j;
1022 }
1023 bitsRemain--;
1024 if (bitsRemain == 0) {
1025 goto out;
1026 }
1027 }
1028 curWord <<= 1;
1029 } /* for - checking bits set in word */
1030
1031 /* If this is last valid word, stop the search */
1032 if (validBitsInWord != kBitsPerWord) {
1033 goto out;
1034 }
1035 } /* else - not all bits set in a word */
1036 } /* for - segment is partially full */
1037 } /* for - loop over all segments */
1038
1039out:
1040 if (bitsRemain == 0) {
1041 /* Return the new start block found */
1042 *actualStartBlock = startBlock;
1043 retval = 0;
1044 } else {
1045 *actualStartBlock = 0;
1046 }
1047
1048 return retval;
1049}
1050
1051/* Function: AllocateContigBitmapBits
1052 *
1053 * Description: Find contigous free bitmap bits (allocation blocks) from
1054 * the in-memory volume bitmap. If found, also mark the bits as used.
1055 *
1056 * Input:
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.
1061 *
1062 * Output:
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
1069 * extent found).
1070 */
1071int AllocateContigBitmapBits (SVCB *vcb, UInt32 numBlocks, UInt32 *actualStartBlock)
1072{
1073 int error;
1074
1075 error = FindContigClearedBitmapBits (vcb, numBlocks, actualStartBlock);
1076 if (error == noErr) {
1077 error = CaptureBitmapBits (*actualStartBlock, numBlocks);
1078 }
1079
1080 return error;
1081}
1082
1083enum { kMaxTrimExtents = 256 };
1084dk_extent_t gTrimExtents[kMaxTrimExtents];
1085dk_unmap_t gTrimData;
1086
1087static void TrimInit(void)
1088{
1089 bzero(&gTrimData, sizeof(gTrimData));
1090 gTrimData.extents = gTrimExtents;
1091}
1092
1093static void TrimFlush(void)
1094{
1095 int err;
1096
1097 if (gTrimData.extentsCount == 0)
1098 {
1099 DPRINTF(d_info|d_trim, "TrimFlush: nothing to flush\n");
1100 return;
1101 }
1102
1103 err = ioctl(fsreadfd, DKIOCUNMAP, &gTrimData);
1104 if (err == -1)
1105 {
1106 DPRINTF(d_error|d_trim, "TrimFlush: error %d\n", errno);
1107 }
1108 gTrimData.extentsCount = 0;
1109}
1110
1111static void TrimExtent(SGlobPtr g, UInt32 startBlock, UInt32 blockCount)
1112{
1113 UInt64 offset;
1114 UInt64 length;
1115
1116 DPRINTF(d_info|d_trim, "Trimming: startBlock=%10u, blockCount=%10u\n", startBlock, blockCount);
1117
1118 offset = (UInt64) startBlock * g->calculatedVCB->vcbBlockSize;
1119 if (VolumeObjectIsHFSPlus())
1120 offset += g->calculatedVCB->vcbEmbeddedOffset;
1121 else
1122 offset += g->calculatedVCB->vcbAlBlSt * 512ULL;
1123 length = (UInt64) blockCount * g->calculatedVCB->vcbBlockSize;
1124
1125 gTrimExtents[gTrimData.extentsCount].offset = offset;
1126 gTrimExtents[gTrimData.extentsCount].length = length;
1127 if (++gTrimData.extentsCount == kMaxTrimExtents)
1128 TrimFlush();
1129}
1130
1131/* Function: TrimFreeBlocks
1132 *
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
1136 * space.
1137 *
1138 * Input:
1139 * g - global scavenger structure pointer
1140 */
1141void TrimFreeBlocks(SGlobPtr g)
1142{
1143 UInt32 *buffer;
1144 UInt32 bit;
1145 UInt32 wordWithinSegment;
1146 UInt32 bitWithinWordMask;
1147 UInt32 currentWord;
1148 UInt32 startBlock;
1149 UInt32 blockCount;
1150 UInt32 totalTrimmed = 0;
1151
1152 TrimInit();
1153
1154 /* We haven't seen any free blocks yet. */
1155 startBlock = 0;
1156 blockCount = 0;
1157
1158 /* Loop through bitmap segments */
1159 for (bit = 0; bit < gTotalBits; /* bit incremented below */) {
1160 assert((bit % kBitsPerSegment) == 0);
1161
1162 (void) GetSegmentBitmap(bit, &buffer, kTestingBits);
1163
1164 if (buffer == gFullBitmapSegment) {
1165 /*
1166 * There are no free blocks in this segment, so trim any previous
1167 * extent (that ended at the end of the previous segment).
1168 */
1169 if (blockCount != 0) {
1170 TrimExtent(g, startBlock, blockCount);
1171 totalTrimmed += blockCount;
1172 blockCount = 0;
1173 }
1174 bit += kBitsPerSegment;
1175 continue;
1176 }
1177
1178 if (buffer == gEmptyBitmapSegment) {
1179 /*
1180 * This entire segment is free. Add it to a previous extent, or
1181 * start a new one.
1182 */
1183 if (blockCount == 0) {
1184 startBlock = bit;
1185 }
1186 if (gTotalBits - bit < kBitsPerSegment) {
1187 blockCount += gTotalBits - bit;
1188 } else {
1189 blockCount += kBitsPerSegment;
1190 }
1191 bit += kBitsPerSegment;
1192 continue;
1193 }
1194
1195 /*
1196 * If we get here, the current segment has some free and some used
1197 * blocks, so we have to iterate over them.
1198 */
1199 for (wordWithinSegment = 0;
1200 wordWithinSegment < kWordsPerSegment && bit < gTotalBits;
1201 ++wordWithinSegment)
1202 {
1203 assert((bit % kBitsPerWord) == 0);
1204
1205 currentWord = SWAP_BE32(buffer[wordWithinSegment]);
1206
1207 /* Iterate over all the bits in the current word. */
1208 for (bitWithinWordMask = kMSBBitSetInWord;
1209 bitWithinWordMask != 0 && bit < gTotalBits;
1210 ++bit, bitWithinWordMask >>= 1)
1211 {
1212 if (currentWord & bitWithinWordMask) {
1213 /* Found a used block. */
1214 if (blockCount != 0) {
1215 TrimExtent(g, startBlock, blockCount);
1216 totalTrimmed += blockCount;
1217 blockCount = 0;
1218 }
1219 } else {
1220 /*
1221 * Found an unused block. Add it to the current extent,
1222 * or start a new one.
1223 */
1224 if (blockCount == 0) {
1225 startBlock = bit;
1226 }
1227 ++blockCount;
1228 }
1229 }
1230 }
1231 }
1232 if (blockCount != 0) {
1233 TrimExtent(g, startBlock, blockCount);
1234 totalTrimmed += blockCount;
1235 blockCount = 0;
1236 }
1237
1238 TrimFlush();
1239 DPRINTF(d_info|d_trim, "Trimmed %u allocation blocks.\n", totalTrimmed);
1240}
1241
1242/* Function: IsTrimSupported
1243 *
1244 * Description: Determine whether the device we're verifying/repairing suppports
1245 * trimming (i.e., whether it supports DKIOCUNMAP).
1246 *
1247 * Result:
1248 * non-zero Trim supported
1249 * zero Trim not supported
1250 */
1251int IsTrimSupported(void)
1252{
1253 int err;
1254 uint32_t features = 0;
1255
1256 err = ioctl(fsreadfd, DKIOCGETFEATURES, &features);
1257 if (err < 0)
1258 {
1259 /* Can't tell if UNMAP is supported. Assume no. */
1260 return 0;
1261 }
1262
1263 return features & DK_FEATURE_UNMAP;
1264}
1265
1266/*
1267 * BITMAP SEGMENT TREE
1268 *
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)
1274 */
1275
1276static int
1277BMS_InitTree(void)
1278{
1279 gBMS_PoolCount = 0;
1280 BMS_GrowNodePool();
1281
1282 gBMS_Root = gBMS_FreeNodes;
1283 gBMS_FreeNodes = gBMS_FreeNodes->right;
1284 gBMS_Root->right = NULL;
1285
1286 return (0);
1287}
1288
1289
1290static int
1291BMS_DisposeTree(void)
1292{
1293 while(gBMS_PoolCount > 0)
1294 free(gBMS_PoolList[--gBMS_PoolCount]);
1295
1296 gBMS_Root = gBMS_FreeNodes = 0;
1297 return (0);
1298}
1299
1300
1301static BMS_Node *
1302BMS_Lookup(UInt32 segment)
1303{
1304 BMS_Node *ptree = gBMS_Root;
1305
1306 while (ptree && ptree->segment != segment) {
1307
1308 if (segment > ptree->segment)
1309 ptree = ptree->right;
1310 else
1311 ptree = ptree->left;
1312 }
1313
1314 return ((BMS_Node *)ptree);
1315}
1316
1317
1318static BMS_Node *
1319BMS_InsertTree(BMS_Node *NewEntry)
1320{
1321 BMS_Node *ptree;
1322 register UInt32 segment;
1323
1324 segment = NewEntry->segment;
1325 ptree = gBMS_Root;
1326 if (ptree == (BMS_Node *)NULL) {
1327 gBMS_Root = NewEntry;
1328 return (NewEntry);
1329 }
1330
1331 while (ptree) {
1332 if (segment > ptree->segment) { /* walk the right sub-tree */
1333 if (ptree->right)
1334 ptree = ptree->right;
1335 else {
1336 ptree->right = NewEntry;
1337 return (ptree);
1338 }
1339 }
1340 else { /* walk the left sub-tree */
1341 if (ptree->left)
1342 ptree = ptree->left;
1343 else {
1344 ptree->left = NewEntry;
1345 return (ptree);
1346 }
1347 }
1348 }
1349
1350 return ((BMS_Node *)NULL);
1351}
1352
1353
1354/* insert a new segment into the tree */
1355static BMS_Node *
1356BMS_Insert(UInt32 segment, int segmentType)
1357{
1358 BMS_Node *new;
1359
1360 if ((new = gBMS_FreeNodes) == NULL) {
1361 BMS_GrowNodePool();
1362 if ((new = gBMS_FreeNodes) == NULL)
1363 return ((BMS_Node *)NULL);
1364 }
1365
1366 gBMS_FreeNodes = gBMS_FreeNodes->right;
1367
1368 ++gSegmentNodes; /* debugging stats */
1369
1370 new->right = NULL;
1371 new->segment = segment;
1372 if (segmentType == kFullSegment)
1373 bcopy(gFullBitmapSegment, new->bitmap, kBytesPerSegment);
1374 else
1375 bzero(new->bitmap, sizeof(new->bitmap));
1376
1377 if (BMS_InsertTree(new) != NULL)
1378 return (new);
1379 else
1380 return ((BMS_Node *)NULL);
1381}
1382
1383
1384static BMS_Node *
1385BMS_Delete(UInt32 segment)
1386{
1387 BMS_Node *seg_found, *pprevious, *pnext, *pnextl, *psub;
1388
1389 pprevious = NULL;
1390 seg_found = gBMS_Root;
1391
1392 /* don't allow the root to be deleted! */
1393 if (seg_found->segment == segment)
1394 return ((BMS_Node *)NULL);
1395
1396 while (seg_found && seg_found->segment != segment) {
1397 pprevious = seg_found;
1398 if (segment > seg_found->segment)
1399 seg_found = seg_found->right;
1400 else
1401 seg_found = seg_found->left;
1402 }
1403
1404 if (seg_found) {
1405 /*
1406 * we found the entry, now reorg the sub-trees
1407 * spanning from our node.
1408 */
1409 if ((pnext = seg_found->right)) {
1410 /*
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
1414 */
1415 psub = pnext;
1416
1417 /* walk the Right/Left sub tree from current node */
1418 while ((pnextl = psub->left))
1419 psub = pnextl;
1420
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;
1425 }
1426 /*
1427 * Now, plug the current node sub tree to
1428 * the good pointer of our parent node.
1429 */
1430 if (pprevious->left == seg_found)
1431 pprevious->left = pnext;
1432 else
1433 pprevious->right = pnext;
1434
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;
1439 }
1440
1441 return (seg_found);
1442}
1443
1444
1445static void
1446BMS_GrowNodePool(void)
1447{
1448 BMS_Node *nodePool;
1449 short i;
1450
558d2836 1451 if (gBMS_PoolCount >= kBMS_PoolMax)
51e135ce
A
1452 return;
1453
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];
1459 }
1460
1461 gBMS_FreeNodes = &nodePool[0];
1462 gBMS_PoolList[gBMS_PoolCount++] = nodePool;
1463 }
1464}
1465
1466
1467#if _VBC_DEBUG_
1468static void
1469BMS_MaxDepth(BMS_Node * root, int depth, int *maxdepth)
1470{
1471 if (root) {
1472 depth++;
1473 if (depth > *maxdepth)
1474 *maxdepth = depth;
1475 BMS_MaxDepth(root->left, depth, maxdepth);
1476 BMS_MaxDepth(root->right, depth, maxdepth);
1477 }
1478}
1479
1480static void
1481BMS_PrintTree(BMS_Node * root)
1482{
1483 if (root) {
1484 BMS_PrintTree(root->left);
1485 plog("seg %d\n", root->segment);
1486 BMS_PrintTree(root->right);
1487 }
1488}
1489#endif
1490