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>
15 #include <sys/types.h>
19 #include <netinet/in.h>
26 extern struct vlheader cheader;
27 struct vlheader xheader;
28 extern struct ubik_dbase *VL_dbase;
29 extern afs_uint32 HostAddress[];
30 extern int maxnservers;
31 struct extentaddr extentaddr;
32 extern struct extentaddr *ex_addr[];
35 static int index_OK();
37 #define ERROR_EXIT(code) {error=(code); goto error_exit;}
39 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
40 afs_int32 IDHash(volumeid)
43 return((abs(volumeid)) % HASHSIZE);
47 /* Hashing algorithm based on the volume name; name's size is implicit (64 chars) and if changed it should be reflected here. */
48 afs_int32 NameHash (volumename)
49 register char *volumename;
50 { register unsigned int hash;
54 for (i=strlen(volumename), volumename += i-1; i--; volumename--)
55 hash = (hash*63) + (*((unsigned char *)volumename) - 63);
56 return(hash % HASHSIZE);
60 /* package up seek and write into one procedure for ease of use */
61 afs_int32 vlwrite (trans, offset, buffer, length)
62 struct ubik_trans *trans;
66 { afs_int32 errorcode;
68 if (errorcode = ubik_Seek(trans, 0, offset)) return errorcode;
69 return(ubik_Write(trans, buffer, length));
73 /* Package up seek and read into one procedure for ease of use */
74 afs_int32 vlread (trans, offset, buffer, length)
75 struct ubik_trans *trans;
79 { afs_int32 errorcode;
81 if (errorcode = ubik_Seek(trans, 0, offset)) return errorcode;
82 return(ubik_Read(trans, buffer, length));
86 /* take entry and convert to network order and write to disk */
87 afs_int32 vlentrywrite(trans, offset, buffer, length)
88 struct ubik_trans *trans;
92 struct vlentry oentry, *oep;
93 struct nvlentry nentry, *nep;
97 if (length != sizeof(oentry)) return -1;
98 if (maxnservers == 13) {
99 nep = (struct nvlentry *)buffer;
100 for (i=0;i<MAXTYPES;i++)
101 nentry.volumeId[i] = htonl(nep->volumeId[i]);
102 nentry.flags = htonl(nep->flags);
103 nentry.LockAfsId = htonl(nep->LockAfsId);
104 nentry.LockTimestamp = htonl(nep->LockTimestamp);
105 nentry.cloneId = htonl(nep->cloneId);
106 for (i=0;i<MAXTYPES;i++)
107 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
108 nentry.nextNameHash = htonl(nep->nextNameHash);
109 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
110 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
111 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
112 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
113 bufp = (char *)&nentry;
115 memset(&oentry, 0, sizeof(struct vlentry));
116 nep = (struct nvlentry *)buffer;
117 for (i=0;i<MAXTYPES;i++)
118 oentry.volumeId[i] = htonl(nep->volumeId[i]);
119 oentry.flags = htonl(nep->flags);
120 oentry.LockAfsId = htonl(nep->LockAfsId);
121 oentry.LockTimestamp = htonl(nep->LockTimestamp);
122 oentry.cloneId = htonl(nep->cloneId);
123 for (i=0;i<MAXTYPES;i++)
124 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
125 oentry.nextNameHash = htonl(nep->nextNameHash);
126 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
127 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
128 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
129 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
130 bufp = (char *)&oentry;
132 return vlwrite(trans, offset, bufp, length);
135 /* read entry and convert to host order and write to disk */
136 afs_int32 vlentryread(trans, offset, buffer, length)
137 struct ubik_trans *trans;
141 struct vlentry *oep, *obufp, tentry;
142 struct nvlentry *nep, *nbufp;
143 char *bufp = (char *)&tentry;
144 register afs_int32 i;
146 if (length != sizeof(vlentry)) return -1;
147 i = vlread(trans, offset, bufp, length);
149 if (maxnservers == 13) {
150 nep = (struct nvlentry *)bufp;
151 nbufp = (struct nvlentry *)buffer;
152 for(i=0;i<MAXTYPES;i++)
153 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
154 nbufp->flags = ntohl(nep->flags);
155 nbufp->LockAfsId = ntohl(nep->LockAfsId);
156 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
157 nbufp->cloneId = ntohl(nep->cloneId);
158 for(i=0;i<MAXTYPES;i++)
159 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
160 nbufp->nextNameHash = ntohl(nep->nextNameHash);
161 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
162 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
163 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
164 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
166 oep = (struct vlentry *)bufp;
167 nbufp = (struct nvlentry *)buffer;
168 memset(nbufp, 0, sizeof (struct nvlentry));
169 for(i=0;i<MAXTYPES;i++)
170 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
171 nbufp->flags = ntohl(oep->flags);
172 nbufp->LockAfsId = ntohl(oep->LockAfsId);
173 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
174 nbufp->cloneId = ntohl(oep->cloneId);
175 for(i=0;i<MAXTYPES;i++)
176 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
177 nbufp->nextNameHash = ntohl(oep->nextNameHash);
178 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
179 memcpy(nbufp->serverNumber, oep->serverNumber, NMAXNSERVERS);
180 memcpy(nbufp->serverPartition, oep->serverPartition, NMAXNSERVERS);
181 memcpy(nbufp->serverFlags, oep->serverFlags, NMAXNSERVERS);
186 /* Convenient write of small critical vldb header info to the database. */
187 int write_vital_vlheader(trans)
188 register struct ubik_trans *trans;
190 if (vlwrite(trans, 0, (char *) &cheader.vital_header, sizeof(vital_vlheader))) return VL_IO;
197 /* This routine reads in the extent blocks for multi-homed servers.
198 * There used to be an initialization bug that would cause the contaddrs
199 * pointers in the first extent block to be bad. Here we will check the
200 * pointers and zero them in the in-memory copy if we find them bad. We
201 * also try to write the extent blocks back out. If we can't, then we
202 * will wait until the next write transaction to write them out
203 * (extent_mod tells us the on-disk copy is bad).
205 afs_int32 readExtents(trans)
206 struct ubik_trans *trans;
208 afs_uint32 extentAddr;
209 afs_int32 error=0, code;
213 extentAddr = ntohl(cheader.SIT);
217 /* Read the first extension block */
219 ex_addr[0] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
221 ERROR_EXIT(VL_NOMEM);
223 code = vlread(trans, extentAddr, (char *)ex_addr[0], VL_ADDREXTBLK_SIZE);
225 free(ex_addr[0]); /* Not the place to create it */
230 /* In case more that 64 mh servers are in use they're kept in these
231 * continuation blocks
233 for (i=1; i < VL_MAX_ADDREXTBLKS; i++) {
234 if (!ex_addr[0]->ex_contaddrs[i])
237 /* Before reading it in, check to see if the address is good */
238 if ( (ntohl(ex_addr[0]->ex_contaddrs[i]) <
239 ntohl(ex_addr[0]->ex_contaddrs[i-1])+VL_ADDREXTBLK_SIZE) ||
240 (ntohl(ex_addr[0]->ex_contaddrs[i]) >
241 ntohl(cheader.vital_header.eofPtr)-VL_ADDREXTBLK_SIZE) ) {
243 ex_addr[0]->ex_contaddrs[i] = 0;
248 /* Read the continuation block */
250 ex_addr[i] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
252 ERROR_EXIT(VL_NOMEM);
254 code = vlread(trans, ntohl(ex_addr[0]->ex_contaddrs[i]),
255 (char *)ex_addr[i], VL_ADDREXTBLK_SIZE);
257 free(ex_addr[i]); /* Not the place to create it */
262 /* After reading it in, check to see if its a real continuation block */
263 if (ntohl(ex_addr[i]->ex_flags) != VLCONTBLOCK) {
265 ex_addr[0]->ex_contaddrs[i] = 0;
266 free(ex_addr[i]); /* Not the place to create it */
273 code = vlwrite(trans, extentAddr, ex_addr[0], VL_ADDREXTBLK_SIZE);
275 VLog(0, ("Multihome server support modification\n"));
277 /* Keep extent_mod true in-case the transaction aborts */
278 /* Don't return error so we don't abort transaction */
285 /* Check that the database has been initialized. Be careful to fail in a safe
286 manner, to avoid bogusly reinitializing the db. */
287 afs_int32 CheckInit (trans, builddb)
288 struct ubik_trans *trans;
291 afs_int32 error=0, i, code, ubcode=0;
293 /* ubik_CacheUpdate must be called on every transaction. It returns 0 if the
294 * previous transaction would have left the cache fine, and non-zero otherwise.
295 * Thus, a local abort or a remote commit will cause this to return non-zero
296 * and force a header re-read. Necessary for a local abort because we may
297 * have damaged cheader during the operation. Necessary for a remote commit
298 * since it may have changed cheader.
300 if (ubik_CacheUpdate(trans) != 0) {
301 /* if version changed (or first call), read the header */
302 ubcode = vlread (trans, 0, (char *) &cheader, sizeof(cheader));
303 vldbversion = ntohl(cheader.vital_header.vldbversion);
305 if (!ubcode && (vldbversion != 0)) {
306 memcpy(HostAddress, cheader.IpMappedAddr, sizeof(cheader.IpMappedAddr));
307 for (i=0; i<MAXSERVERID+1; i++) { /* cvt HostAddress to host order */
308 HostAddress[i] = ntohl(HostAddress[i]);
311 code = readExtents(trans);
317 vldbversion = ntohl(cheader.vital_header.vldbversion);
319 /* now, if can't read, or header is wrong, write a new header */
320 if (ubcode || vldbversion == 0) {
322 printf("Can't read VLDB header, re-initialising...\n");
324 /* try to write a good header */
325 memset(&cheader, 0, sizeof(cheader));
326 cheader.vital_header.vldbversion = htonl(VLDBVERSION);
327 cheader.vital_header.headersize = htonl(sizeof(cheader));
328 /* DANGER: Must get this from a master place!! */
329 cheader.vital_header.MaxVolumeId = htonl(0x20000000);
330 cheader.vital_header.eofPtr = htonl(sizeof(cheader));
331 for (i=0; i<MAXSERVERID+1; i++) {
332 cheader.IpMappedAddr[i] = 0;
335 code = vlwrite(trans, 0, (char *) &cheader, sizeof(cheader));
337 printf("Can't write VLDB header (error = %d)\n", code);
341 else ERROR_EXIT(VL_EMPTY);
343 else if ((vldbversion != VLDBVERSION) &&
344 (vldbversion != OVLDBVERSION) &&
345 (vldbversion != VLDBVERSION_4)) {
346 printf("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
347 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION);
348 ERROR_EXIT(VL_BADVERSION);
351 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
359 afs_int32 GetExtentBlock(trans, base)
360 register struct ubik_trans *trans;
361 register afs_int32 base;
363 afs_int32 blockindex, code, error = 0;
365 /* Base 0 must exist before any other can be created */
366 if ((base != 0) && !ex_addr[0])
367 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
369 if (!ex_addr[0] || !ex_addr[0]->ex_contaddrs[base]) {
370 /* Create a new extension block */
371 if (!ex_addr[base]) {
372 ex_addr[base] = (struct extentaddr *)malloc(VL_ADDREXTBLK_SIZE);
374 ERROR_EXIT(VL_NOMEM);
376 memset((char *)ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
378 /* Write the full extension block at end of vldb */
379 ex_addr[base]->ex_flags = htonl(VLCONTBLOCK);
380 blockindex = ntohl(cheader.vital_header.eofPtr);
381 code = vlwrite(trans, blockindex, (char *)ex_addr[base], VL_ADDREXTBLK_SIZE);
382 if (code) ERROR_EXIT(VL_IO);
384 /* Update the cheader.vitalheader structure on disk */
385 cheader.vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
386 cheader.vital_header.eofPtr = htonl(cheader.vital_header.eofPtr);
387 code = write_vital_vlheader(trans);
388 if (code) ERROR_EXIT(VL_IO);
390 /* Write the address of the base extension block in the vldb header */
392 cheader.SIT = htonl(blockindex);
393 code = vlwrite(trans, DOFFSET(0,&cheader,&cheader.SIT),
394 (char *)&cheader.SIT, sizeof(cheader.SIT));
395 if (code) ERROR_EXIT(VL_IO);
398 /* Write the address of this extension block into the base extension block */
399 ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
400 code = vlwrite(trans, ntohl(cheader.SIT), ex_addr[0], sizeof(struct extentaddr));
401 if (code) ERROR_EXIT(VL_IO);
409 afs_int32 FindExtentBlock(trans, uuidp, createit, hostslot, expp, basep)
410 register struct ubik_trans *trans;
412 afs_int32 createit, hostslot, *basep;
413 struct extentaddr **expp;
416 struct extentaddr *exp;
417 register afs_int32 i, j, code, base, index, error=0;
419 *expp = (struct extentaddr *)0;
422 /* Create the first extension block if it does not exist */
424 code = GetExtentBlock(trans, 0);
425 if (code) ERROR_EXIT(code);
428 for (i = 0; i < MAXSERVERID+1; i++) {
429 if ((HostAddress[i] & 0xff000000) == 0xff000000) {
430 if ((base = (HostAddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
431 ERROR_EXIT(VL_INDEXERANGE);
433 if ((index = HostAddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
434 ERROR_EXIT(VL_INDEXERANGE);
436 exp = &ex_addr[base][index];
437 tuuid = exp->ex_hostuuid;
438 afs_ntohuuid(&tuuid);
439 if (afs_uuid_equal(uuidp, &tuuid)) {
448 if (hostslot == -1) {
449 for (i=0; i<MAXSERVERID+1; i++) {
450 if (!HostAddress[i]) break;
452 if (i > MAXSERVERID) ERROR_EXIT(VL_REPSFULL);
457 for (base=0; base<VL_MAX_ADDREXTBLKS; base++) {
458 if (!ex_addr[0]->ex_contaddrs[base]) {
459 code = GetExtentBlock(trans, base);
460 if (code) ERROR_EXIT(code);
462 for (j=1; j<VL_MHSRV_PERBLK; j++) {
463 exp = &ex_addr[base][j];
464 tuuid = exp->ex_hostuuid;
465 afs_ntohuuid(&tuuid);
466 if (afs_uuid_is_nil(&tuuid)) {
468 afs_htonuuid(&tuuid);
469 exp->ex_hostuuid = tuuid;
470 code = vlwrite(trans, DOFFSET(ntohl(ex_addr[0]->ex_contaddrs[base]),
471 (char *)ex_addr[base], (char *)exp),
472 (char *) &tuuid, sizeof(tuuid));
473 if (code) ERROR_EXIT(VL_IO);
474 HostAddress[i] = 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
477 if (vldbversion != VLDBVERSION_4) {
478 vldbversion != VLDBVERSION_4;
479 cheader.vital_header.vldbversion = htonl(VLDBVERSION_4);
480 code = write_vital_vlheader(trans);
481 if (code) ERROR_EXIT(VL_IO);
483 cheader.IpMappedAddr[i] = htonl(HostAddress[i]);
484 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.IpMappedAddr[i]),
485 (char *) &cheader.IpMappedAddr[i], sizeof(afs_int32));
486 if (code) ERROR_EXIT(VL_IO);
491 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
498 /* Allocate a free block of storage for entry, returning address of a new
499 zeroed entry (or zero if something is wrong). */
500 afs_int32 AllocBlock (trans, tentry)
501 register struct ubik_trans *trans;
502 struct nvlentry *tentry;
503 { register afs_int32 blockindex;
505 if (cheader.vital_header.freePtr) {
506 /* allocate this dude */
507 blockindex = ntohl(cheader.vital_header.freePtr);
508 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(vlentry))) return 0;
509 cheader.vital_header.freePtr = htonl(tentry->nextIdHash[0]);
512 /* hosed, nothing on free list, grow file */
513 blockindex = ntohl(cheader.vital_header.eofPtr); /* remember this guy */
514 cheader.vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
516 cheader.vital_header.allocs++;
517 if (write_vital_vlheader(trans)) return 0;
518 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
523 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
524 int FreeBlock (trans, blockindex)
525 struct ubik_trans *trans;
526 afs_int32 blockindex;
527 { struct nvlentry tentry;
529 /* check validity of blockindex just to be on the safe side */
530 if (!index_OK (trans, blockindex)) return VL_BADINDEX;
531 memset(&tentry, 0, sizeof(nvlentry));
532 tentry.nextIdHash[0] = cheader.vital_header.freePtr; /* already in network order */
533 tentry.flags = htonl(VLFREE);
534 cheader.vital_header.freePtr = htonl(blockindex);
535 if (vlwrite (trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
537 cheader.vital_header.frees++;
538 if (write_vital_vlheader(trans)) return VL_IO;
543 /* 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. */
544 afs_int32 FindByID (trans, volid, voltype, tentry, error)
545 struct ubik_trans *trans;
548 struct nvlentry *tentry;
550 { register afs_int32 typeindex, hashindex, blockindex;
553 hashindex = IDHash(volid);
555 /* Should we have one big hash table for volids as opposed to the three ones? */
556 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
557 for (blockindex = ntohl(cheader.VolidHash[typeindex][hashindex]); blockindex != NULLO; blockindex = tentry->nextIdHash[typeindex]) {
558 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
562 if (volid == tentry->volumeId[typeindex])
567 for (blockindex = ntohl(cheader.VolidHash[voltype][hashindex]); blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
568 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
572 if (volid == tentry->volumeId[voltype])
576 return 0; /* no such entry */
580 /* 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. */
581 afs_int32 FindByName (trans, volname, tentry, error)
582 struct ubik_trans *trans;
584 struct nvlentry *tentry;
586 { register afs_int32 hashindex;
587 register afs_int32 blockindex;
588 char tname[VL_MAXNAMELEN];
590 /* remove .backup or .readonly extensions for stupid backwards compatibility */
591 hashindex = strlen(volname); /* really string length */
592 if (hashindex >= 8 && strcmp(volname+hashindex-7, ".backup")==0) {
593 /* this is a backup volume */
594 strcpy(tname, volname);
595 tname[hashindex-7] = 0; /* zap extension */
597 else if (hashindex >= 10 && strcmp(volname+hashindex-9, ".readonly")==0) {
598 /* this is a readonly volume */
599 strcpy(tname, volname);
600 tname[hashindex-9] = 0; /* zap extension */
602 else strcpy(tname, volname);
605 hashindex = NameHash(tname);
606 for (blockindex = ntohl(cheader.VolnameHash[hashindex]); blockindex != NULLO; blockindex = tentry->nextNameHash) {
607 if (vlentryread(trans, blockindex, (char *) tentry, sizeof(nvlentry))) {
611 if (!strcmp(tname, tentry->name))
614 return 0; /* no such entry */
617 int HashNDump (trans, hashindex)
618 struct ubik_trans *trans;
622 register int blockindex;
623 struct nvlentry tentry;
625 for (blockindex = ntohl(cheader.VolnameHash[hashindex]); blockindex != NULLO; blockindex = tentry.nextNameHash) {
626 if (vlentryread(trans, blockindex, (char *) &tentry, sizeof(nvlentry))) return 0;
628 VLog(0, ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
629 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
634 int HashIdDump (trans, hashindex)
635 struct ubik_trans *trans;
639 register int blockindex;
640 struct nvlentry tentry;
642 for (blockindex = ntohl(cheader.VolidHash[0][hashindex]); blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
643 if (vlentryread(trans, blockindex, (char *) &tentry, sizeof(nvlentry))) return 0;
645 VLog(0, ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
646 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
651 /* 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. */
652 int ThreadVLentry (trans, blockindex, tentry)
653 struct ubik_trans *trans;
654 afs_int32 blockindex;
655 struct nvlentry *tentry;
658 if (!index_OK(trans, blockindex)) return VL_BADINDEX;
659 /* Insert into volid's hash linked list */
660 if (errorcode = HashVolid(trans, RWVOL, blockindex, tentry))
663 /* 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! */
664 if (tentry->volumeId[ROVOL]) {
665 if (errorcode = HashVolid(trans, ROVOL, blockindex, tentry))
668 if (tentry->volumeId[BACKVOL]) {
669 if (errorcode = HashVolid(trans, BACKVOL, blockindex, tentry))
673 /* Insert into volname's hash linked list */
674 HashVolname(trans, blockindex, tentry);
676 /* Update cheader entry */
677 if (write_vital_vlheader(trans)) return VL_IO;
679 /* Update hash list pointers in the entry itself */
680 if (vlentrywrite(trans, blockindex, (char *)tentry, sizeof(nvlentry))) return VL_IO;
685 /* Remove a block from both the hash tables. If success return 0, else return an error code. */
686 int UnthreadVLentry (trans, blockindex, aentry)
687 struct ubik_trans *trans;
688 afs_int32 blockindex;
689 struct nvlentry *aentry;
690 { register afs_int32 errorcode, typeindex;
692 if (!index_OK(trans, blockindex)) return VL_BADINDEX;
693 if (errorcode = UnhashVolid(trans, RWVOL, blockindex, aentry))
696 /* Take the RO/RW entries of their respective hash linked lists. */
697 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
698 if (errorcode = UnhashVolid(trans, typeindex, blockindex, aentry))
702 /* Take it out of the Volname hash list */
703 if (errorcode = UnhashVolname(trans, blockindex, aentry))
706 /* Update cheader entry */
707 write_vital_vlheader(trans);
712 /* cheader must have be read before this routine is called. */
713 int HashVolid(trans, voltype, blockindex, tentry)
714 struct ubik_trans *trans;
716 afs_int32 blockindex;
717 struct nvlentry *tentry;
718 { afs_int32 hashindex, errorcode;
719 struct vlentry ventry;
721 if (FindByID(trans, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
722 return VL_IDALREADYHASHED;
723 else if (errorcode) return errorcode;
724 hashindex = IDHash(tentry->volumeId[voltype]);
725 tentry->nextIdHash[voltype] = ntohl(cheader.VolidHash[voltype][hashindex]);
726 cheader.VolidHash[voltype][hashindex] = htonl(blockindex);
727 if (vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]), (char *) &cheader.VolidHash[voltype][hashindex], sizeof(afs_int32))) return VL_IO;
732 /* cheader must have be read before this routine is called. */
733 int UnhashVolid(trans, voltype, blockindex, aentry)
734 struct ubik_trans *trans;
736 afs_int32 blockindex;
737 struct nvlentry *aentry;
738 { int hashindex, nextblockindex, prevblockindex;
739 struct nvlentry tentry;
743 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
745 /* Take it out of the VolId[voltype] hash list */
746 hashindex = IDHash(aentry->volumeId[voltype]);
747 nextblockindex = ntohl(cheader.VolidHash[voltype][hashindex]);
748 if (nextblockindex == blockindex) {
749 /* First on the hash list; just adjust pointers */
750 cheader.VolidHash[voltype][hashindex] = htonl(aentry->nextIdHash[voltype]);
751 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolidHash[voltype][hashindex]), (char *) &cheader.VolidHash[voltype][hashindex], sizeof(afs_int32));
752 if (code) return VL_IO;
754 while (nextblockindex != blockindex) {
755 prevblockindex = nextblockindex; /* always done once */
756 if (vlentryread(trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
758 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
761 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
762 temp = htonl(temp); /* convert to network byte order before writing */
763 if (vlwrite(trans, DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]), (char *)&temp, sizeof(afs_int32)))
766 aentry->nextIdHash[voltype] = 0;
771 int HashVolname(trans, blockindex, aentry)
772 struct ubik_trans *trans;
773 afs_int32 blockindex;
774 struct nvlentry *aentry;
775 { register afs_int32 hashindex;
776 register afs_int32 code;
778 /* Insert into volname's hash linked list */
779 hashindex = NameHash(aentry->name);
780 aentry->nextNameHash = ntohl(cheader.VolnameHash[hashindex]);
781 cheader.VolnameHash[hashindex] = htonl(blockindex);
782 code = vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]), (char *) &cheader.VolnameHash[hashindex], sizeof(afs_int32));
783 if (code) return VL_IO;
788 int UnhashVolname(trans, blockindex, aentry)
789 struct ubik_trans *trans;
790 afs_int32 blockindex;
791 struct nvlentry *aentry;
792 { register afs_int32 hashindex, nextblockindex, prevblockindex;
793 struct nvlentry tentry;
796 /* Take it out of the Volname hash list */
797 hashindex = NameHash(aentry->name);
798 nextblockindex = ntohl(cheader.VolnameHash[hashindex]);
799 if (nextblockindex == blockindex) {
800 /* First on the hash list; just adjust pointers */
801 cheader.VolnameHash[hashindex] = htonl(aentry->nextNameHash);
802 if (vlwrite(trans, DOFFSET(0, &cheader, &cheader.VolnameHash[hashindex]), (char *) &cheader.VolnameHash[hashindex], sizeof(afs_int32))) return VL_IO;
804 while (nextblockindex != blockindex) {
805 prevblockindex = nextblockindex; /* always done at least once */
806 if (vlentryread(trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
808 if ((nextblockindex = tentry.nextNameHash) == NULLO)
811 tentry.nextNameHash = aentry->nextNameHash;
812 temp = htonl(tentry.nextNameHash);
813 if (vlwrite(trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash), (char *)&temp, sizeof(afs_int32)))
816 aentry->nextNameHash = 0;
821 /* 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 */
823 afs_int32 NextEntry (trans, blockindex, tentry, remaining)
824 struct ubik_trans *trans;
825 afs_int32 blockindex;
826 struct nvlentry *tentry;
827 afs_int32 *remaining;
828 { register afs_int32 lastblockindex;
830 if (blockindex == 0) /* get first one */
831 blockindex = sizeof(cheader);
833 if (!index_OK (trans, blockindex)) {
834 *remaining = -1; /* error */
837 blockindex += sizeof(nvlentry);
839 /* now search for the first entry that isn't free */
840 for (lastblockindex = ntohl(cheader.vital_header.eofPtr); blockindex < lastblockindex;) {
841 if (vlentryread(trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
845 if (tentry->flags == VLCONTBLOCK) {
847 * This is a special mh extension block just simply skip over it
849 blockindex += VL_ADDREXTBLK_SIZE;
851 if (tentry->flags != VLFREE) {
852 /* estimate remaining number of entries, not including this one */
853 *remaining = (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
856 blockindex += sizeof(nvlentry);
859 *remaining = 0; /* no more entries */
864 /* Routine to verify that index is a legal offset to a vldb entry in the table */
865 static int index_OK (trans, blockindex)
866 struct ubik_trans *trans;
867 afs_int32 blockindex;
869 if ((blockindex < sizeof(cheader)) || (blockindex >= ntohl(cheader.vital_header.eofPtr)))