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>
16 #include <sys/types.h>
21 #include <netinet/in.h>
29 extern struct vlheader cheader;
30 struct vlheader xheader;
31 extern afs_uint32 HostAddress[];
32 extern int maxnservers;
33 struct extentaddr extentaddr;
34 extern struct extentaddr *ex_addr[];
37 static int index_OK();
39 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
41 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
46 return ((abs(volumeid)) % HASHSIZE);
50 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
53 register char *volumename;
55 register unsigned int hash;
59 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
60 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
61 return (hash % HASHSIZE);
65 /* package up seek and write into one procedure for ease of use */
67 vlwrite(trans, offset, buffer, length)
68 struct ubik_trans *trans;
75 if (errorcode = ubik_Seek(trans, 0, offset))
77 return (ubik_Write(trans, buffer, length));
81 /* Package up seek and read into one procedure for ease of use */
83 vlread(trans, offset, buffer, length)
84 struct ubik_trans *trans;
91 if (errorcode = ubik_Seek(trans, 0, offset))
93 return (ubik_Read(trans, buffer, length));
97 /* take entry and convert to network order and write to disk */
99 vlentrywrite(trans, offset, buffer, length)
100 struct ubik_trans *trans;
105 struct vlentry oentry;
106 struct nvlentry nentry, *nep;
108 register afs_int32 i;
110 if (length != sizeof(oentry))
112 if (maxnservers == 13) {
113 nep = (struct nvlentry *)buffer;
114 for (i = 0; i < MAXTYPES; i++)
115 nentry.volumeId[i] = htonl(nep->volumeId[i]);
116 nentry.flags = htonl(nep->flags);
117 nentry.LockAfsId = htonl(nep->LockAfsId);
118 nentry.LockTimestamp = htonl(nep->LockTimestamp);
119 nentry.cloneId = htonl(nep->cloneId);
120 for (i = 0; i < MAXTYPES; i++)
121 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
122 nentry.nextNameHash = htonl(nep->nextNameHash);
123 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
124 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
125 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
126 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
127 bufp = (char *)&nentry;
129 memset(&oentry, 0, sizeof(struct vlentry));
130 nep = (struct nvlentry *)buffer;
131 for (i = 0; i < MAXTYPES; i++)
132 oentry.volumeId[i] = htonl(nep->volumeId[i]);
133 oentry.flags = htonl(nep->flags);
134 oentry.LockAfsId = htonl(nep->LockAfsId);
135 oentry.LockTimestamp = htonl(nep->LockTimestamp);
136 oentry.cloneId = htonl(nep->cloneId);
137 for (i = 0; i < MAXTYPES; i++)
138 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
139 oentry.nextNameHash = htonl(nep->nextNameHash);
140 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
141 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
142 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
143 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
144 bufp = (char *)&oentry;
146 return vlwrite(trans, offset, bufp, length);
149 /* read entry and convert to host order and write to disk */
151 vlentryread(trans, offset, buffer, length)
152 struct ubik_trans *trans;
157 struct vlentry *oep, tentry;
158 struct nvlentry *nep, *nbufp;
159 char *bufp = (char *)&tentry;
160 register afs_int32 i;
162 if (length != sizeof(vlentry))
164 i = vlread(trans, offset, bufp, length);
167 if (maxnservers == 13) {
168 nep = (struct nvlentry *)bufp;
169 nbufp = (struct nvlentry *)buffer;
170 for (i = 0; i < MAXTYPES; i++)
171 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
172 nbufp->flags = ntohl(nep->flags);
173 nbufp->LockAfsId = ntohl(nep->LockAfsId);
174 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
175 nbufp->cloneId = ntohl(nep->cloneId);
176 for (i = 0; i < MAXTYPES; i++)
177 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
178 nbufp->nextNameHash = ntohl(nep->nextNameHash);
179 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
180 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
181 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
182 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
184 oep = (struct vlentry *)bufp;
185 nbufp = (struct nvlentry *)buffer;
186 memset(nbufp, 0, sizeof(struct nvlentry));
187 for (i = 0; i < MAXTYPES; i++)
188 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
189 nbufp->flags = ntohl(oep->flags);
190 nbufp->LockAfsId = ntohl(oep->LockAfsId);
191 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
192 nbufp->cloneId = ntohl(oep->cloneId);
193 for (i = 0; i < MAXTYPES; i++)
194 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
195 nbufp->nextNameHash = ntohl(oep->nextNameHash);
196 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
197 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
198 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
199 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
204 /* Convenient write of small critical vldb header info to the database. */
206 write_vital_vlheader(trans)
207 register struct ubik_trans *trans;
210 (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
218 /* This routine reads in the extent blocks for multi-homed servers.
219 * There used to be an initialization bug that would cause the contaddrs
220 * pointers in the first extent block to be bad. Here we will check the
221 * pointers and zero them in the in-memory copy if we find them bad. We
222 * also try to write the extent blocks back out. If we can't, then we
223 * will wait until the next write transaction to write them out
224 * (extent_mod tells us the on-disk copy is bad).
228 struct ubik_trans *trans;
230 afs_uint32 extentAddr;
231 afs_int32 error = 0, code;
235 extentAddr = ntohl(cheader.SIT);
239 /* Read the first extension block */
241 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
243 ERROR_EXIT(VL_NOMEM);
245 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
247 free(ex_addr[0]); /* Not the place to create it */
252 /* In case more that 64 mh servers are in use they're kept in these
253 * continuation blocks
255 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
256 if (!ex_addr[0]->ex_contaddrs[i])
259 /* Before reading it in, check to see if the address is good */
260 if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
261 ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
262 || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
263 ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
265 ex_addr[0]->ex_contaddrs[i] = 0;
270 /* Read the continuation block */
272 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
274 ERROR_EXIT(VL_NOMEM);
277 vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
278 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
280 free(ex_addr[i]); /* Not the place to create it */
285 /* After reading it in, check to see if its a real continuation block */
286 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
288 ex_addr[0]->ex_contaddrs[i] = 0;
289 free(ex_addr[i]); /* Not the place to create it */
296 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
298 VLog(0, ("Multihome server support modification\n"));
300 /* Keep extent_mod true in-case the transaction aborts */
301 /* Don't return error so we don't abort transaction */
308 /* Check that the database has been initialized. Be careful to fail in a safe
309 manner, to avoid bogusly reinitializing the db. */
311 CheckInit(trans, builddb)
312 struct ubik_trans *trans;
315 afs_int32 error = 0, i, code, ubcode = 0;
317 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
318 * previous transaction would have left the cache fine, and non-zero otherwise.
319 * Thus, a local abort or a remote commit will cause this to return non-zero
320 * and force a header re-read. Necessary for a local abort because we may
321 * have damaged cheader during the operation. Necessary for a remote commit
322 * since it may have changed cheader.
324 if (ubik_CacheUpdate(trans) != 0) {
325 /* if version changed (or first call), read the header */
326 ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
327 vldbversion = ntohl(cheader.vital_header.vldbversion);
329 if (!ubcode && (vldbversion != 0)) {
330 memcpy(HostAddress, cheader.IpMappedAddr,
331 sizeof(cheader.IpMappedAddr));
332 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
333 HostAddress[i] = ntohl(HostAddress[i]);
336 code = readExtents(trans);
342 vldbversion = ntohl(cheader.vital_header.vldbversion);
344 /* now, if can't read, or header is wrong, write a new header */
345 if (ubcode || vldbversion == 0) {
347 printf("Can't read VLDB header, re-initialising...\n");
349 /* try to write a good header */
350 memset(&cheader, 0, sizeof(cheader));
351 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
352 cheader.vital_header.headersize = htonl(sizeof(cheader));
353 /* DANGER: Must get this from a master place!! */
354 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
355 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
356 for (i = 0; i < MAXSERVERID + 1; i++) {
357 cheader.IpMappedAddr[i] = 0;
360 code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
362 printf("Can't write VLDB header (error = %d)\n", code);
366 ERROR_EXIT(VL_EMPTY);
367 } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
368 && (vldbversion != VLDBVERSION_4)) {
370 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
371 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
372 ERROR_EXIT(VL_BADVERSION);
375 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
384 GetExtentBlock(trans, base)
385 register struct ubik_trans *trans;
386 register afs_int32 base;
388 afs_int32 blockindex, code, error = 0;
390 /* Base 0 must exist before any other can be created */
391 if ((base != 0) && !ex_addr[0])
392 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
394 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
395 /* Create a new extension block */
396 if (!ex_addr[base]) {
397 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
399 ERROR_EXIT(VL_NOMEM);
401 memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
403 /* Write the full extension block at end of vldb */
404 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
405 blockindex = ntohl(cheader.vital_header.eofPtr);
407 vlwrite(trans, blockindex, (char *)ex_addr[base],
412 /* Update the cheader.vitalheader structure on disk */
413 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
414 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
415 code = write_vital_vlheader(trans);
419 /* Write the address of the base extension block in the vldb header */
421 cheader.SIT = htonl(blockindex);
423 vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
424 (char *)&cheader.SIT, sizeof(cheader.SIT));
429 /* Write the address of this extension block into the base extension block */
430 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
432 vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
433 sizeof(struct extentaddr));
444 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
445 register struct ubik_trans *trans;
447 afs_int32 createit, hostslot, *basep;
448 struct extentaddr **expp;
451 struct extentaddr *exp;
452 register afs_int32 i, j, code, base, index, error = 0;
457 /* Create the first extension block if it does not exist */
459 code = GetExtentBlock(trans, 0);
464 for (i = 0; i < MAXSERVERID + 1; i++) {
465 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
466 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
467 ERROR_EXIT(VL_INDEXERANGE);
469 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
470 ERROR_EXIT(VL_INDEXERANGE);
472 exp = &ex_addr[base][index];
473 tuuid = exp->ex_hostuuid;
474 afs_ntohuuid(&tuuid);
475 if (afs_uuid_equal(uuidp, &tuuid)) {
484 if (hostslot == -1) {
485 for (i = 0; i < MAXSERVERID + 1; i++) {
490 ERROR_EXIT(VL_REPSFULL);
495 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
496 if (!ex_addr[0]->ex_contaddrs[base]) {
497 code = GetExtentBlock(trans, base);
501 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
502 exp = &ex_addr[base][j];
503 tuuid = exp->ex_hostuuid;
504 afs_ntohuuid(&tuuid);
505 if (afs_uuid_is_nil(&tuuid)) {
507 afs_htonuuid(&tuuid);
508 exp->ex_hostuuid = tuuid;
511 DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
512 (char *)ex_addr[base], (char *)exp),
513 (char *)&tuuid, sizeof(tuuid));
517 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
520 if (vldbversion != VLDBVERSION_4) {
521 cheader.vital_header.vldbversion =
522 htonl(VLDBVERSION_4);
523 code = write_vital_vlheader(trans);
527 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
531 &cheader.IpMappedAddr[i]),
532 (char *)&cheader.IpMappedAddr[i],
540 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
547 /* Allocate a free block of storage for entry, returning address of a new
548 zeroed entry (or zero if something is wrong). */
550 AllocBlock(trans, tentry)
551 register struct ubik_trans *trans;
552 struct nvlentry *tentry;
554 register afs_int32 blockindex;
556 if (cheader.vital_header.freePtr) {
557 /* allocate this dude */
558 blockindex = ntohl(cheader.vital_header.freePtr);
559 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
561 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
563 /* hosed, nothing on free list, grow file */
564 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
565 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
567 cheader.vital_header.allocs++;
568 if (write_vital_vlheader(trans))
570 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
575 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
577 FreeBlock(trans, blockindex)
578 struct ubik_trans *trans;
579 afs_int32 blockindex;
581 struct nvlentry tentry;
583 /* check validity of blockindex just to be on the safe side */
584 if (!index_OK(trans, blockindex))
586 memset(&tentry, 0, sizeof(nvlentry));
587 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
588 tentry.flags = htonl(VLFREE);
589 cheader.vital_header.freePtr = htonl(blockindex);
590 if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
592 cheader.vital_header.frees++;
593 if (write_vital_vlheader(trans))
599 /* 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. */
601 FindByID(trans, volid, voltype, tentry, error)
602 struct ubik_trans *trans;
605 struct nvlentry *tentry;
608 register afs_int32 typeindex, hashindex, blockindex;
611 hashindex = IDHash(volid);
613 /* Should we have one big hash table for volids as opposed to the three ones? */
614 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
615 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
617 blockindex = tentry->nextIdHash[typeindex]) {
619 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
623 if (volid == tentry->volumeId[typeindex])
628 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
629 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
631 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
635 if (volid == tentry->volumeId[voltype])
639 return 0; /* no such entry */
643 /* 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. */
645 FindByName(trans, volname, tentry, error)
646 struct ubik_trans *trans;
648 struct nvlentry *tentry;
651 register afs_int32 hashindex;
652 register afs_int32 blockindex;
653 char tname[VL_MAXNAMELEN];
655 /* remove .backup or .readonly extensions for stupid backwards compatibility */
656 hashindex = strlen(volname); /* really string length */
657 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
658 /* this is a backup volume */
659 strcpy(tname, volname);
660 tname[hashindex - 7] = 0; /* zap extension */
661 } else if (hashindex >= 10
662 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
663 /* this is a readonly volume */
664 strcpy(tname, volname);
665 tname[hashindex - 9] = 0; /* zap extension */
667 strcpy(tname, volname);
670 hashindex = NameHash(tname);
671 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
672 blockindex != NULLO; blockindex = tentry->nextNameHash) {
673 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
677 if (!strcmp(tname, tentry->name))
680 return 0; /* no such entry */
684 HashNDump(trans, hashindex)
685 struct ubik_trans *trans;
690 register int blockindex;
691 struct nvlentry tentry;
693 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
694 blockindex != NULLO; blockindex = tentry.nextNameHash) {
695 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
699 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
700 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
707 HashIdDump(trans, hashindex)
708 struct ubik_trans *trans;
713 register int blockindex;
714 struct nvlentry tentry;
716 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
717 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
718 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
722 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
723 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
729 /* 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. */
731 ThreadVLentry(trans, blockindex, tentry)
732 struct ubik_trans *trans;
733 afs_int32 blockindex;
734 struct nvlentry *tentry;
738 if (!index_OK(trans, blockindex))
740 /* Insert into volid's hash linked list */
741 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
744 /* 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! */
745 if (tentry->volumeId[ROVOL]) {
746 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
749 if (tentry->volumeId[BACKVOL]) {
750 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
754 /* Insert into volname's hash linked list */
755 HashVolname(trans, blockindex, tentry);
757 /* Update cheader entry */
758 if (write_vital_vlheader(trans))
761 /* Update hash list pointers in the entry itself */
762 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
768 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
770 UnthreadVLentry(trans, blockindex, aentry)
771 struct ubik_trans *trans;
772 afs_int32 blockindex;
773 struct nvlentry *aentry;
775 register afs_int32 errorcode, typeindex;
777 if (!index_OK(trans, blockindex))
779 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
782 /* Take the RO/RW entries of their respective hash linked lists. */
783 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
784 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
788 /* Take it out of the Volname hash list */
789 if (errorcode = UnhashVolname(trans, blockindex, aentry))
792 /* Update cheader entry */
793 write_vital_vlheader(trans);
798 /* cheader must have be read before this routine is called. */
800 HashVolid(trans, voltype, blockindex, tentry)
801 struct ubik_trans *trans;
803 afs_int32 blockindex;
804 struct nvlentry *tentry;
806 afs_int32 hashindex, errorcode;
807 struct vlentry ventry;
810 (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
811 return VL_IDALREADYHASHED;
814 hashindex = IDHash(tentry->volumeId[voltype]);
815 tentry->nextIdHash[voltype] =
816 ntohl(cheader.VolidHash[voltype][hashindex]);
817 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
819 (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
820 (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
826 /* cheader must have be read before this routine is called. */
828 UnhashVolid(trans, voltype, blockindex, aentry)
829 struct ubik_trans *trans;
831 afs_int32 blockindex;
832 struct nvlentry *aentry;
834 int hashindex, nextblockindex, prevblockindex;
835 struct nvlentry tentry;
839 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
841 /* Take it out of the VolId[voltype] hash list */
842 hashindex = IDHash(aentry->volumeId[voltype]);
843 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
844 if (nextblockindex == blockindex) {
845 /* First on the hash list; just adjust pointers */
846 cheader.VolidHash[voltype][hashindex] =
847 htonl(aentry->nextIdHash[voltype]);
851 &cheader.VolidHash[voltype][hashindex]),
852 (char *)&cheader.VolidHash[voltype][hashindex],
857 while (nextblockindex != blockindex) {
858 prevblockindex = nextblockindex; /* always done once */
860 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
862 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
865 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
866 temp = htonl(temp); /* convert to network byte order before writing */
869 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
870 (char *)&temp, sizeof(afs_int32)))
873 aentry->nextIdHash[voltype] = 0;
879 HashVolname(trans, blockindex, aentry)
880 struct ubik_trans *trans;
881 afs_int32 blockindex;
882 struct nvlentry *aentry;
884 register afs_int32 hashindex;
885 register afs_int32 code;
887 /* Insert into volname's hash linked list */
888 hashindex = NameHash(aentry->name);
889 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
890 cheader.VolnameHash[hashindex] = htonl(blockindex);
892 vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
893 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
901 UnhashVolname(trans, blockindex, aentry)
902 struct ubik_trans *trans;
903 afs_int32 blockindex;
904 struct nvlentry *aentry;
906 register afs_int32 hashindex, nextblockindex, prevblockindex;
907 struct nvlentry tentry;
910 /* Take it out of the Volname hash list */
911 hashindex = NameHash(aentry->name);
912 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
913 if (nextblockindex == blockindex) {
914 /* First on the hash list; just adjust pointers */
915 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
917 (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
918 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
921 while (nextblockindex != blockindex) {
922 prevblockindex = nextblockindex; /* always done at least once */
924 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
926 if ((nextblockindex = tentry.nextNameHash) == NULLO)
929 tentry.nextNameHash = aentry->nextNameHash;
930 temp = htonl(tentry.nextNameHash);
932 (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
933 (char *)&temp, sizeof(afs_int32)))
936 aentry->nextNameHash = 0;
941 /* 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 */
944 NextEntry(trans, blockindex, tentry, remaining)
945 struct ubik_trans *trans;
946 afs_int32 blockindex;
947 struct nvlentry *tentry;
948 afs_int32 *remaining;
950 register afs_int32 lastblockindex;
952 if (blockindex == 0) /* get first one */
953 blockindex = sizeof(cheader);
955 if (!index_OK(trans, blockindex)) {
956 *remaining = -1; /* error */
959 blockindex += sizeof(nvlentry);
961 /* now search for the first entry that isn't free */
962 for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
963 blockindex < lastblockindex;) {
964 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
968 if (tentry->flags == VLCONTBLOCK) {
970 * This is a special mh extension block just simply skip over it
972 blockindex += VL_ADDREXTBLK_SIZE;
974 if (tentry->flags != VLFREE) {
975 /* estimate remaining number of entries, not including this one */
977 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
980 blockindex += sizeof(nvlentry);
983 *remaining = 0; /* no more entries */
988 /* Routine to verify that index is a legal offset to a vldb entry in the table */
990 index_OK(trans, blockindex)
991 struct ubik_trans *trans;
992 afs_int32 blockindex;
994 if ((blockindex < sizeof(cheader))
995 || (blockindex >= ntohl(cheader.vital_header.eofPtr)))