2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 Contains: BTree Node Allocation routines for the BTree Module.
27 Version: xxx put the technology version here xxx
29 Written by: Gordon Sheridan and Bill Bruffey
31 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
37 Other Contact: Mark Day
39 Technology: File Systems
47 Change History (most recent first):
49 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
50 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
51 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
52 <CS1> 4/23/97 djb first checked in
54 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
55 <HFS1> 12/19/96 djb first checked in
57 History applicable to original Scarecrow Design:
59 <4> 10/25/96 ser Changing for new VFPI
60 <3> 10/18/96 ser Converting over VFPI changes
61 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
62 <1> 10/18/95 rst Moved from Scarecrow project.
64 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
65 <7> 9/30/94 prp Get in sync with D2 interface changes.
66 <6> 7/22/94 wjk Convert to the new set of header files.
67 <5> 8/31/93 prp Use U64SetU instead of S64Set.
68 <4> 5/21/93 gs Fix ExtendBTree bug.
69 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
70 <2> 3/23/93 gs finish ExtendBTree routine.
71 <1> 2/8/93 gs first checked in
72 <0> 1/1/93 gs begin AllocateNode and FreeNode
76 #include "../../hfs_endian.h"
77 #include "../headers/BTreesPrivate.h"
79 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
81 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
82 BlockDescriptor
*nodePtr
,
86 /////////////////////////////////////////////////////////////////////////////////
88 /*-------------------------------------------------------------------------------
90 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
92 Function: Searches the map records for the first free node, marks it "in use" and
93 returns the node number found. This routine should really only be called
94 when we know there are free blocks, otherwise it's just a waste of time.
96 Note: We have to examine map nodes a word at a time rather than a long word
97 because the External BTree Mgr used map records that were not an integral
98 number of long words. Too bad. In our spare time could develop a more
99 sophisticated algorithm that read map records by long words (and long
100 word aligned) and handled the spare bytes at the beginning and end
103 Input: btreePtr - pointer to control block for BTree file
105 Output: nodeNum - number of node allocated
108 Result: noErr - success
109 fsBTNoMoreMapNodesErr - no free blocks were found
111 -------------------------------------------------------------------------------*/
113 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
116 BlockDescriptor node
;
117 UInt16
*mapPtr
, *pos
;
118 UInt16 mapSize
, size
;
125 nodeNumber
= 0; // first node number of header map record
126 node
.buffer
= nil
; // clear node.buffer to get header node
127 // - and for ErrorExit
128 node
.blockHeader
= nil
;
132 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
136 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
138 //////////////////////// Find Word with Free Bit ////////////////////////////
142 size
>>= 1; // convert to number of words
143 //\80\80 assumes mapRecords contain an integral number of words
147 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
151 --pos
; // whoa! backup
153 if (*pos
!= 0xFFFF) // hey, we got one!
156 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
159 ///////////////////////// Find Free Bit in Word /////////////////////////////
161 freeWord
= SWAP_BE16 (*pos
);
166 if ( (freeWord
& mask
) == 0)
169 } while (--bitOffset
);
171 ////////////////////// Calculate Free Node Number ///////////////////////////
173 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
176 ///////////////////////// Check for End of Map //////////////////////////////
178 if (nodeNumber
>= btreePtr
->totalNodes
)
184 /////////////////////////// Allocate the Node ///////////////////////////////
186 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
188 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
191 --btreePtr
->freeNodes
;
192 btreePtr
->flags
|= kBTHeaderDirty
;
194 /* Account for allocations from node reserve */
195 BTUpdateReserve(btreePtr
, 1);
197 *nodeNum
= nodeNumber
;
201 ////////////////////////////////// Error Exit ///////////////////////////////////
205 (void) ReleaseNode (btreePtr
, &node
);
213 /*-------------------------------------------------------------------------------
215 Routine: FreeNode - Clear allocation bit for node.
217 Function: Finds the bit representing the node specified by nodeNum in the node
218 map and clears the bit.
221 Input: btreePtr - pointer to control block for BTree file
222 nodeNum - number of node to mark free
226 Result: noErr - success
227 fsBTNoMoreMapNodesErr - node number is beyond end of node map
228 != noErr - GetNode or ReleaseNode encountered some difficulty
229 -------------------------------------------------------------------------------*/
231 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
234 BlockDescriptor node
;
241 //////////////////////////// Find Map Record ////////////////////////////////
242 nodeIndex
= 0; // first node number of header map record
243 node
.buffer
= nil
; // invalidate node.buffer to get header node
244 node
.blockHeader
= nil
;
246 while (nodeNum
>= nodeIndex
)
248 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
251 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
254 //////////////////////////// Mark Node Free /////////////////////////////////
257 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
259 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
260 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
261 mapPos
+= nodeNum
>> 4; // point to word containing map bit
263 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
265 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
268 ++btreePtr
->freeNodes
;
269 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
275 (void) ReleaseNode (btreePtr
, &node
);
282 /*-------------------------------------------------------------------------------
284 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
286 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
287 to accomodate the number of nodes requested. It then allocates as many
288 map nodes as are necessary to account for all the nodes in the B*Tree.
289 If newTotalNodes is less than the current number of nodes, no action is
292 Note: Internal HFS File Manager BTree Module counts on an integral number of
293 long words in map records, although they are not long word aligned.
295 Input: btreePtr - pointer to control block for BTree file
296 newTotalNodes - total number of nodes the B*Tree is to extended to
300 Result: noErr - success
302 -------------------------------------------------------------------------------*/
304 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
305 UInt32 newTotalNodes
)
309 FSSize minEOF
, maxEOF
;
311 UInt32 oldTotalNodes
;
313 UInt32 mapBits
, totalMapBits
;
315 UInt32 nodeNum
, nextNodeNum
;
316 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
317 BlockDescriptor mapNode
, newNode
;
321 UInt16 mapNodeRecSize
;
322 UInt32 bitInWord
, bitInRecord
;
326 oldTotalNodes
= btreePtr
->totalNodes
;
327 if (newTotalNodes
<= oldTotalNodes
) // we're done!
330 nodeSize
= btreePtr
->nodeSize
;
331 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
333 mapNode
.buffer
= nil
;
334 mapNode
.blockHeader
= nil
;
335 newNode
.buffer
= nil
;
336 newNode
.blockHeader
= nil
;
338 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
341 //////////////////////// Count Bits In Node Map /////////////////////////////
345 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
348 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
349 recStartBit
= totalMapBits
; // bit number of first bit in map record
350 totalMapBits
+= mapBits
;
352 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
354 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
355 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
357 /////////////////////// Extend LEOF If Necessary ////////////////////////////
359 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
360 if ( filePtr
->fcbEOF
< minEOF
)
362 maxEOF
= (UInt64
)0x7fffffffLL
* (UInt64
)nodeSize
;
364 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
369 //////////////////// Calc New Total Number Of Nodes /////////////////////////
371 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
372 // do we wish to perform any verification of newTotalNodes at this point?
374 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
377 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
380 if (newTotalNodes
> totalMapBits
)
382 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
383 firstNewMapNodeNum
= oldTotalNodes
;
384 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
388 err
= ReleaseNode (btreePtr
, &mapNode
);
395 /////////////////////// Initialize New Map Nodes ////////////////////////////
396 // XXXdbg - this is the correct place for this:
397 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
399 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
401 nodeNum
= firstNewMapNodeNum
;
404 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
408 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
410 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
411 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
413 // set free space offset
414 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
416 if (nodeNum
++ == lastNewMapNodeNum
)
419 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
421 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
425 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
429 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
431 nodeNum
= firstNewMapNodeNum
;
433 bitInRecord
= nodeNum
- recStartBit
;
435 while (bitInRecord
>= mapBits
)
437 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
438 if ( nextNodeNum
== 0)
440 err
= fsBTNoMoreMapNodesErr
;
444 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
447 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
451 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
455 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
456 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
458 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
460 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
463 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
464 recStartBit
= totalMapBits
; // bit number of first bit in map record
465 totalMapBits
+= mapBits
;
467 bitInRecord
= nodeNum
- recStartBit
;
470 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
471 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
473 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
477 } while (nodeNum
<= lastNewMapNodeNum
);
479 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
483 //////////////////////////////// Success ////////////////////////////////////
487 btreePtr
->totalNodes
= newTotalNodes
;
488 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
490 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
492 /* Force the b-tree header changes to disk */
493 (void) UpdateHeader (btreePtr
, true);
498 ////////////////////////////// Error Exit ///////////////////////////////////
502 (void) ReleaseNode (btreePtr
, &mapNode
);
503 (void) ReleaseNode (btreePtr
, &newNode
);
510 /*-------------------------------------------------------------------------------
512 Routine: GetMapNode - Get the next map node and pointer to the map record.
514 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
515 it and gets the next node. If nodePtr->buffer is nil, then the header
519 Input: btreePtr - pointer to control block for BTree file
520 nodePtr - pointer to a BlockDescriptor of a map node
522 Output: nodePtr - pointer to the BlockDescriptor for the next map node
523 mapPtr - pointer to the map record within the map node
524 mapSize - number of bytes in the map record
526 Result: noErr - success
527 fsBTNoMoreMapNodesErr - we've run out of map nodes
528 fsBTInvalidNodeErr - bad node, or not node type kMapNode
530 -------------------------------------------------------------------------------*/
532 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
533 BlockDescriptor
*nodePtr
,
541 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
543 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
544 if (nextNodeNum
== 0)
546 err
= fsBTNoMoreMapNodesErr
;
550 err
= ReleaseNode (btreePtr
, nodePtr
);
553 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
556 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
558 err
= fsBTBadNodeType
;
562 ++btreePtr
->numMapNodesRead
;
565 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
568 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
570 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
578 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
579 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
586 (void) ReleaseNode (btreePtr
, nodePtr
);
596 ////////////////////////////////// CalcMapBits //////////////////////////////////
598 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
602 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
604 while (mapBits
< btreePtr
->totalNodes
)
605 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;