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 struct ubik_dbase *VL_dbase;
39 extern afs_uint32 HostAddress[];
40 extern int maxnservers;
41 struct extentaddr extentaddr;
42 extern struct extentaddr *ex_addr[];
45 static int index_OK();
47 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
49 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
54 return ((abs(volumeid)) % HASHSIZE);
58 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
61 register char *volumename;
63 register unsigned int hash;
67 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
68 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
69 return (hash % HASHSIZE);
73 /* package up seek and write into one procedure for ease of use */
75 vlwrite(trans, offset, buffer, length)
76 struct ubik_trans *trans;
83 if (errorcode = ubik_Seek(trans, 0, offset))
85 return (ubik_Write(trans, buffer, length));
89 /* Package up seek and read into one procedure for ease of use */
91 vlread(trans, offset, buffer, length)
92 struct ubik_trans *trans;
99 if (errorcode = ubik_Seek(trans, 0, offset))
101 return (ubik_Read(trans, buffer, length));
105 /* take entry and convert to network order and write to disk */
107 vlentrywrite(trans, offset, buffer, length)
108 struct ubik_trans *trans;
113 struct vlentry oentry;
114 struct nvlentry nentry, *nep;
116 register afs_int32 i;
118 if (length != sizeof(oentry))
120 if (maxnservers == 13) {
121 nep = (struct nvlentry *)buffer;
122 for (i = 0; i < MAXTYPES; i++)
123 nentry.volumeId[i] = htonl(nep->volumeId[i]);
124 nentry.flags = htonl(nep->flags);
125 nentry.LockAfsId = htonl(nep->LockAfsId);
126 nentry.LockTimestamp = htonl(nep->LockTimestamp);
127 nentry.cloneId = htonl(nep->cloneId);
128 for (i = 0; i < MAXTYPES; i++)
129 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
130 nentry.nextNameHash = htonl(nep->nextNameHash);
131 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
132 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
133 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
134 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
135 bufp = (char *)&nentry;
137 memset(&oentry, 0, sizeof(struct vlentry));
138 nep = (struct nvlentry *)buffer;
139 for (i = 0; i < MAXTYPES; i++)
140 oentry.volumeId[i] = htonl(nep->volumeId[i]);
141 oentry.flags = htonl(nep->flags);
142 oentry.LockAfsId = htonl(nep->LockAfsId);
143 oentry.LockTimestamp = htonl(nep->LockTimestamp);
144 oentry.cloneId = htonl(nep->cloneId);
145 for (i = 0; i < MAXTYPES; i++)
146 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
147 oentry.nextNameHash = htonl(nep->nextNameHash);
148 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
149 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
150 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
151 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
152 bufp = (char *)&oentry;
154 return vlwrite(trans, offset, bufp, length);
157 /* read entry and convert to host order and write to disk */
159 vlentryread(trans, offset, buffer, length)
160 struct ubik_trans *trans;
165 struct vlentry *oep, tentry;
166 struct nvlentry *nep, *nbufp;
167 char *bufp = (char *)&tentry;
168 register afs_int32 i;
170 if (length != sizeof(vlentry))
172 i = vlread(trans, offset, bufp, length);
175 if (maxnservers == 13) {
176 nep = (struct nvlentry *)bufp;
177 nbufp = (struct nvlentry *)buffer;
178 for (i = 0; i < MAXTYPES; i++)
179 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
180 nbufp->flags = ntohl(nep->flags);
181 nbufp->LockAfsId = ntohl(nep->LockAfsId);
182 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
183 nbufp->cloneId = ntohl(nep->cloneId);
184 for (i = 0; i < MAXTYPES; i++)
185 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
186 nbufp->nextNameHash = ntohl(nep->nextNameHash);
187 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
188 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
189 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
190 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
192 oep = (struct vlentry *)bufp;
193 nbufp = (struct nvlentry *)buffer;
194 memset(nbufp, 0, sizeof(struct nvlentry));
195 for (i = 0; i < MAXTYPES; i++)
196 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
197 nbufp->flags = ntohl(oep->flags);
198 nbufp->LockAfsId = ntohl(oep->LockAfsId);
199 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
200 nbufp->cloneId = ntohl(oep->cloneId);
201 for (i = 0; i < MAXTYPES; i++)
202 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
203 nbufp->nextNameHash = ntohl(oep->nextNameHash);
204 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
205 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
206 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
207 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
212 /* Convenient write of small critical vldb header info to the database. */
214 write_vital_vlheader(trans)
215 register struct ubik_trans *trans;
218 (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
226 /* This routine reads in the extent blocks for multi-homed servers.
227 * There used to be an initialization bug that would cause the contaddrs
228 * pointers in the first extent block to be bad. Here we will check the
229 * pointers and zero them in the in-memory copy if we find them bad. We
230 * also try to write the extent blocks back out. If we can't, then we
231 * will wait until the next write transaction to write them out
232 * (extent_mod tells us the on-disk copy is bad).
236 struct ubik_trans *trans;
238 afs_uint32 extentAddr;
239 afs_int32 error = 0, code;
243 extentAddr = ntohl(cheader.SIT);
247 /* Read the first extension block */
249 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
251 ERROR_EXIT(VL_NOMEM);
253 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
255 free(ex_addr[0]); /* Not the place to create it */
260 /* In case more that 64 mh servers are in use they're kept in these
261 * continuation blocks
263 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
264 if (!ex_addr[0]->ex_contaddrs[i])
267 /* Before reading it in, check to see if the address is good */
268 if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
269 ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
270 || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
271 ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
273 ex_addr[0]->ex_contaddrs[i] = 0;
278 /* Read the continuation block */
280 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
282 ERROR_EXIT(VL_NOMEM);
285 vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
286 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
288 free(ex_addr[i]); /* Not the place to create it */
293 /* After reading it in, check to see if its a real continuation block */
294 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
296 ex_addr[0]->ex_contaddrs[i] = 0;
297 free(ex_addr[i]); /* Not the place to create it */
304 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
306 VLog(0, ("Multihome server support modification\n"));
308 /* Keep extent_mod true in-case the transaction aborts */
309 /* Don't return error so we don't abort transaction */
316 /* Check that the database has been initialized. Be careful to fail in a safe
317 manner, to avoid bogusly reinitializing the db. */
319 CheckInit(trans, builddb)
320 struct ubik_trans *trans;
323 afs_int32 error = 0, i, code, ubcode = 0;
325 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
326 * previous transaction would have left the cache fine, and non-zero otherwise.
327 * Thus, a local abort or a remote commit will cause this to return non-zero
328 * and force a header re-read. Necessary for a local abort because we may
329 * have damaged cheader during the operation. Necessary for a remote commit
330 * since it may have changed cheader.
332 if (ubik_CacheUpdate(trans) != 0) {
333 /* if version changed (or first call), read the header */
334 ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
335 vldbversion = ntohl(cheader.vital_header.vldbversion);
337 if (!ubcode && (vldbversion != 0)) {
338 memcpy(HostAddress, cheader.IpMappedAddr,
339 sizeof(cheader.IpMappedAddr));
340 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
341 HostAddress[i] = ntohl(HostAddress[i]);
344 code = readExtents(trans);
350 vldbversion = ntohl(cheader.vital_header.vldbversion);
352 /* now, if can't read, or header is wrong, write a new header */
353 if (ubcode || vldbversion == 0) {
355 printf("Can't read VLDB header, re-initialising...\n");
357 /* try to write a good header */
358 memset(&cheader, 0, sizeof(cheader));
359 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
360 cheader.vital_header.headersize = htonl(sizeof(cheader));
361 /* DANGER: Must get this from a master place!! */
362 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
363 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
364 for (i = 0; i < MAXSERVERID + 1; i++) {
365 cheader.IpMappedAddr[i] = 0;
368 code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
370 printf("Can't write VLDB header (error = %d)\n", code);
374 ERROR_EXIT(VL_EMPTY);
375 } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
376 && (vldbversion != VLDBVERSION_4)) {
378 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
379 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
380 ERROR_EXIT(VL_BADVERSION);
383 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
392 GetExtentBlock(trans, base)
393 register struct ubik_trans *trans;
394 register afs_int32 base;
396 afs_int32 blockindex, code, error = 0;
398 /* Base 0 must exist before any other can be created */
399 if ((base != 0) && !ex_addr[0])
400 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
402 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
403 /* Create a new extension block */
404 if (!ex_addr[base]) {
405 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
407 ERROR_EXIT(VL_NOMEM);
409 memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
411 /* Write the full extension block at end of vldb */
412 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
413 blockindex = ntohl(cheader.vital_header.eofPtr);
415 vlwrite(trans, blockindex, (char *)ex_addr[base],
420 /* Update the cheader.vitalheader structure on disk */
421 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
422 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
423 code = write_vital_vlheader(trans);
427 /* Write the address of the base extension block in the vldb header */
429 cheader.SIT = htonl(blockindex);
431 vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
432 (char *)&cheader.SIT, sizeof(cheader.SIT));
437 /* Write the address of this extension block into the base extension block */
438 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
440 vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
441 sizeof(struct extentaddr));
452 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
453 register struct ubik_trans *trans;
455 afs_int32 createit, hostslot, *basep;
456 struct extentaddr **expp;
459 struct extentaddr *exp;
460 register afs_int32 i, j, code, base, index, error = 0;
465 /* Create the first extension block if it does not exist */
467 code = GetExtentBlock(trans, 0);
472 for (i = 0; i < MAXSERVERID + 1; i++) {
473 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
474 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
475 ERROR_EXIT(VL_INDEXERANGE);
477 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
478 ERROR_EXIT(VL_INDEXERANGE);
480 exp = &ex_addr[base][index];
481 tuuid = exp->ex_hostuuid;
482 afs_ntohuuid(&tuuid);
483 if (afs_uuid_equal(uuidp, &tuuid)) {
492 if (hostslot == -1) {
493 for (i = 0; i < MAXSERVERID + 1; i++) {
498 ERROR_EXIT(VL_REPSFULL);
503 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
504 if (!ex_addr[0]->ex_contaddrs[base]) {
505 code = GetExtentBlock(trans, base);
509 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
510 exp = &ex_addr[base][j];
511 tuuid = exp->ex_hostuuid;
512 afs_ntohuuid(&tuuid);
513 if (afs_uuid_is_nil(&tuuid)) {
515 afs_htonuuid(&tuuid);
516 exp->ex_hostuuid = tuuid;
519 DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
520 (char *)ex_addr[base], (char *)exp),
521 (char *)&tuuid, sizeof(tuuid));
525 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
528 if (vldbversion != VLDBVERSION_4) {
529 cheader.vital_header.vldbversion =
530 htonl(VLDBVERSION_4);
531 code = write_vital_vlheader(trans);
535 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
539 &cheader.IpMappedAddr[i]),
540 (char *)&cheader.IpMappedAddr[i],
548 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
555 /* Allocate a free block of storage for entry, returning address of a new
556 zeroed entry (or zero if something is wrong). */
558 AllocBlock(trans, tentry)
559 register struct ubik_trans *trans;
560 struct nvlentry *tentry;
562 register afs_int32 blockindex;
564 if (cheader.vital_header.freePtr) {
565 /* allocate this dude */
566 blockindex = ntohl(cheader.vital_header.freePtr);
567 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
569 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
571 /* hosed, nothing on free list, grow file */
572 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
573 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
575 cheader.vital_header.allocs++;
576 if (write_vital_vlheader(trans))
578 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
583 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
585 FreeBlock(trans, blockindex)
586 struct ubik_trans *trans;
587 afs_int32 blockindex;
589 struct nvlentry tentry;
591 /* check validity of blockindex just to be on the safe side */
592 if (!index_OK(trans, blockindex))
594 memset(&tentry, 0, sizeof(nvlentry));
595 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
596 tentry.flags = htonl(VLFREE);
597 cheader.vital_header.freePtr = htonl(blockindex);
598 if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
600 cheader.vital_header.frees++;
601 if (write_vital_vlheader(trans))
607 /* 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. */
609 FindByID(trans, volid, voltype, tentry, error)
610 struct ubik_trans *trans;
613 struct nvlentry *tentry;
616 register afs_int32 typeindex, hashindex, blockindex;
619 hashindex = IDHash(volid);
621 /* Should we have one big hash table for volids as opposed to the three ones? */
622 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
623 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
625 blockindex = tentry->nextIdHash[typeindex]) {
627 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
631 if (volid == tentry->volumeId[typeindex])
636 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
637 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
639 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
643 if (volid == tentry->volumeId[voltype])
647 return 0; /* no such entry */
651 /* 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. */
653 FindByName(trans, volname, tentry, error)
654 struct ubik_trans *trans;
656 struct nvlentry *tentry;
659 register afs_int32 hashindex;
660 register afs_int32 blockindex;
661 char tname[VL_MAXNAMELEN];
663 /* remove .backup or .readonly extensions for stupid backwards compatibility */
664 hashindex = strlen(volname); /* really string length */
665 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
666 /* this is a backup volume */
667 strcpy(tname, volname);
668 tname[hashindex - 7] = 0; /* zap extension */
669 } else if (hashindex >= 10
670 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
671 /* this is a readonly volume */
672 strcpy(tname, volname);
673 tname[hashindex - 9] = 0; /* zap extension */
675 strcpy(tname, volname);
678 hashindex = NameHash(tname);
679 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
680 blockindex != NULLO; blockindex = tentry->nextNameHash) {
681 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
685 if (!strcmp(tname, tentry->name))
688 return 0; /* no such entry */
692 HashNDump(trans, hashindex)
693 struct ubik_trans *trans;
698 register int blockindex;
699 struct nvlentry tentry;
701 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
702 blockindex != NULLO; blockindex = tentry.nextNameHash) {
703 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
707 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
708 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
715 HashIdDump(trans, hashindex)
716 struct ubik_trans *trans;
721 register int blockindex;
722 struct nvlentry tentry;
724 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
725 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
726 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
730 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
731 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
737 /* 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. */
739 ThreadVLentry(trans, blockindex, tentry)
740 struct ubik_trans *trans;
741 afs_int32 blockindex;
742 struct nvlentry *tentry;
746 if (!index_OK(trans, blockindex))
748 /* Insert into volid's hash linked list */
749 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
752 /* 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! */
753 if (tentry->volumeId[ROVOL]) {
754 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
757 if (tentry->volumeId[BACKVOL]) {
758 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
762 /* Insert into volname's hash linked list */
763 HashVolname(trans, blockindex, tentry);
765 /* Update cheader entry */
766 if (write_vital_vlheader(trans))
769 /* Update hash list pointers in the entry itself */
770 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
776 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
778 UnthreadVLentry(trans, blockindex, aentry)
779 struct ubik_trans *trans;
780 afs_int32 blockindex;
781 struct nvlentry *aentry;
783 register afs_int32 errorcode, typeindex;
785 if (!index_OK(trans, blockindex))
787 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
790 /* Take the RO/RW entries of their respective hash linked lists. */
791 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
792 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
796 /* Take it out of the Volname hash list */
797 if (errorcode = UnhashVolname(trans, blockindex, aentry))
800 /* Update cheader entry */
801 write_vital_vlheader(trans);
806 /* cheader must have be read before this routine is called. */
808 HashVolid(trans, voltype, blockindex, tentry)
809 struct ubik_trans *trans;
811 afs_int32 blockindex;
812 struct nvlentry *tentry;
814 afs_int32 hashindex, errorcode;
815 struct vlentry ventry;
818 (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
819 return VL_IDALREADYHASHED;
822 hashindex = IDHash(tentry->volumeId[voltype]);
823 tentry->nextIdHash[voltype] =
824 ntohl(cheader.VolidHash[voltype][hashindex]);
825 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
827 (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
828 (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
834 /* cheader must have be read before this routine is called. */
836 UnhashVolid(trans, voltype, blockindex, aentry)
837 struct ubik_trans *trans;
839 afs_int32 blockindex;
840 struct nvlentry *aentry;
842 int hashindex, nextblockindex, prevblockindex;
843 struct nvlentry tentry;
847 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
849 /* Take it out of the VolId[voltype] hash list */
850 hashindex = IDHash(aentry->volumeId[voltype]);
851 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
852 if (nextblockindex == blockindex) {
853 /* First on the hash list; just adjust pointers */
854 cheader.VolidHash[voltype][hashindex] =
855 htonl(aentry->nextIdHash[voltype]);
859 &cheader.VolidHash[voltype][hashindex]),
860 (char *)&cheader.VolidHash[voltype][hashindex],
865 while (nextblockindex != blockindex) {
866 prevblockindex = nextblockindex; /* always done once */
868 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
870 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
873 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
874 temp = htonl(temp); /* convert to network byte order before writing */
877 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
878 (char *)&temp, sizeof(afs_int32)))
881 aentry->nextIdHash[voltype] = 0;
887 HashVolname(trans, blockindex, aentry)
888 struct ubik_trans *trans;
889 afs_int32 blockindex;
890 struct nvlentry *aentry;
892 register afs_int32 hashindex;
893 register afs_int32 code;
895 /* Insert into volname's hash linked list */
896 hashindex = NameHash(aentry->name);
897 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
898 cheader.VolnameHash[hashindex] = htonl(blockindex);
900 vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
901 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
909 UnhashVolname(trans, blockindex, aentry)
910 struct ubik_trans *trans;
911 afs_int32 blockindex;
912 struct nvlentry *aentry;
914 register afs_int32 hashindex, nextblockindex, prevblockindex;
915 struct nvlentry tentry;
918 /* Take it out of the Volname hash list */
919 hashindex = NameHash(aentry->name);
920 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
921 if (nextblockindex == blockindex) {
922 /* First on the hash list; just adjust pointers */
923 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
925 (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
926 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
929 while (nextblockindex != blockindex) {
930 prevblockindex = nextblockindex; /* always done at least once */
932 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
934 if ((nextblockindex = tentry.nextNameHash) == NULLO)
937 tentry.nextNameHash = aentry->nextNameHash;
938 temp = htonl(tentry.nextNameHash);
940 (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
941 (char *)&temp, sizeof(afs_int32)))
944 aentry->nextNameHash = 0;
949 /* 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 */
952 NextEntry(trans, blockindex, tentry, remaining)
953 struct ubik_trans *trans;
954 afs_int32 blockindex;
955 struct nvlentry *tentry;
956 afs_int32 *remaining;
958 register afs_int32 lastblockindex;
960 if (blockindex == 0) /* get first one */
961 blockindex = sizeof(cheader);
963 if (!index_OK(trans, blockindex)) {
964 *remaining = -1; /* error */
967 blockindex += sizeof(nvlentry);
969 /* now search for the first entry that isn't free */
970 for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
971 blockindex < lastblockindex;) {
972 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
976 if (tentry->flags == VLCONTBLOCK) {
978 * This is a special mh extension block just simply skip over it
980 blockindex += VL_ADDREXTBLK_SIZE;
982 if (tentry->flags != VLFREE) {
983 /* estimate remaining number of entries, not including this one */
985 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
988 blockindex += sizeof(nvlentry);
991 *remaining = 0; /* no more entries */
996 /* Routine to verify that index is a legal offset to a vldb entry in the table */
998 index_OK(trans, blockindex)
999 struct ubik_trans *trans;
1000 afs_int32 blockindex;
1002 if ((blockindex < sizeof(cheader))
1003 || (blockindex >= ntohl(cheader.vital_header.eofPtr)))