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>
20 #include "vlserver_internal.h"
22 struct vlheader xheader;
23 extern int maxnservers;
24 extern afs_uint32 rd_HostAddress[MAXSERVERID + 1];
25 extern afs_uint32 wr_HostAddress[MAXSERVERID + 1];
26 struct extentaddr *rd_ex_addr[VL_MAX_ADDREXTBLKS] = { 0, 0, 0, 0 };
27 struct extentaddr *wr_ex_addr[VL_MAX_ADDREXTBLKS] = { 0, 0, 0, 0 };
28 struct vlheader rd_cheader; /* kept in network byte order */
29 struct vlheader wr_cheader;
32 static int index_OK(struct vl_ctx *ctx, afs_int32 blockindex);
34 #define ERROR_EXIT(code) do { \
39 /* Hashing algorithm based on the volume id; HASHSIZE must be prime */
41 IDHash(afs_int32 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. */
49 NameHash(char *volumename)
55 for (i = strlen(volumename), volumename += i - 1; i--; volumename--)
56 hash = (hash * 63) + (*((unsigned char *)volumename) - 63);
57 return (hash % HASHSIZE);
61 /* package up seek and write into one procedure for ease of use */
63 vlwrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
68 if ((errorcode = ubik_Seek(trans, 0, offset)))
70 return (ubik_Write(trans, buffer, length));
74 /* Package up seek and read into one procedure for ease of use */
76 vlread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
81 if ((errorcode = ubik_Seek(trans, 0, offset)))
83 return (ubik_Read(trans, buffer, length));
87 /* take entry and convert to network order and write to disk */
89 vlentrywrite(struct ubik_trans *trans, afs_int32 offset, void *buffer,
92 struct vlentry oentry;
93 struct nvlentry nentry, *nep;
97 if (length != sizeof(oentry))
99 if (maxnservers == 13) {
100 nep = (struct nvlentry *)buffer;
101 for (i = 0; i < MAXTYPES; i++)
102 nentry.volumeId[i] = htonl(nep->volumeId[i]);
103 nentry.flags = htonl(nep->flags);
104 nentry.LockAfsId = htonl(nep->LockAfsId);
105 nentry.LockTimestamp = htonl(nep->LockTimestamp);
106 nentry.cloneId = htonl(nep->cloneId);
107 for (i = 0; i < MAXTYPES; i++)
108 nentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
109 nentry.nextNameHash = htonl(nep->nextNameHash);
110 memcpy(nentry.name, nep->name, VL_MAXNAMELEN);
111 memcpy(nentry.serverNumber, nep->serverNumber, NMAXNSERVERS);
112 memcpy(nentry.serverPartition, nep->serverPartition, NMAXNSERVERS);
113 memcpy(nentry.serverFlags, nep->serverFlags, NMAXNSERVERS);
114 bufp = (char *)&nentry;
116 memset(&oentry, 0, sizeof(struct vlentry));
117 nep = (struct nvlentry *)buffer;
118 for (i = 0; i < MAXTYPES; i++)
119 oentry.volumeId[i] = htonl(nep->volumeId[i]);
120 oentry.flags = htonl(nep->flags);
121 oentry.LockAfsId = htonl(nep->LockAfsId);
122 oentry.LockTimestamp = htonl(nep->LockTimestamp);
123 oentry.cloneId = htonl(nep->cloneId);
124 for (i = 0; i < MAXTYPES; i++)
125 oentry.nextIdHash[i] = htonl(nep->nextIdHash[i]);
126 oentry.nextNameHash = htonl(nep->nextNameHash);
127 memcpy(oentry.name, nep->name, VL_MAXNAMELEN);
128 memcpy(oentry.serverNumber, nep->serverNumber, OMAXNSERVERS);
129 memcpy(oentry.serverPartition, nep->serverPartition, OMAXNSERVERS);
130 memcpy(oentry.serverFlags, nep->serverFlags, OMAXNSERVERS);
131 bufp = (char *)&oentry;
133 return vlwrite(trans, offset, bufp, length);
136 /* read entry and convert to host order and write to disk */
138 vlentryread(struct ubik_trans *trans, afs_int32 offset, char *buffer,
141 struct vlentry *oep, tentry;
142 struct nvlentry *nep, *nbufp;
143 char *bufp = (char *)&tentry;
146 if (length != sizeof(vlentry))
148 i = vlread(trans, offset, bufp, length);
151 if (maxnservers == 13) {
152 nep = (struct nvlentry *)bufp;
153 nbufp = (struct nvlentry *)buffer;
154 for (i = 0; i < MAXTYPES; i++)
155 nbufp->volumeId[i] = ntohl(nep->volumeId[i]);
156 nbufp->flags = ntohl(nep->flags);
157 nbufp->LockAfsId = ntohl(nep->LockAfsId);
158 nbufp->LockTimestamp = ntohl(nep->LockTimestamp);
159 nbufp->cloneId = ntohl(nep->cloneId);
160 for (i = 0; i < MAXTYPES; i++)
161 nbufp->nextIdHash[i] = ntohl(nep->nextIdHash[i]);
162 nbufp->nextNameHash = ntohl(nep->nextNameHash);
163 memcpy(nbufp->name, nep->name, VL_MAXNAMELEN);
164 memcpy(nbufp->serverNumber, nep->serverNumber, NMAXNSERVERS);
165 memcpy(nbufp->serverPartition, nep->serverPartition, NMAXNSERVERS);
166 memcpy(nbufp->serverFlags, nep->serverFlags, NMAXNSERVERS);
168 oep = (struct vlentry *)bufp;
169 nbufp = (struct nvlentry *)buffer;
170 memset(nbufp, 0, sizeof(struct nvlentry));
171 for (i = 0; i < MAXTYPES; i++)
172 nbufp->volumeId[i] = ntohl(oep->volumeId[i]);
173 nbufp->flags = ntohl(oep->flags);
174 nbufp->LockAfsId = ntohl(oep->LockAfsId);
175 nbufp->LockTimestamp = ntohl(oep->LockTimestamp);
176 nbufp->cloneId = ntohl(oep->cloneId);
177 for (i = 0; i < MAXTYPES; i++)
178 nbufp->nextIdHash[i] = ntohl(oep->nextIdHash[i]);
179 nbufp->nextNameHash = ntohl(oep->nextNameHash);
180 memcpy(nbufp->name, oep->name, VL_MAXNAMELEN);
181 memcpy(nbufp->serverNumber, oep->serverNumber, OMAXNSERVERS);
182 memcpy(nbufp->serverPartition, oep->serverPartition, OMAXNSERVERS);
183 memcpy(nbufp->serverFlags, oep->serverFlags, OMAXNSERVERS);
184 /* initilize the last elements to BADSERVERID */
185 for (i = OMAXNSERVERS; i < NMAXNSERVERS; i++) {
186 nbufp->serverNumber[i] = BADSERVERID;
187 nbufp->serverPartition[i] = BADSERVERID;
188 nbufp->serverFlags[i] = BADSERVERID;
194 /* Convenient write of small critical vldb header info to the database. */
196 write_vital_vlheader(struct vl_ctx *ctx)
199 (ctx->trans, 0, (char *)&ctx->cheader->vital_header, sizeof(vital_vlheader)))
207 /* This routine reads in the extent blocks for multi-homed servers.
208 * There used to be an initialization bug that would cause the contaddrs
209 * pointers in the first extent block to be bad. Here we will check the
210 * pointers and zero them in the in-memory copy if we find them bad. We
211 * also try to write the extent blocks back out. If we can't, then we
212 * will wait until the next write transaction to write them out
213 * (extent_mod tells us the on-disk copy is bad).
216 readExtents(struct ubik_trans *trans)
218 afs_uint32 extentAddr;
219 afs_int32 error = 0, code;
223 extentAddr = ntohl(rd_cheader.SIT);
227 /* Read the first extension block */
228 if (!rd_ex_addr[0]) {
229 rd_ex_addr[0] = malloc(VL_ADDREXTBLK_SIZE);
231 ERROR_EXIT(VL_NOMEM);
233 code = vlread(trans, extentAddr, (char *)rd_ex_addr[0], VL_ADDREXTBLK_SIZE);
235 free(rd_ex_addr[0]); /* Not the place to create it */
240 /* In case more that 64 mh servers are in use they're kept in these
241 * continuation blocks
243 for (i = 1; i < VL_MAX_ADDREXTBLKS; i++) {
244 if (!rd_ex_addr[0]->ex_contaddrs[i])
247 /* Before reading it in, check to see if the address is good */
248 if ((ntohl(rd_ex_addr[0]->ex_contaddrs[i]) <
249 ntohl(rd_ex_addr[0]->ex_contaddrs[i - 1]) + VL_ADDREXTBLK_SIZE)
250 || (ntohl(rd_ex_addr[0]->ex_contaddrs[i]) >
251 ntohl(rd_cheader.vital_header.eofPtr) - VL_ADDREXTBLK_SIZE)) {
253 rd_ex_addr[0]->ex_contaddrs[i] = 0;
258 /* Read the continuation block */
259 if (!rd_ex_addr[i]) {
260 rd_ex_addr[i] = malloc(VL_ADDREXTBLK_SIZE);
262 ERROR_EXIT(VL_NOMEM);
265 vlread(trans, ntohl(rd_ex_addr[0]->ex_contaddrs[i]),
266 (char *)rd_ex_addr[i], VL_ADDREXTBLK_SIZE);
268 free(rd_ex_addr[i]); /* Not the place to create it */
273 /* After reading it in, check to see if its a real continuation block */
274 if (ntohl(rd_ex_addr[i]->ex_hdrflags) != VLCONTBLOCK) {
276 rd_ex_addr[0]->ex_contaddrs[i] = 0;
277 free(rd_ex_addr[i]); /* Not the place to create it */
284 code = vlwrite(trans, extentAddr, rd_ex_addr[0], VL_ADDREXTBLK_SIZE);
286 VLog(0, ("Multihome server support modification\n"));
288 /* Keep extent_mod true in-case the transaction aborts */
289 /* Don't return error so we don't abort transaction */
296 /* Check that the database has been initialized. Be careful to fail in a safe
297 manner, to avoid bogusly reinitializing the db. */
299 * reads in db cache from ubik.
301 * @param[in] ut ubik transaction
302 * @param[in] rock opaque pointer to an int*; if 1, we should rebuild the db
303 * if it appears empty, if 0 we should return an error if the
306 * @return operation status
310 UpdateCache(struct ubik_trans *trans, void *rock)
312 int *builddb_rock = rock;
313 int builddb = *builddb_rock;
314 afs_int32 error = 0, i, code, ubcode;
316 /* if version changed (or first call), read the header */
317 ubcode = vlread(trans, 0, (char *)&rd_cheader, sizeof(rd_cheader));
318 vldbversion = ntohl(rd_cheader.vital_header.vldbversion);
320 if (!ubcode && (vldbversion != 0)) {
321 memcpy(rd_HostAddress, rd_cheader.IpMappedAddr, sizeof(rd_cheader.IpMappedAddr));
322 for (i = 0; i < MAXSERVERID + 1; i++) { /* cvt HostAddress to host order */
323 rd_HostAddress[i] = ntohl(rd_HostAddress[i]);
326 code = readExtents(trans);
331 /* now, if can't read, or header is wrong, write a new header */
332 if (ubcode || vldbversion == 0) {
334 VLog(0, ("Can't read VLDB header, re-initialising...\n"));
336 /* try to write a good header */
337 /* The read cache will be sync'ed to this new header
338 * when the ubik transaction is ended by vlsynccache(). */
339 memset(&wr_cheader, 0, sizeof(wr_cheader));
340 wr_cheader.vital_header.vldbversion = htonl(VLDBVERSION);
341 wr_cheader.vital_header.headersize = htonl(sizeof(wr_cheader));
342 /* DANGER: Must get this from a master place!! */
343 wr_cheader.vital_header.MaxVolumeId = htonl(0x20000000);
344 wr_cheader.vital_header.eofPtr = htonl(sizeof(wr_cheader));
345 for (i = 0; i < MAXSERVERID + 1; i++) {
346 wr_cheader.IpMappedAddr[i] = 0;
347 wr_HostAddress[i] = 0;
349 code = vlwrite(trans, 0, (char *)&wr_cheader, sizeof(wr_cheader));
351 VLog(0, ("Can't write VLDB header (error = %d)\n", code));
354 vldbversion = ntohl(wr_cheader.vital_header.vldbversion);
356 VLog(1, ("Unable to read VLDB header.\n"));
357 ERROR_EXIT(VL_EMPTY);
361 if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
362 && (vldbversion != VLDBVERSION_4)) {
364 ("VLDB version %d doesn't match this software version(%d, %d or %d), quitting!\n",
365 vldbversion, VLDBVERSION_4, VLDBVERSION, OVLDBVERSION));
366 ERROR_EXIT(VL_BADVERSION);
369 maxnservers = ((vldbversion == 3 || vldbversion == 4) ? 13 : 8);
377 CheckInit(struct ubik_trans *trans, int builddb)
381 code = ubik_CheckCache(trans, UpdateCache, &builddb);
386 /* these next two cases shouldn't happen (UpdateCache should either
387 * rebuild the db or return an error if these cases occur), but just to
388 * be on the safe side... */
389 if (vldbversion == 0) {
392 if ((vldbversion != VLDBVERSION) && (vldbversion != OVLDBVERSION)
393 && (vldbversion != VLDBVERSION_4)) {
394 return VL_BADVERSION;
401 * Grow the eofPtr in the header by 'bump' bytes.
403 * @param[inout] cheader VL header
404 * @param[in] bump How many bytes to add to eofPtr
405 * @param[out] a_blockindex On success, set to the original eofPtr before we
407 * @return VL error codes
410 grow_eofPtr(struct vlheader *cheader, afs_int32 bump, afs_int32 *a_blockindex)
412 afs_int32 blockindex = ntohl(cheader->vital_header.eofPtr);
414 if (blockindex < 0 || blockindex >= MAX_AFS_INT32 - bump) {
415 VLog(0, ("Error: Tried to grow the VLDB beyond the 2GiB limit. Either "
416 "find a way to trim down your VLDB, or upgrade to a release "
417 "and database format that supports a larger VLDB.\n"));
421 *a_blockindex = blockindex;
422 cheader->vital_header.eofPtr = htonl(blockindex + bump);
427 GetExtentBlock(struct vl_ctx *ctx, afs_int32 base)
429 afs_int32 blockindex, code, error = 0;
431 /* Base 0 must exist before any other can be created */
432 if ((base != 0) && !ctx->ex_addr[0])
433 ERROR_EXIT(VL_CREATEFAIL); /* internal error */
435 if (!ctx->ex_addr[0] || !ctx->ex_addr[0]->ex_contaddrs[base]) {
436 /* Create a new extension block */
437 if (!ctx->ex_addr[base]) {
438 ctx->ex_addr[base] = malloc(VL_ADDREXTBLK_SIZE);
439 if (!ctx->ex_addr[base])
440 ERROR_EXIT(VL_NOMEM);
442 memset(ctx->ex_addr[base], 0, VL_ADDREXTBLK_SIZE);
444 /* Write the full extension block at end of vldb */
445 ctx->ex_addr[base]->ex_hdrflags = htonl(VLCONTBLOCK);
446 code = grow_eofPtr(ctx->cheader, VL_ADDREXTBLK_SIZE, &blockindex);
451 vlwrite(ctx->trans, blockindex, (char *)ctx->ex_addr[base],
457 code = write_vital_vlheader(ctx);
461 /* Write the address of the base extension block in the vldb header */
463 ctx->cheader->SIT = htonl(blockindex);
465 vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->SIT),
466 (char *)&ctx->cheader->SIT, sizeof(ctx->cheader->SIT));
471 /* Write the address of this extension block into the base extension block */
472 ctx->ex_addr[0]->ex_contaddrs[base] = htonl(blockindex);
474 vlwrite(ctx->trans, ntohl(ctx->cheader->SIT), ctx->ex_addr[0],
475 sizeof(struct extentaddr));
486 FindExtentBlock(struct vl_ctx *ctx, afsUUID *uuidp,
487 afs_int32 createit, afs_int32 hostslot,
488 struct extentaddr **expp, afs_int32 *basep)
491 struct extentaddr *exp;
492 afs_int32 i, j, code, base, index, error = 0;
497 /* Create the first extension block if it does not exist */
498 if (!ctx->cheader->SIT) {
499 code = GetExtentBlock(ctx, 0);
504 for (i = 0; i < MAXSERVERID + 1; i++) {
505 if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
506 if ((base = (ctx->hostaddress[i] >> 16) & 0xff) > VL_MAX_ADDREXTBLKS) {
507 ERROR_EXIT(VL_INDEXERANGE);
509 if ((index = ctx->hostaddress[i] & 0x0000ffff) > VL_MHSRV_PERBLK) {
510 ERROR_EXIT(VL_INDEXERANGE);
512 exp = &ctx->ex_addr[base][index];
513 tuuid = exp->ex_hostuuid;
514 afs_ntohuuid(&tuuid);
515 if (afs_uuid_equal(uuidp, &tuuid)) {
524 if (hostslot == -1) {
525 for (i = 0; i < MAXSERVERID + 1; i++) {
526 if (!ctx->hostaddress[i])
530 ERROR_EXIT(VL_REPSFULL);
535 for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
536 if (!ctx->ex_addr[0]->ex_contaddrs[base]) {
537 code = GetExtentBlock(ctx, base);
541 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
542 exp = &ctx->ex_addr[base][j];
543 tuuid = exp->ex_hostuuid;
544 afs_ntohuuid(&tuuid);
545 if (afs_uuid_is_nil(&tuuid)) {
547 afs_htonuuid(&tuuid);
548 exp->ex_hostuuid = tuuid;
551 DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
552 (char *)ctx->ex_addr[base], (char *)exp),
553 (char *)&tuuid, sizeof(tuuid));
556 ctx->hostaddress[i] =
557 0xff000000 | ((base << 16) & 0xff0000) | (j & 0xffff);
560 if (vldbversion != VLDBVERSION_4) {
561 ctx->cheader->vital_header.vldbversion =
562 htonl(VLDBVERSION_4);
563 code = write_vital_vlheader(ctx);
567 ctx->cheader->IpMappedAddr[i] = htonl(ctx->hostaddress[i]);
570 DOFFSET(0, ctx->cheader,
571 &ctx->cheader->IpMappedAddr[i]),
572 (char *)&ctx->cheader->IpMappedAddr[i],
580 ERROR_EXIT(VL_REPSFULL); /* No reason to utilize a new error code */
587 /* Allocate a free block of storage for entry, returning address of a new
588 zeroed entry (or zero if something is wrong). */
590 AllocBlock(struct vl_ctx *ctx, struct nvlentry *tentry)
592 afs_int32 blockindex;
594 if (ctx->cheader->vital_header.freePtr) {
595 /* allocate this dude */
596 blockindex = ntohl(ctx->cheader->vital_header.freePtr);
597 if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(vlentry)))
599 ctx->cheader->vital_header.freePtr = htonl(tentry->nextIdHash[0]);
602 /* hosed, nothing on free list, grow file */
603 code = grow_eofPtr(ctx->cheader, sizeof(vlentry), &blockindex);
607 ctx->cheader->vital_header.allocs++;
608 if (write_vital_vlheader(ctx))
610 memset(tentry, 0, sizeof(nvlentry)); /* zero new entry */
615 /* Free a block given its index. It must already have been unthreaded. Returns zero for success or an error code on failure. */
617 FreeBlock(struct vl_ctx *ctx, afs_int32 blockindex)
619 struct nvlentry tentry;
621 /* check validity of blockindex just to be on the safe side */
622 if (!index_OK(ctx, blockindex))
624 memset(&tentry, 0, sizeof(nvlentry));
625 tentry.nextIdHash[0] = ctx->cheader->vital_header.freePtr; /* already in network order */
626 tentry.flags = htonl(VLFREE);
627 ctx->cheader->vital_header.freePtr = htonl(blockindex);
628 if (vlwrite(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
630 ctx->cheader->vital_header.frees++;
631 if (write_vital_vlheader(ctx))
637 /* Look for a block by volid and voltype (if not known use -1 which searches
638 * all 3 volid hash lists. Note that the linked lists are read in first from
639 * the database header. If found read the block's contents into the area
640 * pointed to by tentry and return the block's index. If not found return 0.
643 FindByID(struct vl_ctx *ctx, afs_uint32 volid, afs_int32 voltype,
644 struct nvlentry *tentry, afs_int32 *error)
646 afs_int32 typeindex, hashindex, blockindex;
649 hashindex = IDHash(volid);
651 /* Should we have one big hash table for volids as opposed to the three ones? */
652 for (typeindex = 0; typeindex < MAXTYPES; typeindex++) {
653 for (blockindex = ntohl(ctx->cheader->VolidHash[typeindex][hashindex]);
655 blockindex = tentry->nextIdHash[typeindex]) {
657 (ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
661 if (volid == tentry->volumeId[typeindex])
666 for (blockindex = ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
667 blockindex != NULLO; blockindex = tentry->nextIdHash[voltype]) {
669 (ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
673 if (volid == tentry->volumeId[voltype])
677 return 0; /* no such entry */
681 /* Look for a block by volume name. If found read the block's contents into
682 * the area pointed to by tentry and return the block's index. If not
686 FindByName(struct vl_ctx *ctx, char *volname, struct nvlentry *tentry,
690 afs_int32 blockindex;
691 char tname[VL_MAXNAMELEN];
693 /* remove .backup or .readonly extensions for stupid backwards
696 hashindex = strlen(volname); /* really string length */
697 if (hashindex >= 8 && strcmp(volname + hashindex - 7, ".backup") == 0) {
698 /* this is a backup volume */
699 strcpy(tname, volname);
700 tname[hashindex - 7] = 0; /* zap extension */
701 } else if (hashindex >= 10
702 && strcmp(volname + hashindex - 9, ".readonly") == 0) {
703 /* this is a readonly volume */
704 strcpy(tname, volname);
705 tname[hashindex - 9] = 0; /* zap extension */
707 strcpy(tname, volname);
710 hashindex = NameHash(tname);
711 for (blockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
712 blockindex != NULLO; blockindex = tentry->nextNameHash) {
713 if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
717 if (!strcmp(tname, tentry->name))
720 return 0; /* no such entry */
724 * Returns whether or not any of the supplied volume IDs already exist
727 * @param ctx transaction context
728 * @param ids an array of volume IDs
729 * @param ids_len the number of elements in the 'ids' array
730 * @param error filled in with an error code in case of error
732 * @return whether any of the volume IDs are already used
733 * @retval 1 at least one of the volume IDs is already used
734 * @retval 0 none of the volume IDs are used, or an error occurred
737 EntryIDExists(struct vl_ctx *ctx, const afs_uint32 *ids,
738 afs_int32 ids_len, afs_int32 *error)
741 struct nvlentry tentry;
745 for (typeindex = 0; typeindex < ids_len; typeindex++) {
747 && FindByID(ctx, ids[typeindex], -1, &tentry, error)) {
759 * Finds the next range of unused volume IDs in the vldb.
761 * @param ctx transaction context
762 * @param maxvolid the current max vol ID, and where to start looking
763 * for an unused volume ID range
764 * @param bump how many volume IDs we need to be unused
765 * @param error filled in with an error code in case of error
767 * @return the next volume ID 'volid' such that the range
768 * [volid, volid+bump) of volume IDs is unused, or 0 if there's
772 NextUnusedID(struct vl_ctx *ctx, afs_uint32 maxvolid, afs_uint32 bump,
775 struct nvlentry tentry;
781 /* we simply start at the given maxvolid, keep a running tally of
782 * how many free volume IDs we've seen in a row, and return when
783 * we've seen 'bump' unused IDs in a row */
784 for (id = maxvolid, nfree = 0; nfree < bump; ++id) {
785 if (FindByID(ctx, id, -1, &tentry, error)) {
794 /* 'id' is now at the end of the [maxvolid,maxvolid+bump) range,
795 * but we need to return the first unused id, so subtract the
796 * number of current running free IDs to get the beginning */
801 HashNDump(struct vl_ctx *ctx, int hashindex)
805 struct nvlentry tentry;
807 for (blockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
808 blockindex != NULLO; blockindex = tentry.nextNameHash) {
809 if (vlentryread(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
813 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
814 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
821 HashIdDump(struct vl_ctx *ctx, int hashindex)
825 struct nvlentry tentry;
827 for (blockindex = ntohl(ctx->cheader->VolidHash[0][hashindex]);
828 blockindex != NULLO; blockindex = tentry.nextIdHash[0]) {
829 if (vlentryread(ctx->trans, blockindex, (char *)&tentry, sizeof(nvlentry)))
833 ("[%d]#%d: %10d %d %d (%s)\n", hashindex, i, tentry.volumeId[0],
834 tentry.nextIdHash[0], tentry.nextNameHash, tentry.name));
840 /* Add a block to the hash table given a pointer to the block and its index.
841 * The block is threaded onto both hash tables and written to disk. The
842 * routine returns zero if there were no errors.
845 ThreadVLentry(struct vl_ctx *ctx, afs_int32 blockindex,
846 struct nvlentry *tentry)
850 if (!index_OK(ctx, blockindex))
852 /* Insert into volid's hash linked list */
853 if ((errorcode = HashVolid(ctx, RWVOL, blockindex, tentry)))
856 /* For rw entries we also enter the RO and BACK volume ids (if they
857 * exist) in the hash tables; note all there volids (RW, RO, BACK)
858 * should not be hashed yet! */
859 if (tentry->volumeId[ROVOL]) {
860 if ((errorcode = HashVolid(ctx, ROVOL, blockindex, tentry)))
863 if (tentry->volumeId[BACKVOL]) {
864 if ((errorcode = HashVolid(ctx, BACKVOL, blockindex, tentry)))
868 /* Insert into volname's hash linked list */
869 HashVolname(ctx, blockindex, tentry);
871 /* Update cheader entry */
872 if (write_vital_vlheader(ctx))
875 /* Update hash list pointers in the entry itself */
876 if (vlentrywrite(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry)))
882 /* Remove a block from both the hash tables. If success return 0, else
883 * return an error code. */
885 UnthreadVLentry(struct vl_ctx *ctx, afs_int32 blockindex,
886 struct nvlentry *aentry)
888 afs_int32 errorcode, typeindex;
890 if (!index_OK(ctx, blockindex))
892 if ((errorcode = UnhashVolid(ctx, RWVOL, blockindex, aentry)))
895 /* Take the RO/RW entries of their respective hash linked lists. */
896 for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
897 if ((errorcode = UnhashVolid(ctx, typeindex, blockindex, aentry))) {
898 if (errorcode == VL_NOENT) {
899 VLog(0, ("Unable to unhash vlentry '%s' (address %d) from hash "
900 "chain for volid %u (type %d).\n",
901 aentry->name, blockindex, aentry->volumeId[typeindex], typeindex));
902 VLog(0, ("... The VLDB may be partly corrupted; see vldb_check "
903 "for how to check for and fix errors.\n"));
910 /* Take it out of the Volname hash list */
911 if ((errorcode = UnhashVolname(ctx, blockindex, aentry))) {
912 if (errorcode == VL_NOENT) {
913 VLog(0, ("Unable to unhash vlentry '%s' (address %d) from name "
914 "hash chain.\n", aentry->name, blockindex));
915 VLog(0, ("... The VLDB may be partly corrupted; see vldb_check "
916 "for how to check for and fix errors.\n"));
922 /* Update cheader entry */
923 write_vital_vlheader(ctx);
928 /* cheader must have be read before this routine is called. */
930 HashVolid(struct vl_ctx *ctx, afs_int32 voltype, afs_int32 blockindex,
931 struct nvlentry *tentry)
933 afs_int32 hashindex, errorcode;
934 struct nvlentry ventry;
937 (ctx, tentry->volumeId[voltype], voltype, &ventry, &errorcode))
938 return VL_IDALREADYHASHED;
941 hashindex = IDHash(tentry->volumeId[voltype]);
942 tentry->nextIdHash[voltype] =
943 ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
944 ctx->cheader->VolidHash[voltype][hashindex] = htonl(blockindex);
946 (ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolidHash[voltype][hashindex]),
947 (char *)&ctx->cheader->VolidHash[voltype][hashindex], sizeof(afs_int32)))
953 /* cheader must have be read before this routine is called. */
955 UnhashVolid(struct vl_ctx *ctx, afs_int32 voltype, afs_int32 blockindex,
956 struct nvlentry *aentry)
958 int hashindex, nextblockindex, prevblockindex;
959 struct nvlentry tentry;
963 if (aentry->volumeId[voltype] == NULLO) /* Assume no volume id */
965 /* Take it out of the VolId[voltype] hash list */
966 hashindex = IDHash(aentry->volumeId[voltype]);
967 nextblockindex = ntohl(ctx->cheader->VolidHash[voltype][hashindex]);
968 if (nextblockindex == blockindex) {
969 /* First on the hash list; just adjust pointers */
970 ctx->cheader->VolidHash[voltype][hashindex] =
971 htonl(aentry->nextIdHash[voltype]);
974 DOFFSET(0, ctx->cheader,
975 &ctx->cheader->VolidHash[voltype][hashindex]),
976 (char *)&ctx->cheader->VolidHash[voltype][hashindex],
981 while (nextblockindex != blockindex) {
982 prevblockindex = nextblockindex; /* always done once */
984 (ctx->trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
986 if ((nextblockindex = tentry.nextIdHash[voltype]) == NULLO)
989 temp = tentry.nextIdHash[voltype] = aentry->nextIdHash[voltype];
990 temp = htonl(temp); /* convert to network byte order before writing */
993 DOFFSET(prevblockindex, &tentry, &tentry.nextIdHash[voltype]),
994 (char *)&temp, sizeof(afs_int32)))
997 aentry->nextIdHash[voltype] = 0;
1003 HashVolname(struct vl_ctx *ctx, afs_int32 blockindex,
1004 struct nvlentry *aentry)
1006 afs_int32 hashindex;
1009 /* Insert into volname's hash linked list */
1010 hashindex = NameHash(aentry->name);
1011 aentry->nextNameHash = ntohl(ctx->cheader->VolnameHash[hashindex]);
1012 ctx->cheader->VolnameHash[hashindex] = htonl(blockindex);
1014 vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolnameHash[hashindex]),
1015 (char *)&ctx->cheader->VolnameHash[hashindex], sizeof(afs_int32));
1023 UnhashVolname(struct vl_ctx *ctx, afs_int32 blockindex,
1024 struct nvlentry *aentry)
1026 afs_int32 hashindex, nextblockindex, prevblockindex;
1027 struct nvlentry tentry;
1030 /* Take it out of the Volname hash list */
1031 hashindex = NameHash(aentry->name);
1032 nextblockindex = ntohl(ctx->cheader->VolnameHash[hashindex]);
1033 if (nextblockindex == blockindex) {
1034 /* First on the hash list; just adjust pointers */
1035 ctx->cheader->VolnameHash[hashindex] = htonl(aentry->nextNameHash);
1037 (ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->VolnameHash[hashindex]),
1038 (char *)&ctx->cheader->VolnameHash[hashindex], sizeof(afs_int32)))
1041 while (nextblockindex != blockindex) {
1042 prevblockindex = nextblockindex; /* always done at least once */
1044 (ctx->trans, nextblockindex, (char *)&tentry, sizeof(nvlentry)))
1046 if ((nextblockindex = tentry.nextNameHash) == NULLO)
1049 tentry.nextNameHash = aentry->nextNameHash;
1050 temp = htonl(tentry.nextNameHash);
1052 (ctx->trans, DOFFSET(prevblockindex, &tentry, &tentry.nextNameHash),
1053 (char *)&temp, sizeof(afs_int32)))
1056 aentry->nextNameHash = 0;
1061 /* Returns the vldb entry tentry at offset index; remaining is the number of
1062 * entries left; the routine also returns the index of the next sequential
1067 NextEntry(struct vl_ctx *ctx, afs_int32 blockindex,
1068 struct nvlentry *tentry, afs_int32 *remaining)
1070 afs_int32 lastblockindex;
1072 if (blockindex == 0) /* get first one */
1073 blockindex = sizeof(*ctx->cheader);
1075 if (!index_OK(ctx, blockindex)) {
1076 *remaining = -1; /* error */
1079 blockindex += sizeof(nvlentry);
1081 /* now search for the first entry that isn't free */
1082 for (lastblockindex = ntohl(ctx->cheader->vital_header.eofPtr);
1083 blockindex < lastblockindex;) {
1084 if (vlentryread(ctx->trans, blockindex, (char *)tentry, sizeof(nvlentry))) {
1088 if (tentry->flags == VLCONTBLOCK) {
1090 * This is a special mh extension block just simply skip over it
1092 blockindex += VL_ADDREXTBLK_SIZE;
1094 if (tentry->flags != VLFREE) {
1095 /* estimate remaining number of entries, not including this one */
1097 (lastblockindex - blockindex) / sizeof(nvlentry) - 1;
1100 blockindex += sizeof(nvlentry);
1103 *remaining = 0; /* no more entries */
1108 /* Routine to verify that index is a legal offset to a vldb entry in the
1112 index_OK(struct vl_ctx *ctx, afs_int32 blockindex)
1114 if ((blockindex < sizeof(*ctx->cheader))
1115 || (blockindex >= ntohl(ctx->cheader->vital_header.eofPtr)))
1120 /* makes a deep copy of src_ex into dst_ex */
1122 vlexcpy(struct extentaddr **dst_ex, struct extentaddr **src_ex)
1125 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
1128 dst_ex[i] = malloc(VL_ADDREXTBLK_SIZE);
1133 memcpy(dst_ex[i], src_ex[i], VL_ADDREXTBLK_SIZE);
1135 } else if (dst_ex[i]) {
1136 /* we have no src, but we have a dst... meaning, this block
1146 vlsetcache(struct vl_ctx *ctx, int locktype)
1148 if (locktype == LOCKREAD) {
1149 ctx->hostaddress = rd_HostAddress;
1150 ctx->ex_addr = rd_ex_addr;
1151 ctx->cheader = &rd_cheader;
1154 memcpy(wr_HostAddress, rd_HostAddress, sizeof(wr_HostAddress));
1155 memcpy(&wr_cheader, &rd_cheader, sizeof(wr_cheader));
1157 ctx->hostaddress = wr_HostAddress;
1158 ctx->ex_addr = wr_ex_addr;
1159 ctx->cheader = &wr_cheader;
1161 return vlexcpy(wr_ex_addr, rd_ex_addr);
1168 memcpy(rd_HostAddress, wr_HostAddress, sizeof(rd_HostAddress));
1169 memcpy(&rd_cheader, &wr_cheader, sizeof(rd_cheader));
1170 return vlexcpy(rd_ex_addr, wr_ex_addr);