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 <WINNT/afsevent.h>
20 #include <afs/afsutil.h>
26 /* Read a VLDB file and verify it for correctness */
28 #define VL 0x001 /* good volume entry */
29 #define FR 0x002 /* free volume entry */
30 #define MH 0x004 /* multi-homed entry */
32 #define RWH 0x010 /* on rw hash chain */
33 #define ROH 0x020 /* on ro hash chain */
34 #define BKH 0x040 /* on bk hash chain */
35 #define NH 0x080 /* on name hash chain */
37 #define MHC 0x100 /* on multihomed chain */
38 #define FRC 0x200 /* on free chain */
40 #define REFRW 0x1000 /* linked from something (RW) */
41 #define REFRO 0x2000 /* linked from something (RO) */
42 #define REFBK 0x4000 /* linked from something (BK) */
43 #define REFN 0x8000 /* linked from something (name) */
45 #define MULTRW 0x10000 /* multiply-chained (RW) */
46 #define MULTRO 0x20000 /* multiply-chained (RO) */
47 #define MULTBK 0x40000 /* multiply-chained (BK) */
48 #define MULTN 0x80000 /* multiply-chained (name) */
50 #define MISRWH 0x100000 /* mischained (RW) */
51 #define MISROH 0x200000 /* mischained (RO) */
52 #define MISBKH 0x400000 /* mischained (BK) */
53 #define MISNH 0x800000 /* mischained (name) */
55 #define VLDB_CHECK_NO_VLDB_CHECK_ERROR 0
56 #define VLDB_CHECK_WARNING 1
57 #define VLDB_CHECK_ERROR 2
58 #define VLDB_CHECK_FATAL 4
59 #define vldbread(x,y,z) vldbio(x,y,z,0)
60 #define vldbwrite(x,y,z) vldbio(x,y,z,1)
63 #define ADDR(x) ((x)/sizeof(struct nvlentry))
64 #define OFFSET(addr) ((addr) + HDRSIZE)
67 int listentries, listservers, listheader, listuheader, verbose, quiet;
71 /* if quiet, don't send anything to stdout */
73 /* error level. 0 = no error, 1 = warning, 2 = error, 4 = fatal */
81 int serveraddrs[MAXSERVERID + 2];
82 u_char serverxref[MAXSERVERID + 2]; /**< to resolve cross-linked mh entries */
83 int serverref[MAXSERVERID + 2]; /**< which addrs are referenced by vl entries */
86 afs_uint32 addr; /**< vldb file record */
87 char orphan[VL_MHSRV_PERBLK]; /**< unreferenced mh enties */
88 } mhinfo[VL_MAX_ADDREXTBLKS];
91 /* Used to control what goes to stdout based on quiet flag */
93 quiet_println(const char *fmt,...) {
97 vfprintf(stdout, fmt, args);
102 /* Used to set the error level and ship messages to stderr */
104 log_error(int eval, const char *fmt, ...)
107 if (error_level < eval) error_level = eval ; /* bump up the severity */
109 vfprintf(stderr, fmt, args);
112 if (error_level == VLDB_CHECK_FATAL) exit(VLDB_CHECK_FATAL);
120 struct ubik_hdr uheader;
122 offset = lseek(fd, 0, 0);
124 log_error(VLDB_CHECK_FATAL,"error: lseek to 0 failed: %d %d\n", offset, errno);
125 return (VLDB_CHECK_FATAL);
128 /* now read the info */
129 r = read(fd, &uheader, sizeof(uheader));
130 if (r != sizeof(uheader)) {
131 log_error(VLDB_CHECK_FATAL,"error: read of %lu bytes failed: %d %d\n", sizeof(uheader), r,
133 return (VLDB_CHECK_FATAL);
136 uheader.magic = ntohl(uheader.magic);
137 uheader.size = ntohs(uheader.size);
138 uheader.version.epoch = ntohl(uheader.version.epoch);
139 uheader.version.counter = ntohl(uheader.version.counter);
142 quiet_println("Ubik Header\n");
143 quiet_println(" Magic = 0x%x\n", uheader.magic);
144 quiet_println(" Size = %u\n", uheader.size);
145 quiet_println(" Version.epoch = %u\n", uheader.version.epoch);
146 quiet_println(" Version.counter = %u\n", uheader.version.counter);
149 if (uheader.size != HDRSIZE)
150 log_error(VLDB_CHECK_WARNING,"VLDB_CHECK_WARNING: Ubik header size is %u (should be %u)\n", uheader.size,
152 if (uheader.magic != UBIK_MAGIC)
153 log_error(VLDB_CHECK_ERROR,"Ubik header magic is 0x%x (should be 0x%x)\n", uheader.magic,
160 vldbio(int position, void *buffer, int size, int rdwr)
164 /* seek to the correct spot. skip ubik stuff */
165 p = OFFSET(position);
166 offset = lseek(fd, p, 0);
168 log_error(VLDB_CHECK_FATAL,"error: lseek to %d failed: %d %d\n", p, offset, errno);
173 r = write(fd, buffer, size);
175 r = read(fd, buffer, size);
178 log_error(VLDB_CHECK_FATAL,"error: %s of %d bytes failed: %d %d\n", rdwr==1?"write":"read",
202 NameHash(char *volname)
208 for (vchar = volname + strlen(volname) - 1; vchar >= volname; vchar--)
209 hash = (hash * 63) + (*((unsigned char *)vchar) - 63);
210 return (hash % HASHSIZE);
214 IdHash(afs_uint32 volid)
216 return ((abs(volid)) % HASHSIZE);
219 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
221 InvalidVolname(char *volname)
227 slen = strlen(volname);
228 if (slen >= VL_MAXNAMELEN)
232 return (slen != strspn(volname, map));
236 validVolumeAddr(afs_uint32 fileOffset)
238 if (ADDR(fileOffset) >= maxentries) {
239 /* Are we in range */
243 * We cannot test whether the offset is aligned
244 * since the vl entries are not in a regular array
250 readheader(struct vlheader *headerp)
254 vldbread(0, (char *)headerp, sizeof(*headerp));
256 headerp->vital_header.vldbversion =
257 ntohl(headerp->vital_header.vldbversion);
258 headerp->vital_header.headersize =
259 ntohl(headerp->vital_header.headersize);
260 headerp->vital_header.freePtr = ntohl(headerp->vital_header.freePtr);
261 headerp->vital_header.eofPtr = ntohl(headerp->vital_header.eofPtr);
262 headerp->vital_header.allocs = ntohl(headerp->vital_header.allocs);
263 headerp->vital_header.frees = ntohl(headerp->vital_header.frees);
264 headerp->vital_header.MaxVolumeId =
265 ntohl(headerp->vital_header.MaxVolumeId);
266 headerp->vital_header.totalEntries[0] =
267 ntohl(headerp->vital_header.totalEntries[0]);
268 for (i = 0; i < MAXTYPES; i++)
269 headerp->vital_header.totalEntries[i] =
270 ntohl(headerp->vital_header.totalEntries[1]);
272 headerp->SIT = ntohl(headerp->SIT);
273 for (i = 0; i <= MAXSERVERID; i++)
274 headerp->IpMappedAddr[i] = ntohl(headerp->IpMappedAddr[i]);
275 for (i = 0; i < HASHSIZE; i++)
276 headerp->VolnameHash[i] = ntohl(headerp->VolnameHash[i]);
277 for (i = 0; i < MAXTYPES; i++)
278 for (j = 0; j < HASHSIZE; j++)
279 headerp->VolidHash[i][j] = ntohl(headerp->VolidHash[i][j]);
282 quiet_println("vldb header\n");
283 quiet_println(" vldbversion = %u\n",
284 headerp->vital_header.vldbversion);
285 quiet_println(" headersize = %u [actual=%lu]\n",
286 headerp->vital_header.headersize, sizeof(*headerp));
287 quiet_println(" freePtr = 0x%x\n", headerp->vital_header.freePtr);
288 quiet_println(" eofPtr = %u\n", headerp->vital_header.eofPtr);
289 quiet_println(" allocblock calls = %10u\n", headerp->vital_header.allocs);
290 quiet_println(" freeblock calls = %10u\n", headerp->vital_header.frees);
291 quiet_println(" MaxVolumeId = %u\n",
292 headerp->vital_header.MaxVolumeId);
293 quiet_println(" rw vol entries = %u\n",
294 headerp->vital_header.totalEntries[0]);
295 quiet_println(" ro vol entries = %u\n",
296 headerp->vital_header.totalEntries[1]);
297 quiet_println(" bk vol entries = %u\n",
298 headerp->vital_header.totalEntries[2]);
299 quiet_println(" multihome info = 0x%x (%u)\n", headerp->SIT,
301 quiet_println(" server ip addr table: size = %d entries\n",
303 quiet_println(" volume name hash table: size = %d buckets\n", HASHSIZE);
304 quiet_println(" volume id hash table: %d tables with %d buckets each\n",
308 /* Check the header size */
309 if (headerp->vital_header.headersize != sizeof(*headerp))
310 log_error(VLDB_CHECK_WARNING,"Header reports its size as %d (should be %lu)\n",
311 headerp->vital_header.headersize, sizeof(*headerp));
316 writeheader(struct vlheader *headerp)
320 headerp->vital_header.vldbversion =
321 htonl(headerp->vital_header.vldbversion);
322 headerp->vital_header.headersize =
323 htonl(headerp->vital_header.headersize);
324 headerp->vital_header.freePtr = htonl(headerp->vital_header.freePtr);
325 headerp->vital_header.eofPtr = htonl(headerp->vital_header.eofPtr);
326 headerp->vital_header.allocs = htonl(headerp->vital_header.allocs);
327 headerp->vital_header.frees = htonl(headerp->vital_header.frees);
328 headerp->vital_header.MaxVolumeId =
329 htonl(headerp->vital_header.MaxVolumeId);
330 headerp->vital_header.totalEntries[0] =
331 htonl(headerp->vital_header.totalEntries[0]);
332 for (i = 0; i < MAXTYPES; i++)
333 headerp->vital_header.totalEntries[i] =
334 htonl(headerp->vital_header.totalEntries[1]);
336 headerp->SIT = htonl(headerp->SIT);
337 for (i = 0; i <= MAXSERVERID; i++)
338 headerp->IpMappedAddr[i] = htonl(headerp->IpMappedAddr[i]);
339 for (i = 0; i < HASHSIZE; i++)
340 headerp->VolnameHash[i] = htonl(headerp->VolnameHash[i]);
341 for (i = 0; i < MAXTYPES; i++)
342 for (j = 0; j < HASHSIZE; j++)
343 headerp->VolidHash[i][j] = htonl(headerp->VolidHash[i][j]);
345 vldbwrite(0, (char *)headerp, sizeof(*headerp));
349 readMH(afs_uint32 addr, int block, struct extentaddr *mhblockP)
352 struct extentaddr *e;
354 vldbread(addr, (char *)mhblockP, VL_ADDREXTBLK_SIZE);
356 /* Every mh block has the VLCONTBLOCK flag set in the header to
357 * indicate the entry is an 8192 byte extended block. The
358 * VLCONTBLOCK flag is always clear in regular vl entries. The
359 * vlserver depends on the VLCONTBLOCK flag to correctly traverse
360 * the vldb. The flags field is in network byte order. */
361 mhblockP->ex_hdrflags = ntohl(mhblockP->ex_hdrflags);
364 /* These header fields are only used in the first mh block. */
365 mhblockP->ex_count = ntohl(mhblockP->ex_count);
366 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
367 mhblockP->ex_contaddrs[i] = ntohl(mhblockP->ex_contaddrs[i]);
370 for (i = 1; i < VL_MHSRV_PERBLK; i++) {
373 /* won't convert hostuuid */
374 e->ex_uniquifier = ntohl(e->ex_uniquifier);
375 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++)
376 e->ex_addrs[j] = ntohl(e->ex_addrs[j]);
382 readentry(afs_int32 addr, struct nvlentry *vlentryp, afs_int32 *type)
386 vldbread(addr, (char *)vlentryp, sizeof(*vlentryp));
388 for (i = 0; i < MAXTYPES; i++)
389 vlentryp->volumeId[i] = ntohl(vlentryp->volumeId[i]);
390 vlentryp->flags = ntohl(vlentryp->flags);
391 vlentryp->LockAfsId = ntohl(vlentryp->LockAfsId);
392 vlentryp->LockTimestamp = ntohl(vlentryp->LockTimestamp);
393 vlentryp->cloneId = ntohl(vlentryp->cloneId);
394 for (i = 0; i < MAXTYPES; i++)
395 vlentryp->nextIdHash[i] = ntohl(vlentryp->nextIdHash[i]);
396 vlentryp->nextNameHash = ntohl(vlentryp->nextNameHash);
397 for (i = 0; i < NMAXNSERVERS; i++) {
398 /* make sure not to ntohl these, as they're chars, not ints */
399 vlentryp->serverNumber[i] = vlentryp->serverNumber[i];
400 vlentryp->serverPartition[i] = vlentryp->serverPartition[i];
401 vlentryp->serverFlags[i] = vlentryp->serverFlags[i];
404 if (vlentryp->flags == VLCONTBLOCK) {
406 } else if (vlentryp->flags == VLFREE) {
413 quiet_println("address %u (offset 0x%0x): ", addr, OFFSET(addr));
414 if (vlentryp->flags == VLCONTBLOCK) {
415 quiet_println("mh extension block\n");
416 } else if (vlentryp->flags == VLFREE) {
417 quiet_println("free vlentry\n");
419 quiet_println("vlentry %s\n", vlentryp->name);
420 quiet_println(" rw id = %u ; ro id = %u ; bk id = %u\n",
421 vlentryp->volumeId[0], vlentryp->volumeId[1],
422 vlentryp->volumeId[2]);
423 quiet_println(" flags =");
424 if (vlentryp->flags & VLF_RWEXISTS)
425 quiet_println(" rw");
426 if (vlentryp->flags & VLF_ROEXISTS)
427 quiet_println(" ro");
428 if (vlentryp->flags & VLF_BACKEXISTS)
429 quiet_println(" bk");
430 if (vlentryp->flags & VLOP_MOVE)
431 quiet_println(" lock_move");
432 if (vlentryp->flags & VLOP_RELEASE)
433 quiet_println(" lock_release");
434 if (vlentryp->flags & VLOP_BACKUP)
435 quiet_println(" lock_backup");
436 if (vlentryp->flags & VLOP_DELETE)
437 quiet_println(" lock_delete");
438 if (vlentryp->flags & VLOP_DUMP)
439 quiet_println(" lock_dump");
441 /* all bits not covered by VLF_* and VLOP_* constants */
442 if (vlentryp->flags & 0xffff8e0f)
443 quiet_println(" errorflag(0x%x)", vlentryp->flags);
445 quiet_println(" LockAfsId = %d\n", vlentryp->LockAfsId);
446 quiet_println(" LockTimestamp = %d\n", vlentryp->LockTimestamp);
447 quiet_println(" cloneId = %u\n", vlentryp->cloneId);
449 (" next hash for rw = %u ; ro = %u ; bk = %u ; name = %u\n",
450 vlentryp->nextIdHash[0], vlentryp->nextIdHash[1],
451 vlentryp->nextIdHash[2], vlentryp->nextNameHash);
452 for (i = 0; i < NMAXNSERVERS; i++) {
453 if (vlentryp->serverNumber[i] != 255) {
454 quiet_println(" server %d ; partition %d ; flags =",
455 vlentryp->serverNumber[i],
456 vlentryp->serverPartition[i]);
457 if (vlentryp->serverFlags[i] & VLSF_RWVOL)
458 quiet_println(" rw");
459 if (vlentryp->serverFlags[i] & VLSF_ROVOL)
460 quiet_println(" ro");
461 if (vlentryp->serverFlags[i] & VLSF_BACKVOL)
462 quiet_println(" bk");
463 if (vlentryp->serverFlags[i] & VLSF_NEWREPSITE)
464 quiet_println(" newro");
474 writeMH(afs_int32 addr, int block, struct extentaddr *mhblockP)
477 struct extentaddr *e;
480 quiet_println("Writing back MH block % at addr %u\n", block, addr);
483 mhblockP->ex_count = htonl(mhblockP->ex_count);
484 mhblockP->ex_hdrflags = htonl(mhblockP->ex_hdrflags);
485 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
486 mhblockP->ex_contaddrs[i] = htonl(mhblockP->ex_contaddrs[i]);
489 for (i = 1; i < VL_MHSRV_PERBLK; i++) {
491 /* hostuuid was not converted */
492 e->ex_uniquifier = htonl(e->ex_uniquifier);
493 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
494 e->ex_addrs[j] = htonl(e->ex_addrs[j]);
497 vldbwrite(addr, (char *)mhblockP, VL_ADDREXTBLK_SIZE);
501 writeentry(afs_int32 addr, struct nvlentry *vlentryp)
505 if (verbose) quiet_println("Writing back entry at addr %u\n", addr);
506 for (i = 0; i < MAXTYPES; i++)
507 vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
508 vlentryp->flags = htonl(vlentryp->flags);
509 vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
510 vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
511 vlentryp->cloneId = htonl(vlentryp->cloneId);
512 for (i = 0; i < MAXTYPES; i++)
513 vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
514 vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
515 for (i = 0; i < NMAXNSERVERS; i++) {
516 /* make sure not to htonl these, as they're chars, not ints */
517 vlentryp->serverNumber[i] = vlentryp->serverNumber[i] ;
518 vlentryp->serverPartition[i] = vlentryp->serverPartition[i] ;
519 vlentryp->serverFlags[i] = vlentryp->serverFlags[i] ;
521 vldbwrite(addr, (char *)vlentryp, sizeof(*vlentryp));
525 * Read each entry in the database:
526 * Record what type of entry it is and its address in the record array.
527 * Remember what the maximum volume id we found is and check against the header.
530 ReadAllEntries(struct vlheader *header)
532 afs_int32 type, rindex, i, j, e;
533 int freecount = 0, mhcount = 0, vlcount = 0;
534 int rwcount = 0, rocount = 0, bkcount = 0;
535 struct nvlentry vlentry;
537 afs_uint32 entrysize = 0;
538 afs_uint32 maxvolid = 0;
540 if (verbose) quiet_println("Read each entry in the database\n");
541 for (addr = header->vital_header.headersize;
542 addr < header->vital_header.eofPtr; addr += entrysize) {
544 /* Remember the highest volume id */
545 readentry(addr, &vlentry, &type);
548 for (i = 0; i < MAXTYPES; i++)
549 if (maxvolid < vlentry.volumeId[i])
550 maxvolid = vlentry.volumeId[i];
553 for (j = 0; j < NMAXNSERVERS; j++) {
554 if (vlentry.serverNumber[j] == 255)
556 if (vlentry.serverFlags[j] & (VLSF_ROVOL | VLSF_NEWREPSITE)) {
560 if (vlentry.serverFlags[j] & VLSF_RWVOL) {
562 if (vlentry.flags & VLF_BACKEXISTS)
566 if (!vlentry.serverFlags[j]) {
572 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
573 addr, OFFSET(addr), vlentry.name);
577 (" index %d : serverNumber %d : serverPartition %d : serverFlag %d\n",
578 j, vlentry.serverNumber[j], vlentry.serverPartition[j],
579 vlentry.serverFlags[j]);
583 rindex = addr / sizeof(vlentry);
584 if (record[rindex].type) {
585 log_error(VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: record holder %d already in use\n",
589 record[rindex].addr = addr;
590 record[rindex].type = type;
592 /* Determine entrysize and keep count */
594 entrysize = sizeof(vlentry);
596 } else if (type == FR) {
597 entrysize = sizeof(vlentry);
599 } else if (type == MH) {
600 entrysize = VL_ADDREXTBLK_SIZE;
603 log_error(VLDB_CHECK_ERROR, "address %u (offset 0x%0x): Unknown entry. Aborting\n", addr, OFFSET(addr));
608 quiet_println("Found %d entries, %d free entries, %d multihomed blocks\n",
609 vlcount, freecount, mhcount);
610 quiet_println("Found %d RW volumes, %d BK volumes, %d RO volumes\n", rwcount,
614 /* Check the maxmimum volume id in the header */
615 if (maxvolid != header->vital_header.MaxVolumeId - 1)
617 ("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
618 header->vital_header.MaxVolumeId, maxvolid);
622 * Follow each Name hash bucket marking it as read in the record array.
623 * Record we found it in the name hash within the record array.
624 * Check that the name is hashed correctly.
627 FollowNameHash(struct vlheader *header)
629 int count = 0, longest = 0, shortest = -1, chainlength;
630 struct nvlentry vlentry;
632 afs_int32 i, type, rindex;
634 /* Now follow the Name Hash Table */
635 if (verbose) quiet_println("Check Volume Name Hash\n");
636 for (i = 0; i < HASHSIZE; i++) {
639 if (!validVolumeAddr(header->VolnameHash[i])) {
640 log_error(VLDB_CHECK_ERROR,"Name Hash index %d is out of range: %u\n",
641 i, header->VolnameHash[i]);
645 for (addr = header->VolnameHash[i]; addr; addr = vlentry.nextNameHash) {
646 readentry(addr, &vlentry, &type);
648 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: Not a vlentry\n",
649 addr, OFFSET(addr), i);
656 * we know that the address is valid because we
657 * checked it either above or below
659 if (record[rindex].addr != addr && record[rindex].addr) {
661 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
662 record[rindex].addr, addr, rindex);
664 if (record[rindex].type & NH) {
666 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: volume name '%s' is already in the name hash\n",
667 addr, OFFSET(addr), i, vlentry.name);
668 record[rindex].type |= MULTN;
672 if (!validVolumeAddr(vlentry.nextNameHash)) {
673 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash forward link of '%s' is out of range\n",
674 addr, OFFSET(addr), vlentry.name);
675 record[rindex].type |= MULTN;
679 record[rindex].type |= NH;
680 record[rindex].type |= REFN;
685 /* Hash the name and check if in correct hash table */
686 if (NameHash(vlentry.name) != i) {
688 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: volume name '%s': Incorrect name hash chain (should be in %d)\n",
689 addr, OFFSET(addr), i, vlentry.name, NameHash(vlentry.name));
690 record[rindex].type |= MULTN;
693 if (chainlength > longest)
694 longest = chainlength;
695 if ((shortest == -1) || (chainlength < shortest))
696 shortest = chainlength;
700 ("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
701 count, longest, shortest, ((float)count / (float)HASHSIZE));
707 * Follow the ID hash chains for the RW, RO, and BK hash tables.
708 * Record we found it in the id hash within the record array.
709 * Check that the ID is hashed correctly.
712 FollowIdHash(struct vlheader *header)
714 int count = 0, longest = 0, shortest = -1, chainlength;
715 struct nvlentry vlentry;
717 afs_int32 i, j, hash, type, rindex, ref, badref, badhash;
719 /* Now follow the RW, RO, and BK Hash Tables */
720 if (verbose) quiet_println("Check RW, RO, and BK id Hashes\n");
721 for (i = 0; i < MAXTYPES; i++) {
722 hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
723 ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
724 badref = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
725 badhash = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
729 for (j = 0; j < HASHSIZE; j++) {
731 if (!validVolumeAddr(header->VolidHash[i][j])) {
732 log_error(VLDB_CHECK_ERROR,"%s Hash index %d is out of range: %u\n",
733 vtype(i), j, header->VolidHash[i][j]);
737 for (addr = header->VolidHash[i][j]; addr;
738 addr = vlentry.nextIdHash[i]) {
739 readentry(addr, &vlentry, &type);
742 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: Not a vlentry\n",
743 addr, OFFSET(addr), vtype(i), j);
748 if (record[rindex].addr != addr && record[rindex].addr) {
750 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
751 record[rindex].addr, addr, rindex);
753 if (record[rindex].type & hash) {
755 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: volume name '%s': Already in the hash table\n",
756 addr, OFFSET(addr), vtype(i), j, vlentry.name);
757 record[rindex].type |= badref;
761 if (!validVolumeAddr(vlentry.nextIdHash[i])) {
762 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash forward link of '%s' is out of range\n",
763 addr, OFFSET(addr), vtype(i), vlentry.name);
764 record[rindex].type |= badref;
768 record[rindex].type |= hash;
769 record[rindex].type |= ref;
774 /* Hash the id and check if in correct hash table */
775 if (IdHash(vlentry.volumeId[i]) != j) {
777 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: volume name '%s': Incorrect Id hash chain (should be in %d)\n",
778 addr, OFFSET(addr), vtype(i), j, vlentry.name,
779 IdHash(vlentry.volumeId[i]));
780 record[rindex].type |= badhash;
784 if (chainlength > longest)
785 longest = chainlength;
786 if ((shortest == -1) || (chainlength < shortest))
787 shortest = chainlength;
791 ("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
792 count, vtype(i), longest, shortest,((float)count / (float)HASHSIZE));
799 * Follow the free chain.
800 * Record we found it in the free chain within the record array.
803 FollowFreeChain(struct vlheader *header)
806 struct nvlentry vlentry;
808 afs_int32 type, rindex;
810 /* Now follow the Free Chain */
811 if (verbose) quiet_println("Check Volume Free Chain\n");
812 for (addr = header->vital_header.freePtr; addr;
813 addr = vlentry.nextIdHash[0]) {
814 readentry(addr, &vlentry, &type);
817 (VLDB_CHECK_ERROR,"address %u (offset 0%0x): Free Chain %d: Not a free vlentry (0x%x)\n",
818 addr, OFFSET(addr), count, type);
822 rindex = addr / sizeof(vlentry);
823 if (record[rindex].addr != addr && record[rindex].addr) {
825 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u (0x%0x) and %ld (0x%0x) use same record slot %d\n",
826 record[rindex].addr, OFFSET(record[rindex].addr), addr, OFFSET(addr), rindex);
828 if (record[rindex].type & FRC) {
829 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free Chain: Already in the free chain\n",
833 record[rindex].type |= FRC;
838 quiet_println("%d entries on free chain\n", count);
843 * Read each multihomed block and mark it as found in the record.
844 * Read each entry in each multihomed block and mark the serveraddrs
845 * array with the number of ip addresses found for this entry.
847 * Then read the IpMappedAddr array in the header.
848 * Verify that multihomed entries base and index are valid and points to
849 * a good multhomed entry.
850 * Mark the serveraddrs array with 1 ip address for regular entries.
852 * By the end, the severaddrs array will have a 0 if the entry has no
853 * IP addresses in it or the count of the number of IP addresses.
855 * The code does not verify if there are duplicate IP addresses in the
856 * list. The vlserver does this when a fileserver registeres itself.
859 CheckIpAddrs(struct vlheader *header)
862 afs_int32 i, j, m, rindex;
863 afs_int32 mhentries, regentries;
864 char mhblock[VL_ADDREXTBLK_SIZE];
865 struct extentaddr *MHblock = (struct extentaddr *)mhblock;
866 struct extentaddr *e;
867 int ipindex, ipaddrs;
870 memset(&nulluuid, 0, sizeof(nulluuid));
873 quiet_println("Check Multihomed blocks\n");
876 /* Read the first MH block and from it, gather the
877 * addresses of all the mh blocks.
879 readMH(header->SIT, 0, MHblock);
880 if (MHblock->ex_hdrflags != VLCONTBLOCK) {
882 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed Block 0: Not a multihomed block\n",
883 header->SIT, OFFSET(header->SIT));
886 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
887 mhinfo[i].addr = MHblock->ex_contaddrs[i];
890 if (header->SIT != mhinfo[0].addr) {
892 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): MH block does not point to self in header, %u in block\n",
893 header->SIT, OFFSET(header->SIT), mhinfo[0].addr);
896 /* Now read each MH block and record it in the record array */
897 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
901 readMH(mhinfo[i].addr, i, MHblock);
902 if (MHblock->ex_hdrflags != VLCONTBLOCK) {
904 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed Block %d: Not a multihomed block\n",
905 mhinfo[i].addr, OFFSET(mhinfo[i].addr), i);
908 rindex = mhinfo[i].addr / sizeof(vlentry);
909 if (record[rindex].addr != mhinfo[i].addr && record[rindex].addr) {
911 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u (0x%0x) and %u (0x%0x) use same record slot %d\n",
912 record[rindex].addr, OFFSET(record[rindex].addr), mhinfo[i].addr, OFFSET(mhinfo[i].addr), rindex);
914 if (record[rindex].type & FRC) {
916 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): MH Blocks Chain %d: Already a MH block\n",
917 record[rindex].addr, OFFSET(record[rindex].addr), i);
920 record[rindex].type |= MHC;
924 /* Read each entry in a multihomed block.
925 * Find the pointer to the entry in the IpMappedAddr array and
926 * verify that the entry is good (has IP addresses in it).
929 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
930 int first_ipindex = -1;
931 e = (struct extentaddr *)&(MHblock[j]);
933 /* Search the IpMappedAddr array for all the references to this entry. */
934 /* Use the first reference for checking the ip addresses of this entry. */
935 for (ipindex = 0; ipindex <= MAXSERVERID; ipindex++) {
936 if (((header->IpMappedAddr[ipindex] & 0xff000000) == 0xff000000)
937 && (((header-> IpMappedAddr[ipindex] & 0x00ff0000) >> 16) == i)
938 && ((header->IpMappedAddr[ipindex] & 0x0000ffff) == j)) {
939 if (first_ipindex == -1) {
940 first_ipindex = ipindex;
942 serverxref[ipindex] = first_ipindex;
946 ipindex = first_ipindex;
948 serveraddrs[ipindex] = -1;
950 if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
953 (VLDB_CHECK_ERROR,"Server Addrs index %d references null MH block %d, index %d\n",
955 serveraddrs[ipindex] = 0; /* avoids printing 2nd error below */
960 /* Step through each ip address and count the good addresses */
962 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
967 /* If we found any good ip addresses, mark it in the serveraddrs record */
971 mhinfo[i].orphan[j] = 1;
973 (VLDB_CHECK_ERROR,"MH block %d, index %d: Not referenced by server addrs\n",
976 serveraddrs[ipindex] = ipaddrs; /* It is good */
980 if (listservers && ipaddrs) {
981 quiet_println("MH block %d, index %d:", i, j);
982 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
985 quiet_println(" %d.%d.%d.%d",
986 (e->ex_addrs[m] & 0xff000000) >> 24,
987 (e->ex_addrs[m] & 0x00ff0000) >> 16,
988 (e->ex_addrs[m] & 0x0000ff00) >> 8,
989 (e->ex_addrs[m] & 0x000000ff));
995 * if (mhentries != MHblock->ex_count) {
996 * quiet_println("MH blocks says it has %d entries (found %d)\n",
997 * MHblock->ex_count, mhentries);
1003 quiet_println("%d multihomed blocks\n", mhblocks);
1005 /* Check the server addresses */
1007 quiet_println("Check server addresses\n");
1008 mhentries = regentries = 0;
1009 for (i = 0; i <= MAXSERVERID; i++) {
1010 if (header->IpMappedAddr[i]) {
1011 if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
1013 if (((header->IpMappedAddr[i] & 0x00ff0000) >> 16) >
1016 (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome block is bad (%d)\n",
1017 i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1018 if (mhinfo[(header->IpMappedAddr[i] & 0x00ff0000) >> 16].addr == 0)
1019 log_error(VLDB_CHECK_ERROR,"IP Addr for entry %d: No such multihome block (%d)\n",
1020 i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1021 if (((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK)
1022 || ((header->IpMappedAddr[i] & 0x0000ffff) < 1))
1024 (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome index is bad (%d)\n",
1025 i, (header->IpMappedAddr[i] & 0x0000ffff));
1026 if (serveraddrs[i] == -1) {
1028 (VLDB_CHECK_WARNING,"warning: IP Addr for entry %d: Multihome entry has no ip addresses\n",
1032 if (serverxref[i] != BADSERVERID) {
1034 (VLDB_CHECK_WARNING,
1035 "warning: MH block %d, index %d is cross-linked by server numbers %d and %d.\n",
1036 (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1037 (header->IpMappedAddr[i] & 0x0000ffff),
1039 /* set addresses found/not found for this server number,
1040 * using the first index to the mh we found above. */
1041 serveraddrs[i] = serveraddrs[serverxref[i]];
1044 quiet_println(" Server ip addr %d = MH block %d, index %d\n",
1045 i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1046 (header->IpMappedAddr[i] & 0x0000ffff));
1050 serveraddrs[i] = 1; /* It is good */
1052 quiet_println(" Server ip addr %d = %d.%d.%d.%d\n", i,
1053 (header->IpMappedAddr[i] & 0xff000000) >> 24,
1054 (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1055 (header->IpMappedAddr[i] & 0x0000ff00) >> 8,
1056 (header->IpMappedAddr[i] & 0x000000ff));
1062 quiet_println("%d simple entries, %d multihomed entries, Total = %d\n",
1063 regentries, mhentries, mhentries + regentries);
1069 nameForAddr(afs_uint32 addr, int hashtype, afs_uint32 *hash, char *buffer)
1072 * We need to simplify the reporting, while retaining
1073 * legible messages. This is a helper function. The return address
1074 * is either a fixed char or the provided buffer - so don't use the
1075 * name after the valid lifetime of the buffer.
1078 struct nvlentry entry;
1080 /* Distinguished, invalid, hash */
1083 } else if (!validVolumeAddr(addr)) {
1084 /* Different, invalid, hash */
1088 readentry(addr, &entry, &type);
1093 if (hashtype >= MAXTYPES) {
1094 *hash = NameHash(entry.name);
1096 *hash = IdHash(entry.volumeId[hashtype]);
1098 sprintf(buffer, "for '%s'", entry.name);
1103 reportHashChanges(struct vlheader *header, afs_uint32 oldnamehash[HASHSIZE], afs_uint32 oldidhash[MAXTYPES][HASHSIZE])
1106 afs_uint32 oldhash, newhash;
1107 char oldNameBuffer[10 + VL_MAXNAMELEN];
1108 char newNameBuffer[10 + VL_MAXNAMELEN];
1109 char *oldname, *newname;
1111 * report hash changes
1114 for (i = 0; i < HASHSIZE; i++) {
1115 if (oldnamehash[i] != header->VolnameHash[i]) {
1117 oldname = nameForAddr(oldnamehash[i], MAXTYPES, &oldhash, oldNameBuffer);
1118 newname = nameForAddr(header->VolnameHash[i], MAXTYPES, &newhash, newNameBuffer);
1119 if (verbose || (oldhash != newhash)) {
1120 quiet_println("FIX: Name hash header at %d was %s, is now %s\n", i, oldname, newname);
1123 for (j = 0; j < MAXTYPES; j++) {
1124 if (oldidhash[j][i] != header->VolidHash[j][i]) {
1126 oldname = nameForAddr(oldidhash[j][i], j, &oldhash, oldNameBuffer);
1127 newname = nameForAddr(header->VolidHash[j][i], j, &newhash, newNameBuffer);
1128 if (verbose || (oldhash != newhash)) {
1129 quiet_println("FIX: %s hash header at %d was %s, is now %s\n", vtype(j), i, oldname, newname);
1137 * Remove unreferenced, duplicate multi-home address indices.
1139 * Removes entries from IpMappedAddr which where found to be
1140 * duplicates. Only entries which are not referenced by vl entries
1141 * are removed on this pass.
1143 * @param[inout] header the vldb header to be updated.
1146 removeCrossLinkedAddresses(struct vlheader *header)
1150 for (i = 0; i <= MAXSERVERID; i++) {
1151 if (serverref[i] == 0
1152 && (header->IpMappedAddr[i] & 0xff000000) == 0xff000000
1153 && serverxref[i] != BADSERVERID) {
1154 if (serverxref[i] == i) {
1155 log_error(VLDB_CHECK_ERROR,
1156 "INTERNAL VLDB_CHECK_ERROR: serverxref points to self; index %d\n",
1158 } else if (header->IpMappedAddr[serverxref[i]] == 0) {
1159 log_error(VLDB_CHECK_ERROR,
1160 "INTERNAL VLDB_CHECK_ERROR: serverxref points to empty addr; index %d, value %d\n",
1162 } else if (header->IpMappedAddr[serverxref[i]] != header->IpMappedAddr[i]) {
1163 log_error(VLDB_CHECK_ERROR,
1164 "INTERNAL VLDB_CHECK_ERROR: invalid serverxref; index %d, value %d\n",
1168 ("FIX: Removing unreferenced address index %d, which cross-links MH block %d, index %d\n",
1169 i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1170 (header->IpMappedAddr[i] & 0x0000ffff));
1171 header->IpMappedAddr[i] = 0;
1178 WorkerBee(struct cmd_syndesc *as, void *arock)
1182 struct vlheader header;
1183 struct nvlentry vlentry, vlentry2;
1185 afs_uint32 oldnamehash[HASHSIZE];
1186 afs_uint32 oldidhash[MAXTYPES][HASHSIZE];
1188 error_level = 0; /* start clean with no error status */
1189 dbfile = as->parms[0].items->data; /* -database */
1190 listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1191 listheader = (as->parms[2].items ? 1 : 0); /* -vheader */
1192 listservers = (as->parms[3].items ? 1 : 0); /* -servers */
1193 listentries = (as->parms[4].items ? 1 : 0); /* -entries */
1194 verbose = (as->parms[5].items ? 1 : 0); /* -verbose */
1195 quiet = (as->parms[6].items ? 1 : 0); /* -quiet */
1196 fix = (as->parms[7].items ? 1 : 0); /* -fix */
1199 if (quiet && (verbose || listuheader || listheader ||listservers \
1201 log_error(VLDB_CHECK_FATAL," -quiet cannot be used other display flags\n");
1202 return VLDB_CHECK_FATAL;
1206 /* open the vldb database file */
1207 fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
1209 log_error(VLDB_CHECK_FATAL,"can't open file '%s'. error = %d\n", dbfile, errno);
1213 /* read the ubik header and the vldb database header */
1215 readheader(&header);
1216 if (header.vital_header.vldbversion < 3) {
1217 log_error(VLDB_CHECK_FATAL,"does not support vldb with version less than 3\n");
1218 return VLDB_CHECK_FATAL;
1221 maxentries = (header.vital_header.eofPtr / sizeof(vlentry)) + 1;
1222 record = calloc(maxentries, sizeof(struct er));
1223 memset(serveraddrs, 0, sizeof(serveraddrs));
1224 memset(mhinfo, 0, sizeof(mhinfo));
1225 memset(serverref, 0, sizeof(serverref));
1226 for (i = 0; i <= MAXSERVERID; i++) {
1227 serverxref[i] = BADSERVERID;
1230 /* Will fill in the record array of entries it found */
1231 ReadAllEntries(&header);
1232 listentries = 0; /* Listed all the entries */
1234 /* Check the multihomed blocks for valid entries as well as
1235 * the IpMappedAddrs array in the header for valid entries.
1237 CheckIpAddrs(&header);
1239 /* Follow the hash tables */
1240 FollowNameHash(&header);
1241 FollowIdHash(&header);
1243 /* Follow the chain of free entries */
1244 FollowFreeChain(&header);
1246 /* Now check the record we have been keeping for inconsistencies
1247 * For valid vlentries, also check that the server we point to is
1248 * valid (the serveraddrs array).
1251 quiet_println("Verify each volume entry\n");
1252 for (i = 0; i < maxentries; i++) {
1257 if (record[i].type == 0)
1260 /* If a vlentry, verify that its name is valid, its name and ids are
1261 * on the hash chains, and its server numbers are good.
1263 if (record[i].type & VL) {
1265 int foundbroken = 0;
1268 readentry(record[i].addr, &vlentry, &type);
1270 if (!(vlentry.flags & VLF_RWEXISTS))
1271 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has no RW volume\n",
1272 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1274 if (InvalidVolname(vlentry.name))
1275 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has an invalid name\n",
1276 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1278 if (vlentry.volumeId[0] == 0)
1279 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has an invalid volume id\n",
1280 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1282 if (!(record[i].type & NH)) {
1283 hash = NameHash(vlentry.name);
1289 if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
1290 hash = IdHash(vlentry.volumeId[0]);
1292 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1296 if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
1297 hash = IdHash(vlentry.volumeId[1]);
1299 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1303 if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
1304 hash = IdHash(vlentry.volumeId[2]);
1306 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1310 if (!validVolumeAddr(vlentry.nextNameHash) ||
1311 record[ADDR(vlentry.nextNameHash)].type & MULTN) {
1312 hash = NameHash(vlentry.name);
1315 if (validVolumeAddr(vlentry.nextNameHash)) {
1316 readentry(vlentry.nextNameHash, &vlentry2, &type);
1317 nexthash = NameHash(vlentry2.name);
1319 nexthash = 0xFFFFFFFF;
1321 if (hash != nexthash)
1325 if (!validVolumeAddr(vlentry.nextIdHash[0]) ||
1326 record[ADDR(vlentry.nextIdHash[0])].type & MULTRW) {
1327 hash = IdHash(vlentry.volumeId[0]);
1329 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1330 if (validVolumeAddr(vlentry.nextIdHash[0])) {
1331 readentry(vlentry.nextIdHash[0], &vlentry2, &type);
1332 nexthash = IdHash(vlentry2.volumeId[0]);
1334 nexthash = 0xFFFFFFFF;
1336 if (hash != nexthash)
1340 if (!validVolumeAddr(vlentry.nextIdHash[1]) ||
1341 record[ADDR(vlentry.nextIdHash[1])].type & MULTRO) {
1342 hash = IdHash(vlentry.volumeId[1]);
1344 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1345 if (validVolumeAddr(vlentry.nextIdHash[1])) {
1346 readentry(vlentry.nextIdHash[1], &vlentry2, &type);
1347 nexthash = IdHash(vlentry2.volumeId[1]);
1349 nexthash = 0xFFFFFFFF;
1351 if (hash != nexthash)
1355 if (!validVolumeAddr(vlentry.nextIdHash[2]) ||
1356 record[ADDR(vlentry.nextIdHash[2])].type & MULTBK) {
1357 hash = IdHash(vlentry.volumeId[2]);
1359 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1360 if (validVolumeAddr(vlentry.nextIdHash[2])) {
1361 readentry(vlentry.nextIdHash[2], &vlentry2, &type);
1362 nexthash = IdHash(vlentry2.volumeId[2]);
1364 nexthash = 0xFFFFFFFF;
1366 if (hash != nexthash)
1371 log_error(VLDB_CHECK_ERROR,
1372 "address %u (offset 0x%0x): Volume '%s' %s forward link in %s hash chain is broken (hash %d != %d)\n",
1373 record[i].addr, OFFSET(record[i].addr),
1374 vlentry.name, volidbuf, which, hash, nexthash);
1375 } else if (foundbad) {
1376 log_error(VLDB_CHECK_ERROR,
1377 "address %u (offset 0x%0x): Volume '%s' %snot found in %s hash %d\n",
1378 record[i].addr, OFFSET(record[i].addr),
1379 vlentry.name, volidbuf, which, hash);
1382 for (j = 0; j < NMAXNSERVERS; j++) {
1383 if (vlentry.serverNumber[j] != BADSERVERID) {
1384 serverref[vlentry.serverNumber[j]] = 1;
1385 if (serveraddrs[vlentry.serverNumber[j]] == 0) {
1387 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s', index %d points to empty server entry %d\n",
1388 record[i].addr, OFFSET(record[i].addr), vlentry.name, j, vlentry.serverNumber[j]);
1389 } else if (serverxref[vlentry.serverNumber[j]] != BADSERVERID) {
1391 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s', index %d points to server entry %d, which is cross-linked by %d\n",
1392 record[i].addr, OFFSET(record[i].addr), vlentry.name, j, vlentry.serverNumber[j], serverxref[vlentry.serverNumber[j]]);
1397 if (record[i].type & 0xffff0f00)
1399 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' id %u also found on other chains (0x%x)\n",
1400 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0], record[i].type);
1403 } else if (record[i].type & FR) {
1404 if (!(record[i].type & FRC))
1405 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free vlentry not on free chain\n",
1406 record[i].addr, OFFSET(record[i].addr));
1408 if (record[i].type & 0xfffffdf0)
1410 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free vlentry also found on other chains (0x%x)\n",
1411 record[i].addr, OFFSET(record[i].addr), record[i].type);
1413 /* A multihomed entry */
1414 } else if (record[i].type & MH) {
1415 if (!(record[i].type & MHC))
1416 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed block is orphaned\n",
1417 record[i].addr, OFFSET(record[i].addr));
1419 if (record[i].type & 0xfffffef0)
1421 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed block also found on other chains (0x%x)\n",
1422 record[i].addr, OFFSET(record[i].addr), record[i].type);
1425 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Unknown entry type 0x%x\n",
1426 record[i].addr, OFFSET(record[i].addr), record[i].type);
1432 * If we are fixing we will rebuild the free and hash lists from the ground up.
1434 header.vital_header.freePtr = 0;
1435 memcpy(oldnamehash, header.VolnameHash, sizeof(oldnamehash));
1436 memset(header.VolnameHash, 0, sizeof(header.VolnameHash));
1438 memcpy(oldidhash, header.VolidHash, sizeof(oldidhash));
1439 memset(header.VolidHash, 0, sizeof(header.VolidHash));
1440 quiet_println("Rebuilding %u entries\n", maxentries);
1442 quiet_println("Scanning %u entries for possible repairs\n", maxentries);
1444 for (i = 0; i < maxentries; i++) {
1446 if (record[i].type & VL) {
1447 readentry(record[i].addr, &vlentry, &type);
1448 if (!(record[i].type & REFN)) {
1449 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record is not in a name chain (type 0x%0x)\n",
1450 record[i].addr, OFFSET(record[i].addr), record[i].type);
1452 if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
1453 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a RW chain (type 0x%0x)\n",
1454 record[i].addr, OFFSET(record[i].addr), record[i].type);
1456 if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
1457 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a RO chain (type 0x%0x)\n",
1458 record[i].addr, OFFSET(record[i].addr), record[i].type);
1460 if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
1461 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a BK chain (type 0x%0x)\n",
1462 record[i].addr, OFFSET(record[i].addr), record[i].type);
1465 afs_uint32 oldhash, newhash;
1466 char oldNameBuffer[10 + VL_MAXNAMELEN];
1467 char newNameBuffer[10 + VL_MAXNAMELEN];
1468 char *oldname, *newname;
1470 /* Fix broken names and numbers so entries can be inspected and deleted. */
1471 if (InvalidVolname(vlentry.name)) {
1472 char bogus[VL_MAXNAMELEN];
1473 memset(bogus, 0, sizeof(bogus));
1474 snprintf(bogus, sizeof(bogus)-1, ".bogus.%ld", record[i].addr);
1475 strcpy(vlentry.name, bogus);
1476 quiet_println("FIX: Record %ld invalid volume name set to '%s'\n", record[i].addr, bogus);
1478 if (vlentry.volumeId[0] == 0) {
1479 afs_uint32 next_volid = header.vital_header.MaxVolumeId++;
1480 vlentry.volumeId[0] = next_volid;
1481 quiet_println("FIX: Record %ld invalid volume id set to %ld. New max volid is %ld\n",
1482 record[i].addr, next_volid, header.vital_header.MaxVolumeId);
1486 * Put the current hash table contexts into our 'next'
1487 * and our address into the hash table.
1489 hash = NameHash(vlentry.name);
1491 if (vlentry.nextNameHash != header.VolnameHash[hash]) {
1492 oldname = nameForAddr(vlentry.nextNameHash, MAXTYPES, &oldhash, oldNameBuffer);
1493 newname = nameForAddr(header.VolnameHash[hash], MAXTYPES, &newhash, newNameBuffer);
1494 if (verbose || ((oldhash != newhash) &&
1495 (0 != vlentry.nextNameHash) &&
1496 (0 != header.VolnameHash[hash]))) {
1498 * That is, only report if we are verbose
1499 * or the hash is changing (and one side wasn't NULL
1501 quiet_println("FIX: Name hash link for '%s' was %s, is now %s\n",
1502 vlentry.name, oldname, newname);
1506 vlentry.nextNameHash = header.VolnameHash[hash];
1507 header.VolnameHash[hash] = record[i].addr;
1509 for (j = 0; j < MAXTYPES; j++) {
1511 if (0 == vlentry.volumeId[j]) {
1513 * No volume of that type. Continue
1517 hash = IdHash(vlentry.volumeId[j]);
1519 if (vlentry.nextIdHash[j] != header.VolidHash[j][hash]) {
1520 oldname = nameForAddr(vlentry.nextIdHash[j], j, &oldhash, oldNameBuffer);
1521 newname = nameForAddr(header.VolidHash[j][hash], j, &newhash, newNameBuffer);
1522 if (verbose || ((oldhash != newhash) &&
1523 (0 != vlentry.nextIdHash[j]) &&
1524 (0 != header.VolidHash[j][hash]))) {
1525 quiet_println("FIX: %s hash link for '%s' was %s, is now %s\n",
1526 vtype(j), vlentry.name, oldname, newname);
1530 /* Consolidate server numbers which point to the same mh entry.
1531 * The serverref flags are not reset here, since we want to make
1532 * sure the data is actually written before the server number is
1533 * considered unreferenced. */
1534 for (k = 0; k < NMAXNSERVERS; k++) {
1535 if (vlentry.serverNumber[k] != BADSERVERID
1536 && serverxref[vlentry.serverNumber[k]] != BADSERVERID) {
1537 u_char oldsn = vlentry.serverNumber[k];
1538 u_char newsn = serverxref[oldsn];
1539 if (newsn == oldsn) {
1540 log_error(VLDB_CHECK_ERROR,
1541 "INTERNAL VLDB_CHECK_ERROR: serverxref points to self; index %d\n",
1543 } else if (header.IpMappedAddr[oldsn] == 0) {
1544 log_error(VLDB_CHECK_ERROR,
1545 "INTERNAL VLDB_CHECK_ERROR: serverxref; points to empty address; index %d, value %d\n",
1547 } else if (header.IpMappedAddr[newsn] != header.IpMappedAddr[oldsn]) {
1548 log_error(VLDB_CHECK_ERROR,
1549 "INTERNAL VLDB_CHECK_ERROR: invalid serverxref; index %d\n",
1553 ("FIX: Volume '%s', index %d, server number was %d, is now %d\n",
1554 vlentry.name, k, oldsn, newsn);
1555 vlentry.serverNumber[k] = newsn;
1560 vlentry.nextIdHash[j] = header.VolidHash[j][hash];
1561 header.VolidHash[j][hash] = record[i].addr;
1563 writeentry(record[i].addr, &vlentry);
1566 else if (record[i].type & MH) {
1568 char mhblock[VL_ADDREXTBLK_SIZE];
1569 struct extentaddr *MHblock = (struct extentaddr *)mhblock;
1572 for (block = 0; block < VL_MAX_ADDREXTBLKS; block++) {
1573 if (mhinfo[block].addr == record[i].addr)
1576 if (block == VL_MAX_ADDREXTBLKS) {
1577 continue; /* skip orphaned extent block */
1579 readMH(record[i].addr, block, MHblock);
1580 for (index = 0; index < VL_MHSRV_PERBLK; index++) {
1581 if (mhinfo[block].orphan[index]) {
1582 quiet_println("FIX: Removing unreferenced mh entry; block %d, index %d\n",
1584 memset(&(MHblock[index]), 0, sizeof(struct extentaddr));
1587 writeMH(record[i].addr, block, MHblock);
1589 } else if (record[i].type & FR) {
1591 readentry(record[i].addr, &vlentry, &type);
1592 vlentry.nextIdHash[0] = header.vital_header.freePtr;
1593 header.vital_header.freePtr = record[i].addr;
1594 if ((record[i].type & FRC) == 0) {
1596 ("FIX: Putting free entry on the free chain: addr=%lu (offset 0x%0x)\n",
1597 record[i].addr, OFFSET(record[i].addr));
1599 writeentry(record[i].addr, &vlentry);
1604 reportHashChanges(&header, oldnamehash, oldidhash);
1605 removeCrossLinkedAddresses(&header);
1606 writeheader(&header);
1615 main(int argc, char **argv)
1617 struct cmd_syndesc *ts;
1621 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "vldb check");
1622 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
1623 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1624 "Display UBIK header");
1625 cmd_AddParm(ts, "-vheader", CMD_FLAG, CMD_OPTIONAL,
1626 "Display VLDB header");
1627 cmd_AddParm(ts, "-servers", CMD_FLAG, CMD_OPTIONAL,
1628 "Display server list");
1629 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1630 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1631 cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "quiet");
1632 cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
1634 return cmd_Dispatch(argc, argv);