2 * Copyright (c) 2000-2003 Apple Computer, 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@
26 Contains: BTree Node Allocation routines for the BTree Module.
28 Version: xxx put the technology version here xxx
30 Written by: Gordon Sheridan and Bill Bruffey
32 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
38 Other Contact: Mark Day
40 Technology: File Systems
48 Change History (most recent first):
50 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
51 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
52 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
53 <CS1> 4/23/97 djb first checked in
55 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
56 <HFS1> 12/19/96 djb first checked in
58 History applicable to original Scarecrow Design:
60 <4> 10/25/96 ser Changing for new VFPI
61 <3> 10/18/96 ser Converting over VFPI changes
62 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
63 <1> 10/18/95 rst Moved from Scarecrow project.
65 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
66 <7> 9/30/94 prp Get in sync with D2 interface changes.
67 <6> 7/22/94 wjk Convert to the new set of header files.
68 <5> 8/31/93 prp Use U64SetU instead of S64Set.
69 <4> 5/21/93 gs Fix ExtendBTree bug.
70 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
71 <2> 3/23/93 gs finish ExtendBTree routine.
72 <1> 2/8/93 gs first checked in
73 <0> 1/1/93 gs begin AllocateNode and FreeNode
77 #include "../../hfs_endian.h"
78 #include "../headers/BTreesPrivate.h"
80 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
82 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
83 BlockDescriptor
*nodePtr
,
87 /////////////////////////////////////////////////////////////////////////////////
89 /*-------------------------------------------------------------------------------
91 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
93 Function: Searches the map records for the first free node, marks it "in use" and
94 returns the node number found. This routine should really only be called
95 when we know there are free blocks, otherwise it's just a waste of time.
97 Note: We have to examine map nodes a word at a time rather than a long word
98 because the External BTree Mgr used map records that were not an integral
99 number of long words. Too bad. In our spare time could develop a more
100 sophisticated algorithm that read map records by long words (and long
101 word aligned) and handled the spare bytes at the beginning and end
104 Input: btreePtr - pointer to control block for BTree file
106 Output: nodeNum - number of node allocated
109 Result: noErr - success
110 fsBTNoMoreMapNodesErr - no free blocks were found
112 -------------------------------------------------------------------------------*/
114 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
117 BlockDescriptor node
;
118 UInt16
*mapPtr
, *pos
;
119 UInt16 mapSize
, size
;
126 nodeNumber
= 0; // first node number of header map record
127 node
.buffer
= nil
; // clear node.buffer to get header node
128 // - and for ErrorExit
129 node
.blockHeader
= nil
;
133 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
137 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
139 //////////////////////// Find Word with Free Bit ////////////////////////////
143 size
>>= 1; // convert to number of words
144 //\80\80 assumes mapRecords contain an integral number of words
148 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
152 --pos
; // whoa! backup
154 if (*pos
!= 0xFFFF) // hey, we got one!
157 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
160 ///////////////////////// Find Free Bit in Word /////////////////////////////
162 freeWord
= SWAP_BE16 (*pos
);
167 if ( (freeWord
& mask
) == 0)
170 } while (--bitOffset
);
172 ////////////////////// Calculate Free Node Number ///////////////////////////
174 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
177 ///////////////////////// Check for End of Map //////////////////////////////
179 if (nodeNumber
>= btreePtr
->totalNodes
)
185 /////////////////////////// Allocate the Node ///////////////////////////////
187 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
189 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
192 --btreePtr
->freeNodes
;
193 btreePtr
->flags
|= kBTHeaderDirty
;
195 /* Account for allocations from node reserve */
196 BTUpdateReserve(btreePtr
, 1);
198 *nodeNum
= nodeNumber
;
202 ////////////////////////////////// Error Exit ///////////////////////////////////
206 (void) ReleaseNode (btreePtr
, &node
);
214 /*-------------------------------------------------------------------------------
216 Routine: FreeNode - Clear allocation bit for node.
218 Function: Finds the bit representing the node specified by nodeNum in the node
219 map and clears the bit.
222 Input: btreePtr - pointer to control block for BTree file
223 nodeNum - number of node to mark free
227 Result: noErr - success
228 fsBTNoMoreMapNodesErr - node number is beyond end of node map
229 != noErr - GetNode or ReleaseNode encountered some difficulty
230 -------------------------------------------------------------------------------*/
232 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
235 BlockDescriptor node
;
242 //////////////////////////// Find Map Record ////////////////////////////////
243 nodeIndex
= 0; // first node number of header map record
244 node
.buffer
= nil
; // invalidate node.buffer to get header node
245 node
.blockHeader
= nil
;
247 while (nodeNum
>= nodeIndex
)
249 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
252 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
255 //////////////////////////// Mark Node Free /////////////////////////////////
258 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
260 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
261 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
262 mapPos
+= nodeNum
>> 4; // point to word containing map bit
264 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
266 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
269 ++btreePtr
->freeNodes
;
270 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
276 (void) ReleaseNode (btreePtr
, &node
);
283 /*-------------------------------------------------------------------------------
285 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
287 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
288 to accomodate the number of nodes requested. It then allocates as many
289 map nodes as are necessary to account for all the nodes in the B*Tree.
290 If newTotalNodes is less than the current number of nodes, no action is
293 Note: Internal HFS File Manager BTree Module counts on an integral number of
294 long words in map records, although they are not long word aligned.
296 Input: btreePtr - pointer to control block for BTree file
297 newTotalNodes - total number of nodes the B*Tree is to extended to
301 Result: noErr - success
303 -------------------------------------------------------------------------------*/
305 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
306 UInt32 newTotalNodes
)
310 FSSize minEOF
, maxEOF
;
312 UInt32 oldTotalNodes
;
314 UInt32 mapBits
, totalMapBits
;
316 UInt32 nodeNum
, nextNodeNum
;
317 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
318 BlockDescriptor mapNode
, newNode
;
322 UInt16 mapNodeRecSize
;
323 UInt32 bitInWord
, bitInRecord
;
327 oldTotalNodes
= btreePtr
->totalNodes
;
328 if (newTotalNodes
<= oldTotalNodes
) // we're done!
331 nodeSize
= btreePtr
->nodeSize
;
332 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
334 mapNode
.buffer
= nil
;
335 mapNode
.blockHeader
= nil
;
336 newNode
.buffer
= nil
;
337 newNode
.blockHeader
= nil
;
339 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
342 //////////////////////// Count Bits In Node Map /////////////////////////////
346 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
349 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
350 recStartBit
= totalMapBits
; // bit number of first bit in map record
351 totalMapBits
+= mapBits
;
353 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
355 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
356 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
358 /////////////////////// Extend LEOF If Necessary ////////////////////////////
360 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
361 if ( filePtr
->fcbEOF
< minEOF
)
363 maxEOF
= (UInt64
)0x7fffffffLL
* (UInt64
)nodeSize
;
365 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
370 //////////////////// Calc New Total Number Of Nodes /////////////////////////
372 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
373 // do we wish to perform any verification of newTotalNodes at this point?
375 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
378 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
381 if (newTotalNodes
> totalMapBits
)
383 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
384 firstNewMapNodeNum
= oldTotalNodes
;
385 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
389 err
= ReleaseNode (btreePtr
, &mapNode
);
396 /////////////////////// Initialize New Map Nodes ////////////////////////////
397 // XXXdbg - this is the correct place for this:
398 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
400 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
402 nodeNum
= firstNewMapNodeNum
;
405 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
409 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
411 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
412 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
414 // set free space offset
415 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
417 if (nodeNum
++ == lastNewMapNodeNum
)
420 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
422 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
426 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
430 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
432 nodeNum
= firstNewMapNodeNum
;
434 bitInRecord
= nodeNum
- recStartBit
;
436 while (bitInRecord
>= mapBits
)
438 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
439 if ( nextNodeNum
== 0)
441 err
= fsBTNoMoreMapNodesErr
;
445 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
448 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
452 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
456 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
457 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
459 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
461 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
464 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
465 recStartBit
= totalMapBits
; // bit number of first bit in map record
466 totalMapBits
+= mapBits
;
468 bitInRecord
= nodeNum
- recStartBit
;
471 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
472 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
474 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
478 } while (nodeNum
<= lastNewMapNodeNum
);
480 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
484 //////////////////////////////// Success ////////////////////////////////////
488 btreePtr
->totalNodes
= newTotalNodes
;
489 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
491 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
493 /* Force the b-tree header changes to disk */
494 (void) UpdateHeader (btreePtr
, true);
499 ////////////////////////////// Error Exit ///////////////////////////////////
503 (void) ReleaseNode (btreePtr
, &mapNode
);
504 (void) ReleaseNode (btreePtr
, &newNode
);
511 /*-------------------------------------------------------------------------------
513 Routine: GetMapNode - Get the next map node and pointer to the map record.
515 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
516 it and gets the next node. If nodePtr->buffer is nil, then the header
520 Input: btreePtr - pointer to control block for BTree file
521 nodePtr - pointer to a BlockDescriptor of a map node
523 Output: nodePtr - pointer to the BlockDescriptor for the next map node
524 mapPtr - pointer to the map record within the map node
525 mapSize - number of bytes in the map record
527 Result: noErr - success
528 fsBTNoMoreMapNodesErr - we've run out of map nodes
529 fsBTInvalidNodeErr - bad node, or not node type kMapNode
531 -------------------------------------------------------------------------------*/
533 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
534 BlockDescriptor
*nodePtr
,
542 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
544 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
545 if (nextNodeNum
== 0)
547 err
= fsBTNoMoreMapNodesErr
;
551 err
= ReleaseNode (btreePtr
, nodePtr
);
554 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
557 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
559 err
= fsBTBadNodeType
;
563 ++btreePtr
->numMapNodesRead
;
566 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
569 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
571 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
579 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
580 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
587 (void) ReleaseNode (btreePtr
, nodePtr
);
597 ////////////////////////////////// CalcMapBits //////////////////////////////////
599 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
603 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
605 while (mapBits
< btreePtr
->totalNodes
)
606 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;