2 * Copyright (c) 2000-2003, 2005-2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 Contains: BTree Node Allocation routines for the BTree Module.
33 Version: xxx put the technology version here xxx
35 Written by: Gordon Sheridan and Bill Bruffey
37 Copyright: (c) 1992-1999 by Apple Inc., all rights reserved.
43 Other Contact: Mark Day
45 Technology: File Systems
53 Change History (most recent first):
55 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
56 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
57 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
58 <CS1> 4/23/97 djb first checked in
60 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
61 <HFS1> 12/19/96 djb first checked in
63 History applicable to original Scarecrow Design:
65 <4> 10/25/96 ser Changing for new VFPI
66 <3> 10/18/96 ser Converting over VFPI changes
67 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
68 <1> 10/18/95 rst Moved from Scarecrow project.
70 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
71 <7> 9/30/94 prp Get in sync with D2 interface changes.
72 <6> 7/22/94 wjk Convert to the new set of header files.
73 <5> 8/31/93 prp Use U64SetU instead of S64Set.
74 <4> 5/21/93 gs Fix ExtendBTree bug.
75 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
76 <2> 3/23/93 gs finish ExtendBTree routine.
77 <1> 2/8/93 gs first checked in
78 <0> 1/1/93 gs begin AllocateNode and FreeNode
82 #include "hfs_btreeio.h"
83 #include "hfs_endian.h"
84 #include "BTreesPrivate.h"
86 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
88 static OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
89 BlockDescriptor
*nodePtr
,
93 /////////////////////////////////////////////////////////////////////////////////
95 /*-------------------------------------------------------------------------------
97 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
99 Function: Searches the map records for the first free node, marks it "in use" and
100 returns the node number found. This routine should really only be called
101 when we know there are free blocks, otherwise it's just a waste of time.
103 Note: We have to examine map nodes a word at a time rather than a long word
104 because the External BTree Mgr used map records that were not an integral
105 number of long words. Too bad. In our spare time could develop a more
106 sophisticated algorithm that read map records by long words (and long
107 word aligned) and handled the spare bytes at the beginning and end
110 Input: btreePtr - pointer to control block for BTree file
112 Output: nodeNum - number of node allocated
115 Result: noErr - success
116 fsBTNoMoreMapNodesErr - no free blocks were found
118 -------------------------------------------------------------------------------*/
120 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, u_int32_t
*nodeNum
)
123 BlockDescriptor node
;
124 u_int16_t
*mapPtr
, *pos
;
125 u_int16_t mapSize
, size
;
129 u_int32_t nodeNumber
;
132 nodeNumber
= 0; // first node number of header map record
133 node
.buffer
= nil
; // clear node.buffer to get header node
134 // - and for ErrorExit
135 node
.blockHeader
= nil
;
139 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
143 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
145 //////////////////////// Find Word with Free Bit ////////////////////////////
149 size
>>= 1; // convert to number of words
150 //\80\80 assumes mapRecords contain an integral number of words
154 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
158 --pos
; // whoa! backup
160 if (*pos
!= 0xFFFF) // hey, we got one!
163 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
166 ///////////////////////// Find Free Bit in Word /////////////////////////////
168 freeWord
= SWAP_BE16 (*pos
);
173 if ( (freeWord
& mask
) == 0)
176 } while (--bitOffset
);
178 ////////////////////// Calculate Free Node Number ///////////////////////////
180 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
183 ///////////////////////// Check for End of Map //////////////////////////////
185 if (nodeNumber
>= btreePtr
->totalNodes
)
191 /////////////////////////// Allocate the Node ///////////////////////////////
193 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
195 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
198 --btreePtr
->freeNodes
;
199 M_BTreeHeaderDirty(btreePtr
);
201 /* Account for allocations from node reserve */
202 BTUpdateReserve(btreePtr
, 1);
204 *nodeNum
= nodeNumber
;
208 ////////////////////////////////// Error Exit ///////////////////////////////////
212 (void) ReleaseNode (btreePtr
, &node
);
220 /*-------------------------------------------------------------------------------
222 Routine: FreeNode - Clear allocation bit for node.
224 Function: Finds the bit representing the node specified by nodeNum in the node
225 map and clears the bit.
228 Input: btreePtr - pointer to control block for BTree file
229 nodeNum - number of node to mark free
233 Result: noErr - success
234 fsBTNoMoreMapNodesErr - node number is beyond end of node map
235 != noErr - GetNode or ReleaseNode encountered some difficulty
236 -------------------------------------------------------------------------------*/
238 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, u_int32_t nodeNum
)
241 BlockDescriptor node
;
243 u_int16_t mapSize
= 0;
244 u_int16_t
*mapPos
= NULL
;
248 //////////////////////////// Find Map Record ////////////////////////////////
249 nodeIndex
= 0; // first node number of header map record
250 node
.buffer
= nil
; // invalidate node.buffer to get header node
251 node
.blockHeader
= nil
;
253 while (nodeNum
>= nodeIndex
)
255 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
258 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
261 //////////////////////////// Mark Node Free /////////////////////////////////
264 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
266 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
267 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
268 mapPos
+= nodeNum
>> 4; // point to word containing map bit
270 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
272 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
275 ++btreePtr
->freeNodes
;
276 M_BTreeHeaderDirty(btreePtr
);
282 (void) ReleaseNode (btreePtr
, &node
);
289 /*-------------------------------------------------------------------------------
291 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
293 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
294 to accomodate the number of nodes requested. It then allocates as many
295 map nodes as are necessary to account for all the nodes in the B*Tree.
296 If newTotalNodes is less than the current number of nodes, no action is
299 Note: Internal HFS File Manager BTree Module counts on an integral number of
300 long words in map records, although they are not long word aligned.
302 Input: btreePtr - pointer to control block for BTree file
303 newTotalNodes - total number of nodes the B*Tree is to extended to
307 Result: noErr - success
309 -------------------------------------------------------------------------------*/
311 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
312 u_int32_t newTotalNodes
)
316 FSSize minEOF
, maxEOF
;
318 u_int32_t oldTotalNodes
;
319 u_int32_t newMapNodes
;
320 u_int32_t mapBits
, totalMapBits
;
321 u_int32_t recStartBit
;
322 u_int32_t nodeNum
, nextNodeNum
;
323 u_int32_t firstNewMapNodeNum
, lastNewMapNodeNum
;
324 BlockDescriptor mapNode
, newNode
;
328 u_int16_t mapNodeRecSize
;
329 u_int32_t bitInWord
, bitInRecord
;
333 oldTotalNodes
= btreePtr
->totalNodes
;
334 if (newTotalNodes
<= oldTotalNodes
) // we're done!
337 nodeSize
= btreePtr
->nodeSize
;
338 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
340 mapNode
.buffer
= nil
;
341 mapNode
.blockHeader
= nil
;
342 newNode
.buffer
= nil
;
343 newNode
.blockHeader
= nil
;
345 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
348 //////////////////////// Count Bits In Node Map /////////////////////////////
352 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
355 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
356 recStartBit
= totalMapBits
; // bit number of first bit in map record
357 totalMapBits
+= mapBits
;
359 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
362 if (totalMapBits
!= CalcMapBits (btreePtr
))
363 Panic ("ExtendBTree: totalMapBits != CalcMapBits");
366 /////////////////////// Extend LEOF If Necessary ////////////////////////////
368 minEOF
= (u_int64_t
)newTotalNodes
* (u_int64_t
)nodeSize
;
369 if ( (u_int64_t
)filePtr
->fcbEOF
< minEOF
)
371 maxEOF
= (u_int64_t
)0x7fffffffLL
* (u_int64_t
)nodeSize
;
373 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
378 //////////////////// Calc New Total Number Of Nodes /////////////////////////
380 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
381 // do we wish to perform any verification of newTotalNodes at this point?
383 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
386 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
389 if (newTotalNodes
> totalMapBits
)
391 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
392 firstNewMapNodeNum
= oldTotalNodes
;
393 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
397 err
= ReleaseNode (btreePtr
, &mapNode
);
404 /////////////////////// Initialize New Map Nodes ////////////////////////////
405 // XXXdbg - this is the correct place for this:
406 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
408 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
410 nodeNum
= firstNewMapNodeNum
;
413 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
417 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
419 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
420 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
422 // set free space offset
423 *(u_int16_t
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
425 if (nodeNum
++ == lastNewMapNodeNum
)
428 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
430 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
434 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
438 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
440 nodeNum
= firstNewMapNodeNum
;
442 bitInRecord
= nodeNum
- recStartBit
;
444 while (bitInRecord
>= mapBits
)
446 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
447 if ( nextNodeNum
== 0)
449 err
= fsBTNoMoreMapNodesErr
;
453 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
456 err
= GetNode (btreePtr
, nextNodeNum
, 0, &mapNode
);
460 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
464 mapStart
= (u_int16_t
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
465 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
468 if (mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
470 Panic ("ExtendBTree: mapSize != M_MapRecordSize");
474 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
475 recStartBit
= totalMapBits
; // bit number of first bit in map record
476 totalMapBits
+= mapBits
;
478 bitInRecord
= nodeNum
- recStartBit
;
481 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
482 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
484 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
488 } while (nodeNum
<= lastNewMapNodeNum
);
490 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
494 //////////////////////////////// Success ////////////////////////////////////
498 btreePtr
->totalNodes
= newTotalNodes
;
499 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
501 M_BTreeHeaderDirty(btreePtr
);
503 /* Force the b-tree header changes to disk */
504 (void) UpdateHeader (btreePtr
, true);
509 ////////////////////////////// Error Exit ///////////////////////////////////
513 (void) ReleaseNode (btreePtr
, &mapNode
);
514 (void) ReleaseNode (btreePtr
, &newNode
);
521 /*-------------------------------------------------------------------------------
523 Routine: GetMapNode - Get the next map node and pointer to the map record.
525 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
526 it and gets the next node. If nodePtr->buffer is nil, then the header
530 Input: btreePtr - pointer to control block for BTree file
531 nodePtr - pointer to a BlockDescriptor of a map node
533 Output: nodePtr - pointer to the BlockDescriptor for the next map node
534 mapPtr - pointer to the map record within the map node
535 mapSize - number of bytes in the map record
537 Result: noErr - success
538 fsBTNoMoreMapNodesErr - we've run out of map nodes
539 fsBTInvalidNodeErr - bad node, or not node type kMapNode
541 -------------------------------------------------------------------------------*/
544 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
545 BlockDescriptor
*nodePtr
,
551 u_int32_t nextNodeNum
;
553 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
555 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
556 if (nextNodeNum
== 0)
558 err
= fsBTNoMoreMapNodesErr
;
562 err
= ReleaseNode (btreePtr
, nodePtr
);
565 err
= GetNode (btreePtr
, nextNodeNum
, 0, nodePtr
);
568 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
570 err
= fsBTBadNodeType
;
574 ++btreePtr
->numMapNodesRead
;
577 err
= GetNode (btreePtr
, kHeaderNodeNum
, 0, nodePtr
);
580 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
582 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
590 *mapPtr
= (u_int16_t
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
591 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
598 (void) ReleaseNode (btreePtr
, nodePtr
);
608 ////////////////////////////////// CalcMapBits //////////////////////////////////
610 u_int32_t
CalcMapBits (BTreeControlBlockPtr btreePtr
)
614 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
616 while (mapBits
< btreePtr
->totalNodes
)
617 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;
623 /*-------------------------------------------------------------------------------
624 Routine: BTZeroUnusedNodes
626 Function: Write zeros to all nodes in the B-tree that are not currently in use.
627 -------------------------------------------------------------------------------*/
629 BTZeroUnusedNodes(FCB
*filePtr
)
633 BTreeControlBlockPtr btreePtr
;
634 BlockDescriptor mapNode
;
636 u_int32_t nodeNumber
;
637 u_int16_t
*mapPtr
, *pos
;
638 u_int16_t mapSize
, size
;
645 btreePtr
= (BTreeControlBlockPtr
) filePtr
->fcbBTCBPtr
;
648 mapNode
.buffer
= nil
;
649 mapNode
.blockHeader
= nil
;
652 /* Iterate over map nodes. */
655 err
= GetMapNode (btreePtr
, &mapNode
, &mapPtr
, &mapSize
);
658 err
= MacToVFSError(err
);
664 size
>>= 1; /* convert to number of 16-bit words */
666 /* Iterate over 16-bit words in the map record. */
669 if (*pos
!= 0xFFFF) /* Anything free in this word? */
671 word
= SWAP_BE16(*pos
);
673 /* Iterate over bits in the word. */
674 for (bitNumber
= 0, mask
= 0x8000;
676 ++bitNumber
, mask
>>= 1)
679 continue; /* This node is in use. */
681 if (nodeNumber
+ bitNumber
>= btreePtr
->totalNodes
)
683 /* We've processed all of the nodes. */
688 * Get a buffer full of zeros and write it to the unused
689 * node. Since we'll probably be writing a lot of nodes,
690 * bypass the journal (to avoid a transaction that's too
691 * big). Instead, this behaves more like clearing out
692 * nodes when extending a B-tree (eg., ClearBTNodes).
694 bp
= buf_getblk(vp
, nodeNumber
+ bitNumber
, btreePtr
->nodeSize
, 0, 0, BLK_META
);
697 printf("hfs: BTZeroUnusedNodes: unable to read node %u\n", nodeNumber
+ bitNumber
);
702 if (buf_flags(bp
) & B_LOCKED
) {
704 * This node is already part of a transaction and will be written when
705 * the transaction is committed, so don't write it here. If we did, then
706 * we'd hit a panic in hfs_vnop_bwrite because the B_LOCKED bit is still set.
716 * Try not to hog the buffer cache. Wait for the write
717 * every 32 nodes. If VNOP_BWRITE reports an error, bail out and bubble
718 * it up to the function calling us. If we tried to update a read-only
719 * mount on read-only media, for example, catching the error will let
720 * us alert the callers of this function that they should maintain
721 * the mount in read-only mode.
725 if (numWritten
% 32 == 0) {
726 err
= VNOP_BWRITE(bp
);
737 /* Go to the next word in the bitmap */
745 (void) ReleaseNode(btreePtr
, &mapNode
);