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>
20 #include <netinet/in.h>
36 extern struct vlheader cheader;
37 struct vlheader xheader;
38 extern afs_uint32 HostAddress[];
39 extern int maxnservers;
40 struct extentaddr extentaddr;
41 extern struct extentaddr *ex_addr[];
44 static int index_OK();
46 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
48 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
53 return ((abs(volumeid)) % HASHSIZE);
57 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
60 register char *volumename;
62 register unsigned int hash;
66 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
67 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
68 return (hash % HASHSIZE);
72 /* package up seek and write into one procedure for ease of use */
74 vlwrite(trans, offset, buffer, length)
75 struct ubik_trans *trans;
82 if (errorcode = ubik_Seek(trans, 0, offset))
84 return (ubik_Write(trans, buffer, length));
88 /* Package up seek and read into one procedure for ease of use */
90 vlread(trans, offset, buffer, length)
91 struct ubik_trans *trans;
98 if (errorcode = ubik_Seek(trans, 0, offset))
100 return (ubik_Read(trans, buffer, length));
104 /* take entry and convert to network order and write to disk */
106 vlentrywrite(trans, offset, buffer, length)
107 struct ubik_trans *trans;
112 struct vlentry oentry;
113 struct nvlentry nentry, *nep;
115 register afs_int32 i;
117 if (length != sizeof(oentry))
119 if (maxnservers == 13) {
120 nep = (struct nvlentry *)buffer;
121 for (i = 0; i < MAXTYPES; i++)
122 nentry.volumeId[i] = htonl(nep->volumeId[i]);
123 nentry.flags = htonl(nep->flags);
124 nentry.LockAfsId = htonl(nep->LockAfsId);
125 nentry.LockTimestamp = htonl(nep->LockTimestamp);
126 nentry.cloneId = htonl(nep->cloneId);
127 for (i = 0; i < MAXTYPES; i++)
128 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
129 nentry.nextNameHash = htonl(nep->nextNameHash);
130 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
131 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
132 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
133 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
134 bufp = (char *)&nentry;
136 memset(&oentry, 0, sizeof(struct vlentry));
137 nep = (struct nvlentry *)buffer;
138 for (i = 0; i < MAXTYPES; i++)
139 oentry.volumeId[i] = htonl(nep->volumeId[i]);
140 oentry.flags = htonl(nep->flags);
141 oentry.LockAfsId = htonl(nep->LockAfsId);
142 oentry.LockTimestamp = htonl(nep->LockTimestamp);
143 oentry.cloneId = htonl(nep->cloneId);
144 for (i = 0; i < MAXTYPES; i++)
145 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
146 oentry.nextNameHash = htonl(nep->nextNameHash);
147 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
148 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
149 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
150 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
151 bufp = (char *)&oentry;
153 return vlwrite(trans, offset, bufp, length);
156 /* read entry and convert to host order and write to disk */
158 vlentryread(trans, offset, buffer, length)
159 struct ubik_trans *trans;
164 struct vlentry *oep, tentry;
165 struct nvlentry *nep, *nbufp;
166 char *bufp = (char *)&tentry;
167 register afs_int32 i;
169 if (length != sizeof(vlentry))
171 i = vlread(trans, offset, bufp, length);
174 if (maxnservers == 13) {
175 nep = (struct nvlentry *)bufp;
176 nbufp = (struct nvlentry *)buffer;
177 for (i = 0; i < MAXTYPES; i++)
178 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
179 nbufp->flags = ntohl(nep->flags);
180 nbufp->LockAfsId = ntohl(nep->LockAfsId);
181 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
182 nbufp->cloneId = ntohl(nep->cloneId);
183 for (i = 0; i < MAXTYPES; i++)
184 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
185 nbufp->nextNameHash = ntohl(nep->nextNameHash);
186 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
187 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
188 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
189 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
191 oep = (struct vlentry *)bufp;
192 nbufp = (struct nvlentry *)buffer;
193 memset(nbufp, 0, sizeof(struct nvlentry));
194 for (i = 0; i < MAXTYPES; i++)
195 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
196 nbufp->flags = ntohl(oep->flags);
197 nbufp->LockAfsId = ntohl(oep->LockAfsId);
198 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
199 nbufp->cloneId = ntohl(oep->cloneId);
200 for (i = 0; i < MAXTYPES; i++)
201 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
202 nbufp->nextNameHash = ntohl(oep->nextNameHash);
203 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
204 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
205 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
206 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
211 /* Convenient write of small critical vldb header info to the database. */
213 write_vital_vlheader(trans)
214 register struct ubik_trans *trans;
217 (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
225 /* This routine reads in the extent blocks for multi-homed servers.
226 * There used to be an initialization bug that would cause the contaddrs
227 * pointers in the first extent block to be bad. Here we will check the
228 * pointers and zero them in the in-memory copy if we find them bad. We
229 * also try to write the extent blocks back out. If we can't, then we
230 * will wait until the next write transaction to write them out
231 * (extent_mod tells us the on-disk copy is bad).
235 struct ubik_trans *trans;
237 afs_uint32 extentAddr;
238 afs_int32 error = 0, code;
242 extentAddr = ntohl(cheader.SIT);
246 /* Read the first extension block */
248 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
250 ERROR_EXIT(VL_NOMEM);
252 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
254 free(ex_addr[0]); /* Not the place to create it */
259 /* In case more that 64 mh servers are in use they're kept in these
260 * continuation blocks
262 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
263 if (!ex_addr[0]->ex_contaddrs[i])
266 /* Before reading it in, check to see if the address is good */
267 if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
268 ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
269 || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
270 ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
272 ex_addr[0]->ex_contaddrs[i] = 0;
277 /* Read the continuation block */
279 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
281 ERROR_EXIT(VL_NOMEM);
284 vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
285 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
287 free(ex_addr[i]); /* Not the place to create it */
292 /* After reading it in, check to see if its a real continuation block */
293 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
295 ex_addr[0]->ex_contaddrs[i] = 0;
296 free(ex_addr[i]); /* Not the place to create it */
303 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
305 VLog(0, ("Multihome server support modification\n"));
307 /* Keep extent_mod true in-case the transaction aborts */
308 /* Don't return error so we don't abort transaction */
315 /* Check that the database has been initialized. Be careful to fail in a safe
316 manner, to avoid bogusly reinitializing the db. */
318 CheckInit(trans, builddb)
319 struct ubik_trans *trans;
322 afs_int32 error = 0, i, code, ubcode = 0;
324 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
325 * previous transaction would have left the cache fine, and non-zero otherwise.
326 * Thus, a local abort or a remote commit will cause this to return non-zero
327 * and force a header re-read. Necessary for a local abort because we may
328 * have damaged cheader during the operation. Necessary for a remote commit
329 * since it may have changed cheader.
331 if (ubik_CacheUpdate(trans) != 0) {
332 /* if version changed (or first call), read the header */
333 ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
334 vldbversion = ntohl(cheader.vital_header.vldbversion);
336 if (!ubcode && (vldbversion != 0)) {
337 memcpy(HostAddress, cheader.IpMappedAddr,
338 sizeof(cheader.IpMappedAddr));
339 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
340 HostAddress[i] = ntohl(HostAddress[i]);
343 code = readExtents(trans);
349 vldbversion = ntohl(cheader.vital_header.vldbversion);
351 /* now, if can't read, or header is wrong, write a new header */
352 if (ubcode || vldbversion == 0) {
354 printf("Can't read VLDB header, re-initialising...\n");
356 /* try to write a good header */
357 memset(&cheader, 0, sizeof(cheader));
358 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
359 cheader.vital_header.headersize = htonl(sizeof(cheader));
360 /* DANGER: Must get this from a master place!! */
361 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
362 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
363 for (i = 0; i < MAXSERVERID + 1; i++) {
364 cheader.IpMappedAddr[i] = 0;
367 code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
369 printf("Can't write VLDB header (error = %d)\n", code);
373 ERROR_EXIT(VL_EMPTY);
374 } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
375 && (vldbversion != VLDBVERSION_4)) {
377 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
378 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
379 ERROR_EXIT(VL_BADVERSION);
382 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
391 GetExtentBlock(trans, base)
392 register struct ubik_trans *trans;
393 register afs_int32 base;
395 afs_int32 blockindex, code, error = 0;
397 /* Base 0 must exist before any other can be created */
398 if ((base != 0) && !ex_addr[0])
399 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
401 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
402 /* Create a new extension block */
403 if (!ex_addr[base]) {
404 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
406 ERROR_EXIT(VL_NOMEM);
408 memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
410 /* Write the full extension block at end of vldb */
411 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
412 blockindex = ntohl(cheader.vital_header.eofPtr);
414 vlwrite(trans, blockindex, (char *)ex_addr[base],
419 /* Update the cheader.vitalheader structure on disk */
420 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
421 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
422 code = write_vital_vlheader(trans);
426 /* Write the address of the base extension block in the vldb header */
428 cheader.SIT = htonl(blockindex);
430 vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
431 (char *)&cheader.SIT, sizeof(cheader.SIT));
436 /* Write the address of this extension block into the base extension block */
437 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
439 vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
440 sizeof(struct extentaddr));
451 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
452 register struct ubik_trans *trans;
454 afs_int32 createit, hostslot, *basep;
455 struct extentaddr **expp;
458 struct extentaddr *exp;
459 register afs_int32 i, j, code, base, index, error = 0;
464 /* Create the first extension block if it does not exist */
466 code = GetExtentBlock(trans, 0);
471 for (i = 0; i < MAXSERVERID + 1; i++) {
472 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
473 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
474 ERROR_EXIT(VL_INDEXERANGE);
476 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
477 ERROR_EXIT(VL_INDEXERANGE);
479 exp = &ex_addr[base][index];
480 tuuid = exp->ex_hostuuid;
481 afs_ntohuuid(&tuuid);
482 if (afs_uuid_equal(uuidp, &tuuid)) {
491 if (hostslot == -1) {
492 for (i = 0; i < MAXSERVERID + 1; i++) {
497 ERROR_EXIT(VL_REPSFULL);
502 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
503 if (!ex_addr[0]->ex_contaddrs[base]) {
504 code = GetExtentBlock(trans, base);
508 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
509 exp = &ex_addr[base][j];
510 tuuid = exp->ex_hostuuid;
511 afs_ntohuuid(&tuuid);
512 if (afs_uuid_is_nil(&tuuid)) {
514 afs_htonuuid(&tuuid);
515 exp->ex_hostuuid = tuuid;
518 DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
519 (char *)ex_addr[base], (char *)exp),
520 (char *)&tuuid, sizeof(tuuid));
524 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
527 if (vldbversion != VLDBVERSION_4) {
528 cheader.vital_header.vldbversion =
529 htonl(VLDBVERSION_4);
530 code = write_vital_vlheader(trans);
534 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
538 &cheader.IpMappedAddr[i]),
539 (char *)&cheader.IpMappedAddr[i],
547 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
554 /* Allocate a free block of storage for entry, returning address of a new
555 zeroed entry (or zero if something is wrong). */
557 AllocBlock(trans, tentry)
558 register struct ubik_trans *trans;
559 struct nvlentry *tentry;
561 register afs_int32 blockindex;
563 if (cheader.vital_header.freePtr) {
564 /* allocate this dude */
565 blockindex = ntohl(cheader.vital_header.freePtr);
566 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
568 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
570 /* hosed, nothing on free list, grow file */
571 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
572 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
574 cheader.vital_header.allocs++;
575 if (write_vital_vlheader(trans))
577 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
582 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
584 FreeBlock(trans, blockindex)
585 struct ubik_trans *trans;
586 afs_int32 blockindex;
588 struct nvlentry tentry;
590 /* check validity of blockindex just to be on the safe side */
591 if (!index_OK(trans, blockindex))
593 memset(&tentry, 0, sizeof(nvlentry));
594 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
595 tentry.flags = htonl(VLFREE);
596 cheader.vital_header.freePtr = htonl(blockindex);
597 if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
599 cheader.vital_header.frees++;
600 if (write_vital_vlheader(trans))
606 /* 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. */
608 FindByID(trans, volid, voltype, tentry, error)
609 struct ubik_trans *trans;
612 struct nvlentry *tentry;
615 register afs_int32 typeindex, hashindex, blockindex;
618 hashindex = IDHash(volid);
620 /* Should we have one big hash table for volids as opposed to the three ones? */
621 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
622 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
624 blockindex = tentry->nextIdHash[typeindex]) {
626 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
630 if (volid == tentry->volumeId[typeindex])
635 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
636 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
638 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
642 if (volid == tentry->volumeId[voltype])
646 return 0; /* no such entry */
650 /* 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. */
652 FindByName(trans, volname, tentry, error)
653 struct ubik_trans *trans;
655 struct nvlentry *tentry;
658 register afs_int32 hashindex;
659 register afs_int32 blockindex;
660 char tname[VL_MAXNAMELEN];
662 /* remove .backup or .readonly extensions for stupid backwards compatibility */
663 hashindex = strlen(volname); /* really string length */
664 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
665 /* this is a backup volume */
666 strcpy(tname, volname);
667 tname[hashindex - 7] = 0; /* zap extension */
668 } else if (hashindex >= 10
669 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
670 /* this is a readonly volume */
671 strcpy(tname, volname);
672 tname[hashindex - 9] = 0; /* zap extension */
674 strcpy(tname, volname);
677 hashindex = NameHash(tname);
678 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
679 blockindex != NULLO; blockindex = tentry->nextNameHash) {
680 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
684 if (!strcmp(tname, tentry->name))
687 return 0; /* no such entry */
691 HashNDump(trans, hashindex)
692 struct ubik_trans *trans;
697 register int blockindex;
698 struct nvlentry tentry;
700 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
701 blockindex != NULLO; blockindex = tentry.nextNameHash) {
702 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
706 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
707 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
714 HashIdDump(trans, hashindex)
715 struct ubik_trans *trans;
720 register int blockindex;
721 struct nvlentry tentry;
723 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
724 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
725 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
729 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
730 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
736 /* 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. */
738 ThreadVLentry(trans, blockindex, tentry)
739 struct ubik_trans *trans;
740 afs_int32 blockindex;
741 struct nvlentry *tentry;
745 if (!index_OK(trans, blockindex))
747 /* Insert into volid's hash linked list */
748 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
751 /* 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! */
752 if (tentry->volumeId[ROVOL]) {
753 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
756 if (tentry->volumeId[BACKVOL]) {
757 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
761 /* Insert into volname's hash linked list */
762 HashVolname(trans, blockindex, tentry);
764 /* Update cheader entry */
765 if (write_vital_vlheader(trans))
768 /* Update hash list pointers in the entry itself */
769 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
775 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
777 UnthreadVLentry(trans, blockindex, aentry)
778 struct ubik_trans *trans;
779 afs_int32 blockindex;
780 struct nvlentry *aentry;
782 register afs_int32 errorcode, typeindex;
784 if (!index_OK(trans, blockindex))
786 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
789 /* Take the RO/RW entries of their respective hash linked lists. */
790 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
791 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
795 /* Take it out of the Volname hash list */
796 if (errorcode = UnhashVolname(trans, blockindex, aentry))
799 /* Update cheader entry */
800 write_vital_vlheader(trans);
805 /* cheader must have be read before this routine is called. */
807 HashVolid(trans, voltype, blockindex, tentry)
808 struct ubik_trans *trans;
810 afs_int32 blockindex;
811 struct nvlentry *tentry;
813 afs_int32 hashindex, errorcode;
814 struct vlentry ventry;
817 (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
818 return VL_IDALREADYHASHED;
821 hashindex = IDHash(tentry->volumeId[voltype]);
822 tentry->nextIdHash[voltype] =
823 ntohl(cheader.VolidHash[voltype][hashindex]);
824 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
826 (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
827 (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
833 /* cheader must have be read before this routine is called. */
835 UnhashVolid(trans, voltype, blockindex, aentry)
836 struct ubik_trans *trans;
838 afs_int32 blockindex;
839 struct nvlentry *aentry;
841 int hashindex, nextblockindex, prevblockindex;
842 struct nvlentry tentry;
846 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
848 /* Take it out of the VolId[voltype] hash list */
849 hashindex = IDHash(aentry->volumeId[voltype]);
850 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
851 if (nextblockindex == blockindex) {
852 /* First on the hash list; just adjust pointers */
853 cheader.VolidHash[voltype][hashindex] =
854 htonl(aentry->nextIdHash[voltype]);
858 &cheader.VolidHash[voltype][hashindex]),
859 (char *)&cheader.VolidHash[voltype][hashindex],
864 while (nextblockindex != blockindex) {
865 prevblockindex = nextblockindex; /* always done once */
867 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
869 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
872 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
873 temp = htonl(temp); /* convert to network byte order before writing */
876 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
877 (char *)&temp, sizeof(afs_int32)))
880 aentry->nextIdHash[voltype] = 0;
886 HashVolname(trans, blockindex, aentry)
887 struct ubik_trans *trans;
888 afs_int32 blockindex;
889 struct nvlentry *aentry;
891 register afs_int32 hashindex;
892 register afs_int32 code;
894 /* Insert into volname's hash linked list */
895 hashindex = NameHash(aentry->name);
896 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
897 cheader.VolnameHash[hashindex] = htonl(blockindex);
899 vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
900 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
908 UnhashVolname(trans, blockindex, aentry)
909 struct ubik_trans *trans;
910 afs_int32 blockindex;
911 struct nvlentry *aentry;
913 register afs_int32 hashindex, nextblockindex, prevblockindex;
914 struct nvlentry tentry;
917 /* Take it out of the Volname hash list */
918 hashindex = NameHash(aentry->name);
919 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
920 if (nextblockindex == blockindex) {
921 /* First on the hash list; just adjust pointers */
922 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
924 (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
925 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
928 while (nextblockindex != blockindex) {
929 prevblockindex = nextblockindex; /* always done at least once */
931 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
933 if ((nextblockindex = tentry.nextNameHash) == NULLO)
936 tentry.nextNameHash = aentry->nextNameHash;
937 temp = htonl(tentry.nextNameHash);
939 (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
940 (char *)&temp, sizeof(afs_int32)))
943 aentry->nextNameHash = 0;
948 /* 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 */
951 NextEntry(trans, blockindex, tentry, remaining)
952 struct ubik_trans *trans;
953 afs_int32 blockindex;
954 struct nvlentry *tentry;
955 afs_int32 *remaining;
957 register afs_int32 lastblockindex;
959 if (blockindex == 0) /* get first one */
960 blockindex = sizeof(cheader);
962 if (!index_OK(trans, blockindex)) {
963 *remaining = -1; /* error */
966 blockindex += sizeof(nvlentry);
968 /* now search for the first entry that isn't free */
969 for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
970 blockindex < lastblockindex;) {
971 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
975 if (tentry->flags == VLCONTBLOCK) {
977 * This is a special mh extension block just simply skip over it
979 blockindex += VL_ADDREXTBLK_SIZE;
981 if (tentry->flags != VLFREE) {
982 /* estimate remaining number of entries, not including this one */
984 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
987 blockindex += sizeof(nvlentry);
990 *remaining = 0; /* no more entries */
995 /* Routine to verify that index is a legal offset to a vldb entry in the table */
997 index_OK(trans, blockindex)
998 struct ubik_trans *trans;
999 afs_int32 blockindex;
1001 if ((blockindex < sizeof(cheader))
1002 || (blockindex >= ntohl(cheader.vital_header.eofPtr)))