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 <afsconfig.h>
11 #include <afs/param.h>
14 #include <sys/types.h>
19 #include <netinet/in.h>
27 extern struct vlheader cheader;
28 struct vlheader xheader;
29 extern afs_uint32 HostAddress[];
30 extern int maxnservers;
31 struct extentaddr extentaddr;
32 extern struct extentaddr *ex_addr[];
35 static int index_OK();
37 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
39 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
44 return ((abs(volumeid)) % HASHSIZE);
48 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
51 register char *volumename;
53 register unsigned int hash;
57 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
58 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
59 return (hash % HASHSIZE);
63 /* package up seek and write into one procedure for ease of use */
65 vlwrite(trans, offset, buffer, length)
66 struct ubik_trans *trans;
73 if (errorcode = ubik_Seek(trans, 0, offset))
75 return (ubik_Write(trans, buffer, length));
79 /* Package up seek and read into one procedure for ease of use */
81 vlread(trans, offset, buffer, length)
82 struct ubik_trans *trans;
89 if (errorcode = ubik_Seek(trans, 0, offset))
91 return (ubik_Read(trans, buffer, length));
95 /* take entry and convert to network order and write to disk */
97 vlentrywrite(trans, offset, buffer, length)
98 struct ubik_trans *trans;
103 struct vlentry oentry;
104 struct nvlentry nentry, *nep;
106 register afs_int32 i;
108 if (length != sizeof(oentry))
110 if (maxnservers == 13) {
111 nep = (struct nvlentry *)buffer;
112 for (i = 0; i < MAXTYPES; i++)
113 nentry.volumeId[i] = htonl(nep->volumeId[i]);
114 nentry.flags = htonl(nep->flags);
115 nentry.LockAfsId = htonl(nep->LockAfsId);
116 nentry.LockTimestamp = htonl(nep->LockTimestamp);
117 nentry.cloneId = htonl(nep->cloneId);
118 for (i = 0; i < MAXTYPES; i++)
119 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
120 nentry.nextNameHash = htonl(nep->nextNameHash);
121 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
122 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
123 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
124 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
125 bufp = (char *)&nentry;
127 memset(&oentry, 0, sizeof(struct vlentry));
128 nep = (struct nvlentry *)buffer;
129 for (i = 0; i < MAXTYPES; i++)
130 oentry.volumeId[i] = htonl(nep->volumeId[i]);
131 oentry.flags = htonl(nep->flags);
132 oentry.LockAfsId = htonl(nep->LockAfsId);
133 oentry.LockTimestamp = htonl(nep->LockTimestamp);
134 oentry.cloneId = htonl(nep->cloneId);
135 for (i = 0; i < MAXTYPES; i++)
136 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
137 oentry.nextNameHash = htonl(nep->nextNameHash);
138 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
139 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
140 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
141 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
142 bufp = (char *)&oentry;
144 return vlwrite(trans, offset, bufp, length);
147 /* read entry and convert to host order and write to disk */
149 vlentryread(trans, offset, buffer, length)
150 struct ubik_trans *trans;
155 struct vlentry *oep, tentry;
156 struct nvlentry *nep, *nbufp;
157 char *bufp = (char *)&tentry;
158 register afs_int32 i;
160 if (length != sizeof(vlentry))
162 i = vlread(trans, offset, bufp, length);
165 if (maxnservers == 13) {
166 nep = (struct nvlentry *)bufp;
167 nbufp = (struct nvlentry *)buffer;
168 for (i = 0; i < MAXTYPES; i++)
169 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
170 nbufp->flags = ntohl(nep->flags);
171 nbufp->LockAfsId = ntohl(nep->LockAfsId);
172 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
173 nbufp->cloneId = ntohl(nep->cloneId);
174 for (i = 0; i < MAXTYPES; i++)
175 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
176 nbufp->nextNameHash = ntohl(nep->nextNameHash);
177 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
178 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
179 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
180 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
182 oep = (struct vlentry *)bufp;
183 nbufp = (struct nvlentry *)buffer;
184 memset(nbufp, 0, sizeof(struct nvlentry));
185 for (i = 0; i < MAXTYPES; i++)
186 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
187 nbufp->flags = ntohl(oep->flags);
188 nbufp->LockAfsId = ntohl(oep->LockAfsId);
189 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
190 nbufp->cloneId = ntohl(oep->cloneId);
191 for (i = 0; i < MAXTYPES; i++)
192 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
193 nbufp->nextNameHash = ntohl(oep->nextNameHash);
194 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
195 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
196 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
197 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
202 /* Convenient write of small critical vldb header info to the database. */
204 write_vital_vlheader(trans)
205 register struct ubik_trans *trans;
208 (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
216 /* This routine reads in the extent blocks for multi-homed servers.
217 * There used to be an initialization bug that would cause the contaddrs
218 * pointers in the first extent block to be bad. Here we will check the
219 * pointers and zero them in the in-memory copy if we find them bad. We
220 * also try to write the extent blocks back out. If we can't, then we
221 * will wait until the next write transaction to write them out
222 * (extent_mod tells us the on-disk copy is bad).
226 struct ubik_trans *trans;
228 afs_uint32 extentAddr;
229 afs_int32 error = 0, code;
233 extentAddr = ntohl(cheader.SIT);
237 /* Read the first extension block */
239 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
241 ERROR_EXIT(VL_NOMEM);
243 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
245 free(ex_addr[0]); /* Not the place to create it */
250 /* In case more that 64 mh servers are in use they're kept in these
251 * continuation blocks
253 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
254 if (!ex_addr[0]->ex_contaddrs[i])
257 /* Before reading it in, check to see if the address is good */
258 if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
259 ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
260 || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
261 ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
263 ex_addr[0]->ex_contaddrs[i] = 0;
268 /* Read the continuation block */
270 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
272 ERROR_EXIT(VL_NOMEM);
275 vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
276 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
278 free(ex_addr[i]); /* Not the place to create it */
283 /* After reading it in, check to see if its a real continuation block */
284 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
286 ex_addr[0]->ex_contaddrs[i] = 0;
287 free(ex_addr[i]); /* Not the place to create it */
294 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
296 VLog(0, ("Multihome server support modification\n"));
298 /* Keep extent_mod true in-case the transaction aborts */
299 /* Don't return error so we don't abort transaction */
306 /* Check that the database has been initialized. Be careful to fail in a safe
307 manner, to avoid bogusly reinitializing the db. */
309 CheckInit(trans, builddb)
310 struct ubik_trans *trans;
313 afs_int32 error = 0, i, code, ubcode = 0;
315 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
316 * previous transaction would have left the cache fine, and non-zero otherwise.
317 * Thus, a local abort or a remote commit will cause this to return non-zero
318 * and force a header re-read. Necessary for a local abort because we may
319 * have damaged cheader during the operation. Necessary for a remote commit
320 * since it may have changed cheader.
322 if (ubik_CacheUpdate(trans) != 0) {
323 /* if version changed (or first call), read the header */
324 ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
325 vldbversion = ntohl(cheader.vital_header.vldbversion);
327 if (!ubcode && (vldbversion != 0)) {
328 memcpy(HostAddress, cheader.IpMappedAddr,
329 sizeof(cheader.IpMappedAddr));
330 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
331 HostAddress[i] = ntohl(HostAddress[i]);
334 code = readExtents(trans);
340 vldbversion = ntohl(cheader.vital_header.vldbversion);
342 /* now, if can't read, or header is wrong, write a new header */
343 if (ubcode || vldbversion == 0) {
345 printf("Can't read VLDB header, re-initialising...\n");
347 /* try to write a good header */
348 memset(&cheader, 0, sizeof(cheader));
349 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
350 cheader.vital_header.headersize = htonl(sizeof(cheader));
351 /* DANGER: Must get this from a master place!! */
352 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
353 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
354 for (i = 0; i < MAXSERVERID + 1; i++) {
355 cheader.IpMappedAddr[i] = 0;
358 code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
360 printf("Can't write VLDB header (error = %d)\n", code);
364 ERROR_EXIT(VL_EMPTY);
365 } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
366 && (vldbversion != VLDBVERSION_4)) {
368 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
369 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
370 ERROR_EXIT(VL_BADVERSION);
373 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
382 GetExtentBlock(trans, base)
383 register struct ubik_trans *trans;
384 register afs_int32 base;
386 afs_int32 blockindex, code, error = 0;
388 /* Base 0 must exist before any other can be created */
389 if ((base != 0) && !ex_addr[0])
390 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
392 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
393 /* Create a new extension block */
394 if (!ex_addr[base]) {
395 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
397 ERROR_EXIT(VL_NOMEM);
399 memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
401 /* Write the full extension block at end of vldb */
402 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
403 blockindex = ntohl(cheader.vital_header.eofPtr);
405 vlwrite(trans, blockindex, (char *)ex_addr[base],
410 /* Update the cheader.vitalheader structure on disk */
411 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
412 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
413 code = write_vital_vlheader(trans);
417 /* Write the address of the base extension block in the vldb header */
419 cheader.SIT = htonl(blockindex);
421 vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
422 (char *)&cheader.SIT, sizeof(cheader.SIT));
427 /* Write the address of this extension block into the base extension block */
428 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
430 vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
431 sizeof(struct extentaddr));
442 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
443 register struct ubik_trans *trans;
445 afs_int32 createit, hostslot, *basep;
446 struct extentaddr **expp;
449 struct extentaddr *exp;
450 register afs_int32 i, j, code, base, index, error = 0;
455 /* Create the first extension block if it does not exist */
457 code = GetExtentBlock(trans, 0);
462 for (i = 0; i < MAXSERVERID + 1; i++) {
463 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
464 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
465 ERROR_EXIT(VL_INDEXERANGE);
467 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
468 ERROR_EXIT(VL_INDEXERANGE);
470 exp = &ex_addr[base][index];
471 tuuid = exp->ex_hostuuid;
472 afs_ntohuuid(&tuuid);
473 if (afs_uuid_equal(uuidp, &tuuid)) {
482 if (hostslot == -1) {
483 for (i = 0; i < MAXSERVERID + 1; i++) {
488 ERROR_EXIT(VL_REPSFULL);
493 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
494 if (!ex_addr[0]->ex_contaddrs[base]) {
495 code = GetExtentBlock(trans, base);
499 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
500 exp = &ex_addr[base][j];
501 tuuid = exp->ex_hostuuid;
502 afs_ntohuuid(&tuuid);
503 if (afs_uuid_is_nil(&tuuid)) {
505 afs_htonuuid(&tuuid);
506 exp->ex_hostuuid = tuuid;
509 DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
510 (char *)ex_addr[base], (char *)exp),
511 (char *)&tuuid, sizeof(tuuid));
515 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
518 if (vldbversion != VLDBVERSION_4) {
519 cheader.vital_header.vldbversion =
520 htonl(VLDBVERSION_4);
521 code = write_vital_vlheader(trans);
525 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
529 &cheader.IpMappedAddr[i]),
530 (char *)&cheader.IpMappedAddr[i],
538 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
545 /* Allocate a free block of storage for entry, returning address of a new
546 zeroed entry (or zero if something is wrong). */
548 AllocBlock(trans, tentry)
549 register struct ubik_trans *trans;
550 struct nvlentry *tentry;
552 register afs_int32 blockindex;
554 if (cheader.vital_header.freePtr) {
555 /* allocate this dude */
556 blockindex = ntohl(cheader.vital_header.freePtr);
557 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
559 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
561 /* hosed, nothing on free list, grow file */
562 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
563 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
565 cheader.vital_header.allocs++;
566 if (write_vital_vlheader(trans))
568 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
573 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
575 FreeBlock(trans, blockindex)
576 struct ubik_trans *trans;
577 afs_int32 blockindex;
579 struct nvlentry tentry;
581 /* check validity of blockindex just to be on the safe side */
582 if (!index_OK(trans, blockindex))
584 memset(&tentry, 0, sizeof(nvlentry));
585 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
586 tentry.flags = htonl(VLFREE);
587 cheader.vital_header.freePtr = htonl(blockindex);
588 if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
590 cheader.vital_header.frees++;
591 if (write_vital_vlheader(trans))
597 /* 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. */
599 FindByID(trans, volid, voltype, tentry, error)
600 struct ubik_trans *trans;
603 struct nvlentry *tentry;
606 register afs_int32 typeindex, hashindex, blockindex;
609 hashindex = IDHash(volid);
611 /* Should we have one big hash table for volids as opposed to the three ones? */
612 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
613 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
615 blockindex = tentry->nextIdHash[typeindex]) {
617 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
621 if (volid == tentry->volumeId[typeindex])
626 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
627 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
629 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
633 if (volid == tentry->volumeId[voltype])
637 return 0; /* no such entry */
641 /* 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. */
643 FindByName(trans, volname, tentry, error)
644 struct ubik_trans *trans;
646 struct nvlentry *tentry;
649 register afs_int32 hashindex;
650 register afs_int32 blockindex;
651 char tname[VL_MAXNAMELEN];
653 /* remove .backup or .readonly extensions for stupid backwards compatibility */
654 hashindex = strlen(volname); /* really string length */
655 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
656 /* this is a backup volume */
657 strcpy(tname, volname);
658 tname[hashindex - 7] = 0; /* zap extension */
659 } else if (hashindex >= 10
660 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
661 /* this is a readonly volume */
662 strcpy(tname, volname);
663 tname[hashindex - 9] = 0; /* zap extension */
665 strcpy(tname, volname);
668 hashindex = NameHash(tname);
669 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
670 blockindex != NULLO; blockindex = tentry->nextNameHash) {
671 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
675 if (!strcmp(tname, tentry->name))
678 return 0; /* no such entry */
682 HashNDump(trans, hashindex)
683 struct ubik_trans *trans;
688 register int blockindex;
689 struct nvlentry tentry;
691 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
692 blockindex != NULLO; blockindex = tentry.nextNameHash) {
693 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
697 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
698 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
705 HashIdDump(trans, hashindex)
706 struct ubik_trans *trans;
711 register int blockindex;
712 struct nvlentry tentry;
714 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
715 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
716 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
720 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
721 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
727 /* 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. */
729 ThreadVLentry(trans, blockindex, tentry)
730 struct ubik_trans *trans;
731 afs_int32 blockindex;
732 struct nvlentry *tentry;
736 if (!index_OK(trans, blockindex))
738 /* Insert into volid's hash linked list */
739 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
742 /* 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! */
743 if (tentry->volumeId[ROVOL]) {
744 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
747 if (tentry->volumeId[BACKVOL]) {
748 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
752 /* Insert into volname's hash linked list */
753 HashVolname(trans, blockindex, tentry);
755 /* Update cheader entry */
756 if (write_vital_vlheader(trans))
759 /* Update hash list pointers in the entry itself */
760 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
766 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
768 UnthreadVLentry(trans, blockindex, aentry)
769 struct ubik_trans *trans;
770 afs_int32 blockindex;
771 struct nvlentry *aentry;
773 register afs_int32 errorcode, typeindex;
775 if (!index_OK(trans, blockindex))
777 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
780 /* Take the RO/RW entries of their respective hash linked lists. */
781 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
782 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
786 /* Take it out of the Volname hash list */
787 if (errorcode = UnhashVolname(trans, blockindex, aentry))
790 /* Update cheader entry */
791 write_vital_vlheader(trans);
796 /* cheader must have be read before this routine is called. */
798 HashVolid(trans, voltype, blockindex, tentry)
799 struct ubik_trans *trans;
801 afs_int32 blockindex;
802 struct nvlentry *tentry;
804 afs_int32 hashindex, errorcode;
805 struct vlentry ventry;
808 (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
809 return VL_IDALREADYHASHED;
812 hashindex = IDHash(tentry->volumeId[voltype]);
813 tentry->nextIdHash[voltype] =
814 ntohl(cheader.VolidHash[voltype][hashindex]);
815 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
817 (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
818 (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
824 /* cheader must have be read before this routine is called. */
826 UnhashVolid(trans, voltype, blockindex, aentry)
827 struct ubik_trans *trans;
829 afs_int32 blockindex;
830 struct nvlentry *aentry;
832 int hashindex, nextblockindex, prevblockindex;
833 struct nvlentry tentry;
837 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
839 /* Take it out of the VolId[voltype] hash list */
840 hashindex = IDHash(aentry->volumeId[voltype]);
841 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
842 if (nextblockindex == blockindex) {
843 /* First on the hash list; just adjust pointers */
844 cheader.VolidHash[voltype][hashindex] =
845 htonl(aentry->nextIdHash[voltype]);
849 &cheader.VolidHash[voltype][hashindex]),
850 (char *)&cheader.VolidHash[voltype][hashindex],
855 while (nextblockindex != blockindex) {
856 prevblockindex = nextblockindex; /* always done once */
858 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
860 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
863 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
864 temp = htonl(temp); /* convert to network byte order before writing */
867 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
868 (char *)&temp, sizeof(afs_int32)))
871 aentry->nextIdHash[voltype] = 0;
877 HashVolname(trans, blockindex, aentry)
878 struct ubik_trans *trans;
879 afs_int32 blockindex;
880 struct nvlentry *aentry;
882 register afs_int32 hashindex;
883 register afs_int32 code;
885 /* Insert into volname's hash linked list */
886 hashindex = NameHash(aentry->name);
887 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
888 cheader.VolnameHash[hashindex] = htonl(blockindex);
890 vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
891 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
899 UnhashVolname(trans, blockindex, aentry)
900 struct ubik_trans *trans;
901 afs_int32 blockindex;
902 struct nvlentry *aentry;
904 register afs_int32 hashindex, nextblockindex, prevblockindex;
905 struct nvlentry tentry;
908 /* Take it out of the Volname hash list */
909 hashindex = NameHash(aentry->name);
910 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
911 if (nextblockindex == blockindex) {
912 /* First on the hash list; just adjust pointers */
913 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
915 (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
916 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
919 while (nextblockindex != blockindex) {
920 prevblockindex = nextblockindex; /* always done at least once */
922 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
924 if ((nextblockindex = tentry.nextNameHash) == NULLO)
927 tentry.nextNameHash = aentry->nextNameHash;
928 temp = htonl(tentry.nextNameHash);
930 (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
931 (char *)&temp, sizeof(afs_int32)))
934 aentry->nextNameHash = 0;
939 /* 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 */
942 NextEntry(trans, blockindex, tentry, remaining)
943 struct ubik_trans *trans;
944 afs_int32 blockindex;
945 struct nvlentry *tentry;
946 afs_int32 *remaining;
948 register afs_int32 lastblockindex;
950 if (blockindex == 0) /* get first one */
951 blockindex = sizeof(cheader);
953 if (!index_OK(trans, blockindex)) {
954 *remaining = -1; /* error */
957 blockindex += sizeof(nvlentry);
959 /* now search for the first entry that isn't free */
960 for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
961 blockindex < lastblockindex;) {
962 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
966 if (tentry->flags == VLCONTBLOCK) {
968 * This is a special mh extension block just simply skip over it
970 blockindex += VL_ADDREXTBLK_SIZE;
972 if (tentry->flags != VLFREE) {
973 /* estimate remaining number of entries, not including this one */
975 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
978 blockindex += sizeof(nvlentry);
981 *remaining = 0; /* no more entries */
986 /* Routine to verify that index is a legal offset to a vldb entry in the table */
988 index_OK(trans, blockindex)
989 struct ubik_trans *trans;
990 afs_int32 blockindex;
992 if ((blockindex < sizeof(cheader))
993 || (blockindex >= ntohl(cheader.vital_header.eofPtr)))