1 #include "asmsupport.h"
4 #include <exec/types.h>
5 #include <proto/exec.h>
9 #include "adminspaces_protos.h"
10 #include "cachebuffers_protos.h"
12 #include "req_protos.h"
13 #include "support_protos.h"
17 extern LONG
readcachebuffercheck(struct CacheBuffer
**,ULONG
,ULONG
);
18 extern void setchecksum(struct CacheBuffer
*);
20 LONG
parentnodecontainer(BLCK noderoot
, struct CacheBuffer
**io_cb
) {
21 BLCK childblock
=(*io_cb
)->blckno
;
22 NODE nodenumber
=BE2L(((struct fsNodeContainer
*)((*io_cb
)->data
))->be_nodenumber
);
25 /* Looks for the parent of the passed-in CacheBuffer (fsNodeContainer)
26 starting from the root. It returns an error if any error occured.
27 If error is 0 and io_cb is 0 as well, then there was no parent (ie,
28 you asked parent of the root). Otherwise io_cb should contain the
29 parent of the passed-in NodeContainer. */
33 while(noderoot
!=childblock
&& (errorcode
=readcachebuffercheck(io_cb
, noderoot
, NODECONTAINER_ID
))==0) {
34 struct fsNodeContainer
*nc
=(*io_cb
)->data
;
36 if(BE2L(nc
->be_nodes
)==1) {
37 /* We've descended the tree to a leaf NodeContainer, something
38 which should never happen if the passed-in CacheBuffer had
39 contained a valid fsNodeContainer. */
41 req_unusual("Failed to locate the parent NodeContainer\n"\
49 UWORD containerentry
=(nodenumber
- BE2L(nc
->be_nodenumber
))/BE2L(nc
->be_nodes
);
51 noderoot
=BE2L(nc
->be_node
[containerentry
])>>globals
->shifts_block32
;
60 int isfull(struct fsNodeContainer
*nc
) {
62 WORD n
=globals
->node_containers
;
65 if(*p
==0 || (BE2L(*p
) & 0x00000001)==0) {
76 LONG
markparentfull(BLCK noderoot
, struct CacheBuffer
*cb
) {
77 NODE nodenumber
=BE2L(((struct fsNodeContainer
*)(cb
->data
))->be_nodenumber
);
80 if((errorcode
=parentnodecontainer(noderoot
, &cb
))==0 && cb
!=0) {
81 struct fsNodeContainer
*nc
=cb
->data
;
83 preparecachebuffer(cb
);
85 nc
->be_node
[(nodenumber
-BE2L(nc
->be_nodenumber
))/BE2L(nc
->be_nodes
)]|=L2BE(0x00000001);
87 if((errorcode
=storecachebuffer(cb
))==0) {
88 if(isfull(nc
)) { /* This container now is full as well! Mark the next higher up container too then! */
89 return(markparentfull(noderoot
, cb
));
99 LONG
markparentempty(BLCK noderoot
, struct CacheBuffer
*cb
) {
100 NODE nodenumber
=BE2L(((struct fsNodeContainer
*)(cb
->data
))->be_nodenumber
);
103 if((errorcode
=parentnodecontainer(noderoot
, &cb
))==0 && cb
!=0) {
104 struct fsNodeContainer
*nc
=cb
->data
;
109 preparecachebuffer(cb
);
111 nc
->be_node
[(nodenumber
-BE2L(nc
->be_nodenumber
))/BE2L(nc
->be_nodes
)]&=~L2BE(0x00000001);
113 if((errorcode
=storecachebuffer(cb
))==0) {
115 /* This container was completely full before! Mark the next higher up container too then! */
117 return(markparentempty(noderoot
, cb
));
127 LONG
freecontainer(BLCK noderoot
, struct CacheBuffer
*cb
) {
128 NODE nodenumber
=BE2L(((struct fsNodeContainer
*)(cb
->data
))->be_nodenumber
);
131 if((errorcode
=parentnodecontainer(noderoot
, &cb
))==0 && cb
!=0) { /* This line also prevents the freeing of the noderoot. */
132 struct fsNodeContainer
*nc
=cb
->data
;
133 UWORD containerindex
=(nodenumber
-BE2L(nc
->be_nodenumber
))/BE2L(nc
->be_nodes
);
137 if((errorcode
=freeadminspace(BE2L(nc
->be_node
[containerindex
])>>globals
->shifts_block32
))==0) {
139 unlockcachebuffer(cb
);
141 preparecachebuffer(cb
);
143 nc
->be_node
[containerindex
]=0;
145 if((errorcode
=storecachebuffer(cb
))==0) {
146 BLCKn
*p
=nc
->be_node
;
147 WORD n
=globals
->node_containers
;
155 if(n
<0) { /* This container is now completely empty! Free this NodeIndexContainer too then! */
156 return(freecontainer(noderoot
, cb
));
161 unlockcachebuffer(cb
);
170 static LONG
addnewnodelevel(BLCK noderoot
, UWORD nodesize
) {
171 struct CacheBuffer
*cb
;
174 /* Adds a new level to the Node tree. */
176 _XDEBUG((DEBUG_NODES
,"addnewnodelevel: Entry\n"));
178 if((errorcode
=readcachebuffercheck(&cb
, noderoot
, NODECONTAINER_ID
))==0) {
179 struct CacheBuffer
*newcb
;
181 lockcachebuffer(cb
); /* Locking cb, because allocadminspace & storecachebuffer below may destroy it otherwise */
183 if((errorcode
=allocadminspace(&newcb
))==0) {
184 struct fsNodeContainer
*nc
=cb
->data
;
185 struct fsNodeContainer
*newnc
=newcb
->data
;
186 BLCK newblock
=newcb
->blckno
;
188 /* The newly allocated block will become a copy of the current root. */
190 newnc
->bheader
.id
=NODECONTAINER_ID
;
191 newnc
->bheader
.be_ownblock
=L2BE(newcb
->blckno
);
192 newnc
->be_nodenumber
=nc
->be_nodenumber
; // Be->Be copy!
193 newnc
->be_nodes
=nc
->be_nodes
; // Be->Be copy!
194 CopyMemQuick(nc
->be_node
, newnc
->be_node
, globals
->bytes_block
-sizeof(struct fsNodeContainer
));
196 if((errorcode
=storecachebuffer(newcb
))==0) {
198 /* The current root will now be transformed into a new root. */
200 preparecachebuffer(cb
);
202 if(BE2L(nc
->be_nodes
)==1) {
203 nc
->be_nodes
=L2BE((globals
->bytes_block
-sizeof(struct fsNodeContainer
))/nodesize
);
206 nc
->be_nodes
=L2BE(BE2L(nc
->be_nodes
)*globals
->node_containers
);
209 nc
->be_node
[0]=L2BE((newblock
<<globals
->shifts_block32
)+1); /* Tree is full from that point! */
211 ClearMemQuick(&nc
->be_node
[1], globals
->bytes_block
-sizeof(struct fsNodeContainer
)-4);
213 errorcode
=storecachebuffer(cb
);
217 unlockcachebuffer(cb
);
220 _XDEBUG((DEBUG_NODES
,"addnewnodelevel: Exiting with errorcode %ld\n",errorcode
));
227 LONG
deletenode(BLCK noderoot
, struct CacheBuffer
*cb
, struct fsNode
*n
, UWORD nodesize
) {
228 struct fsNodeContainer
*nc
=cb
->data
;
229 UWORD nodecount
=(globals
->bytes_block
-sizeof(struct fsNodeContainer
))/nodesize
;
234 preparecachebuffer(cb
);
238 n
=(struct fsNode
*)nc
->be_node
;
244 n
=(struct fsNode
*)((UBYTE
*)n
+nodesize
);
247 if((errorcode
=storecachebuffer(cb
))==0) {
248 if(empty
==1) { /* NodeContainer was completely full before, so we need to mark it empty now. */
249 errorcode
=markparentempty(noderoot
, cb
);
251 else if(empty
==nodecount
) { /* NodeContainer is now completely empty! Free it! */
252 errorcode
=freecontainer(noderoot
, cb
);
261 static LONG
createnodecontainer(ULONG nodenumber
, ULONG nodes
, BLCK
*returned_block
) {
262 struct CacheBuffer
*cb
;
265 _XDEBUG((DEBUG_NODES
,"createnodecontainer: nodenumber = %ld, nodes = %ld\n",nodenumber
,nodes
));
267 if((errorcode
=allocadminspace(&cb
))==0) {
268 struct fsNodeContainer
*nc
=cb
->data
;
270 nc
->bheader
.id
=NODECONTAINER_ID
;
271 nc
->bheader
.be_ownblock
=L2BE(cb
->blckno
);
273 nc
->be_nodenumber
=L2BE(nodenumber
);
274 nc
->be_nodes
=L2BE(nodes
);
276 errorcode
=storecachebuffer(cb
);
277 *returned_block
=cb
->blckno
;
280 _XDEBUG((DEBUG_NODES
,"createnodecontainer: Exiting with errorcode %ld\n",errorcode
));
287 LONG
createnode(BLCK noderoot
, UWORD nodesize
, struct CacheBuffer
**returned_cb
, struct fsNode
**returned_node
, NODE
*returned_nodeno
) {
288 struct CacheBuffer
*cb
;
289 UWORD nodecount
=(globals
->bytes_block
-sizeof(struct fsNodeContainer
))/nodesize
;
290 BLCK nodeindex
=noderoot
;
293 /* This function creates a new fsNode structure in a fsNodeContainer. If needed
294 it will create a new fsNodeContainers and a new fsNodeIndexContainer. newoperation()
295 should be called prior to calling this function. */
297 // _XDEBUG((DEBUG_NODES,"createnode: Entry\n"));
299 while((errorcode
=readcachebuffercheck(&cb
, nodeindex
, NODECONTAINER_ID
))==0) {
300 struct fsNodeContainer
*nc
=cb
->data
;
302 if(BE2L(nc
->be_nodes
)==1) { // Is it a leaf-container?
306 n
=(struct fsNode
*)nc
->be_node
;
312 n
=(struct fsNode
*)((UBYTE
*)n
+nodesize
);
316 /* Found an empty fsNode structure! */
318 preparecachebuffer(cb
);
322 *returned_nodeno
=BE2L(nc
->be_nodenumber
)+((UBYTE
*)n
-(UBYTE
*)nc
->be_node
)/nodesize
;
324 _XDEBUG((DEBUG_NODES
,"createnode: Created Node %ld\n",*returned_nodeno
));
326 /* Below we continue to look through the NodeContainer block. We skip the entry
327 we found to be unused, and see if there are any more unused entries. If we
328 do not find any more unused entries then this container is now full. */
330 n
=(struct fsNode
*)((UBYTE
*)n
+nodesize
);
336 n
=(struct fsNode
*)((UBYTE
*)n
+nodesize
);
340 /* No more empty fsNode structures in this block. Mark parent full. */
341 if((errorcode
=markparentfull(noderoot
, cb
))!=0) {
349 /* What happened now is that we found a leaf-container which was
350 completely filled. In practice this should only happen when there
351 is only a single NodeContainer (only this container), or when there
352 was an error in one of the full-bits in a higher level container. */
354 if(noderoot
!=nodeindex
) {
355 /*** Hmmm... it looks like there was a damaged full-bit or something.
356 In this case we'd probably better call markcontainerfull. */
358 // errorcode=markcontainerfull(nc->parent,nc->nodenumber);
360 req("Couldn't find empty Node in NodeContainer at block %ld\n"\
361 "while NodeIndexContainer indicated there should be one.\n",
364 errorcode
=ERROR_DISK_FULL
;
368 /* Container is completely filled. */
370 if((errorcode
=addnewnodelevel(noderoot
, nodesize
))!=0) {
378 else { // This isn't a leaf container
379 BLCKn
*p
=nc
->be_node
;
380 WORD i
=globals
->node_containers
;
382 /* We've read a normal container */
385 if(*p
!=0 && (BE2L(*p
) & 0x00000001)==0) {
392 /* Found a not completely filled Container */
394 nodeindex
=BE2L(*p
)>>globals
->shifts_block32
;
397 /* Everything in the NodeIndexContainer was completely filled. There possibly
398 are some unused pointers in this block however. */
400 _XDEBUG((DEBUG_NODES
,"createnode: NodeContainer at block %ld has no empty Nodes\n",cb
->blckno
));
403 i
=globals
->node_containers
;
416 /* Found an unused Container pointer */
418 preparecachebuffer(cb
);
420 if(BE2L(nc
->be_nodes
)==(globals
->bytes_block
-sizeof(struct fsNodeContainer
))/nodesize
) {
424 nodes
=BE2L(nc
->be_nodes
)/globals
->node_containers
;
427 if((errorcode
=createnodecontainer(BE2L(nc
->be_nodenumber
)+(p
-nc
->be_node
)*BE2L(nc
->be_nodes
), nodes
, &newblock
))!=0) {
432 *p
=L2BE(newblock
<<globals
->shifts_block32
);
434 if((errorcode
=storecachebuffer(cb
))!=0) {
439 /* Container is completely filled. This must be the top-level NodeIndex container
440 as otherwise the full-bit would have been wrong! */
442 if((errorcode
=addnewnodelevel(noderoot
, nodesize
))!=0) {
452 // _XDEBUG((DEBUG_NODES,"createnode: Exiting with errorcode %ld\n",errorcode));
459 LONG
findnode(BLCK nodeindex
,UWORD nodesize
,NODE nodeno
,struct CacheBuffer
**returned_cb
,struct fsNode
**returned_node
) {
460 struct CacheBuffer
*cb
;
463 _XDEBUG((DEBUG_NODES
,"findnode: Entry -- looking for nodeno %ld\n",nodeno
));
465 /* Finds a specific node by number. It returns the cachebuffer which contains the fsNode
466 structure and a pointer to the fsNode structure directly. */
468 while((errorcode
=readcachebuffercheck(&cb
,nodeindex
,NODECONTAINER_ID
))==0) {
469 struct fsNodeContainer
*nc
=cb
->data
;
471 _XDEBUG((DDEBUG_NODES
,"findnode: Read NodeContainer at block %ld with nodenumber = %ld, nodes = %ld\n",nodeindex
,BE2L(nc
->be_nodenumber
),BE2L(nc
->be_nodes
)));
473 if(BE2L(nc
->be_nodes
)==1) {
474 /* We've descended the tree to a leaf NodeContainer */
477 *returned_node
=(struct fsNode
*)((UBYTE
*)nc
->be_node
+nodesize
*(nodeno
-BE2L(nc
->be_nodenumber
)));
482 UWORD containerentry
=(nodeno
-BE2L(nc
->be_nodenumber
))/BE2L(nc
->be_nodes
);
484 nodeindex
=BE2L(nc
->be_node
[containerentry
])>>globals
->shifts_block32
;
488 _XDEBUG((DEBUG_NODES
,"findnode: Exiting with errorcode %ld\n",errorcode
));