tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / rom / filesys / pfs3 / fs / anodes.c
blobd1ef6e3e1f9b4636a3ea6bccb29d8b6e67877676
1 /* $Id$ */
2 /* $Log: anodes.c $
3 * Revision 13.9 1998/09/27 11:26:37 Michiel
4 * bugfixes
5 * ErrorMsg param
7 * Revision 13.8 1998/09/03 07:12:14 Michiel
8 * versie 17.4
9 * bugfixes 118, 121, 123 and superindexblocks and td64 support
11 * Revision 13.7 1997/03/03 22:04:04 Michiel
12 * Release 16.21
14 * Revision 13.6 1996/03/07 10:10:14 Michiel
15 * format bug (wt)
16 * realloc anodebitmap bug (wt)
18 * Revision 13.5 1996/01/30 12:50:15 Michiel
19 * --- working tree overlap ---
20 * anodebitmap implemented
22 * Revision 13.4 1995/11/07 14:50:07 Michiel
23 * NewAnodeBlock: lock clear after use
24 * GetAnodeBlock: no lock on indexblock
26 * Revision 13.3 1995/10/20 10:10:58 Michiel
27 * Anode reserved area adaptions (16.3)
28 * --> AllocAnode changed
30 * Revision 13.2 1995/10/04 09:00:30 Michiel
31 * Bug in CorrectAnodeAC (instruction order) fixed
33 * Revision 13.1 1995/10/03 10:48:07 Michiel
34 * merged develop tree: anodecache
36 * Revision 12.9 1995/07/11 17:29:31 Michiel
37 * ErrorMsg () calls use messages.c variables now.
39 * Revision 12.8 1995/06/19 09:48:44 Michiel
40 * small optimise and a couple of debug statements in GetAnodeBlock
42 * Revision 12.7 1995/06/04 06:06:38 Michiel
43 * assembly divide function used
45 * Revision 12.6 1995/02/28 18:30:49 Michiel
46 * Splitted mode and UWORD optimize
48 * Revision 12.5 1995/02/15 16:43:39 Michiel
49 * Release version
50 * Using new headers (struct.h & blocks.h)
52 * Revision 12.4 1995/01/29 07:34:57 Michiel
53 * Reserved Raw read/write and locking change
55 * Revision 12.3 1995/01/24 09:52:21 Michiel
56 * Cache hashing added
58 * Revision 12.2 1995/01/18 04:29:34 Michiel
59 * Bugfixes. Now ready for beta release.
61 * Revision 12.1 1995/01/08 15:41:09 Michiel
62 * Compiled
64 * Revision 11.2 1994/12/30 11:21:40 Michiel
65 * adapted to bitmaps
66 * Compilable
68 * Revision 11.1 1994/12/01 11:31:25 Michiel
69 * Added indexblocks.
70 * Uses new anodes.h include.
72 * Revision 10.2 1994/10/27 11:33:30 Michiel
73 * Added some MakeBlockDirty() calls in anode routines
75 * Revision 10.1 1994/10/24 11:16:28 Michiel
76 * first RCS revision
77 * */
79 /* 9-10-94 Added usage of g->curranblk.
80 * Added InitAnodes()
81 * */
83 #define __USE_SYSBASE
85 #include <exec/types.h>
86 #include <exec/memory.h>
87 #include <dos/dos.h>
88 #include <stdlib.h>
89 #include "debug.h"
91 #include "blocks.h"
92 #include "struct.h"
93 #include "anodes_protos.h"
94 #include "allocation_protos.h"
95 #include "disk_protos.h"
96 #include "lru_protos.h"
97 #include "update_protos.h"
98 #include "ass_protos.h"
99 #include "volume_protos.h"
102 * Contents (local functions)
104 static struct anodechain *MakeAnodeChain (ULONG anodenr, globaldata *g);
105 static struct anodechain *FindAnodeChain (ULONG anodenr, globaldata *g);
106 static void FreeAnodeChain (struct anodechain *chain, globaldata *g);
107 static struct canodeblock *big_GetAnodeBlock(UWORD seqnr, globaldata *g);
108 static struct canodeblock *big_NewAnodeBlock(UWORD , globaldata * );
109 static struct cindexblock *NewIndexBlock(UWORD , globaldata * );
110 static struct cindexblock *NewSuperBlock (UWORD seqnr, globaldata *g);
111 static void MakeAnodeBitmap (BOOL formatting, globaldata *g);
112 static void ReallocAnodeBitmap (ULONG newseqnr, globaldata *g);
115 /*********************************************************************/
116 /* Anode cache functions */
117 /*********************************************************************/
120 * Get anodechain of anodenr, making it if necessary.
121 * Returns chain or NULL for failure
123 struct anodechain *GetAnodeChain(ULONG anodenr, globaldata *g)
125 struct anodechain *ac;
127 if (!(ac = FindAnodeChain(anodenr, g)))
128 ac = MakeAnodeChain(anodenr, g);
129 if (ac)
130 ac->refcount++;
132 return ac;
136 * Called when a reference to an anodechain ceases to exist
138 void DetachAnodeChain(struct anodechain *chain, globaldata *g)
140 chain->refcount--;
141 if (!chain->refcount)
142 FreeAnodeChain(chain, g);
147 * makes anodechain
149 static struct anodechain *MakeAnodeChain(ULONG anodenr, globaldata *g)
151 struct anodechain *ac;
152 struct anodechainnode *node, *newnode;
154 ENTER("MakeAnodeChain");
155 if (!(ac = AllocMemP(sizeof(struct anodechain), g)))
156 return NULL;
158 ac->refcount = 0;
159 node = &ac->head;
160 GetAnode(&node->an, anodenr, g);
161 while (node->an.next)
163 if (!(newnode = AllocMemP(sizeof(struct anodechainnode), g)))
164 goto failure;
165 node->next = newnode;
166 GetAnode(&newnode->an, node->an.next, g);
167 node = newnode;
170 MinAddHead(&g->currentvolume->anodechainlist, ac);
171 return ac;
173 failure:
174 FreeAnodeChain(ac, g);
175 return NULL;
180 * search anodechain.
181 * Return anodechain found, or 0 if not found
183 static struct anodechain *FindAnodeChain (ULONG anodenr, globaldata *g)
185 struct anodechain *chain;
187 ENTER("FindAnodeChain");
188 for (chain = HeadOf(&g->currentvolume->anodechainlist); chain->next; chain=chain->next)
190 if (chain->head.an.nr == anodenr)
191 return chain;
194 return NULL;
198 * Free an anodechain. Anodechain will be removed from list if it is
199 * in the list.
201 static void FreeAnodeChain (struct anodechain *chain, globaldata *g)
203 struct anodechainnode *node, *nextnode;
205 ENTER("FreeAnodeChain");
206 for (node=chain->head.next; node; node=nextnode)
208 nextnode = node->next;
209 FreeMemP (node, g);
212 if (chain->next)
213 MinRemove (chain);
215 FreeMemP (chain, g);
219 * Tries to fetch the block that follows after anodeoffset. Returns success,
220 * updates anodechainpointer and anodeoffset. If failed, acnode will point to
221 * the tail of the anodechain
223 BOOL NextBlockAC (struct anodechainnode **acnode, ULONG *anodeoffset, globaldata *g)
225 (*anodeoffset)++;
226 return CorrectAnodeAC (acnode, anodeoffset, g);
230 * Correct anodeoffset overflow. Corrects anodechainnode pointer pointed to by acnode.
231 * Returns success. If correction was not possible, acnode will be the tail of the
232 * anodechain. Anodeoffset is updated to point to a block within the current
233 * anodechainnode.
235 BOOL CorrectAnodeAC (struct anodechainnode **acnode, ULONG *anodeoffset, globaldata *g)
237 while (*anodeoffset >= (*acnode)->an.clustersize)
239 if (!(*acnode)->next)
240 return DOSFALSE;
242 *anodeoffset -= (*acnode)->an.clustersize;
243 *acnode = (*acnode)->next;
246 return DOSTRUE;
250 /*********************************************************************/
251 /* Main functions */
252 /*********************************************************************/
255 * Tries to fetch the block that follows after anodeoffset. Returns
256 * success and anodeoffset is updated.
258 BOOL NextBlock (struct canode *anode, ULONG *anodeoffset, globaldata *g)
260 (*anodeoffset)++;
261 return CorrectAnode(anode, anodeoffset, g);
265 * Correct anodeoffset overflow
267 BOOL CorrectAnode (struct canode *anode, ULONG *anodeoffset, globaldata *g)
269 while(*anodeoffset >= anode->clustersize)
271 if(!anode->next)
272 return DOSFALSE;
274 *anodeoffset -= anode->clustersize;
275 GetAnode(anode, anode->next, g);
278 return DOSTRUE;
282 * Retrieve an anode from disk
284 void GetAnode (struct canode *anode, ULONG anodenr, globaldata *g)
286 ULONG temp;
287 UWORD seqnr, anodeoffset;
288 struct canodeblock *ablock;
290 if(g->anodesplitmode)
292 anodenr_t *split = (anodenr_t *)&anodenr;
293 seqnr = split->seqnr;
294 anodeoffset = split->offset;
296 else
298 temp = divide(anodenr, andata.anodesperblock);
299 seqnr = temp; // 1e block = 0
300 anodeoffset = temp >> 16;
303 ablock = GetAnodeBlock(seqnr, g);
304 if(ablock)
306 anode->clustersize = ablock->blk.nodes[anodeoffset].clustersize;
307 anode->blocknr = ablock->blk.nodes[anodeoffset].blocknr;
308 anode->next = ablock->blk.nodes[anodeoffset].next;
309 anode->nr = anodenr;
311 else
313 anode->clustersize = anode->next = 0;
314 anode->blocknr = ~0;
315 // ErrorMsg (AFS_ERROR_DNV_ALLOC_INFO, NULL);
320 /* saves and anode..
322 void SaveAnode (struct canode *anode, ULONG anodenr, globaldata *g)
324 ULONG temp;
325 UWORD seqnr, anodeoffset;
326 struct canodeblock *ablock;
328 if (g->anodesplitmode)
330 anodenr_t *split = (anodenr_t *)&anodenr;
331 seqnr = split->seqnr;
332 anodeoffset = split->offset;
334 else
336 temp = divide(anodenr,andata.anodesperblock);
337 seqnr = temp; // 1e block = 0
338 anodeoffset = temp >> 16;
341 anode->nr = anodenr;
343 /* Save Anode */
344 ablock = GetAnodeBlock (seqnr, g);
345 if (ablock)
347 ablock->blk.nodes[anodeoffset].clustersize = anode->clustersize;
348 ablock->blk.nodes[anodeoffset].blocknr = anode->blocknr;
349 ablock->blk.nodes[anodeoffset].next = anode->next;
350 MakeBlockDirty ((struct cachedblock *)ablock, g);
352 else
354 DB(Trace(5,"SaveAnode","ERR: anode = 0x%lx\n",anodenr));
355 // ErrorMsg (AFS_ERROR_DNV_ALLOC_BLOCK, NULL);
360 /* allocates an anode and marks it as reserved
361 * connect is anodenr to connect to (0 = no connection)
363 ULONG AllocAnode (ULONG connect, globaldata *g)
365 WORD i, j, k;
366 struct canodeblock *ablock;
367 struct anode *anodes;
368 BOOL found = 0;
369 ULONG seqnr = 0, field;
371 if (connect && g->anodesplitmode)
373 /* try to place new anode in same block */
374 ablock = big_GetAnodeBlock (seqnr = connect>>16, g);
375 if (ablock)
377 anodes = ablock->blk.nodes;
378 for (k = andata.anodesperblock-1; k > -1 && !found; k--)
379 found = (anodes[k].clustersize == 0 &&
380 anodes[k].blocknr == 0 &&
381 anodes[k].next == 0);
384 else
386 for (i = andata.curranseqnr/32; i < andata.maxanseqnr/32 + 1; i++)
388 field = andata.anblkbitmap[i];
389 if (field)
391 for (j = 31; j >= 0; j--)
393 if (field & (1 << j))
395 seqnr = i*32 + 31-j;
396 ablock = big_GetAnodeBlock(seqnr, g);
397 if (ablock)
399 anodes = ablock->blk.nodes;
400 for (k=0; k<andata.reserved && !found; k++)
401 found = (anodes[k].clustersize == 0 &&
402 anodes[k].blocknr == 0 &&
403 anodes[k].next == 0);
405 if (found)
406 goto found_it;
407 else
408 /* mark anodeblock as full */
409 andata.anblkbitmap[i] &= ~(1 << j);
411 /* anodeblock does not exist */
412 else goto found_it;
418 seqnr = andata.maxanseqnr + 1;
421 found_it:
423 if (!found)
425 /* give up connect mode and try again */
426 if (connect)
427 return AllocAnode (0, g);
429 /* start over if not started from start of list;
430 * else make new block
432 if (andata.curranseqnr)
434 andata.curranseqnr = 0;
435 return AllocAnode (0, g);
437 else
439 if (!(ablock = big_NewAnodeBlock (seqnr, g)))
440 return 0;
441 anodes = ablock->blk.nodes;
442 k = 0;
445 else
447 if (connect)
448 k++;
449 else
450 k--;
453 anodes[k].clustersize = 0;
454 anodes[k].blocknr = 0xffffffff;
455 anodes[k].next = 0;
457 MakeBlockDirty((struct cachedblock *)ablock, g);
458 andata.curranseqnr = seqnr;
460 if(g->anodesplitmode)
461 return (ULONG)(seqnr<<16 | k);
462 else
463 return (ULONG)(seqnr*andata.anodesperblock + k);
468 * frees an anode for later reuse
469 * universal version
471 void FreeAnode (ULONG anodenr, globaldata *g)
473 struct canode anode = {0};
475 /* don't kill reserved anodes */
476 if (anodenr < ANODE_USERFIRST)
478 anode.blocknr = (ULONG)~0L;
481 SaveAnode (&anode, anodenr, g);
482 andata.anblkbitmap[(anodenr>>16)/32] |= 1 << (31 - (anodenr>>16)%32);
486 /***********************************************************************/
487 /* LOCAL functions */
488 /***********************************************************************/
491 /* MODE_BIG has indexblocks, and negative blocknrs indicating freenode
492 ** blocks instead of anodeblocks
494 static struct canodeblock *big_GetAnodeBlock (UWORD seqnr, globaldata *g)
496 ULONG blocknr;
497 ULONG temp;
498 struct canodeblock *ablock;
499 struct cindexblock *indexblock;
500 struct volumedata *volume = g->currentvolume;
502 temp = divide (seqnr, andata.indexperblock);
504 /* not in cache, put it in */
505 /* get the indexblock */
506 if (!(indexblock = GetIndexBlock (temp /*& 0xffff*/, g)))
508 DB(Trace(5, "GetAnodeBlock","ERR: index not found\n"));
509 return NULL;
512 /* get blocknr */
513 if (!(blocknr = indexblock->blk.index[temp >> 16]))
515 DB(Trace(5,"GetAnodeBlock","ERR: index zero\n"));
516 return NULL;
519 /* check cache */
520 ablock = (struct canodeblock *)CheckCache (volume->anblks, HASHM_ANODE, blocknr, g);
521 if (ablock)
522 return ablock;
524 if (!(ablock = (struct canodeblock *)AllocLRU(g)))
526 DB(Trace(5,"GetAnodeBlock","ERR: alloclru failed\n"));
527 return NULL;
530 DB(Trace(10,"GetAnodeBlock", "seqnr = %ld blocknr = %lx\n", seqnr, blocknr));
532 /* read it */
533 if (RawRead ((UBYTE*)&ablock->blk, RESCLUSTER, blocknr, g) != 0)
535 DB(Trace(5,"GetAnodeBlock","Read ERR: seqnr = %d blocknr = %lx\n", seqnr, blocknr));
536 FreeLRU ((struct cachedblock *)ablock);
537 return NULL;
540 /* check it */
541 if (ablock->blk.id != ABLKID)
543 ULONG args[2];
544 args[0] = ablock->blk.id;
545 args[1] = blocknr;
546 FreeLRU ((struct cachedblock *)ablock);
547 ErrorMsg (AFS_ERROR_DNV_WRONG_ANID, args, g);
548 return NULL;
551 /* initialize it */
552 ablock->volume = volume;
553 ablock->blocknr = blocknr;
554 ablock->used = FALSE;
555 ablock->changeflag = FALSE;
556 Hash (ablock, volume->anblks, HASHM_ANODE);
558 return ablock;
562 /* MODE_BIG has difference between anodeblocks and fnodeblocks
564 static struct canodeblock *big_NewAnodeBlock (UWORD seqnr, globaldata *g)
566 struct canodeblock *blok;
567 struct volumedata *volume = g->currentvolume;
568 struct cindexblock *indexblock;
569 ULONG indexblnr;
570 LONG blocknr;
571 UWORD indexoffset, oldlock;
573 DB(Trace(10, "NewAnodeBlock", "seqnr = %ld\n", seqnr));
575 /* get indexblock */
576 indexblnr = seqnr/andata.indexperblock;
577 indexoffset = seqnr%andata.indexperblock;
578 if (!(indexblock = GetIndexBlock(indexblnr, g)))
579 if (!(indexblock = NewIndexBlock(indexblnr, g)))
580 return NULL;
582 oldlock = indexblock->used;
583 LOCK(indexblock);
584 if (!(blok = (struct canodeblock *)AllocLRU(g)) ||
585 !(blocknr = AllocReservedBlock(g)) )
586 return NULL;
588 indexblock->blk.index[indexoffset] = blocknr;
590 blok->volume = volume;
591 blok->blocknr = blocknr;
592 blok->used = FALSE;
593 blok->blk.id = ABLKID;
594 blok->blk.seqnr = seqnr;
595 blok->changeflag = TRUE;
596 Hash(blok, volume->anblks, HASHM_ANODE);
597 MakeBlockDirty((struct cachedblock *)indexblock, g);
598 indexblock->used = oldlock; // unlock block
600 ReallocAnodeBitmap (seqnr, g);
601 return blok;
606 /**********************************************************************/
607 /* indexblocks */
608 /**********************************************************************/
611 * get indexblock nr
612 * returns 0 if failure
614 struct cindexblock *GetIndexBlock (UWORD nr, globaldata *g)
616 ULONG blocknr, temp;
617 struct cindexblock *indexblk;
618 struct cindexblock *superblk;
619 struct volumedata *volume = g->currentvolume;
621 /* check cache (can be empty) */
622 for (indexblk = HeadOf(&volume->indexblks); indexblk->next; indexblk=indexblk->next)
624 if (indexblk->blk.seqnr == nr)
626 MakeLRU (indexblk);
627 return indexblk;
631 /* not in cache, put it in
632 * first, get blocknr
634 if (g->supermode)
636 /* temp is chopped by auto cast */
637 temp = divide(nr, andata.indexperblock);
638 if (!(superblk = GetSuperBlock (temp, g)))
640 DB(Trace(5, "GetIndexBlock", "ERR: superblock not found\n"));
641 return NULL;
644 if (!(blocknr = superblk->blk.index[temp>>16]))
646 DB(Trace(5, "GetIndexBlock", "ERR: super zero\n"));
647 return NULL;
650 else
652 if ((nr>MAXSMALLINDEXNR) || !(blocknr = volume->rootblk->idx.small.indexblocks[nr]))
653 return NULL;
656 /* allocate space from cache */
657 if (!(indexblk = (struct cindexblock *)AllocLRU(g)))
658 return NULL;
660 DB(Trace(10,"GetIndexBlock","seqnr = %d\n, blocknr = %lx\n", nr, blocknr));
662 if (RawRead ((UBYTE*)&indexblk->blk, RESCLUSTER, blocknr, g) != 0) {
663 FreeLRU ((struct cachedblock *)indexblk);
664 return NULL;
667 if (indexblk->blk.id == IBLKID)
669 indexblk->volume = volume;
670 indexblk->blocknr = blocknr;
671 indexblk->used = FALSE;
672 indexblk->changeflag = FALSE;
673 MinAddHead (&volume->indexblks, indexblk);
675 else
677 ULONG args[5] = { indexblk->blk.id, IBLKID, blocknr, nr, andata.indexperblock };
678 FreeLRU ((struct cachedblock *)indexblk);
679 ErrorMsg (AFS_ERROR_DNV_WRONG_INDID, args, g);
680 return NULL;
683 return indexblk;
687 static struct cindexblock *NewIndexBlock (UWORD seqnr, globaldata *g)
689 struct cindexblock *blok;
690 struct cindexblock *superblok = NULL;
691 struct volumedata *volume = g->currentvolume;
692 ULONG superblnr;
693 LONG blocknr;
694 UWORD superoffset = 0;
696 DB(Trace(10,"NewIndexBlock", "seqnr = %ld\n", seqnr));
698 if (g->supermode)
700 superblnr = seqnr/andata.indexperblock;
701 superoffset = seqnr%andata.indexperblock;
702 if (!(superblok = GetSuperBlock (superblnr, g)))
703 if (!(superblok = NewSuperBlock (superblnr, g)))
704 return NULL;
706 LOCK(superblok);
708 else if (seqnr > MAXSMALLINDEXNR) {
709 return NULL;
712 if (!(blok = (struct cindexblock *)AllocLRU(g)) ||
713 !(blocknr = AllocReservedBlock(g)) )
715 if (blok)
716 FreeLRU((struct cachedblock *)blok);
717 return NULL;
720 if (g->supermode)
721 superblok->blk.index[superoffset] = blocknr;
722 else {
723 volume->rootblk->idx.small.indexblocks[seqnr] = blocknr;
724 volume->rootblockchangeflag = TRUE;
727 blok->volume = volume;
728 blok->blocknr = blocknr;
729 blok->used = FALSE;
730 blok->blk.id = IBLKID;
731 blok->blk.seqnr = seqnr;
732 blok->changeflag = TRUE;
733 MinAddHead(&volume->indexblks, blok);
735 return blok;
738 struct cindexblock *GetSuperBlock (UWORD nr, globaldata *g)
740 ULONG blocknr;
741 struct cindexblock *superblk;
742 struct volumedata *volume = g->currentvolume;
744 /* check supermode */
745 if (!g->supermode) {
746 DB(Trace(1, "GetSuperBlock", "ERR: Illegaly entered\n"));
747 return NULL;
750 /* check cache (can be empty) */
751 for (superblk = HeadOf(&volume->superblks); superblk->next; superblk=superblk->next)
753 if (superblk->blk.seqnr == nr)
755 MakeLRU (superblk);
756 return superblk;
760 /* not in cache, put it in
761 * first, get blocknr
763 if ((nr>MAXSUPER) || !(blocknr = volume->rblkextension->blk.superindex[nr]))
764 return NULL;
766 /* allocate space from cache */
767 if (!(superblk = (struct cindexblock *)AllocLRU(g)))
768 return NULL;
770 DB(Trace(10,"GetSuperBlock","seqnr = %d\n, blocknr = %lx\n", nr, blocknr));
772 if (RawRead ((UBYTE*)&superblk->blk, RESCLUSTER, blocknr, g) != 0) {
773 FreeLRU ((struct cachedblock *)superblk);
774 return NULL;
777 if (superblk->blk.id == SBLKID)
779 superblk->volume = volume;
780 superblk->blocknr = blocknr;
781 superblk->used = FALSE;
782 superblk->changeflag = FALSE;
783 MinAddHead (&volume->superblks, superblk);
785 else
787 ULONG args[5] = { superblk->blk.id, SBLKID, blocknr, nr, 0 };
788 FreeLRU ((struct cachedblock *)superblk);
789 ErrorMsg (AFS_ERROR_DNV_WRONG_INDID, args, g);
790 return NULL;
793 return superblk;
796 static struct cindexblock *NewSuperBlock (UWORD seqnr, globaldata *g)
798 struct cindexblock *blok;
799 struct volumedata *volume = g->currentvolume;
801 DB(Trace(10,"NewSuperBlock", "seqnr = %ld\n", seqnr));
803 if ((seqnr > MAXSUPER) ||
804 !(blok = (struct cindexblock *)AllocLRU(g)) )
805 return NULL;
807 if (!(volume->rblkextension->blk.superindex[seqnr] = AllocReservedBlock(g)))
809 FreeLRU((struct cachedblock *)blok);
810 return NULL;
813 volume->rblkextension->changeflag = TRUE;
815 blok->volume = volume;
816 blok->blocknr = volume->rblkextension->blk.superindex[seqnr];
817 blok->used = FALSE;
818 blok->blk.id = SBLKID;
819 blok->blk.seqnr = seqnr;
820 blok->changeflag = TRUE;
821 MinAddHead(&volume->superblks, blok);
823 return blok;
826 /* Remove anode from anodechain
827 * If previous==0, anode->next becomes head.
828 * Otherwise previous->next becomes anode->next.
829 * Anode is freed.
831 * Arguments:
832 * anode = anode to be removed
833 * previous = previous in chain; or 0 if anode is head
834 * head = anodenr of head of list
836 void RemoveFromAnodeChain (const struct canode *anode, ULONG previous, ULONG head, globaldata *g)
838 struct canode sparenode;
840 if(previous)
842 GetAnode(&sparenode, previous, g);
843 sparenode.next = anode->next;
844 SaveAnode(&sparenode, sparenode.nr, g);
845 FreeAnode(anode->nr, g);
847 else
849 /* anode is head of list (check both tails here) */
850 if (anode->next)
852 /* There is a next entry -> becomes head */
853 GetAnode(&sparenode, anode->next, g);
854 SaveAnode(&sparenode, head, g); // overwrites [anode]
855 FreeAnode(anode->next, g);
857 else
859 /* No anode->next: Free list. */
860 FreeAnode(head, g);
866 /*********************************************************************/
867 /* Initialization */
868 /*********************************************************************/
870 void InitAnodes (struct volumedata *volume, BOOL formatting, globaldata *g)
872 if(!g->harddiskmode)
874 ErrorMsg (AFS_ERROR_ANODE_INIT, NULL, g);
876 else
878 g->getanodeblock = big_GetAnodeBlock;
880 andata.curranseqnr = volume->rblkextension ?
881 volume->rblkextension->blk.curranseqnr : 0;
882 andata.anodesperblock = (volume->rootblk->reserved_blksize - sizeof(anodeblock_t)) /
883 sizeof(anode_t);
884 andata.indexperblock = (volume->rootblk->reserved_blksize - sizeof(indexblock_t)) /
885 sizeof(LONG);
886 andata.maxanodeseqnr = g->supermode ?
887 ((MAXSUPER+1) * andata.indexperblock * andata.indexperblock * andata.anodesperblock - 1) :
888 (MAXSMALLINDEXNR * andata.indexperblock - 1);
889 andata.reserved = andata.anodesperblock - RESERVEDANODES;
890 MakeAnodeBitmap (formatting, g);
895 /* Find out how large the anblkbitmap must be, allocate it and
896 * initialise it. Free any preexisting anblkbitmap
898 * The anode bitmap is used for allocating anodes. It has the
899 * following properties:
900 * - It is maintained in memory only (not on disk).
901 * - Intialization is lazy: all anodes are marked as available
902 * - When allocation anodes (see AllocAnode), this bitmap is used
903 * to find available anodes. It then checks with the actual
904 * anode (which should be 0,0,0 if available). If it isn't really
905 * available, the anodebitmap is updated, otherwise the anode is
906 * taken.
908 static void MakeAnodeBitmap (BOOL formatting, globaldata *g)
910 struct cindexblock *iblk;
911 struct cindexblock *sblk;
912 int i, j, s;
913 ULONG size;
915 if (andata.anblkbitmap)
916 FreeMemP (andata.anblkbitmap, g);
918 /* count number of anodeblocks and allocate bitmap */
919 if (formatting)
921 i = 0; s = 0; j = 1;
923 else
925 if (g->supermode)
927 for (s=MAXSUPER; s >= 0 && !g->currentvolume->rblkextension->blk.superindex[s]; s--);
928 if (s < 0)
929 goto error;
931 sblk = GetSuperBlock (s, g);
932 for (i=andata.indexperblock - 1; i >= 0 && !sblk->blk.index[i]; i--);
934 else
936 for (s=0, i=MAXSMALLINDEXNR; i >= 0 && !g->rootblock->idx.small.indexblocks[i]; i--);
939 if (i < 0)
940 goto error;
941 iblk = GetIndexBlock (s * andata.indexperblock + i, g);
942 for (j=andata.indexperblock - 1; j >= 0 && !iblk->blk.index[j]; j--);
945 if (g->supermode)
947 andata.maxanseqnr = s * andata.indexperblock * andata.indexperblock
948 + i * andata.indexperblock + j;
949 size = ((s * andata.indexperblock + i + 1) * andata.indexperblock + 7) / 8;
951 else
953 andata.maxanseqnr = i * andata.indexperblock + j;
954 size = ((i+1) * andata.indexperblock + 7) / 8;
956 andata.anblkbitmapsize = (size + 3) & 0xfffffffc;
957 andata.anblkbitmap = AllocMemP (andata.anblkbitmapsize, g);
959 for (i = 0; i < andata.anblkbitmapsize/4; i++)
960 andata.anblkbitmap[i] = 0xffffffff; /* all available */
962 return;
964 error:
965 ErrorMsg(AFS_ERROR_ANODE_ERROR, NULL, g);
969 /* test if new anodeseqnr causes change in anblkbitmap */
970 static void ReallocAnodeBitmap (ULONG newseqnr, globaldata *g)
972 ULONG *newbitmap, newsize;
973 int t;
975 if (newseqnr > andata.maxanseqnr)
977 andata.maxanseqnr = newseqnr;
978 newsize = ((newseqnr/andata.indexperblock + 1)
979 * andata.indexperblock + 7) / 8;
980 if (newsize > andata.anblkbitmapsize)
982 newsize = (newsize + 3) & 0xfffffffc; /* longwords */
983 newbitmap = AllocMemP (newsize, g);
984 for (t=0; t < newsize/4; t++)
985 newbitmap[t] = 0xffffffff;
986 memcpy (newbitmap, andata.anblkbitmap, andata.anblkbitmapsize);
987 FreeMemP (andata.anblkbitmap, g);
988 andata.anblkbitmap = newbitmap;
989 andata.anblkbitmapsize = newsize;