]> git.saurik.com Git - apple/hfs.git/blob - core/BTreeAllocate.c
d9b3b6379408748d8553afcea2efc38d577fc03f
[apple/hfs.git] / core / BTreeAllocate.c
1 /*
2 * Copyright (c) 2000-2003, 2005-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 File: BTreeAllocate.c
30
31 Contains: BTree Node Allocation routines for the BTree Module.
32
33 Version: xxx put the technology version here xxx
34
35 Written by: Gordon Sheridan and Bill Bruffey
36
37 Copyright: (c) 1992-1999 by Apple Inc., all rights reserved.
38
39 File Ownership:
40
41 DRI: Don Brady
42
43 Other Contact: Mark Day
44
45 Technology: File Systems
46
47 Writers:
48
49 (djb) Don Brady
50 (ser) Scott Roberts
51 (msd) Mark Day
52
53 Change History (most recent first):
54
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
59
60 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
61 <HFS1> 12/19/96 djb first checked in
62
63 History applicable to original Scarecrow Design:
64
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.
69
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
79
80 */
81
82 #include "hfs_btreeio.h"
83 #include "hfs_endian.h"
84 #include "BTreesPrivate.h"
85
86 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
87
88 static OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
89 BlockDescriptor *nodePtr,
90 u_int16_t **mapPtr,
91 u_int16_t *mapSize );
92
93 /////////////////////////////////////////////////////////////////////////////////
94
95 /*-------------------------------------------------------------------------------
96
97 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
98
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.
102
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
108 appropriately.
109
110 Input: btreePtr - pointer to control block for BTree file
111
112 Output: nodeNum - number of node allocated
113
114
115 Result: noErr - success
116 fsBTNoMoreMapNodesErr - no free blocks were found
117 != noErr - failure
118 -------------------------------------------------------------------------------*/
119
120 OSStatus AllocateNode (BTreeControlBlockPtr btreePtr, u_int32_t *nodeNum)
121 {
122 OSStatus err;
123 BlockDescriptor node;
124 u_int16_t *mapPtr, *pos;
125 u_int16_t mapSize, size;
126 u_int16_t freeWord;
127 u_int16_t mask;
128 u_int16_t bitOffset;
129 u_int32_t nodeNumber;
130
131
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;
136
137 while (true)
138 {
139 err = GetMapNode (btreePtr, &node, &mapPtr, &mapSize);
140 M_ExitOnError (err);
141
142 // XXXdbg
143 ModifyBlockStart(btreePtr->fileRefNum, &node);
144
145 //////////////////////// Find Word with Free Bit ////////////////////////////
146
147 pos = mapPtr;
148 size = mapSize;
149 size >>= 1; // convert to number of words
150 //\80\80 assumes mapRecords contain an integral number of words
151
152 while ( size-- )
153 {
154 if ( *pos++ != 0xFFFF ) // assume test fails, and increment pos
155 break;
156 }
157
158 --pos; // whoa! backup
159
160 if (*pos != 0xFFFF) // hey, we got one!
161 break;
162
163 nodeNumber += mapSize << 3; // covert to number of bits (nodes)
164 }
165
166 ///////////////////////// Find Free Bit in Word /////////////////////////////
167
168 freeWord = SWAP_BE16 (*pos);
169 bitOffset = 15;
170 mask = 0x8000;
171
172 do {
173 if ( (freeWord & mask) == 0)
174 break;
175 mask >>= 1;
176 } while (--bitOffset);
177
178 ////////////////////// Calculate Free Node Number ///////////////////////////
179
180 nodeNumber += ((pos - mapPtr) << 4) + (15 - bitOffset); // (pos-mapPtr) = # of words!
181
182
183 ///////////////////////// Check for End of Map //////////////////////////////
184
185 if (nodeNumber >= btreePtr->totalNodes)
186 {
187 err = fsBTFullErr;
188 goto ErrorExit;
189 }
190
191 /////////////////////////// Allocate the Node ///////////////////////////////
192
193 *pos |= SWAP_BE16 (mask); // set the map bit for the node
194
195 err = UpdateNode (btreePtr, &node, 0, kLockTransaction);
196 M_ExitOnError (err);
197
198 --btreePtr->freeNodes;
199 M_BTreeHeaderDirty(btreePtr);
200
201 /* Account for allocations from node reserve */
202 BTUpdateReserve(btreePtr, 1);
203
204 *nodeNum = nodeNumber;
205
206 return noErr;
207
208 ////////////////////////////////// Error Exit ///////////////////////////////////
209
210 ErrorExit:
211
212 (void) ReleaseNode (btreePtr, &node);
213 *nodeNum = 0;
214
215 return err;
216 }
217
218
219
220 /*-------------------------------------------------------------------------------
221
222 Routine: FreeNode - Clear allocation bit for node.
223
224 Function: Finds the bit representing the node specified by nodeNum in the node
225 map and clears the bit.
226
227
228 Input: btreePtr - pointer to control block for BTree file
229 nodeNum - number of node to mark free
230
231 Output: none
232
233 Result: noErr - success
234 fsBTNoMoreMapNodesErr - node number is beyond end of node map
235 != noErr - GetNode or ReleaseNode encountered some difficulty
236 -------------------------------------------------------------------------------*/
237
238 OSStatus FreeNode (BTreeControlBlockPtr btreePtr, u_int32_t nodeNum)
239 {
240 OSStatus err;
241 BlockDescriptor node;
242 u_int32_t nodeIndex;
243 u_int16_t mapSize = 0;
244 u_int16_t *mapPos = NULL;
245 u_int16_t bitOffset;
246
247
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;
252
253 while (nodeNum >= nodeIndex)
254 {
255 err = GetMapNode (btreePtr, &node, &mapPos, &mapSize);
256 M_ExitOnError (err);
257
258 nodeIndex += mapSize << 3; // covert to number of bits (nodes)
259 }
260
261 //////////////////////////// Mark Node Free /////////////////////////////////
262
263 // XXXdbg
264 ModifyBlockStart(btreePtr->fileRefNum, &node);
265
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
269
270 M_SWAP_BE16_ClearBitNum (*mapPos, bitOffset); // clear it
271
272 err = UpdateNode (btreePtr, &node, 0, kLockTransaction);
273 M_ExitOnError (err);
274
275 ++btreePtr->freeNodes;
276 M_BTreeHeaderDirty(btreePtr);
277
278 return noErr;
279
280 ErrorExit:
281
282 (void) ReleaseNode (btreePtr, &node);
283
284 return err;
285 }
286
287
288
289 /*-------------------------------------------------------------------------------
290
291 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
292
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
297 taken.
298
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.
301
302 Input: btreePtr - pointer to control block for BTree file
303 newTotalNodes - total number of nodes the B*Tree is to extended to
304
305 Output: none
306
307 Result: noErr - success
308 != noErr - failure
309 -------------------------------------------------------------------------------*/
310
311 OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr,
312 u_int32_t newTotalNodes )
313 {
314 OSStatus err;
315 FCB *filePtr;
316 FSSize minEOF, maxEOF;
317 u_int16_t nodeSize;
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;
325 u_int16_t *mapPos;
326 u_int16_t *mapStart;
327 u_int16_t mapSize;
328 u_int16_t mapNodeRecSize;
329 u_int32_t bitInWord, bitInRecord;
330 u_int16_t mapIndex;
331
332
333 oldTotalNodes = btreePtr->totalNodes;
334 if (newTotalNodes <= oldTotalNodes) // we're done!
335 return noErr;
336
337 nodeSize = btreePtr->nodeSize;
338 filePtr = GetFileControlBlock(btreePtr->fileRefNum);
339
340 mapNode.buffer = nil;
341 mapNode.blockHeader = nil;
342 newNode.buffer = nil;
343 newNode.blockHeader = nil;
344
345 mapNodeRecSize = nodeSize - sizeof(BTNodeDescriptor) - 6; // 2 bytes of free space (see note)
346
347
348 //////////////////////// Count Bits In Node Map /////////////////////////////
349
350 totalMapBits = 0;
351 do {
352 err = GetMapNode (btreePtr, &mapNode, &mapStart, &mapSize);
353 M_ExitOnError (err);
354
355 mapBits = mapSize << 3; // mapSize (in bytes) * 8
356 recStartBit = totalMapBits; // bit number of first bit in map record
357 totalMapBits += mapBits;
358
359 } while ( ((BTNodeDescriptor*)mapNode.buffer)->fLink != 0 );
360
361 #if DEBUG
362 if (totalMapBits != CalcMapBits (btreePtr))
363 Panic ("ExtendBTree: totalMapBits != CalcMapBits");
364 #endif
365
366 /////////////////////// Extend LEOF If Necessary ////////////////////////////
367
368 minEOF = (u_int64_t)newTotalNodes * (u_int64_t)nodeSize;
369 if ( (u_int64_t)filePtr->fcbEOF < minEOF )
370 {
371 maxEOF = (u_int64_t)0x7fffffffLL * (u_int64_t)nodeSize;
372
373 err = btreePtr->setEndOfForkProc (btreePtr->fileRefNum, minEOF, maxEOF);
374 M_ExitOnError (err);
375 }
376
377
378 //////////////////// Calc New Total Number Of Nodes /////////////////////////
379
380 newTotalNodes = filePtr->fcbEOF / nodeSize; // hack!
381 // do we wish to perform any verification of newTotalNodes at this point?
382
383 btreePtr->totalNodes = newTotalNodes; // do we need to update freeNodes here too?
384
385
386 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
387
388 newMapNodes = 0;
389 if (newTotalNodes > totalMapBits)
390 {
391 newMapNodes = (((newTotalNodes - totalMapBits) >> 3) / mapNodeRecSize) + 1;
392 firstNewMapNodeNum = oldTotalNodes;
393 lastNewMapNodeNum = firstNewMapNodeNum + newMapNodes - 1;
394 }
395 else
396 {
397 err = ReleaseNode (btreePtr, &mapNode);
398 M_ExitOnError (err);
399
400 goto Success;
401 }
402
403
404 /////////////////////// Initialize New Map Nodes ////////////////////////////
405 // XXXdbg - this is the correct place for this:
406 ModifyBlockStart(btreePtr->fileRefNum, &mapNode);
407
408 ((BTNodeDescriptor*)mapNode.buffer)->fLink = firstNewMapNodeNum;
409
410 nodeNum = firstNewMapNodeNum;
411 while (true)
412 {
413 err = GetNewNode (btreePtr, nodeNum, &newNode);
414 M_ExitOnError (err);
415
416 // XXXdbg
417 ModifyBlockStart(btreePtr->fileRefNum, &newNode);
418
419 ((NodeDescPtr)newNode.buffer)->numRecords = 1;
420 ((NodeDescPtr)newNode.buffer)->kind = kBTMapNode;
421
422 // set free space offset
423 *(u_int16_t *)((Ptr)newNode.buffer + nodeSize - 4) = nodeSize - 6;
424
425 if (nodeNum++ == lastNewMapNodeNum)
426 break;
427
428 ((BTNodeDescriptor*)newNode.buffer)->fLink = nodeNum; // point to next map node
429
430 err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction);
431 M_ExitOnError (err);
432 }
433
434 err = UpdateNode (btreePtr, &newNode, 0, kLockTransaction);
435 M_ExitOnError (err);
436
437
438 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
439
440 nodeNum = firstNewMapNodeNum;
441 do {
442 bitInRecord = nodeNum - recStartBit;
443
444 while (bitInRecord >= mapBits)
445 {
446 nextNodeNum = ((NodeDescPtr)mapNode.buffer)->fLink;
447 if ( nextNodeNum == 0)
448 {
449 err = fsBTNoMoreMapNodesErr;
450 goto ErrorExit;
451 }
452
453 err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction);
454 M_ExitOnError (err);
455
456 err = GetNode (btreePtr, nextNodeNum, 0, &mapNode);
457 M_ExitOnError (err);
458
459 // XXXdbg
460 ModifyBlockStart(btreePtr->fileRefNum, &mapNode);
461
462 mapIndex = 0;
463
464 mapStart = (u_int16_t *) GetRecordAddress (btreePtr, mapNode.buffer, mapIndex);
465 mapSize = GetRecordSize (btreePtr, mapNode.buffer, mapIndex);
466
467 #if DEBUG
468 if (mapSize != M_MapRecordSize (btreePtr->nodeSize) )
469 {
470 Panic ("ExtendBTree: mapSize != M_MapRecordSize");
471 }
472 #endif
473
474 mapBits = mapSize << 3; // mapSize (in bytes) * 8
475 recStartBit = totalMapBits; // bit number of first bit in map record
476 totalMapBits += mapBits;
477
478 bitInRecord = nodeNum - recStartBit;
479 }
480
481 mapPos = mapStart + ((nodeNum - recStartBit) >> 4);
482 bitInWord = 15 - ((nodeNum - recStartBit) & 0x0000000F);
483
484 M_SWAP_BE16_SetBitNum (*mapPos, bitInWord);
485
486 ++nodeNum;
487
488 } while (nodeNum <= lastNewMapNodeNum);
489
490 err = UpdateNode (btreePtr, &mapNode, 0, kLockTransaction);
491 M_ExitOnError (err);
492
493
494 //////////////////////////////// Success ////////////////////////////////////
495
496 Success:
497
498 btreePtr->totalNodes = newTotalNodes;
499 btreePtr->freeNodes += (newTotalNodes - oldTotalNodes) - newMapNodes;
500
501 M_BTreeHeaderDirty(btreePtr);
502
503 /* Force the b-tree header changes to disk */
504 (void) UpdateHeader (btreePtr, true);
505
506 return noErr;
507
508
509 ////////////////////////////// Error Exit ///////////////////////////////////
510
511 ErrorExit:
512
513 (void) ReleaseNode (btreePtr, &mapNode);
514 (void) ReleaseNode (btreePtr, &newNode);
515
516 return err;
517 }
518
519
520
521 /*-------------------------------------------------------------------------------
522
523 Routine: GetMapNode - Get the next map node and pointer to the map record.
524
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
527 node is retrieved.
528
529
530 Input: btreePtr - pointer to control block for BTree file
531 nodePtr - pointer to a BlockDescriptor of a map node
532
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
536
537 Result: noErr - success
538 fsBTNoMoreMapNodesErr - we've run out of map nodes
539 fsBTInvalidNodeErr - bad node, or not node type kMapNode
540 != noErr - failure
541 -------------------------------------------------------------------------------*/
542
543 static
544 OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
545 BlockDescriptor *nodePtr,
546 u_int16_t **mapPtr,
547 u_int16_t *mapSize )
548 {
549 OSStatus err;
550 u_int16_t mapIndex;
551 u_int32_t nextNodeNum;
552
553 if (nodePtr->buffer != nil) // if iterator is valid...
554 {
555 nextNodeNum = ((NodeDescPtr)nodePtr->buffer)->fLink;
556 if (nextNodeNum == 0)
557 {
558 err = fsBTNoMoreMapNodesErr;
559 goto ErrorExit;
560 }
561
562 err = ReleaseNode (btreePtr, nodePtr);
563 M_ExitOnError (err);
564
565 err = GetNode (btreePtr, nextNodeNum, 0, nodePtr);
566 M_ExitOnError (err);
567
568 if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTMapNode)
569 {
570 err = fsBTBadNodeType;
571 goto ErrorExit;
572 }
573
574 ++btreePtr->numMapNodesRead;
575 mapIndex = 0;
576 } else {
577 err = GetNode (btreePtr, kHeaderNodeNum, 0, nodePtr);
578 M_ExitOnError (err);
579
580 if ( ((NodeDescPtr)nodePtr->buffer)->kind != kBTHeaderNode)
581 {
582 err = fsBTInvalidHeaderErr; //\80\80 or fsBTBadNodeType
583 goto ErrorExit;
584 }
585
586 mapIndex = 2;
587 }
588
589
590 *mapPtr = (u_int16_t *) GetRecordAddress (btreePtr, nodePtr->buffer, mapIndex);
591 *mapSize = GetRecordSize (btreePtr, nodePtr->buffer, mapIndex);
592
593 return noErr;
594
595
596 ErrorExit:
597
598 (void) ReleaseNode (btreePtr, nodePtr);
599
600 *mapPtr = nil;
601 *mapSize = 0;
602
603 return err;
604 }
605
606
607
608 ////////////////////////////////// CalcMapBits //////////////////////////////////
609
610 u_int32_t CalcMapBits (BTreeControlBlockPtr btreePtr)
611 {
612 u_int32_t mapBits;
613
614 mapBits = M_HeaderMapRecordSize (btreePtr->nodeSize) << 3;
615
616 while (mapBits < btreePtr->totalNodes)
617 mapBits += M_MapRecordSize (btreePtr->nodeSize) << 3;
618
619 return mapBits;
620 }
621
622
623 /*-------------------------------------------------------------------------------
624 Routine: BTZeroUnusedNodes
625
626 Function: Write zeros to all nodes in the B-tree that are not currently in use.
627 -------------------------------------------------------------------------------*/
628 int
629 BTZeroUnusedNodes(FCB *filePtr)
630 {
631 int err;
632 vnode_t vp;
633 BTreeControlBlockPtr btreePtr;
634 BlockDescriptor mapNode;
635 buf_t bp;
636 u_int32_t nodeNumber;
637 u_int16_t *mapPtr, *pos;
638 u_int16_t mapSize, size;
639 u_int16_t mask;
640 u_int16_t bitNumber;
641 u_int16_t word;
642 int numWritten;
643
644 vp = FTOV(filePtr);
645 btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
646 bp = NULL;
647 nodeNumber = 0;
648 mapNode.buffer = nil;
649 mapNode.blockHeader = nil;
650 numWritten = 0;
651
652 /* Iterate over map nodes. */
653 while (true)
654 {
655 err = GetMapNode (btreePtr, &mapNode, &mapPtr, &mapSize);
656 if (err)
657 {
658 err = MacToVFSError(err);
659 goto ErrorExit;
660 }
661
662 pos = mapPtr;
663 size = mapSize;
664 size >>= 1; /* convert to number of 16-bit words */
665
666 /* Iterate over 16-bit words in the map record. */
667 while (size--)
668 {
669 if (*pos != 0xFFFF) /* Anything free in this word? */
670 {
671 word = SWAP_BE16(*pos);
672
673 /* Iterate over bits in the word. */
674 for (bitNumber = 0, mask = 0x8000;
675 bitNumber < 16;
676 ++bitNumber, mask >>= 1)
677 {
678 if (word & mask)
679 continue; /* This node is in use. */
680
681 if (nodeNumber + bitNumber >= btreePtr->totalNodes)
682 {
683 /* We've processed all of the nodes. */
684 goto done;
685 }
686
687 /*
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).
693 */
694 bp = buf_getblk(vp, nodeNumber + bitNumber, btreePtr->nodeSize, 0, 0, BLK_META);
695 if (bp == NULL)
696 {
697 printf("hfs: BTZeroUnusedNodes: unable to read node %u\n", nodeNumber + bitNumber);
698 err = EIO;
699 goto ErrorExit;
700 }
701
702 if (buf_flags(bp) & B_LOCKED) {
703 /*
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.
707 */
708 buf_brelse(bp);
709 continue;
710 }
711
712 buf_clear(bp);
713 buf_markaged(bp);
714
715 /*
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.
722
723 */
724 ++numWritten;
725 if (numWritten % 32 == 0) {
726 err = VNOP_BWRITE(bp);
727 if (err) {
728 goto ErrorExit;
729 }
730 }
731 else {
732 buf_bawrite(bp);
733 }
734 }
735 }
736
737 /* Go to the next word in the bitmap */
738 ++pos;
739 nodeNumber += 16;
740 }
741 }
742
743 ErrorExit:
744 done:
745 (void) ReleaseNode(btreePtr, &mapNode);
746
747 return err;
748 }