]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_btree_allocate.c
hfs-556.100.11.tar.gz
[apple/hfs.git] / livefiles_hfs_plugin / lf_hfs_btree_allocate.c
1 //
2 // lf_hfs_btree_allocate.c
3 // livefiles_hfs
4 //
5 // Created by Yakov Ben Zaken on 22/03/2018.
6 //
7 #include "lf_hfs_btrees_io.h"
8 #include "lf_hfs_endian.h"
9 #include "lf_hfs_btrees_private.h"
10 #include "lf_hfs_vfsutils.h"
11 #include "lf_hfs_generic_buf.h"
12
13 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
14
15 static OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
16 BlockDescriptor *nodePtr,
17 u_int16_t **mapPtr,
18 u_int16_t *mapSize );
19
20 /////////////////////////////////////////////////////////////////////////////////
21
22 /*-------------------------------------------------------------------------------
23
24 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
25
26 Function: Searches the map records for the first free node, marks it "in use" and
27 returns the node number found. This routine should really only be called
28 when we know there are free blocks, otherwise it's just a waste of time.
29
30 Note: We have to examine map nodes a word at a time rather than a long word
31 because the External BTree Mgr used map records that were not an integral
32 number of long words. Too bad. In our spare time could develop a more
33 sophisticated algorithm that read map records by long words (and long
34 word aligned) and handled the spare bytes at the beginning and end
35 appropriately.
36
37 Input: btreePtr - pointer to control block for BTree file
38
39 Output: nodeNum - number of node allocated
40
41
42 Result: noErr - success
43 fsBTNoMoreMapNodesErr - no free blocks were found
44 != noErr - failure
45 -------------------------------------------------------------------------------*/
46
47 OSStatus AllocateNode (BTreeControlBlockPtr btreePtr, u_int32_t *nodeNum)
48 {
49 OSStatus err;
50 BlockDescriptor node;
51 u_int16_t *mapPtr, *pos;
52 u_int16_t mapSize, size;
53 u_int16_t freeWord;
54 u_int16_t mask;
55 u_int16_t bitOffset;
56 u_int32_t nodeNumber;
57
58
59 nodeNumber = 0; // first node number of header map record
60 node.buffer = nil; // clear node.buffer to get header node
61 // - and for ErrorExit
62 node.blockHeader = nil;
63
64 while (true)
65 {
66 err = GetMapNode (btreePtr, &node, &mapPtr, &mapSize);
67 M_ExitOnError (err);
68
69 // XXXdbg
70 ModifyBlockStart(btreePtr->fileRefNum, &node);
71
72 //////////////////////// Find Word with Free Bit ////////////////////////////
73
74 pos = mapPtr;
75 size = mapSize;
76 size >>= 1; // convert to number of words
77 //assumes mapRecords contain an integral number of words
78
79 while ( size-- )
80 {
81 if ( *pos++ != 0xFFFF ) // assume test fails, and increment pos
82 break;
83 }
84
85 --pos; // whoa! backup
86
87 if (*pos != 0xFFFF) // hey, we got one!
88 break;
89
90 nodeNumber += mapSize << 3; // covert to number of bits (nodes)
91 }
92
93 ///////////////////////// Find Free Bit in Word /////////////////////////////
94
95 freeWord = SWAP_BE16 (*pos);
96 bitOffset = 15;
97 mask = 0x8000;
98
99 do {
100 if ( (freeWord & mask) == 0)
101 break;
102 mask >>= 1;
103 } while (--bitOffset);
104
105 ////////////////////// Calculate Free Node Number ///////////////////////////
106
107 nodeNumber += ((pos - mapPtr) << 4) + (15 - bitOffset); // (pos-mapPtr) = # of words!
108
109
110 ///////////////////////// Check for End of Map //////////////////////////////
111
112 if (nodeNumber >= btreePtr->totalNodes)
113 {
114 err = fsBTFullErr;
115 goto ErrorExit;
116 }
117
118 /////////////////////////// Allocate the Node ///////////////////////////////
119
120 *pos |= SWAP_BE16 (mask); // set the map bit for the node
121
122 err = UpdateNode (btreePtr, &node, 0, kLockTransaction);
123 M_ExitOnError (err);
124
125 --btreePtr->freeNodes;
126 M_BTreeHeaderDirty(btreePtr);
127
128 /* Account for allocations from node reserve */
129 BTUpdateReserve(btreePtr, 1);
130
131 *nodeNum = nodeNumber;
132
133 return noErr;
134
135 ////////////////////////////////// Error Exit ///////////////////////////////////
136
137 ErrorExit:
138
139 (void) ReleaseNode (btreePtr, &node);
140 *nodeNum = 0;
141
142 return err;
143 }
144
145
146
147 /*-------------------------------------------------------------------------------
148
149 Routine: FreeNode - Clear allocation bit for node.
150
151 Function: Finds the bit representing the node specified by nodeNum in the node
152 map and clears the bit.
153
154
155 Input: btreePtr - pointer to control block for BTree file
156 nodeNum - number of node to mark free
157
158 Output: none
159
160 Result: noErr - success
161 fsBTNoMoreMapNodesErr - node number is beyond end of node map
162 != noErr - GetNode or ReleaseNode encountered some difficulty
163 -------------------------------------------------------------------------------*/
164
165 OSStatus FreeNode (BTreeControlBlockPtr btreePtr, u_int32_t nodeNum)
166 {
167 OSStatus err;
168 BlockDescriptor node;
169 u_int32_t nodeIndex;
170 u_int16_t mapSize = 0;
171 u_int16_t *mapPos = NULL;
172 u_int16_t bitOffset;
173
174
175 //////////////////////////// Find Map Record ////////////////////////////////
176 nodeIndex = 0; // first node number of header map record
177 node.buffer = nil; // invalidate node.buffer to get header node
178 node.blockHeader = nil;
179
180 while (nodeNum >= nodeIndex)
181 {
182 err = GetMapNode (btreePtr, &node, &mapPos, &mapSize);
183 M_ExitOnError (err);
184
185 nodeIndex += mapSize << 3; // covert to number of bits (nodes)
186 }
187
188 //////////////////////////// Mark Node Free /////////////////////////////////
189
190 // XXXdbg
191 ModifyBlockStart(btreePtr->fileRefNum, &node);
192
193 nodeNum -= (nodeIndex - (mapSize << 3)); // relative to this map record
194 bitOffset = 15 - (nodeNum & 0x0000000F); // last 4 bits are bit offset
195 mapPos += nodeNum >> 4; // point to word containing map bit
196
197 M_SWAP_BE16_ClearBitNum (*mapPos, bitOffset); // clear it
198
199 err = UpdateNode (btreePtr, &node, 0, kLockTransaction);
200 M_ExitOnError (err);
201
202 ++btreePtr->freeNodes;
203 M_BTreeHeaderDirty(btreePtr);
204
205 return noErr;
206
207 ErrorExit:
208
209 (void) ReleaseNode (btreePtr, &node);
210
211 return err;
212 }
213
214
215
216 /*-------------------------------------------------------------------------------
217
218 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
219
220 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
221 to accomodate the number of nodes requested. It then allocates as many
222 map nodes as are necessary to account for all the nodes in the B*Tree.
223 If newTotalNodes is less than the current number of nodes, no action is
224 taken.
225
226 Note: Internal HFS File Manager BTree Module counts on an integral number of
227 long words in map records, although they are not long word aligned.
228
229 Input: btreePtr - pointer to control block for BTree file
230 newTotalNodes - total number of nodes the B*Tree is to extended to
231
232 Output: none
233
234 Result: noErr - success
235 != noErr - failure
236 -------------------------------------------------------------------------------*/
237
238 OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr,
239 u_int32_t newTotalNodes )
240 {
241 OSStatus err;
242 FCB *filePtr;
243 FSSize minEOF, maxEOF;
244 u_int16_t nodeSize;
245 u_int32_t oldTotalNodes;
246 u_int32_t newMapNodes;
247 u_int32_t mapBits, totalMapBits;
248 u_int32_t recStartBit;
249 u_int32_t nodeNum, nextNodeNum;
250 u_int32_t firstNewMapNodeNum, lastNewMapNodeNum;
251 BlockDescriptor mapNode, newNode;
252 u_int16_t *mapPos;
253 u_int16_t *mapStart;
254 u_int16_t mapSize;
255 u_int16_t mapNodeRecSize;
256 u_int32_t bitInWord, bitInRecord;
257 u_int16_t mapIndex;
258
259
260 oldTotalNodes = btreePtr->totalNodes;
261 if (newTotalNodes <= oldTotalNodes) // we're done!
262 return noErr;
263
264 nodeSize = btreePtr->nodeSize;
265 filePtr = GetFileControlBlock(btreePtr->fileRefNum);
266
267 mapNode.buffer = nil;
268 mapNode.blockHeader = nil;
269 newNode.buffer = nil;
270 newNode.blockHeader = nil;
271
272 mapNodeRecSize = nodeSize - sizeof(BTNodeDescriptor) - 6; // 2 bytes of free space (see note)
273
274
275 //////////////////////// Count Bits In Node Map /////////////////////////////
276
277 totalMapBits = 0;
278 do {
279 err = GetMapNode (btreePtr, &mapNode, &mapStart, &mapSize);
280 M_ExitOnError (err);
281
282 mapBits = mapSize << 3; // mapSize (in bytes) * 8
283 recStartBit = totalMapBits; // bit number of first bit in map record
284 totalMapBits += mapBits;
285
286 } while ( ((BTNodeDescriptor*)mapNode.buffer)->fLink != 0 );
287
288 #if DEBUG
289 if (totalMapBits != CalcMapBits (btreePtr))
290 LFHFS_LOG(LEVEL_ERROR, "ExtendBTree: totalMapBits != CalcMapBits");
291 #endif
292
293 /////////////////////// Extend LEOF If Necessary ////////////////////////////
294
295 minEOF = (u_int64_t)newTotalNodes * (u_int64_t)nodeSize;
296 if ( (u_int64_t)filePtr->fcbEOF < minEOF )
297 {
298 maxEOF = (u_int64_t)0x7fffffffLL * (u_int64_t)nodeSize;
299
300 err = btreePtr->setEndOfForkProc (btreePtr->fileRefNum, minEOF, maxEOF);
301 M_ExitOnError (err);
302 }
303
304
305 //////////////////// Calc New Total Number Of Nodes /////////////////////////
306
307 newTotalNodes = (uint32_t)(filePtr->fcbEOF / nodeSize); // hack!
308 // do we wish to perform any verification of newTotalNodes at this point?
309
310 btreePtr->totalNodes = newTotalNodes; // do we need to update freeNodes here too?
311
312
313 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
314
315 newMapNodes = 0;
316 if (newTotalNodes > totalMapBits)
317 {
318 newMapNodes = (((newTotalNodes - totalMapBits) >> 3) / mapNodeRecSize) + 1;
319 firstNewMapNodeNum = oldTotalNodes;
320 lastNewMapNodeNum = firstNewMapNodeNum + newMapNodes - 1;
321 }
322 else
323 {
324 err = ReleaseNode (btreePtr, &mapNode);
325 M_ExitOnError (err);
326
327 goto Success;
328 }
329
330
331 /////////////////////// Initialize New Map Nodes ////////////////////////////
332 // XXXdbg - this is the correct place for this:
333 ModifyBlockStart(btreePtr->fileRefNum, &mapNode);
334
335 ((BTNodeDescriptor*)mapNode.buffer)->fLink = firstNewMapNodeNum;
336
337 nodeNum = firstNewMapNodeNum;
338 while (true)
339 {
340 err = GetNewNode (btreePtr, nodeNum, &newNode);
341 M_ExitOnError (err);
342
343 // XXXdbg
344 ModifyBlockStart(btreePtr->fileRefNum, &newNode);
345
346 ((NodeDescPtr)newNode.buffer)->numRecords = 1;
347 ((NodeDescPtr)newNode.buffer)->kind = kBTMapNode;
348
349 // set free space offset
350 *(u_int16_t *)((Ptr)newNode.buffer + nodeSize - 4) = nodeSize - 6;
351
352 if (nodeNum++ == lastNewMapNodeNum)
353 break;
354
355 ((BTNodeDescriptor*)newNode.buffer)->fLink = nodeNum; // point to next map node
356
357 err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction);
358 M_ExitOnError (err);
359 }
360
361 err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction);
362 M_ExitOnError (err);
363
364
365 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
366
367 nodeNum = firstNewMapNodeNum;
368 do {
369 bitInRecord = nodeNum - recStartBit;
370
371 while (bitInRecord >= mapBits)
372 {
373 nextNodeNum = ((NodeDescPtr)mapNode.buffer)->fLink;
374 if ( nextNodeNum == 0)
375 {
376 err = fsBTNoMoreMapNodesErr;
377 goto ErrorExit;
378 }
379
380 err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction);
381 M_ExitOnError (err);
382
383 err = GetNode (btreePtr, nextNodeNum, 0, &mapNode);
384 M_ExitOnError (err);
385
386 // XXXdbg
387 ModifyBlockStart(btreePtr->fileRefNum, &mapNode);
388
389 mapIndex = 0;
390
391 mapStart = (u_int16_t *) GetRecordAddress (btreePtr, mapNode.buffer, mapIndex);
392 mapSize = GetRecordSize (btreePtr, mapNode.buffer, mapIndex);
393
394 #if DEBUG
395 if (mapSize != M_MapRecordSize (btreePtr->nodeSize) )
396 {
397 LFHFS_LOG(LEVEL_ERROR, "ExtendBTree: mapSize != M_MapRecordSize");
398 }
399 #endif
400
401 mapBits = mapSize << 3; // mapSize (in bytes) * 8
402 recStartBit = totalMapBits; // bit number of first bit in map record
403 totalMapBits += mapBits;
404
405 bitInRecord = nodeNum - recStartBit;
406 }
407
408 mapPos = mapStart + ((nodeNum - recStartBit) >> 4);
409 bitInWord = 15 - ((nodeNum - recStartBit) & 0x0000000F);
410
411 M_SWAP_BE16_SetBitNum (*mapPos, bitInWord);
412
413 ++nodeNum;
414
415 } while (nodeNum <= lastNewMapNodeNum);
416
417 err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction);
418 M_ExitOnError (err);
419
420
421 //////////////////////////////// Success ////////////////////////////////////
422
423 Success:
424
425 btreePtr->totalNodes = newTotalNodes;
426 btreePtr->freeNodes += (newTotalNodes - oldTotalNodes) - newMapNodes;
427
428 M_BTreeHeaderDirty(btreePtr);
429
430 /* Force the b-tree header changes to disk */
431 (void) UpdateHeader (btreePtr, true);
432
433 return noErr;
434
435
436 ////////////////////////////// Error Exit ///////////////////////////////////
437
438 ErrorExit:
439
440 (void) ReleaseNode (btreePtr, &mapNode);
441 (void) ReleaseNode (btreePtr, &newNode);
442
443 return err;
444 }
445
446
447
448 /*-------------------------------------------------------------------------------
449
450 Routine: GetMapNode - Get the next map node and pointer to the map record.
451
452 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
453 it and gets the next node. If nodePtr->buffer is nil, then the header
454 node is retrieved.
455
456
457 Input: btreePtr - pointer to control block for BTree file
458 nodePtr - pointer to a BlockDescriptor of a map node
459
460 Output: nodePtr - pointer to the BlockDescriptor for the next map node
461 mapPtr - pointer to the map record within the map node
462 mapSize - number of bytes in the map record
463
464 Result: noErr - success
465 fsBTNoMoreMapNodesErr - we've run out of map nodes
466 fsBTInvalidNodeErr - bad node, or not node type kMapNode
467 != noErr - failure
468 -------------------------------------------------------------------------------*/
469
470 static
471 OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
472 BlockDescriptor *nodePtr,
473 u_int16_t **mapPtr,
474 u_int16_t *mapSize )
475 {
476 OSStatus err;
477 u_int16_t mapIndex;
478 u_int32_t nextNodeNum;
479
480 if (nodePtr->buffer != nil) // if iterator is valid...
481 {
482 nextNodeNum = ((NodeDescPtr)nodePtr->buffer)->fLink;
483 if (nextNodeNum == 0)
484 {
485 err = fsBTNoMoreMapNodesErr;
486 goto ErrorExit;
487 }
488
489 err = ReleaseNode (btreePtr, nodePtr);
490 M_ExitOnError (err);
491
492 err = GetNode (btreePtr, nextNodeNum, 0, nodePtr);
493 M_ExitOnError (err);
494
495 if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTMapNode)
496 {
497 err = fsBTBadNodeType;
498 goto ErrorExit;
499 }
500
501 ++btreePtr->numMapNodesRead;
502 mapIndex = 0;
503 } else {
504 err = GetNode (btreePtr, kHeaderNodeNum, 0, nodePtr);
505 M_ExitOnError (err);
506
507 if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTHeaderNode)
508 {
509 err = fsBTInvalidHeaderErr; //or fsBTBadNodeType
510 goto ErrorExit;
511 }
512
513 mapIndex = 2;
514 }
515
516
517 *mapPtr = (u_int16_t *) GetRecordAddress (btreePtr, nodePtr->buffer, mapIndex);
518 *mapSize = GetRecordSize (btreePtr, nodePtr->buffer, mapIndex);
519
520 return noErr;
521
522
523 ErrorExit:
524
525 (void) ReleaseNode (btreePtr, nodePtr);
526
527 *mapPtr = nil;
528 *mapSize = 0;
529
530 return err;
531 }
532
533
534
535 ////////////////////////////////// CalcMapBits //////////////////////////////////
536
537 u_int32_t CalcMapBits (BTreeControlBlockPtr btreePtr)
538 {
539 u_int32_t mapBits;
540
541 mapBits = (u_int32_t)(M_HeaderMapRecordSize (btreePtr->nodeSize) << 3);
542
543 while (mapBits < btreePtr->totalNodes)
544 mapBits += M_MapRecordSize (btreePtr->nodeSize) << 3;
545
546 return mapBits;
547 }
548
549 /*-------------------------------------------------------------------------------
550 Routine: BTZeroUnusedNodes
551
552 Function: Write zeros to all nodes in the B-tree that are not currently in use.
553 -------------------------------------------------------------------------------*/
554 int
555 BTZeroUnusedNodes(FCB *filePtr)
556 {
557 int err=0;
558 u_int16_t *mapPtr, *pos;
559 u_int16_t mapSize, size;
560 u_int16_t mask;
561 u_int16_t bitNumber;
562 u_int16_t word;
563
564 vnode_t vp = FTOV(filePtr);
565 BTreeControlBlockPtr btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
566 GenericLFBufPtr bp = NULL;
567 u_int32_t nodeNumber = 0;
568 BlockDescriptor mapNode = {0};
569 mapNode.buffer = nil;
570 mapNode.blockHeader = nil;
571
572 /* Iterate over map nodes. */
573 while (true)
574 {
575 err = GetMapNode (btreePtr, &mapNode, &mapPtr, &mapSize);
576 if (err)
577 {
578 err = MacToVFSError(err);
579 goto ErrorExit;
580 }
581
582 pos = mapPtr;
583 size = mapSize;
584 size >>= 1; /* convert to number of 16-bit words */
585
586 /* Iterate over 16-bit words in the map record. */
587 while (size--)
588 {
589 if (*pos != 0xFFFF) /* Anything free in this word? */
590 {
591 word = SWAP_BE16(*pos);
592
593 /* Iterate over bits in the word. */
594 for (bitNumber = 0, mask = 0x8000;
595 bitNumber < 16;
596 ++bitNumber, mask >>= 1)
597 {
598 if (word & mask)
599 continue; /* This node is in use. */
600
601 if (nodeNumber + bitNumber >= btreePtr->totalNodes)
602 {
603 /* We've processed all of the nodes. */
604 goto done;
605 }
606
607 /*
608 * Get a buffer full of zeros and write it to the unused
609 * node. Since we'll probably be writing a lot of nodes,
610 * bypass the journal (to avoid a transaction that's too
611 * big). Instead, this behaves more like clearing out
612 * nodes when extending a B-tree (eg., ClearBTNodes).
613 */
614 bp = lf_hfs_generic_buf_allocate(vp, nodeNumber + bitNumber, btreePtr->nodeSize, 0); // buf_getblk(vp, nodeNumber + bitNumber, btreePtr->nodeSize, 0, 0, BLK_META);
615 if (bp == NULL)
616 {
617 LFHFS_LOG(LEVEL_ERROR , "BTZeroUnusedNodes: unable to read node %u\n", nodeNumber + bitNumber);
618 err = EIO;
619 goto ErrorExit;
620 }
621
622 if (bp->uCacheFlags & GEN_BUF_WRITE_LOCK) {
623 /*
624 * This node is already part of a transaction and will be written when
625 * the transaction is committed, so don't write it here. If we did, then
626 * we'd hit a panic in hfs_vnop_bwrite because the B_LOCKED bit is still set.
627 */
628 lf_hfs_generic_buf_release(bp);
629 continue;
630 }
631
632 lf_hfs_generic_buf_clear(bp);
633
634 err = lf_hfs_generic_buf_write(bp);
635 if (err) {
636 goto ErrorExit;
637 }
638
639 lf_hfs_generic_buf_release(bp);
640 }
641 }
642
643 /* Go to the next word in the bitmap */
644 ++pos;
645 nodeNumber += 16;
646 }
647 }
648
649 ErrorExit:
650 done:
651 (void) ReleaseNode(btreePtr, &mapNode);
652
653 return err;
654 }
655