2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
11 #include <sys/types.h>
15 #include <netinet/in.h>
22 extern struct vlheader cheader;
23 struct vlheader xheader;
24 extern struct ubik_dbase *VL_dbase;
25 extern afs_uint32 HostAddress[];
26 extern int maxnservers;
27 struct extentaddr extentaddr;
28 extern struct extentaddr *ex_addr[];
31 static int index_OK();
33 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
35 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
36 afs_int32 IDHash(volumeid)
39 return((abs(volumeid)) % HASHSIZE);
43 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
44 afs_int32 NameHash (volumename)
45 register char *volumename;
46 { register unsigned int hash;
50 for (i=strlen(volumename), volumename += i-1; i--; volumename--)
51 hash = (hash*63) + (*((unsigned char *)volumename) - 63);
52 return(hash % HASHSIZE);
56 /* package up seek and write into one procedure for ease of use */
57 afs_int32 vlwrite (trans, offset, buffer, length)
58 struct ubik_trans *trans;
62 { afs_int32 errorcode;
64 if (errorcode = ubik_Seek(trans, 0, offset)) return errorcode;
65 return(ubik_Write(trans, buffer, length));
69 /* Package up seek and read into one procedure for ease of use */
70 afs_int32 vlread (trans, offset, buffer, length)
71 struct ubik_trans *trans;
75 { afs_int32 errorcode;
77 if (errorcode = ubik_Seek(trans, 0, offset)) return errorcode;
78 return(ubik_Read(trans, buffer, length));
82 /* take entry and convert to network order and write to disk */
83 afs_int32 vlentrywrite(trans, offset, buffer, length)
84 struct ubik_trans *trans;
88 struct vlentry oentry, *oep;
89 struct nvlentry nentry, *nep;
93 if (length != sizeof(oentry)) return -1;
94 if (maxnservers == 13) {
95 nep = (struct nvlentry *)buffer;
96 for (i=0;i<MAXTYPES;i++)
97 nentry.volumeId[i] = htonl(nep->volumeId[i]);
98 nentry.flags = htonl(nep->flags);
99 nentry.LockAfsId = htonl(nep->LockAfsId);
100 nentry.LockTimestamp = htonl(nep->LockTimestamp);
101 nentry.cloneId = htonl(nep->cloneId);
102 for (i=0;i<MAXTYPES;i++)
103 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
104 nentry.nextNameHash = htonl(nep->nextNameHash);
105 bcopy(nep->name, nentry.name, VL_MAXNAMELEN);
106 bcopy(nep->serverNumber, nentry.serverNumber, NMAXNSERVERS);
107 bcopy(nep->serverPartition, nentry.serverPartition, NMAXNSERVERS);
108 bcopy(nep->serverFlags, nentry.serverFlags, NMAXNSERVERS);
109 bufp = (char *)&nentry;
111 bzero(&oentry, sizeof(struct vlentry));
112 nep = (struct nvlentry *)buffer;
113 for (i=0;i<MAXTYPES;i++)
114 oentry.volumeId[i] = htonl(nep->volumeId[i]);
115 oentry.flags = htonl(nep->flags);
116 oentry.LockAfsId = htonl(nep->LockAfsId);
117 oentry.LockTimestamp = htonl(nep->LockTimestamp);
118 oentry.cloneId = htonl(nep->cloneId);
119 for (i=0;i<MAXTYPES;i++)
120 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
121 oentry.nextNameHash = htonl(nep->nextNameHash);
122 bcopy(nep->name, oentry.name, VL_MAXNAMELEN);
123 bcopy(nep->serverNumber, oentry.serverNumber, OMAXNSERVERS);
124 bcopy(nep->serverPartition, oentry.serverPartition, OMAXNSERVERS);
125 bcopy(nep->serverFlags, oentry.serverFlags, OMAXNSERVERS);
126 bufp = (char *)&oentry;
128 return vlwrite(trans, offset, bufp, length);
131 /* read entry and convert to host order and write to disk */
132 afs_int32 vlentryread(trans, offset, buffer, length)
133 struct ubik_trans *trans;
137 struct vlentry *oep, *obufp, tentry;
138 struct nvlentry *nep, *nbufp;
139 char *bufp = (char *)&tentry;
140 register afs_int32 i;
142 if (length != sizeof(vlentry)) return -1;
143 i = vlread(trans, offset, bufp, length);
145 if (maxnservers == 13) {
146 nep = (struct nvlentry *)bufp;
147 nbufp = (struct nvlentry *)buffer;
148 for(i=0;i<MAXTYPES;i++)
149 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
150 nbufp->flags = ntohl(nep->flags);
151 nbufp->LockAfsId = ntohl(nep->LockAfsId);
152 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
153 nbufp->cloneId = ntohl(nep->cloneId);
154 for(i=0;i<MAXTYPES;i++)
155 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
156 nbufp->nextNameHash = ntohl(nep->nextNameHash);
157 bcopy(nep->name, nbufp->name, VL_MAXNAMELEN);
158 bcopy(nep->serverNumber, nbufp->serverNumber, NMAXNSERVERS);
159 bcopy(nep->serverPartition, nbufp->serverPartition, NMAXNSERVERS);
160 bcopy(nep->serverFlags, nbufp->serverFlags, NMAXNSERVERS);
162 oep = (struct vlentry *)bufp;
163 nbufp = (struct nvlentry *)buffer;
164 bzero(nbufp, sizeof (struct nvlentry));
165 for(i=0;i<MAXTYPES;i++)
166 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
167 nbufp->flags = ntohl(oep->flags);
168 nbufp->LockAfsId = ntohl(oep->LockAfsId);
169 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
170 nbufp->cloneId = ntohl(oep->cloneId);
171 for(i=0;i<MAXTYPES;i++)
172 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
173 nbufp->nextNameHash = ntohl(oep->nextNameHash);
174 bcopy(oep->name, nbufp->name, VL_MAXNAMELEN);
175 bcopy(oep->serverNumber, nbufp->serverNumber, NMAXNSERVERS);
176 bcopy(oep->serverPartition, nbufp->serverPartition, NMAXNSERVERS);
177 bcopy(oep->serverFlags, nbufp->serverFlags, NMAXNSERVERS);
182 /* Convenient write of small critical vldb header info to the database. */
183 int write_vital_vlheader(trans)
184 register struct ubik_trans *trans;
186 if (vlwrite(trans, 0, (char *) &cheader.vital_header, sizeof(vital_vlheader))) return VL_IO;
193 /* This routine reads in the extent blocks for multi-homed servers.
194 * There used to be an initialization bug that would cause the contaddrs
195 * pointers in the first extent block to be bad. Here we will check the
196 * pointers and zero them in the in-memory copy if we find them bad. We
197 * also try to write the extent blocks back out. If we can't, then we
198 * will wait until the next write transaction to write them out
199 * (extent_mod tells us the on-disk copy is bad).
201 afs_int32 readExtents(trans)
202 struct ubik_trans *trans;
204 afs_uint32 extentAddr;
205 afs_int32 error=0, code;
209 extentAddr = ntohl(cheader.SIT);
213 /* Read the first extension block */
215 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
217 ERROR_EXIT(VL_NOMEM);
219 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
221 free(ex_addr[0]); /* Not the place to create it */
226 /* In case more that 64 mh servers are in use they're kept in these
227 * continuation blocks
229 for (i=1; i < VL_MAX_ADDREXTBLKS; i++) {
230 if (!ex_addr[0]->ex_contaddrs[i])
233 /* Before reading it in, check to see if the address is good */
234 if ( (ntohl(ex_addr[0]->ex_contaddrs[i]) <
235 ntohl(ex_addr[0]->ex_contaddrs[i-1])+VL_ADDREXTBLK_SIZE) ||
236 (ntohl(ex_addr[0]->ex_contaddrs[i]) >
237 ntohl(cheader.vital_header.eofPtr)-VL_ADDREXTBLK_SIZE) ) {
239 ex_addr[0]->ex_contaddrs[i] = 0;
244 /* Read the continuation block */
246 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
248 ERROR_EXIT(VL_NOMEM);
250 code = vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
251 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
253 free(ex_addr[i]); /* Not the place to create it */
258 /* After reading it in, check to see if its a real continuation block */
259 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
261 ex_addr[0]->ex_contaddrs[i] = 0;
262 free(ex_addr[i]); /* Not the place to create it */
269 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
271 VLog(0, ("Multihome server support modification\n"));
273 /* Keep extent_mod true in-case the transaction aborts */
274 /* Don't return error so we don't abort transaction */
281 /* Check that the database has been initialized. Be careful to fail in a safe
282 manner, to avoid bogusly reinitializing the db. */
283 afs_int32 CheckInit (trans, builddb)
284 struct ubik_trans *trans;
287 afs_int32 error=0, i, code, ubcode=0;
289 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
290 * previous transaction would have left the cache fine, and non-zero otherwise.
291 * Thus, a local abort or a remote commit will cause this to return non-zero
292 * and force a header re-read. Necessary for a local abort because we may
293 * have damaged cheader during the operation. Necessary for a remote commit
294 * since it may have changed cheader.
296 if (ubik_CacheUpdate(trans) != 0) {
297 /* if version changed (or first call), read the header */
298 ubcode = vlread (trans, 0, (char *) &cheader, sizeof(cheader));
299 vldbversion = ntohl(cheader.vital_header.vldbversion);
301 if (!ubcode && (vldbversion != 0)) {
302 bcopy(cheader.IpMappedAddr, HostAddress, sizeof(cheader.IpMappedAddr));
303 for (i=0; i<MAXSERVERID+1; i++) { /* cvt HostAddress to host order */
304 HostAddress[i] = ntohl(HostAddress[i]);
307 code = readExtents(trans);
313 vldbversion = ntohl(cheader.vital_header.vldbversion);
315 /* now, if can't read, or header is wrong, write a new header */
316 if (ubcode || vldbversion == 0) {
318 printf("Can't read VLDB header, re-initialising...\n");
320 /* try to write a good header */
321 bzero(&cheader,sizeof(cheader));
322 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
323 cheader.vital_header.headersize = htonl(sizeof(cheader));
324 /* DANGER: Must get this from a master place!! */
325 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
326 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
327 for (i=0; i<MAXSERVERID+1; i++) {
328 cheader.IpMappedAddr[i] = 0;
331 code = vlwrite(trans, 0, (char *) &cheader, sizeof(cheader));
333 printf("Can't write VLDB header (error = %d)\n", code);
337 else ERROR_EXIT(VL_EMPTY);
339 else if ((vldbversion != VLDBVERSION) &&
340 (vldbversion != OVLDBVERSION) &&
341 (vldbversion != VLDBVERSION_4)) {
342 printf("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
343 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
344 ERROR_EXIT(VL_BADVERSION);
347 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
355 afs_int32 GetExtentBlock(trans, base)
356 register struct ubik_trans *trans;
357 register afs_int32 base;
359 afs_int32 blockindex, code, error = 0;
361 /* Base 0 must exist before any other can be created */
362 if ((base != 0) && !ex_addr[0])
363 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
365 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
366 /* Create a new extension block */
367 if (!ex_addr[base]) {
368 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
370 ERROR_EXIT(VL_NOMEM);
372 bzero((char *)ex_addr[base], VL_ADDREXTBLK_SIZE);
374 /* Write the full extension block at end of vldb */
375 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
376 blockindex = ntohl(cheader.vital_header.eofPtr);
377 code = vlwrite(trans, blockindex, (char *)ex_addr[base], VL_ADDREXTBLK_SIZE);
378 if (code) ERROR_EXIT(VL_IO);
380 /* Update the cheader.vitalheader structure on disk */
381 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
382 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
383 code = write_vital_vlheader(trans);
384 if (code) ERROR_EXIT(VL_IO);
386 /* Write the address of the base extension block in the vldb header */
388 cheader.SIT = htonl(blockindex);
389 code = vlwrite(trans, DOFFSET(0,&cheader,&cheader.SIT),
390 (char *)&cheader.SIT, sizeof(cheader.SIT));
391 if (code) ERROR_EXIT(VL_IO);
394 /* Write the address of this extension block into the base extension block */
395 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
396 code = vlwrite(trans, ntohl(cheader.SIT), ex_addr[0], sizeof(struct extentaddr));
397 if (code) ERROR_EXIT(VL_IO);
405 afs_int32 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
406 register struct ubik_trans *trans;
408 afs_int32 createit, hostslot, *basep;
409 struct extentaddr **expp;
412 struct extentaddr *exp;
413 register afs_int32 i, j, code, base, index, error=0;
415 *expp = (struct extentaddr *)0;
418 /* Create the first extension block if it does not exist */
420 code = GetExtentBlock(trans, 0);
421 if (code) ERROR_EXIT(code);
424 for (i = 0; i < MAXSERVERID+1; i++) {
425 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
426 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
427 ERROR_EXIT(VL_INDEXERANGE);
429 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
430 ERROR_EXIT(VL_INDEXERANGE);
432 exp = &ex_addr[base][index];
433 tuuid = exp->ex_hostuuid;
434 afs_ntohuuid(&tuuid);
435 if (afs_uuid_equal(uuidp, &tuuid)) {
444 if (hostslot == -1) {
445 for (i=0; i<MAXSERVERID+1; i++) {
446 if (!HostAddress[i]) break;
448 if (i > MAXSERVERID) ERROR_EXIT(VL_REPSFULL);
453 for (base=0; base<VL_MAX_ADDREXTBLKS; base++) {
454 if (!ex_addr[0]->ex_contaddrs[base]) {
455 code = GetExtentBlock(trans, base);
456 if (code) ERROR_EXIT(code);
458 for (j=1; j<VL_MHSRV_PERBLK; j++) {
459 exp = &ex_addr[base][j];
460 tuuid = exp->ex_hostuuid;
461 afs_ntohuuid(&tuuid);
462 if (afs_uuid_is_nil(&tuuid)) {
464 afs_htonuuid(&tuuid);
465 exp->ex_hostuuid = tuuid;
466 code = vlwrite(trans, DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
467 (char *)ex_addr[base], (char *)exp),
468 (char *) &tuuid, sizeof(tuuid));
469 if (code) ERROR_EXIT(VL_IO);
470 HostAddress[i] = 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
473 if (vldbversion != VLDBVERSION_4) {
474 vldbversion != VLDBVERSION_4;
475 cheader.vital_header.vldbversion = htonl(VLDBVERSION_4);
476 code = write_vital_vlheader(trans);
477 if (code) ERROR_EXIT(VL_IO);
479 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
480 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.IpMappedAddr[i]),
481 (char *) &cheader.IpMappedAddr[i], sizeof(afs_int32));
482 if (code) ERROR_EXIT(VL_IO);
487 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
494 /* Allocate a free block of storage for entry, returning address of a new
495 zeroed entry (or zero if something is wrong). */
496 afs_int32 AllocBlock (trans, tentry)
497 register struct ubik_trans *trans;
498 struct nvlentry *tentry;
499 { register afs_int32 blockindex;
501 if (cheader.vital_header.freePtr) {
502 /* allocate this dude */
503 blockindex = ntohl(cheader.vital_header.freePtr);
504 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(vlentry))) return 0;
505 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
508 /* hosed, nothing on free list, grow file */
509 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
510 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
512 cheader.vital_header.allocs++;
513 if (write_vital_vlheader(trans)) return 0;
514 bzero (tentry, sizeof(nvlentry)); /* zero new entry */
519 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
520 int FreeBlock (trans, blockindex)
521 struct ubik_trans *trans;
522 afs_int32 blockindex;
523 { struct nvlentry tentry;
525 /* check validity of blockindex just to be on the safe side */
526 if (!index_OK (trans, blockindex)) return VL_BADINDEX;
527 bzero (&tentry, sizeof(nvlentry));
528 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
529 tentry.flags = htonl(VLFREE);
530 cheader.vital_header.freePtr = htonl(blockindex);
531 if (vlwrite (trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
533 cheader.vital_header.frees++;
534 if (write_vital_vlheader(trans)) return VL_IO;
539 /* Look for a block by volid and voltype (if not known use -1 which searches all 3 volid hash lists. Note that the linked lists are read in first from the database header. If found read the block's contents into the area pointed to by tentry and return the block's index. If not found return 0. */
540 afs_int32 FindByID (trans, volid, voltype, tentry, error)
541 struct ubik_trans *trans;
544 struct nvlentry *tentry;
546 { register afs_int32 typeindex, hashindex, blockindex;
549 hashindex = IDHash(volid);
551 /* Should we have one big hash table for volids as opposed to the three ones? */
552 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
553 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]); blockindex != NULLO; blockindex = tentry->nextIdHash[typeindex]) {
554 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
558 if (volid == tentry->volumeId[typeindex])
563 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]); blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
564 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
568 if (volid == tentry->volumeId[voltype])
572 return 0; /* no such entry */
576 /* Look for a block by volume name. If found read the block's contents into the area pointed to by tentry and return the block's index. If not found return 0. */
577 afs_int32 FindByName (trans, volname, tentry, error)
578 struct ubik_trans *trans;
580 struct nvlentry *tentry;
582 { register afs_int32 hashindex;
583 register afs_int32 blockindex;
584 char tname[VL_MAXNAMELEN];
586 /* remove .backup or .readonly extensions for stupid backwards compatibility */
587 hashindex = strlen(volname); /* really string length */
588 if (hashindex >= 8 && strcmp(volname+hashindex-7, ".backup")==0) {
589 /* this is a backup volume */
590 strcpy(tname, volname);
591 tname[hashindex-7] = 0; /* zap extension */
593 else if (hashindex >= 10 && strcmp(volname+hashindex-9, ".readonly")==0) {
594 /* this is a readonly volume */
595 strcpy(tname, volname);
596 tname[hashindex-9] = 0; /* zap extension */
598 else strcpy(tname, volname);
601 hashindex = NameHash(tname);
602 for (blockindex = ntohl(cheader.VolnameHash[hashindex]); blockindex != NULLO; blockindex = tentry->nextNameHash) {
603 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
607 if (!strcmp(tname, tentry->name))
610 return 0; /* no such entry */
613 int HashNDump (trans, hashindex)
614 struct ubik_trans *trans;
618 register int blockindex;
619 struct nvlentry tentry;
621 for (blockindex = ntohl(cheader.VolnameHash[hashindex]); blockindex != NULLO; blockindex = tentry.nextNameHash) {
622 if (vlentryread(trans, blockindex, (char *) &tentry, sizeof(nvlentry))) return 0;
624 VLog(0, ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
625 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
630 int HashIdDump (trans, hashindex)
631 struct ubik_trans *trans;
635 register int blockindex;
636 struct nvlentry tentry;
638 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]); blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
639 if (vlentryread(trans, blockindex, (char *) &tentry, sizeof(nvlentry))) return 0;
641 VLog(0, ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
642 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
647 /* Add a block to the hash table given a pointer to the block and its index. The block is threaded onto both hash tables and written to disk. The routine returns zero if there were no errors. */
648 int ThreadVLentry (trans, blockindex, tentry)
649 struct ubik_trans *trans;
650 afs_int32 blockindex;
651 struct nvlentry *tentry;
654 if (!index_OK(trans, blockindex)) return VL_BADINDEX;
655 /* Insert into volid's hash linked list */
656 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
659 /* For rw entries we also enter the RO and BACK volume ids (if they exist) in the hash tables; note all there volids (RW, RO, BACK) should not be hashed yet! */
660 if (tentry->volumeId[ROVOL]) {
661 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
664 if (tentry->volumeId[BACKVOL]) {
665 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
669 /* Insert into volname's hash linked list */
670 HashVolname(trans, blockindex, tentry);
672 /* Update cheader entry */
673 if (write_vital_vlheader(trans)) return VL_IO;
675 /* Update hash list pointers in the entry itself */
676 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry))) return VL_IO;
681 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
682 int UnthreadVLentry (trans, blockindex, aentry)
683 struct ubik_trans *trans;
684 afs_int32 blockindex;
685 struct nvlentry *aentry;
686 { register afs_int32 errorcode, typeindex;
688 if (!index_OK(trans, blockindex)) return VL_BADINDEX;
689 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
692 /* Take the RO/RW entries of their respective hash linked lists. */
693 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
694 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
698 /* Take it out of the Volname hash list */
699 if (errorcode = UnhashVolname(trans, blockindex, aentry))
702 /* Update cheader entry */
703 write_vital_vlheader(trans);
708 /* cheader must have be read before this routine is called. */
709 int HashVolid(trans, voltype, blockindex, tentry)
710 struct ubik_trans *trans;
712 afs_int32 blockindex;
713 struct nvlentry *tentry;
714 { afs_int32 hashindex, errorcode;
715 struct vlentry ventry;
717 if (FindByID(trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
718 return VL_IDALREADYHASHED;
719 else if (errorcode) return errorcode;
720 hashindex = IDHash(tentry->volumeId[voltype]);
721 tentry->nextIdHash[voltype] = ntohl(cheader.VolidHash[voltype][hashindex]);
722 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
723 if (vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]), (char *) &cheader.VolidHash[voltype][hashindex], sizeof(afs_int32))) return VL_IO;
728 /* cheader must have be read before this routine is called. */
729 int UnhashVolid(trans, voltype, blockindex, aentry)
730 struct ubik_trans *trans;
732 afs_int32 blockindex;
733 struct nvlentry *aentry;
734 { int hashindex, nextblockindex, prevblockindex;
735 struct nvlentry tentry;
739 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
741 /* Take it out of the VolId[voltype] hash list */
742 hashindex = IDHash(aentry->volumeId[voltype]);
743 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
744 if (nextblockindex == blockindex) {
745 /* First on the hash list; just adjust pointers */
746 cheader.VolidHash[voltype][hashindex] = htonl(aentry->nextIdHash[voltype]);
747 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]), (char *) &cheader.VolidHash[voltype][hashindex], sizeof(afs_int32));
748 if (code) return VL_IO;
750 while (nextblockindex != blockindex) {
751 prevblockindex = nextblockindex; /* always done once */
752 if (vlentryread(trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
754 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
757 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
758 temp = htonl(temp); /* convert to network byte order before writing */
759 if (vlwrite(trans, DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]), (char *)&temp, sizeof(afs_int32)))
762 aentry->nextIdHash[voltype] = 0;
767 int HashVolname(trans, blockindex, aentry)
768 struct ubik_trans *trans;
769 afs_int32 blockindex;
770 struct nvlentry *aentry;
771 { register afs_int32 hashindex;
772 register afs_int32 code;
774 /* Insert into volname's hash linked list */
775 hashindex = NameHash(aentry->name);
776 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
777 cheader.VolnameHash[hashindex] = htonl(blockindex);
778 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]), (char *) &cheader.VolnameHash[hashindex], sizeof(afs_int32));
779 if (code) return VL_IO;
784 int UnhashVolname(trans, blockindex, aentry)
785 struct ubik_trans *trans;
786 afs_int32 blockindex;
787 struct nvlentry *aentry;
788 { register afs_int32 hashindex, nextblockindex, prevblockindex;
789 struct nvlentry tentry;
792 /* Take it out of the Volname hash list */
793 hashindex = NameHash(aentry->name);
794 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
795 if (nextblockindex == blockindex) {
796 /* First on the hash list; just adjust pointers */
797 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
798 if (vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]), (char *) &cheader.VolnameHash[hashindex], sizeof(afs_int32))) return VL_IO;
800 while (nextblockindex != blockindex) {
801 prevblockindex = nextblockindex; /* always done at least once */
802 if (vlentryread(trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
804 if ((nextblockindex = tentry.nextNameHash) == NULLO)
807 tentry.nextNameHash = aentry->nextNameHash;
808 temp = htonl(tentry.nextNameHash);
809 if (vlwrite(trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash), (char *)&temp, sizeof(afs_int32)))
812 aentry->nextNameHash = 0;
817 /* Returns the vldb entry tentry at offset index; remaining is the number of entries left; the routine also returns the index of the next sequential entry in the vldb */
819 afs_int32 NextEntry (trans, blockindex, tentry, remaining)
820 struct ubik_trans *trans;
821 afs_int32 blockindex;
822 struct nvlentry *tentry;
823 afs_int32 *remaining;
824 { register afs_int32 lastblockindex;
826 if (blockindex == 0) /* get first one */
827 blockindex = sizeof(cheader);
829 if (!index_OK (trans, blockindex)) {
830 *remaining = -1; /* error */
833 blockindex += sizeof(nvlentry);
835 /* now search for the first entry that isn't free */
836 for (lastblockindex = ntohl(cheader.vital_header.eofPtr); blockindex < lastblockindex;) {
837 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
841 if (tentry->flags == VLCONTBLOCK) {
843 * This is a special mh extension block just simply skip over it
845 blockindex += VL_ADDREXTBLK_SIZE;
847 if (tentry->flags != VLFREE) {
848 /* estimate remaining number of entries, not including this one */
849 *remaining = (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
852 blockindex += sizeof(nvlentry);
855 *remaining = 0; /* no more entries */
860 /* Routine to verify that index is a legal offset to a vldb entry in the table */
861 static int index_OK (trans, blockindex)
862 struct ubik_trans *trans;
863 afs_int32 blockindex;
865 if ((blockindex < sizeof(cheader)) || (blockindex >= ntohl(cheader.vital_header.eofPtr)))