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>
26 #include "vlserver_internal.h"
28 extern struct vlheader cheader;
29 struct vlheader xheader;
30 extern afs_uint32 HostAddress[];
31 extern int maxnservers;
32 struct extentaddr extentaddr;
33 extern struct extentaddr *ex_addr[];
36 static int index_OK(struct ubik_trans *trans, afs_int32 blockindex);
38 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
40 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
42 IDHash(afs_int32 volumeid)
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. */
50 NameHash(register char *volumename)
52 register unsigned int hash;
56 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
57 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
58 return (hash % HASHSIZE);
62 /* package up seek and write into one procedure for ease of use */
64 vlwrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
69 if ((errorcode = ubik_Seek(trans, 0, offset)))
71 return (ubik_Write(trans, buffer, length));
75 /* Package up seek and read into one procedure for ease of use */
77 vlread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
82 if ((errorcode = ubik_Seek(trans, 0, offset)))
84 return (ubik_Read(trans, buffer, length));
88 /* take entry and convert to network order and write to disk */
90 vlentrywrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
93 struct vlentry oentry;
94 struct nvlentry nentry, *nep;
98 if (length != sizeof(oentry))
100 if (maxnservers == 13) {
101 nep = (struct nvlentry *)buffer;
102 for (i = 0; i < MAXTYPES; i++)
103 nentry.volumeId[i] = htonl(nep->volumeId[i]);
104 nentry.flags = htonl(nep->flags);
105 nentry.LockAfsId = htonl(nep->LockAfsId);
106 nentry.LockTimestamp = htonl(nep->LockTimestamp);
107 nentry.cloneId = htonl(nep->cloneId);
108 for (i = 0; i < MAXTYPES; i++)
109 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
110 nentry.nextNameHash = htonl(nep->nextNameHash);
111 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
112 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
113 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
114 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
115 bufp = (char *)&nentry;
117 memset(&oentry, 0, sizeof(struct vlentry));
118 nep = (struct nvlentry *)buffer;
119 for (i = 0; i < MAXTYPES; i++)
120 oentry.volumeId[i] = htonl(nep->volumeId[i]);
121 oentry.flags = htonl(nep->flags);
122 oentry.LockAfsId = htonl(nep->LockAfsId);
123 oentry.LockTimestamp = htonl(nep->LockTimestamp);
124 oentry.cloneId = htonl(nep->cloneId);
125 for (i = 0; i < MAXTYPES; i++)
126 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
127 oentry.nextNameHash = htonl(nep->nextNameHash);
128 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
129 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
130 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
131 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
132 bufp = (char *)&oentry;
134 return vlwrite(trans, offset, bufp, length);
137 /* read entry and convert to host order and write to disk */
139 vlentryread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
142 struct vlentry *oep, tentry;
143 struct nvlentry *nep, *nbufp;
144 char *bufp = (char *)&tentry;
145 register afs_int32 i;
147 if (length != sizeof(vlentry))
149 i = vlread(trans, offset, bufp, length);
152 if (maxnservers == 13) {
153 nep = (struct nvlentry *)bufp;
154 nbufp = (struct nvlentry *)buffer;
155 for (i = 0; i < MAXTYPES; i++)
156 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
157 nbufp->flags = ntohl(nep->flags);
158 nbufp->LockAfsId = ntohl(nep->LockAfsId);
159 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
160 nbufp->cloneId = ntohl(nep->cloneId);
161 for (i = 0; i < MAXTYPES; i++)
162 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
163 nbufp->nextNameHash = ntohl(nep->nextNameHash);
164 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
165 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
166 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
167 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
169 oep = (struct vlentry *)bufp;
170 nbufp = (struct nvlentry *)buffer;
171 memset(nbufp, 0, sizeof(struct nvlentry));
172 for (i = 0; i < MAXTYPES; i++)
173 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
174 nbufp->flags = ntohl(oep->flags);
175 nbufp->LockAfsId = ntohl(oep->LockAfsId);
176 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
177 nbufp->cloneId = ntohl(oep->cloneId);
178 for (i = 0; i < MAXTYPES; i++)
179 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
180 nbufp->nextNameHash = ntohl(oep->nextNameHash);
181 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
182 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
183 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
184 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
189 /* Convenient write of small critical vldb header info to the database. */
191 write_vital_vlheader(register struct ubik_trans *trans)
194 (trans, 0, (char *)&cheader.vital_header, sizeof(vital_vlheader)))
202 /* This routine reads in the extent blocks for multi-homed servers.
203 * There used to be an initialization bug that would cause the contaddrs
204 * pointers in the first extent block to be bad. Here we will check the
205 * pointers and zero them in the in-memory copy if we find them bad. We
206 * also try to write the extent blocks back out. If we can't, then we
207 * will wait until the next write transaction to write them out
208 * (extent_mod tells us the on-disk copy is bad).
211 readExtents(struct ubik_trans *trans)
213 afs_uint32 extentAddr;
214 afs_int32 error = 0, code;
218 extentAddr = ntohl(cheader.SIT);
222 /* Read the first extension block */
224 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
226 ERROR_EXIT(VL_NOMEM);
228 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
230 free(ex_addr[0]); /* Not the place to create it */
235 /* In case more that 64 mh servers are in use they're kept in these
236 * continuation blocks
238 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
239 if (!ex_addr[0]->ex_contaddrs[i])
242 /* Before reading it in, check to see if the address is good */
243 if ((ntohl(ex_addr[0]->ex_contaddrs[i]) <
244 ntohl(ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
245 || (ntohl(ex_addr[0]->ex_contaddrs[i]) >
246 ntohl(cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
248 ex_addr[0]->ex_contaddrs[i] = 0;
253 /* Read the continuation block */
255 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
257 ERROR_EXIT(VL_NOMEM);
260 vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
261 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
263 free(ex_addr[i]); /* Not the place to create it */
268 /* After reading it in, check to see if its a real continuation block */
269 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
271 ex_addr[0]->ex_contaddrs[i] = 0;
272 free(ex_addr[i]); /* Not the place to create it */
279 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
281 VLog(0, ("Multihome server support modification\n"));
283 /* Keep extent_mod true in-case the transaction aborts */
284 /* Don't return error so we don't abort transaction */
291 /* Check that the database has been initialized. Be careful to fail in a safe
292 manner, to avoid bogusly reinitializing the db. */
294 CheckInit(struct ubik_trans *trans, int builddb)
296 afs_int32 error = 0, i, code, ubcode = 0;
298 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
299 * previous transaction would have left the cache fine, and non-zero otherwise.
300 * Thus, a local abort or a remote commit will cause this to return non-zero
301 * and force a header re-read. Necessary for a local abort because we may
302 * have damaged cheader during the operation. Necessary for a remote commit
303 * since it may have changed cheader.
305 if (ubik_CacheUpdate(trans) != 0) {
306 /* if version changed (or first call), read the header */
307 ubcode = vlread(trans, 0, (char *)&cheader, sizeof(cheader));
308 vldbversion = ntohl(cheader.vital_header.vldbversion);
310 if (!ubcode && (vldbversion != 0)) {
311 memcpy(HostAddress, cheader.IpMappedAddr,
312 sizeof(cheader.IpMappedAddr));
313 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
314 HostAddress[i] = ntohl(HostAddress[i]);
317 code = readExtents(trans);
323 vldbversion = ntohl(cheader.vital_header.vldbversion);
325 /* now, if can't read, or header is wrong, write a new header */
326 if (ubcode || vldbversion == 0) {
328 printf("Can't read VLDB header, re-initialising...\n");
330 /* try to write a good header */
331 memset(&cheader, 0, sizeof(cheader));
332 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
333 cheader.vital_header.headersize = htonl(sizeof(cheader));
334 /* DANGER: Must get this from a master place!! */
335 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
336 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
337 for (i = 0; i < MAXSERVERID + 1; i++) {
338 cheader.IpMappedAddr[i] = 0;
341 code = vlwrite(trans, 0, (char *)&cheader, sizeof(cheader));
343 printf("Can't write VLDB header (error = %d)\n", code);
347 ERROR_EXIT(VL_EMPTY);
348 } else if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
349 && (vldbversion != VLDBVERSION_4)) {
351 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
352 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
353 ERROR_EXIT(VL_BADVERSION);
356 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
365 GetExtentBlock(register struct ubik_trans *trans, register afs_int32 base)
367 afs_int32 blockindex, code, error = 0;
369 /* Base 0 must exist before any other can be created */
370 if ((base != 0) && !ex_addr[0])
371 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
373 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
374 /* Create a new extension block */
375 if (!ex_addr[base]) {
376 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
378 ERROR_EXIT(VL_NOMEM);
380 memset(ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
382 /* Write the full extension block at end of vldb */
383 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
384 blockindex = ntohl(cheader.vital_header.eofPtr);
386 vlwrite(trans, blockindex, (char *)ex_addr[base],
391 /* Update the cheader.vitalheader structure on disk */
392 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
393 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
394 code = write_vital_vlheader(trans);
398 /* Write the address of the base extension block in the vldb header */
400 cheader.SIT = htonl(blockindex);
402 vlwrite(trans, DOFFSET(0, &cheader, &cheader.SIT),
403 (char *)&cheader.SIT, sizeof(cheader.SIT));
408 /* Write the address of this extension block into the base extension block */
409 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
411 vlwrite(trans, ntohl(cheader.SIT), ex_addr[0],
412 sizeof(struct extentaddr));
423 FindExtentBlock(register struct ubik_trans *trans, afsUUID *uuidp,
424 afs_int32 createit, afs_int32 hostslot,
425 struct extentaddr **expp, afs_int32 *basep)
428 struct extentaddr *exp;
429 register afs_int32 i, j, code, base, index, error = 0;
434 /* Create the first extension block if it does not exist */
436 code = GetExtentBlock(trans, 0);
441 for (i = 0; i < MAXSERVERID + 1; i++) {
442 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
443 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
444 ERROR_EXIT(VL_INDEXERANGE);
446 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
447 ERROR_EXIT(VL_INDEXERANGE);
449 exp = &ex_addr[base][index];
450 tuuid = exp->ex_hostuuid;
451 afs_ntohuuid(&tuuid);
452 if (afs_uuid_equal(uuidp, &tuuid)) {
461 if (hostslot == -1) {
462 for (i = 0; i < MAXSERVERID + 1; i++) {
467 ERROR_EXIT(VL_REPSFULL);
472 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
473 if (!ex_addr[0]->ex_contaddrs[base]) {
474 code = GetExtentBlock(trans, base);
478 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
479 exp = &ex_addr[base][j];
480 tuuid = exp->ex_hostuuid;
481 afs_ntohuuid(&tuuid);
482 if (afs_uuid_is_nil(&tuuid)) {
484 afs_htonuuid(&tuuid);
485 exp->ex_hostuuid = tuuid;
488 DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
489 (char *)ex_addr[base], (char *)exp),
490 (char *)&tuuid, sizeof(tuuid));
494 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
497 if (vldbversion != VLDBVERSION_4) {
498 cheader.vital_header.vldbversion =
499 htonl(VLDBVERSION_4);
500 code = write_vital_vlheader(trans);
504 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
508 &cheader.IpMappedAddr[i]),
509 (char *)&cheader.IpMappedAddr[i],
517 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
524 /* Allocate a free block of storage for entry, returning address of a new
525 zeroed entry (or zero if something is wrong). */
527 AllocBlock(register struct ubik_trans *trans, struct nvlentry *tentry)
529 register afs_int32 blockindex;
531 if (cheader.vital_header.freePtr) {
532 /* allocate this dude */
533 blockindex = ntohl(cheader.vital_header.freePtr);
534 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(vlentry)))
536 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
538 /* hosed, nothing on free list, grow file */
539 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
540 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
542 cheader.vital_header.allocs++;
543 if (write_vital_vlheader(trans))
545 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
550 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
552 FreeBlock(struct ubik_trans *trans, afs_int32 blockindex)
554 struct nvlentry tentry;
556 /* check validity of blockindex just to be on the safe side */
557 if (!index_OK(trans, blockindex))
559 memset(&tentry, 0, sizeof(nvlentry));
560 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
561 tentry.flags = htonl(VLFREE);
562 cheader.vital_header.freePtr = htonl(blockindex);
563 if (vlwrite(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
565 cheader.vital_header.frees++;
566 if (write_vital_vlheader(trans))
572 /* Look for a block by volid and voltype (if not known use -1 which searches
573 * all 3 volid hash lists. Note that the linked lists are read in first from
574 * the database header. If found read the block's contents into the area
575 * pointed to by tentry and return the block's index. If not found return 0.
578 FindByID(struct ubik_trans *trans, afs_uint32 volid, afs_int32 voltype,
579 struct nvlentry *tentry, afs_int32 *error)
581 register afs_int32 typeindex, hashindex, blockindex;
584 hashindex = IDHash(volid);
586 /* Should we have one big hash table for volids as opposed to the three ones? */
587 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
588 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]);
590 blockindex = tentry->nextIdHash[typeindex]) {
592 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
596 if (volid == tentry->volumeId[typeindex])
601 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
602 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
604 (trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
608 if (volid == tentry->volumeId[voltype])
612 return 0; /* no such entry */
616 /* Look for a block by volume name. If found read the block's contents into
617 * the area pointed to by tentry and return the block's index. If not
621 FindByName(struct ubik_trans *trans, char *volname, struct nvlentry *tentry,
624 register afs_int32 hashindex;
625 register afs_int32 blockindex;
626 char tname[VL_MAXNAMELEN];
628 /* remove .backup or .readonly extensions for stupid backwards
631 hashindex = strlen(volname); /* really string length */
632 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
633 /* this is a backup volume */
634 strcpy(tname, volname);
635 tname[hashindex - 7] = 0; /* zap extension */
636 } else if (hashindex >= 10
637 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
638 /* this is a readonly volume */
639 strcpy(tname, volname);
640 tname[hashindex - 9] = 0; /* zap extension */
642 strcpy(tname, volname);
645 hashindex = NameHash(tname);
646 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
647 blockindex != NULLO; blockindex = tentry->nextNameHash) {
648 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
652 if (!strcmp(tname, tentry->name))
655 return 0; /* no such entry */
659 * Returns whether or not any of the supplied volume IDs already exist
662 * @param trans the ubik transaction
663 * @param ids an array of volume IDs
664 * @param ids_len the number of elements in the 'ids' array
665 * @param error filled in with an error code in case of error
667 * @return whether any of the volume IDs are already used
668 * @retval 1 at least one of the volume IDs is already used
669 * @retval 0 none of the volume IDs are used, or an error occurred
672 EntryIDExists(struct ubik_trans *trans, const afs_uint32 *ids,
673 afs_int32 ids_len, afs_int32 *error)
676 struct nvlentry tentry;
680 for (typeindex = 0; typeindex < ids_len; typeindex++) {
682 && FindByID(trans, ids[typeindex], -1, &tentry, error)) {
694 * Finds the next range of unused volume IDs in the vldb.
696 * @param trans the ubik transaction
697 * @param maxvolid the current max vol ID, and where to start looking
698 * for an unused volume ID range
699 * @param bump how many volume IDs we need to be unused
700 * @param error filled in with an error code in case of error
702 * @return the next volume ID 'volid' such that the range
703 * [volid, volid+bump) of volume IDs is unused, or 0 if there's
707 NextUnusedID(struct ubik_trans *trans, afs_uint32 maxvolid, afs_uint32 bump,
710 struct nvlentry tentry;
716 /* we simply start at the given maxvolid, keep a running tally of
717 * how many free volume IDs we've seen in a row, and return when
718 * we've seen 'bump' unused IDs in a row */
719 for (id = maxvolid, nfree = 0; nfree < bump; ++id) {
720 if (FindByID(trans, id, -1, &tentry, error)) {
729 /* 'id' is now at the end of the [maxvolid,maxvolid+bump) range,
730 * but we need to return the first unused id, so subtract the
731 * number of current running free IDs to get the beginning */
736 HashNDump(struct ubik_trans *trans, int hashindex)
739 register int blockindex;
740 struct nvlentry tentry;
742 for (blockindex = ntohl(cheader.VolnameHash[hashindex]);
743 blockindex != NULLO; blockindex = tentry.nextNameHash) {
744 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
748 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
749 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
756 HashIdDump(struct ubik_trans *trans, int hashindex)
759 register int blockindex;
760 struct nvlentry tentry;
762 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]);
763 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
764 if (vlentryread(trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
768 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
769 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
775 /* Add a block to the hash table given a pointer to the block and its index.
776 * The block is threaded onto both hash tables and written to disk. The
777 * routine returns zero if there were no errors.
780 ThreadVLentry(struct ubik_trans *trans, afs_int32 blockindex,
781 struct nvlentry *tentry)
785 if (!index_OK(trans, blockindex))
787 /* Insert into volid's hash linked list */
788 if ((errorcode = HashVolid(trans, RWVOL, blockindex, tentry)))
791 /* For rw entries we also enter the RO and BACK volume ids (if they
792 * exist) in the hash tables; note all there volids (RW, RO, BACK)
793 * should not be hashed yet! */
794 if (tentry->volumeId[ROVOL]) {
795 if ((errorcode = HashVolid(trans, ROVOL, blockindex, tentry)))
798 if (tentry->volumeId[BACKVOL]) {
799 if ((errorcode = HashVolid(trans, BACKVOL, blockindex, tentry)))
803 /* Insert into volname's hash linked list */
804 HashVolname(trans, blockindex, tentry);
806 /* Update cheader entry */
807 if (write_vital_vlheader(trans))
810 /* Update hash list pointers in the entry itself */
811 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry)))
817 /* Remove a block from both the hash tables. If success return 0, else
818 * return an error code. */
820 UnthreadVLentry(struct ubik_trans *trans, afs_int32 blockindex,
821 struct nvlentry *aentry)
823 register afs_int32 errorcode, typeindex;
825 if (!index_OK(trans, blockindex))
827 if ((errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry)))
830 /* Take the RO/RW entries of their respective hash linked lists. */
831 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
832 if ((errorcode = UnhashVolid(trans, typeindex, blockindex, aentry)))
836 /* Take it out of the Volname hash list */
837 if ((errorcode = UnhashVolname(trans, blockindex, aentry)))
840 /* Update cheader entry */
841 write_vital_vlheader(trans);
846 /* cheader must have be read before this routine is called. */
848 HashVolid(struct ubik_trans *trans, afs_int32 voltype, afs_int32 blockindex,
849 struct nvlentry *tentry)
851 afs_int32 hashindex, errorcode;
852 struct nvlentry ventry;
855 (trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
856 return VL_IDALREADYHASHED;
859 hashindex = IDHash(tentry->volumeId[voltype]);
860 tentry->nextIdHash[voltype] =
861 ntohl(cheader.VolidHash[voltype][hashindex]);
862 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
864 (trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]),
865 (char *)&cheader.VolidHash[voltype][hashindex], sizeof(afs_int32)))
871 /* cheader must have be read before this routine is called. */
873 UnhashVolid(struct ubik_trans *trans, afs_int32 voltype, afs_int32 blockindex,
874 struct nvlentry *aentry)
876 int hashindex, nextblockindex, prevblockindex;
877 struct nvlentry tentry;
881 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
883 /* Take it out of the VolId[voltype] hash list */
884 hashindex = IDHash(aentry->volumeId[voltype]);
885 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
886 if (nextblockindex == blockindex) {
887 /* First on the hash list; just adjust pointers */
888 cheader.VolidHash[voltype][hashindex] =
889 htonl(aentry->nextIdHash[voltype]);
893 &cheader.VolidHash[voltype][hashindex]),
894 (char *)&cheader.VolidHash[voltype][hashindex],
899 while (nextblockindex != blockindex) {
900 prevblockindex = nextblockindex; /* always done once */
902 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
904 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
907 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
908 temp = htonl(temp); /* convert to network byte order before writing */
911 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
912 (char *)&temp, sizeof(afs_int32)))
915 aentry->nextIdHash[voltype] = 0;
921 HashVolname(struct ubik_trans *trans, afs_int32 blockindex,
922 struct nvlentry *aentry)
924 register afs_int32 hashindex;
925 register afs_int32 code;
927 /* Insert into volname's hash linked list */
928 hashindex = NameHash(aentry->name);
929 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
930 cheader.VolnameHash[hashindex] = htonl(blockindex);
932 vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
933 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32));
941 UnhashVolname(struct ubik_trans *trans, afs_int32 blockindex,
942 struct nvlentry *aentry)
944 register afs_int32 hashindex, nextblockindex, prevblockindex;
945 struct nvlentry tentry;
948 /* Take it out of the Volname hash list */
949 hashindex = NameHash(aentry->name);
950 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
951 if (nextblockindex == blockindex) {
952 /* First on the hash list; just adjust pointers */
953 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
955 (trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]),
956 (char *)&cheader.VolnameHash[hashindex], sizeof(afs_int32)))
959 while (nextblockindex != blockindex) {
960 prevblockindex = nextblockindex; /* always done at least once */
962 (trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
964 if ((nextblockindex = tentry.nextNameHash) == NULLO)
967 tentry.nextNameHash = aentry->nextNameHash;
968 temp = htonl(tentry.nextNameHash);
970 (trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
971 (char *)&temp, sizeof(afs_int32)))
974 aentry->nextNameHash = 0;
979 /* Returns the vldb entry tentry at offset index; remaining is the number of
980 * entries left; the routine also returns the index of the next sequential
985 NextEntry(struct ubik_trans *trans, afs_int32 blockindex,
986 struct nvlentry *tentry, afs_int32 *remaining)
988 register afs_int32 lastblockindex;
990 if (blockindex == 0) /* get first one */
991 blockindex = sizeof(cheader);
993 if (!index_OK(trans, blockindex)) {
994 *remaining = -1; /* error */
997 blockindex += sizeof(nvlentry);
999 /* now search for the first entry that isn't free */
1000 for (lastblockindex = ntohl(cheader.vital_header.eofPtr);
1001 blockindex < lastblockindex;) {
1002 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
1006 if (tentry->flags == VLCONTBLOCK) {
1008 * This is a special mh extension block just simply skip over it
1010 blockindex += VL_ADDREXTBLK_SIZE;
1012 if (tentry->flags != VLFREE) {
1013 /* estimate remaining number of entries, not including this one */
1015 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
1018 blockindex += sizeof(nvlentry);
1021 *remaining = 0; /* no more entries */
1026 /* Routine to verify that index is a legal offset to a vldb entry in the
1030 index_OK(struct ubik_trans *trans, afs_int32 blockindex)
1032 if ((blockindex < sizeof(cheader))
1033 || (blockindex >= ntohl(cheader.vital_header.eofPtr)))