]>
Commit | Line | Data |
---|---|---|
de8ee011 A |
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 |