14 * $Log: allocation.c $
15 * Revision 14.8 1999/09/11 17:05:14 Michiel
18 * Revision 14.7 1999/05/14 11:31:34 Michiel
19 * Long filename support implemented; bugfixes
21 * Revision 14.6 1999/03/09 10:35:13 Michiel
22 * 00114: reserved roving op bit resolutie
24 * Revision 14.5 1998/09/27 11:26:37 Michiel
28 * Revision 14.4 1998/09/03 07:12:14 Michiel
30 * bugfixes 118, 121, 123 and superindexblocks and td64 support
32 * Revision 14.3 1997/03/03 22:04:04 Michiel
35 * Revision 14.2 1995/12/21 12:02:28 Michiel
36 * Using reserved roving from rootblock extension
39 * Revision 14.1 1995/11/15 15:10:44 Michiel
40 * Postponed operation implemented and bugfixed
41 * (FreeBlocksAC, RestoreAnodeChain)
43 * Revision 13.4 1995/11/07 14:48:30 Michiel
46 * Revision 13.3 1995/10/20 10:11:52 Michiel
47 * Anode reserved area adaptions (16.3)
49 * Revision 13.2 1995/10/04 17:15:52 Michiel
50 * preallocation for extended files implemented (in
53 * Revision 13.1 1995/10/03 10:47:40 Michiel
54 * merged develop tree: anodecache
56 * Revision 12.11 1995/10/03 09:56:57 Michiel
57 * AllocReservedBlock --> g->dirty
59 * Revision 12.10 1995/08/21 18:31:24 Michiel
60 * fixed deldir FreeBlocks problem: disk was not dirty after
61 * full tobefreed cache
63 * Revision 12.9 1995/08/21 04:17:36 Michiel
64 * fixed deldir related bug in FreeBlocks
66 * Revision 12.8 1995/08/04 04:12:43 Michiel
67 * extra CUTDOWN protection
69 * Revision 12.7 1995/07/21 06:51:11 Michiel
70 * Adapted FreeBlocks() to allow for the anodes to be kept (needed for deldir)
72 * Revision 12.6 1995/07/11 17:29:31 Michiel
73 * ErrorMsg () calls use messages.c variables now.
75 * Revision 12.5 1995/02/28 18:32:06 Michiel
77 * AllocReservedBlockSave update
79 * Revision 12.4 1995/02/15 16:43:39 Michiel
81 * Using new headers (struct.h & blocks.h)
83 * Revision 12.3 1995/01/29 07:34:57 Michiel
84 * Small UpdateFreeList improvement
85 * Raw res read/write and LOCK update
87 * Revision 12.2 1995/01/18 04:29:34 Michiel
88 * Bugfixes. Now ready for beta release.
90 * Revision 12.1 1995/01/08 15:14:15 Michiel
93 * Revision 11.2 1994/12/30 08:41:20 Michiel
97 * Revision 11.1 1994/12/28 09:41:29 Michiel
98 * Now using bitmaps for allocation
99 * also using allocation.h now
106 #define __USE_SYSBASE
108 #include <exec/types.h>
109 #include <exec/memory.h>
110 #include <exec/devices.h>
112 #include <dos/filehandler.h>
113 #include <proto/dos.h>
114 #include <proto/exec.h>
119 #include "ass_protos.h"
126 #include "allocation_protos.h"
127 #include "update_protos.h"
128 #include "anodes_protos.h"
129 #include "disk_protos.h"
130 #include "lru_protos.h"
131 #include "volume_protos.h"
132 #include "directory_protos.h"
137 static struct cindexblock
*NewBitmapIndexBlock(UWORD
, globaldata
* );
140 * Get bitmapblock seqnr
146 * currentvolume has to be ok.
148 VOID
InitAllocation (struct volumedata
*volume
, globaldata
*g
)
151 rootblock_t
*rootblock
= volume
->rootblk
;
155 alloc_data
.clean_blocksfree
= rootblock
->blocksfree
;
156 alloc_data
.alloc_available
= rootblock
->blocksfree
- rootblock
->alwaysfree
;
157 alloc_data
.longsperbmb
= LONGS_PER_BMB
;
159 t
= (volume
->numblocks
- (rootblock
->lastreserved
+ 1) + 31)/32;
160 t
= (t
+LONGS_PER_BMB
-1)/LONGS_PER_BMB
;
161 alloc_data
.no_bmb
= t
;
162 alloc_data
.bitmapstart
= rootblock
->lastreserved
+ 1;
163 memset (alloc_data
.tobefreed
, 0, TBF_CACHE_SIZE
*2*sizeof(ULONG
));
164 alloc_data
.tobefreed_index
= 0;
165 alloc_data
.tbf_resneed
= 0;
166 alloc_data
.res_bitmap
= (bitmapblock_t
*)(rootblock
+1); /* bitmap directly behind rootblock */
168 if (volume
->rblkextension
)
170 if (!(rootblock
->options
& MODE_EXTROVING
))
172 rootblock
->options
|= MODE_EXTROVING
;
174 volume
->rblkextension
->blk
.reserved_roving
*= 32;
176 alloc_data
.res_roving
= volume
->rblkextension
->blk
.reserved_roving
;
177 alloc_data
.rovingbit
= volume
->rblkextension
->blk
.rovingbit
;
181 alloc_data
.res_roving
= 0;
182 alloc_data
.rovingbit
= 0;
185 alloc_data
.numreserved
= (rootblock
->lastreserved
- rootblock
->firstreserved
+ 1)/(volume
->rescluster
);
186 alloc_data
.reservedtobefreed
= NULL
;
187 alloc_data
.rtbf_size
= 0;
188 alloc_data
.rtbf_index
= 0;
189 alloc_data
.res_alert
= 0;
193 ErrorMsg (AFS_ERROR_ANODE_INIT
, NULL
, g
);
201 BOOL
AllocateBlocks (ULONG anodenr
, ULONG size
, globaldata
*g
)
203 struct anodechain
*ac
;
206 if (!(ac
= GetAnodeChain (anodenr
, g
)))
209 success
= AllocateBlocksAC (ac
, size
, NULL
, g
);
210 DetachAnodeChain (ac
, g
);
216 * Allocate blocks to end of (cached) anodechain.
217 * If ref != NULL then online directory update enabled.
218 * Make sure the state is valid before you call this function!
220 * if FAIL, then a part of the needed blocks could already have been allocated
222 BOOL
AllocateBlocksAC (struct anodechain
*achain
, ULONG size
,
223 struct fileinfo
*ref
, globaldata
*g
)
225 ULONG nr
, field
, i
, j
, blocknr
, blocksdone
= 0;
227 FSIZE oldfilesize
= 0;
228 UWORD bmseqnr
, bmoffset
, oldlocknr
;
229 cbitmapblock_t
*bitmap
;
230 struct anodechainnode
*chnode
;
231 struct volumedata
*vol
= g
->currentvolume
;
232 BOOL extend
= FALSE
, updateroving
= TRUE
;
235 ENTER("AllocateBlocksAC");
237 /* Check if allocation possible */
238 if(alloc_data
.alloc_available
< size
)
241 /* check for sufficient clean freespace (freespace that doesn't overlap
242 * with the current state on disk)
244 if (alloc_data
.clean_blocksfree
< size
)
248 /* remember filesize in order to be able to cancel */
250 oldfilesize
= GetDEFileSize(ref
->direntry
, g
);
253 /* count number of fragments and decide on fileextend preallocation
254 * get anode to expand
256 chnode
= &achain
->head
;
257 for (i
=0; chnode
->next
; i
++)
258 chnode
= chnode
->next
;
260 extra
= min (256, i
*8);
261 if (chnode
->an
.blocknr
&& (chnode
->an
.blocknr
!= -1))
263 i
= chnode
->an
.blocknr
+ chnode
->an
.clustersize
- alloc_data
.bitmapstart
;
267 bmseqnr
= nr
/alloc_data
.longsperbmb
;
268 bmoffset
= nr
%alloc_data
.longsperbmb
;
269 bitmap
= GetBitmapBlock (bmseqnr
, g
);
270 field
= bitmap
->blk
.bitmap
[bmoffset
];
272 /* block directly behind file free ? */
277 /* if the position we want to allocate does not corresponds to the
278 * rovingpointer, the rovingpointer should not be updated
280 if (nr
!= g
->rootblock
->roving_ptr
)
281 updateroving
= false;
286 /* Get bitmap to allocate from */
289 nr
= g
->rootblock
->roving_ptr
;
290 bmseqnr
= nr
/alloc_data
.longsperbmb
;
291 bmoffset
= nr
%alloc_data
.longsperbmb
;
292 i
= alloc_data
.rovingbit
;
299 /* scan all bitmapblocks */
300 bitmap
= GetBitmapBlock(bmseqnr
, g
);
301 oldlocknr
= bitmap
->used
;
303 /* find all empty fields */
304 while (bmoffset
< alloc_data
.longsperbmb
)
306 field
= bitmap
->blk
.bitmap
[bmoffset
];
309 /* take all empty bits */
310 for ( ; i
<32; j
>>=1, i
++)
314 /* block is available, calc blocknr */
315 blocknr
= (bmseqnr
*alloc_data
.longsperbmb
+ bmoffset
)*32 + i
+
316 alloc_data
.bitmapstart
;
319 if (blocknr
>= vol
->numblocks
)
321 bmoffset
= alloc_data
.longsperbmb
;
328 /* uninitialized anode */
329 if (chnode
->an
.blocknr
== -1)
331 chnode
->an
.blocknr
= blocknr
;
332 chnode
->an
.clustersize
= 0;
336 /* check blockconnect */
337 else if (!(chnode
->an
.blocknr
+ chnode
->an
.clustersize
== blocknr
))
343 if (!(chnode
->next
= AllocMemP (sizeof(struct anodechainnode
), g
)))
348 SetDEFileSize(ref
->direntry
, oldfilesize
, g
);
349 MakeBlockDirty ((struct cachedblock
*)ref
->dirblock
, g
);
352 /* undo allocation so far */
353 FreeBlocksAC (achain
, blocksdone
, freeanodes
, g
);
357 anodenr
= AllocAnode (chnode
->an
.nr
, g
); /* should not go wrong! */
358 chnode
->an
.next
= anodenr
;
359 SaveAnode (&chnode
->an
, chnode
->an
.nr
, g
);
360 chnode
= chnode
->next
;
361 chnode
->an
.nr
= anodenr
;
362 chnode
->an
.blocknr
= blocknr
;
363 chnode
->an
.clustersize
= 0;
367 bitmap
->blk
.bitmap
[bmoffset
] &= ~j
; /* remove block from freelist */
368 chnode
->an
.clustersize
++; /* to file */
369 MakeBlockDirty ((struct cachedblock
*)bitmap
, g
);
371 /* update counters */
372 alloc_data
.clean_blocksfree
--;
373 alloc_data
.alloc_available
--;
376 /* update reference */
379 SetDEFileSize(ref
->direntry
, GetDEFileSize(ref
->direntry
, g
) + BLOCKSIZE
, g
);
380 if (IsUpdateNeeded(RTBF_POSTPONED_TH
))
382 /* make state valid and update disk */
383 MakeBlockDirty ((struct cachedblock
*)ref
->dirblock
, g
);
384 SaveAnode (&chnode
->an
, chnode
->an
.nr
, g
);
387 /* abort if running out of reserved blocks */
388 if (g
->rootblock
->reserved_free
<= RESFREE_THRESHOLD
)
391 SetDEFileSize(ref
->direntry
, oldfilesize
, g
);
392 MakeBlockDirty ((struct cachedblock
*)ref
->dirblock
, g
);
394 FreeBlocksAC (achain
, blocksdone
, freeanodes
, g
);
413 bitmap
->used
= oldlocknr
;
415 /* get ready for next block */
416 bmseqnr
= (bmseqnr
+1)%(alloc_data
.no_bmb
);
422 /* finish by saving anode and updating roving ptr */
423 SaveAnode (&chnode
->an
, chnode
->an
.nr
, g
);
425 /* add fileextension preallocation */
431 alloc_data
.rovingbit
= i
%32;
433 if (bmoffset
> alloc_data
.longsperbmb
)
435 bmoffset
-= alloc_data
.longsperbmb
;
436 bmseqnr
= (bmseqnr
+1)%(alloc_data
.no_bmb
);
441 alloc_data
.rovingbit
= i
;
444 g
->rootblock
->roving_ptr
= bmseqnr
*alloc_data
.longsperbmb
+ bmoffset
;
447 EXIT ("AllocateBlocksAC");
453 * Free all blocks in an anodechain? Use FreeBlocksAC(achain,ULONG_MAX,freetype,g)
457 * Frees blocks allocated with AllocateBlocks. Freed blocks are added
458 * to tobefreed list, and are not actually freed until UpdateFreeList
459 * is called. Frees from END of anodelist.
461 * 'freetype' specifies if the anodes involved should be freed (freeanodes) or
462 * not (keepanodes). In keepanodes mode the whole file (size >= filesize) should
463 * be deleted, since otherwise the anodes cannot consistently be kept (dual
464 * definition). In freeanodes mode the leading anode is not freed.
466 * VERSION23: uses tobedone fields. Because freeing blocks is idem-potent, fully
467 * repeating an interrupted operation after reboot is ok. The blocks should not
468 * be added to the blocksfree counter twice, however (see DoPostoned())
470 * -> all references that indicate the freed blocks must have been
473 static void RestoreAnodeChain (struct anodechain
*achain
, BOOL empty
, struct anodechainnode
*tail
, globaldata
*g
);
474 VOID
FreeBlocksAC (struct anodechain
*achain
, ULONG size
, enum freeblocktype freetype
, globaldata
*g
)
476 struct anodechainnode
*chnode
, *tail
;
480 struct crootblockextension
*rext
;
481 ULONG blocksdone
= 0;
483 ENTER("FreeBlocksAC");
485 i
= alloc_data
.tobefreed_index
;
488 /* store operation tobedone */
489 rext
= g
->currentvolume
->rblkextension
;
492 if (freetype
== keepanodes
)
493 rext
->blk
.tobedone
.operation_id
= PP_FREEBLOCKS_KEEP
;
495 rext
->blk
.tobedone
.operation_id
= PP_FREEBLOCKS_FREE
;
497 rext
->blk
.tobedone
.argument1
= achain
->head
.an
.nr
;
498 rext
->blk
.tobedone
.argument2
= size
;
499 rext
->blk
.tobedone
.argument3
= 0; /* blocks done (FREEBLOCKS_KEEP) */
500 MakeBlockDirty ((struct cachedblock
*)rext
, g
);
503 /* check if tobefreedcache is sufficiently large,
504 * otherwise updatedisk
506 for (chnode
= &achain
->head
; chnode
->next
; t
++)
507 chnode
= chnode
->next
;
509 if ((i
>0) && (t
+i
>= TBF_CACHE_SIZE
-1))
512 i
= alloc_data
.tobefreed_index
;
518 /* reverse order freeloop */
519 while (size
&& !empty
)
521 /* Get chainnode to free from */
522 chnode
= &achain
->head
;
523 while (chnode
->next
!= tail
)
524 chnode
= chnode
->next
;
526 l1
: /* get blocks to free */
527 if (chnode
->an
.clustersize
<= size
)
529 freeing
= chnode
->an
.clustersize
;
530 chnode
->an
.clustersize
= 0;
533 empty
= tail
== &achain
->head
;
537 /* anode is partially freed;
538 * should only be possible in freeanodes mode
541 chnode
->an
.clustersize
-= size
;
543 if (freetype
== freeanodes
)
544 SaveAnode (&chnode
->an
, chnode
->an
.nr
, g
);
547 /* and put them in the tobefreed list */
550 alloc_data
.tobefreed
[i
][TBF_BLOCKNR
] = chnode
->an
.blocknr
+ chnode
->an
.clustersize
;
551 alloc_data
.tobefreed
[i
++][TBF_SIZE
] = freeing
;
552 alloc_data
.tbf_resneed
+= 3 + freeing
/(32*alloc_data
.longsperbmb
);
553 alloc_data
.alloc_available
+= freeing
;
555 blocksdone
+= freeing
;
557 /* free anode if it is empty, we're supposed to and it is not the head */
558 if (!empty
&& freetype
== freeanodes
&& !chnode
->an
.clustersize
)
560 FreeAnode (chnode
->an
.nr
, g
);
561 FreeMemP (chnode
, g
);
565 /* check if intermediate update is needed
566 * (tobefreed cache full, low on reserved blocks etc)
568 if (i
>=TBF_CACHE_SIZE
|| IsUpdateNeeded(RTBF_POSTPONED_TH
))
570 alloc_data
.tobefreed_index
= i
;
572 if (rext
&& freetype
== freeanodes
)
574 /* make anodechain consistent */
575 RestoreAnodeChain (achain
, empty
, tail
, g
);
578 /* postponed op: finish operation later */
579 rext
->blk
.tobedone
.argument2
= size
;
582 /* postponed op: repeat operation later, but don't increase blocks free twice */
583 rext
->blk
.tobedone
.argument3
= blocksdone
;
585 MakeBlockDirty ((struct cachedblock
*)rext
, g
);
587 i
= alloc_data
.tobefreed_index
;
591 /* restore anode chain (both cached and on disk) */
592 if (freetype
== freeanodes
)
593 RestoreAnodeChain (achain
, empty
, tail
, g
);
595 /* cancel posponed operation */
598 rext
->blk
.tobedone
.operation_id
= 0;
599 rext
->blk
.tobedone
.argument1
= 0;
600 rext
->blk
.tobedone
.argument2
= 0;
601 rext
->blk
.tobedone
.argument3
= 0;
602 MakeBlockDirty ((struct cachedblock
*)rext
, g
);
605 /* update tobefreed index */
607 alloc_data
.tobefreed_index
= i
;
609 EXIT ("FreeBlocksAC");
613 /* local function of FreeBlocksAC
614 * restore anodechain (freeanode mode only)
616 static void RestoreAnodeChain (struct anodechain
*achain
, BOOL empty
,
617 struct anodechainnode
*tail
, globaldata
*g
)
619 struct anodechainnode
*chnode
;
623 achain
->head
.next
= NULL
;
624 achain
->head
.an
.clustersize
= 0;
625 achain
->head
.an
.blocknr
= ~0L;
626 achain
->head
.an
.next
= 0;
627 SaveAnode (&achain
->head
.an
, achain
->head
.an
.nr
, g
);
631 chnode
= &achain
->head
;
632 while (chnode
->next
!= tail
)
633 chnode
= chnode
->next
;
637 SaveAnode (&chnode
->an
, chnode
->an
.nr
, g
);
644 void UpdateFreeList (globaldata
*g
)
646 cbitmapblock_t
*bitmap
= 0;
648 ULONG longnr
, blocknr
, bmseqnr
, newbmseqnr
, bmoffset
, bitnr
;
650 /* sort the free list */
651 // not done right now
653 /* free all blocks in list */
655 for (i
=0; i
<alloc_data
.tobefreed_index
; i
++)
657 for ( blocknr
= alloc_data
.tobefreed
[i
][TBF_BLOCKNR
];
658 blocknr
< alloc_data
.tobefreed
[i
][TBF_SIZE
] + alloc_data
.tobefreed
[i
][TBF_BLOCKNR
];
661 /* now free block blocknr */
662 bitnr
= blocknr
- alloc_data
.bitmapstart
;
664 newbmseqnr
= longnr
/alloc_data
.longsperbmb
;
665 bmoffset
= longnr
%alloc_data
.longsperbmb
;
666 if(newbmseqnr
!= bmseqnr
)
668 bmseqnr
= newbmseqnr
;
669 bitmap
= GetBitmapBlock (bmseqnr
, g
);
671 bitmap
->blk
.bitmap
[bmoffset
] |= (1<<(31-(bitnr
%32)));
672 MakeBlockDirty ((struct cachedblock
*)bitmap
, g
);
675 alloc_data
.clean_blocksfree
+= alloc_data
.tobefreed
[i
][TBF_SIZE
];
678 /* update global data */
679 /* alloc_data.alloc_available should already be equal blocksfree - alwaysfree */
680 alloc_data
.tobefreed_index
= 0;
681 alloc_data
.tbf_resneed
= 0;
682 g
->rootblock
->blocksfree
= alloc_data
.clean_blocksfree
;
683 g
->currentvolume
->rootblockchangeflag
= TRUE
;
690 ULONG
AllocReservedBlock (globaldata
*g
)
692 struct volumedata
*vol
= g
->currentvolume
;
693 ULONG
*bitmap
= alloc_data
.res_bitmap
->bitmap
;
694 ULONG
*free
= &g
->rootblock
->reserved_free
;
698 ENTER("AllocReservedBlock");
700 /* Check if allocation possible
701 * (really necessary?)
706 j
= 31 - alloc_data
.res_roving
% 32;
707 for (i
= alloc_data
.res_roving
/ 32; i
<= (alloc_data
.numreserved
/32); i
++, j
=31)
711 ULONG field
= bitmap
[i
];
714 if (field
& (1 << j
))
716 blocknr
= g
->rootblock
->firstreserved
+ (i
*32+(31-j
))*vol
->rescluster
;
717 if (blocknr
<= g
->rootblock
->lastreserved
)
719 bitmap
[i
] &= ~(1 << j
);
720 g
->currentvolume
->rootblockchangeflag
= TRUE
;
723 alloc_data
.res_roving
= 32*i
+ (31 - j
);
724 DB(Trace(10,"AllocReservedBlock","allocated %ld\n", blocknr
));
732 /* end of bitmap reached. Reset roving pointer and try again
734 if (alloc_data
.res_roving
)
736 alloc_data
.res_roving
= 0;
737 return AllocReservedBlock (g
);
742 EXIT("AllocReservedBlock");
748 * Allocates a reserved block while keeping at least
749 * RESERVED_BUFFER reserved blocks free
751 ULONG
AllocReservedBlockSave (globaldata
*g
)
753 ULONG free
= g
->rootblock
->reserved_free
;
756 /* dirty blocks claim two blocks, so */
757 if (free
+ g
->blocks_dirty
< RESERVED_BUFFER
)
760 if (!(blocknr
= AllocReservedBlock(g
)))
763 blocknr
= AllocReservedBlock(g
);
771 * frees reserved block, or does nothing if blocknr = 0
773 VOID
FreeReservedBlock (ULONG blocknr
, globaldata
*g
)
777 if (blocknr
&& blocknr
<= g
->rootblock
->lastreserved
)
779 bitmap
= alloc_data
.res_bitmap
->bitmap
;
780 t
= (blocknr
- g
->rootblock
->firstreserved
)/g
->currentvolume
->rescluster
;
781 bitmap
[t
/32] |= (0x80000000UL
>> (t
%32));
782 g
->rootblock
->reserved_free
++;
783 g
->currentvolume
->rootblockchangeflag
= TRUE
;
787 /* this routine is analogous GetAnodeBlock()
788 * GetBitmapIndex is analogous GetIndexBlock()
790 struct cbitmapblock
*GetBitmapBlock(UWORD seqnr
, globaldata
*g
)
794 cindexblock_t
*indexblock
;
795 struct volumedata
*volume
= g
->currentvolume
;
798 for (bmb
= HeadOf(&volume
->bmblks
); bmb
->next
; bmb
=bmb
->next
)
800 if (bmb
->blk
.seqnr
== seqnr
)
807 /* not in cache, put it in */
808 /* get the indexblock */
809 temp
= divide (seqnr
, andata
.indexperblock
);
810 if (!(indexblock
= GetBitmapIndex(temp
/* & 0xffff */, g
)))
814 if (!(blocknr
= indexblock
->blk
.index
[temp
>>16]) ||
815 !(bmb
= (cbitmapblock_t
*)AllocLRU(g
)))
818 DB(Trace(10,"GetBitmapBlock", "seqnr = %ld blocknr = %lx\n", seqnr
, blocknr
));
821 if (RawRead((UBYTE
*)&bmb
->blk
, RESCLUSTER
, blocknr
, g
) != 0)
823 FreeLRU((struct cachedblock
*)bmb
);
828 if (bmb
->blk
.id
!= BMBLKID
)
831 args
[0] = bmb
->blk
.id
;
833 FreeLRU ((struct cachedblock
*)bmb
);
834 ErrorMsg (AFS_ERROR_DNV_WRONG_BMID
, args
, g
);
839 bmb
->volume
= volume
;
840 bmb
->blocknr
= blocknr
;
842 bmb
->changeflag
= FALSE
;
843 MinAddHead(&volume
->bmblks
, bmb
);
848 cindexblock_t
*GetBitmapIndex (UWORD nr
, globaldata
*g
)
851 cindexblock_t
*indexblk
;
852 struct volumedata
*volume
= g
->currentvolume
;
855 for (indexblk
= HeadOf(&volume
->bmindexblks
); indexblk
->next
; indexblk
=indexblk
->next
)
857 if (indexblk
->blk
.seqnr
== nr
)
864 /* not in cache, put it in */
865 if ((nr
> (g
->supermode
? MAXBITMAPINDEX
: MAXSMALLBITMAPINDEX
)) ||
866 !(blocknr
= volume
->rootblk
->idx
.large
.bitmapindex
[nr
]) ||
867 !(indexblk
= (struct cindexblock
*)AllocLRU(g
)) )
870 DB(Trace(10,"GetBitmapIndex", "seqnr = %ld blocknr = %lx\n", nr
, blocknr
));
872 if (RawRead((UBYTE
*)&indexblk
->blk
, RESCLUSTER
, blocknr
, g
) != 0) {
873 FreeLRU((struct cachedblock
*)indexblk
);
877 if (indexblk
->blk
.id
== BMIBLKID
)
879 indexblk
->volume
= volume
;
880 indexblk
->blocknr
= blocknr
;
881 indexblk
->used
= FALSE
;
882 indexblk
->changeflag
= FALSE
;
883 MinAddHead (&volume
->bmindexblks
, indexblk
);
887 ULONG args
[5] = { indexblk
->blk
.id
, BMIBLKID
, blocknr
, nr
, 0 };
888 FreeLRU ((struct cachedblock
*)indexblk
);
889 ErrorMsg (AFS_ERROR_DNV_WRONG_INDID
, args
, g
);
898 * the following routines (NewBitmapBlock & NewBitmapIndexBlock are
899 * primarily (read only) used by Format
901 struct cbitmapblock
*NewBitmapBlock (UWORD seqnr
, globaldata
*g
)
903 struct cbitmapblock
*blok
;
904 struct cindexblock
*indexblock
;
905 struct volumedata
*volume
= g
->currentvolume
;
906 ULONG indexblnr
, blocknr
, indexoffset
;
911 indexblnr
= seqnr
/andata
.indexperblock
;
912 indexoffset
= seqnr
%andata
.indexperblock
;
913 if (!(indexblock
= GetBitmapIndex(indexblnr
, g
)))
914 if (!(indexblock
= NewBitmapIndexBlock(indexblnr
, g
)))
917 oldlock
= indexblock
->used
;
919 if (!(blok
= (struct cbitmapblock
*)AllocLRU(g
)) ||
920 !(blocknr
= AllocReservedBlock(g
)) )
923 indexblock
->blk
.index
[indexoffset
] = blocknr
;
925 blok
->volume
= volume
;
926 blok
->blocknr
= blocknr
;
928 blok
->blk
.id
= BMBLKID
;
929 blok
->blk
.seqnr
= seqnr
;
930 blok
->changeflag
= TRUE
;
933 bitmap
= blok
->blk
.bitmap
;
934 for (i
= 0; i
<alloc_data
.longsperbmb
; i
++)
937 MinAddHead(&volume
->bmblks
, blok
);
938 MakeBlockDirty((struct cachedblock
*)indexblock
, g
);
939 indexblock
->used
= oldlock
; // unlock;
944 static struct cindexblock
*NewBitmapIndexBlock (UWORD seqnr
, globaldata
*g
)
946 struct cindexblock
*blok
;
947 struct volumedata
*volume
= g
->currentvolume
;
949 if (seqnr
> (g
->supermode
? MAXBITMAPINDEX
: MAXSMALLBITMAPINDEX
) ||
950 !(blok
= (struct cindexblock
*)AllocLRU(g
)))
953 if (!(g
->rootblock
->idx
.large
.bitmapindex
[seqnr
] = AllocReservedBlock (g
)))
955 FreeLRU((struct cachedblock
*)blok
);
959 volume
->rootblockchangeflag
= TRUE
;
961 blok
->volume
= volume
;
962 blok
->blocknr
= volume
->rootblk
->idx
.large
.bitmapindex
[seqnr
];
964 blok
->blk
.id
= BMIBLKID
;
965 blok
->blk
.seqnr
= seqnr
;
966 blok
->changeflag
= TRUE
;
967 MinAddHead(&volume
->bmindexblks
, blok
);