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 (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);
482 mhblockP->ex_hdrflags = htonl(mhblockP->ex_hdrflags);
485 * These header fields are only used in the first mh block, so were
486 * converted to host byte order only when the first mh block was read.
488 mhblockP->ex_count = htonl(mhblockP->ex_count);
489 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
490 mhblockP->ex_contaddrs[i] = htonl(mhblockP->ex_contaddrs[i]);
493 for (i = 1; i < VL_MHSRV_PERBLK; i++) {
495 /* hostuuid was not converted */
496 e->ex_uniquifier = htonl(e->ex_uniquifier);
497 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
498 e->ex_addrs[j] = htonl(e->ex_addrs[j]);
501 vldbwrite(addr, (char *)mhblockP, VL_ADDREXTBLK_SIZE);
505 writeentry(afs_int32 addr, struct nvlentry *vlentryp)
509 if (verbose) quiet_println("Writing back entry at addr %u\n", addr);
510 for (i = 0; i < MAXTYPES; i++)
511 vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
512 vlentryp->flags = htonl(vlentryp->flags);
513 vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
514 vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
515 vlentryp->cloneId = htonl(vlentryp->cloneId);
516 for (i = 0; i < MAXTYPES; i++)
517 vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
518 vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
519 for (i = 0; i < NMAXNSERVERS; i++) {
520 /* make sure not to htonl these, as they're chars, not ints */
521 vlentryp->serverNumber[i] = vlentryp->serverNumber[i] ;
522 vlentryp->serverPartition[i] = vlentryp->serverPartition[i] ;
523 vlentryp->serverFlags[i] = vlentryp->serverFlags[i] ;
525 vldbwrite(addr, (char *)vlentryp, sizeof(*vlentryp));
529 * Read each entry in the database:
530 * Record what type of entry it is and its address in the record array.
531 * Remember what the maximum volume id we found is and check against the header.
534 ReadAllEntries(struct vlheader *header)
536 afs_int32 type, rindex, i, j, e;
537 int freecount = 0, mhcount = 0, vlcount = 0;
538 int rwcount = 0, rocount = 0, bkcount = 0;
539 struct nvlentry vlentry;
541 afs_uint32 entrysize = 0;
542 afs_uint32 maxvolid = 0;
544 if (verbose) quiet_println("Read each entry in the database\n");
545 for (addr = header->vital_header.headersize;
546 addr < header->vital_header.eofPtr; addr += entrysize) {
548 /* Remember the highest volume id */
549 readentry(addr, &vlentry, &type);
552 for (i = 0; i < MAXTYPES; i++)
553 if (maxvolid < vlentry.volumeId[i])
554 maxvolid = vlentry.volumeId[i];
557 for (j = 0; j < NMAXNSERVERS; j++) {
558 if (vlentry.serverNumber[j] == 255)
560 if (vlentry.serverFlags[j] & (VLSF_ROVOL | VLSF_NEWREPSITE)) {
564 if (vlentry.serverFlags[j] & VLSF_RWVOL) {
566 if (vlentry.flags & VLF_BACKEXISTS)
570 if (!vlentry.serverFlags[j]) {
576 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
577 addr, OFFSET(addr), vlentry.name);
581 (" index %d : serverNumber %d : serverPartition %d : serverFlag %d\n",
582 j, vlentry.serverNumber[j], vlentry.serverPartition[j],
583 vlentry.serverFlags[j]);
587 rindex = addr / sizeof(vlentry);
588 if (record[rindex].type) {
589 log_error(VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: record holder %d already in use\n",
593 record[rindex].addr = addr;
594 record[rindex].type = type;
596 /* Determine entrysize and keep count */
598 entrysize = sizeof(vlentry);
600 } else if (type == FR) {
601 entrysize = sizeof(vlentry);
603 } else if (type == MH) {
604 entrysize = VL_ADDREXTBLK_SIZE;
607 log_error(VLDB_CHECK_ERROR, "address %u (offset 0x%0x): Unknown entry. Aborting\n", addr, OFFSET(addr));
612 quiet_println("Found %d entries, %d free entries, %d multihomed blocks\n",
613 vlcount, freecount, mhcount);
614 quiet_println("Found %d RW volumes, %d BK volumes, %d RO volumes\n", rwcount,
618 /* Check the maxmimum volume id in the header */
619 if (maxvolid != header->vital_header.MaxVolumeId - 1)
621 ("Header's maximum volume id is %u and largest id found in VLDB is %u\n",
622 header->vital_header.MaxVolumeId, maxvolid);
626 * Follow each Name hash bucket marking it as read in the record array.
627 * Record we found it in the name hash within the record array.
628 * Check that the name is hashed correctly.
631 FollowNameHash(struct vlheader *header)
633 int count = 0, longest = 0, shortest = -1, chainlength;
634 struct nvlentry vlentry;
636 afs_int32 i, type, rindex;
638 /* Now follow the Name Hash Table */
639 if (verbose) quiet_println("Check Volume Name Hash\n");
640 for (i = 0; i < HASHSIZE; i++) {
643 if (!validVolumeAddr(header->VolnameHash[i])) {
644 log_error(VLDB_CHECK_ERROR,"Name Hash index %d is out of range: %u\n",
645 i, header->VolnameHash[i]);
649 for (addr = header->VolnameHash[i]; addr; addr = vlentry.nextNameHash) {
650 readentry(addr, &vlentry, &type);
652 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: Not a vlentry\n",
653 addr, OFFSET(addr), i);
660 * we know that the address is valid because we
661 * checked it either above or below
663 if (record[rindex].addr != addr && record[rindex].addr) {
665 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
666 record[rindex].addr, addr, rindex);
668 if (record[rindex].type & NH) {
670 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: volume name '%s' is already in the name hash\n",
671 addr, OFFSET(addr), i, vlentry.name);
672 record[rindex].type |= MULTN;
676 if (!validVolumeAddr(vlentry.nextNameHash)) {
677 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash forward link of '%s' is out of range\n",
678 addr, OFFSET(addr), vlentry.name);
679 record[rindex].type |= MULTN;
683 record[rindex].type |= NH;
684 record[rindex].type |= REFN;
689 /* Hash the name and check if in correct hash table */
690 if (NameHash(vlentry.name) != i) {
692 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Name Hash %d: volume name '%s': Incorrect name hash chain (should be in %d)\n",
693 addr, OFFSET(addr), i, vlentry.name, NameHash(vlentry.name));
694 record[rindex].type |= MULTN;
697 if (chainlength > longest)
698 longest = chainlength;
699 if ((shortest == -1) || (chainlength < shortest))
700 shortest = chainlength;
704 ("%d entries in name hash, longest is %d, shortest is %d, average length is %f\n",
705 count, longest, shortest, ((float)count / (float)HASHSIZE));
711 * Follow the ID hash chains for the RW, RO, and BK hash tables.
712 * Record we found it in the id hash within the record array.
713 * Check that the ID is hashed correctly.
716 FollowIdHash(struct vlheader *header)
718 int count = 0, longest = 0, shortest = -1, chainlength;
719 struct nvlentry vlentry;
721 afs_int32 i, j, hash, type, rindex, ref, badref, badhash;
723 /* Now follow the RW, RO, and BK Hash Tables */
724 if (verbose) quiet_println("Check RW, RO, and BK id Hashes\n");
725 for (i = 0; i < MAXTYPES; i++) {
726 hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
727 ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
728 badref = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
729 badhash = ((i == 0) ? MULTRW : ((i == 1) ? MULTRO : MULTBK));
733 for (j = 0; j < HASHSIZE; j++) {
735 if (!validVolumeAddr(header->VolidHash[i][j])) {
736 log_error(VLDB_CHECK_ERROR,"%s Hash index %d is out of range: %u\n",
737 vtype(i), j, header->VolidHash[i][j]);
741 for (addr = header->VolidHash[i][j]; addr;
742 addr = vlentry.nextIdHash[i]) {
743 readentry(addr, &vlentry, &type);
746 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: Not a vlentry\n",
747 addr, OFFSET(addr), vtype(i), j);
752 if (record[rindex].addr != addr && record[rindex].addr) {
754 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %ld and %u use same record slot %d\n",
755 record[rindex].addr, addr, rindex);
757 if (record[rindex].type & hash) {
759 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: volume name '%s': Already in the hash table\n",
760 addr, OFFSET(addr), vtype(i), j, vlentry.name);
761 record[rindex].type |= badref;
765 if (!validVolumeAddr(vlentry.nextIdHash[i])) {
766 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash forward link of '%s' is out of range\n",
767 addr, OFFSET(addr), vtype(i), vlentry.name);
768 record[rindex].type |= badref;
772 record[rindex].type |= hash;
773 record[rindex].type |= ref;
778 /* Hash the id and check if in correct hash table */
779 if (IdHash(vlentry.volumeId[i]) != j) {
781 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): %s Id Hash %d: volume name '%s': Incorrect Id hash chain (should be in %d)\n",
782 addr, OFFSET(addr), vtype(i), j, vlentry.name,
783 IdHash(vlentry.volumeId[i]));
784 record[rindex].type |= badhash;
788 if (chainlength > longest)
789 longest = chainlength;
790 if ((shortest == -1) || (chainlength < shortest))
791 shortest = chainlength;
795 ("%d entries in %s hash, longest is %d, shortest is %d, average length is %f\n",
796 count, vtype(i), longest, shortest,((float)count / (float)HASHSIZE));
803 * Follow the free chain.
804 * Record we found it in the free chain within the record array.
807 FollowFreeChain(struct vlheader *header)
810 struct nvlentry vlentry;
812 afs_int32 type, rindex;
814 /* Now follow the Free Chain */
815 if (verbose) quiet_println("Check Volume Free Chain\n");
816 for (addr = header->vital_header.freePtr; addr;
817 addr = vlentry.nextIdHash[0]) {
818 readentry(addr, &vlentry, &type);
821 (VLDB_CHECK_ERROR,"address %u (offset 0%0x): Free Chain %d: Not a free vlentry (0x%x)\n",
822 addr, OFFSET(addr), count, type);
826 rindex = addr / sizeof(vlentry);
827 if (record[rindex].addr != addr && record[rindex].addr) {
829 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u (0x%0x) and %ld (0x%0x) use same record slot %d\n",
830 record[rindex].addr, OFFSET(record[rindex].addr), addr, OFFSET(addr), rindex);
832 if (record[rindex].type & FRC) {
833 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free Chain: Already in the free chain\n",
837 record[rindex].type |= FRC;
842 quiet_println("%d entries on free chain\n", count);
847 * Read each multihomed block and mark it as found in the record.
848 * Read each entry in each multihomed block and mark the serveraddrs
849 * array with the number of ip addresses found for this entry.
851 * Then read the IpMappedAddr array in the header.
852 * Verify that multihomed entries base and index are valid and points to
853 * a good multhomed entry.
854 * Mark the serveraddrs array with 1 ip address for regular entries.
856 * By the end, the severaddrs array will have a 0 if the entry has no
857 * IP addresses in it or the count of the number of IP addresses.
859 * The code does not verify if there are duplicate IP addresses in the
860 * list. The vlserver does this when a fileserver registeres itself.
863 CheckIpAddrs(struct vlheader *header)
866 afs_int32 i, j, m, rindex;
867 afs_int32 mhentries, regentries;
868 char mhblock[VL_ADDREXTBLK_SIZE];
869 struct extentaddr *MHblock = (struct extentaddr *)mhblock;
870 struct extentaddr *e;
871 int ipindex, ipaddrs;
874 memset(&nulluuid, 0, sizeof(nulluuid));
877 quiet_println("Check Multihomed blocks\n");
880 /* Read the first MH block and from it, gather the
881 * addresses of all the mh blocks.
883 readMH(header->SIT, 0, MHblock);
884 if (MHblock->ex_hdrflags != VLCONTBLOCK) {
886 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed Block 0: Not a multihomed block\n",
887 header->SIT, OFFSET(header->SIT));
890 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
891 mhinfo[i].addr = MHblock->ex_contaddrs[i];
894 if (header->SIT != mhinfo[0].addr) {
896 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): MH block does not point to self in header, %u in block\n",
897 header->SIT, OFFSET(header->SIT), mhinfo[0].addr);
900 /* Now read each MH block and record it in the record array */
901 for (i = 0; i < VL_MAX_ADDREXTBLKS; i++) {
905 readMH(mhinfo[i].addr, i, MHblock);
906 if (MHblock->ex_hdrflags != VLCONTBLOCK) {
908 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed Block %d: Not a multihomed block\n",
909 mhinfo[i].addr, OFFSET(mhinfo[i].addr), i);
912 rindex = mhinfo[i].addr / sizeof(vlentry);
913 if (record[rindex].addr != mhinfo[i].addr && record[rindex].addr) {
915 (VLDB_CHECK_ERROR,"INTERNAL VLDB_CHECK_ERROR: addresses %u (0x%0x) and %u (0x%0x) use same record slot %d\n",
916 record[rindex].addr, OFFSET(record[rindex].addr), mhinfo[i].addr, OFFSET(mhinfo[i].addr), rindex);
918 if (record[rindex].type & FRC) {
920 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): MH Blocks Chain %d: Already a MH block\n",
921 record[rindex].addr, OFFSET(record[rindex].addr), i);
924 record[rindex].type |= MHC;
928 /* Read each entry in a multihomed block.
929 * Find the pointer to the entry in the IpMappedAddr array and
930 * verify that the entry is good (has IP addresses in it).
933 for (j = 1; j < VL_MHSRV_PERBLK; j++) {
934 int first_ipindex = -1;
935 e = (struct extentaddr *)&(MHblock[j]);
937 /* Search the IpMappedAddr array for all the references to this entry. */
938 /* Use the first reference for checking the ip addresses of this entry. */
939 for (ipindex = 0; ipindex <= MAXSERVERID; ipindex++) {
940 if (((header->IpMappedAddr[ipindex] & 0xff000000) == 0xff000000)
941 && (((header-> IpMappedAddr[ipindex] & 0x00ff0000) >> 16) == i)
942 && ((header->IpMappedAddr[ipindex] & 0x0000ffff) == j)) {
943 if (first_ipindex == -1) {
944 first_ipindex = ipindex;
946 serverxref[ipindex] = first_ipindex;
950 ipindex = first_ipindex;
952 serveraddrs[ipindex] = -1;
954 if (memcmp(&e->ex_hostuuid, &nulluuid, sizeof(afsUUID)) == 0) {
957 (VLDB_CHECK_ERROR,"Server Addrs index %d references null MH block %d, index %d\n",
959 serveraddrs[ipindex] = 0; /* avoids printing 2nd error below */
964 /* Step through each ip address and count the good addresses */
966 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
971 /* If we found any good ip addresses, mark it in the serveraddrs record */
975 mhinfo[i].orphan[j] = 1;
977 (VLDB_CHECK_ERROR,"MH block %d, index %d: Not referenced by server addrs\n",
980 serveraddrs[ipindex] = ipaddrs; /* It is good */
984 if (listservers && ipaddrs) {
985 quiet_println("MH block %d, index %d:", i, j);
986 for (m = 0; m < VL_MAXIPADDRS_PERMH; m++) {
989 quiet_println(" %d.%d.%d.%d",
990 (e->ex_addrs[m] & 0xff000000) >> 24,
991 (e->ex_addrs[m] & 0x00ff0000) >> 16,
992 (e->ex_addrs[m] & 0x0000ff00) >> 8,
993 (e->ex_addrs[m] & 0x000000ff));
999 * if (mhentries != MHblock->ex_count) {
1000 * quiet_println("MH blocks says it has %d entries (found %d)\n",
1001 * MHblock->ex_count, mhentries);
1007 quiet_println("%d multihomed blocks\n", mhblocks);
1009 /* Check the server addresses */
1011 quiet_println("Check server addresses\n");
1012 mhentries = regentries = 0;
1013 for (i = 0; i <= MAXSERVERID; i++) {
1014 if (header->IpMappedAddr[i]) {
1015 if ((header->IpMappedAddr[i] & 0xff000000) == 0xff000000) {
1017 if (((header->IpMappedAddr[i] & 0x00ff0000) >> 16) >
1020 (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome block is bad (%d)\n",
1021 i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1022 if (mhinfo[(header->IpMappedAddr[i] & 0x00ff0000) >> 16].addr == 0)
1023 log_error(VLDB_CHECK_ERROR,"IP Addr for entry %d: No such multihome block (%d)\n",
1024 i, ((header->IpMappedAddr[i] & 0x00ff0000) >> 16));
1025 if (((header->IpMappedAddr[i] & 0x0000ffff) > VL_MHSRV_PERBLK)
1026 || ((header->IpMappedAddr[i] & 0x0000ffff) < 1))
1028 (VLDB_CHECK_ERROR,"IP Addr for entry %d: Multihome index is bad (%d)\n",
1029 i, (header->IpMappedAddr[i] & 0x0000ffff));
1030 if (serveraddrs[i] == -1) {
1032 (VLDB_CHECK_WARNING,"warning: IP Addr for entry %d: Multihome entry has no ip addresses\n",
1036 if (serverxref[i] != BADSERVERID) {
1038 (VLDB_CHECK_WARNING,
1039 "warning: MH block %d, index %d is cross-linked by server numbers %d and %d.\n",
1040 (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1041 (header->IpMappedAddr[i] & 0x0000ffff),
1043 /* set addresses found/not found for this server number,
1044 * using the first index to the mh we found above. */
1045 serveraddrs[i] = serveraddrs[serverxref[i]];
1048 quiet_println(" Server ip addr %d = MH block %d, index %d\n",
1049 i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1050 (header->IpMappedAddr[i] & 0x0000ffff));
1054 serveraddrs[i] = 1; /* It is good */
1056 quiet_println(" Server ip addr %d = %d.%d.%d.%d\n", i,
1057 (header->IpMappedAddr[i] & 0xff000000) >> 24,
1058 (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1059 (header->IpMappedAddr[i] & 0x0000ff00) >> 8,
1060 (header->IpMappedAddr[i] & 0x000000ff));
1066 quiet_println("%d simple entries, %d multihomed entries, Total = %d\n",
1067 regentries, mhentries, mhentries + regentries);
1073 nameForAddr(afs_uint32 addr, int hashtype, afs_uint32 *hash, char *buffer)
1076 * We need to simplify the reporting, while retaining
1077 * legible messages. This is a helper function. The return address
1078 * is either a fixed char or the provided buffer - so don't use the
1079 * name after the valid lifetime of the buffer.
1082 struct nvlentry entry;
1084 /* Distinguished, invalid, hash */
1087 } else if (!validVolumeAddr(addr)) {
1088 /* Different, invalid, hash */
1092 readentry(addr, &entry, &type);
1097 if (hashtype >= MAXTYPES) {
1098 *hash = NameHash(entry.name);
1100 *hash = IdHash(entry.volumeId[hashtype]);
1102 sprintf(buffer, "for '%s'", entry.name);
1107 reportHashChanges(struct vlheader *header, afs_uint32 oldnamehash[HASHSIZE], afs_uint32 oldidhash[MAXTYPES][HASHSIZE])
1110 afs_uint32 oldhash, newhash;
1111 char oldNameBuffer[10 + VL_MAXNAMELEN];
1112 char newNameBuffer[10 + VL_MAXNAMELEN];
1113 char *oldname, *newname;
1115 * report hash changes
1118 for (i = 0; i < HASHSIZE; i++) {
1119 if (oldnamehash[i] != header->VolnameHash[i]) {
1121 oldname = nameForAddr(oldnamehash[i], MAXTYPES, &oldhash, oldNameBuffer);
1122 newname = nameForAddr(header->VolnameHash[i], MAXTYPES, &newhash, newNameBuffer);
1123 if (verbose || (oldhash != newhash)) {
1124 quiet_println("FIX: Name hash header at %d was %s, is now %s\n", i, oldname, newname);
1127 for (j = 0; j < MAXTYPES; j++) {
1128 if (oldidhash[j][i] != header->VolidHash[j][i]) {
1130 oldname = nameForAddr(oldidhash[j][i], j, &oldhash, oldNameBuffer);
1131 newname = nameForAddr(header->VolidHash[j][i], j, &newhash, newNameBuffer);
1132 if (verbose || (oldhash != newhash)) {
1133 quiet_println("FIX: %s hash header at %d was %s, is now %s\n", vtype(j), i, oldname, newname);
1141 * Remove unreferenced, duplicate multi-home address indices.
1143 * Removes entries from IpMappedAddr which where found to be
1144 * duplicates. Only entries which are not referenced by vl entries
1145 * are removed on this pass.
1147 * @param[inout] header the vldb header to be updated.
1150 removeCrossLinkedAddresses(struct vlheader *header)
1154 for (i = 0; i <= MAXSERVERID; i++) {
1155 if (serverref[i] == 0
1156 && (header->IpMappedAddr[i] & 0xff000000) == 0xff000000
1157 && serverxref[i] != BADSERVERID) {
1158 if (serverxref[i] == i) {
1159 log_error(VLDB_CHECK_ERROR,
1160 "INTERNAL VLDB_CHECK_ERROR: serverxref points to self; index %d\n",
1162 } else if (header->IpMappedAddr[serverxref[i]] == 0) {
1163 log_error(VLDB_CHECK_ERROR,
1164 "INTERNAL VLDB_CHECK_ERROR: serverxref points to empty addr; index %d, value %d\n",
1166 } else if (header->IpMappedAddr[serverxref[i]] != header->IpMappedAddr[i]) {
1167 log_error(VLDB_CHECK_ERROR,
1168 "INTERNAL VLDB_CHECK_ERROR: invalid serverxref; index %d, value %d\n",
1172 ("FIX: Removing unreferenced address index %d, which cross-links MH block %d, index %d\n",
1173 i, (header->IpMappedAddr[i] & 0x00ff0000) >> 16,
1174 (header->IpMappedAddr[i] & 0x0000ffff));
1175 header->IpMappedAddr[i] = 0;
1182 WorkerBee(struct cmd_syndesc *as, void *arock)
1186 struct vlheader header;
1187 struct nvlentry vlentry, vlentry2;
1189 afs_uint32 oldnamehash[HASHSIZE];
1190 afs_uint32 oldidhash[MAXTYPES][HASHSIZE];
1192 error_level = 0; /* start clean with no error status */
1193 dbfile = as->parms[0].items->data; /* -database */
1194 listuheader = (as->parms[1].items ? 1 : 0); /* -uheader */
1195 listheader = (as->parms[2].items ? 1 : 0); /* -vheader */
1196 listservers = (as->parms[3].items ? 1 : 0); /* -servers */
1197 listentries = (as->parms[4].items ? 1 : 0); /* -entries */
1198 verbose = (as->parms[5].items ? 1 : 0); /* -verbose */
1199 quiet = (as->parms[6].items ? 1 : 0); /* -quiet */
1200 fix = (as->parms[7].items ? 1 : 0); /* -fix */
1203 if (quiet && (verbose || listuheader || listheader ||listservers \
1205 log_error(VLDB_CHECK_FATAL," -quiet cannot be used other display flags\n");
1206 return VLDB_CHECK_FATAL;
1210 /* open the vldb database file */
1211 fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
1213 log_error(VLDB_CHECK_FATAL,"can't open file '%s'. error = %d\n", dbfile, errno);
1217 /* read the ubik header and the vldb database header */
1219 readheader(&header);
1220 if (header.vital_header.vldbversion < 3) {
1221 log_error(VLDB_CHECK_FATAL,"does not support vldb with version less than 3\n");
1222 return VLDB_CHECK_FATAL;
1225 maxentries = (header.vital_header.eofPtr / sizeof(vlentry)) + 1;
1226 record = calloc(maxentries, sizeof(struct er));
1227 memset(serveraddrs, 0, sizeof(serveraddrs));
1228 memset(mhinfo, 0, sizeof(mhinfo));
1229 memset(serverref, 0, sizeof(serverref));
1230 for (i = 0; i <= MAXSERVERID; i++) {
1231 serverxref[i] = BADSERVERID;
1234 /* Will fill in the record array of entries it found */
1235 ReadAllEntries(&header);
1236 listentries = 0; /* Listed all the entries */
1238 /* Check the multihomed blocks for valid entries as well as
1239 * the IpMappedAddrs array in the header for valid entries.
1241 CheckIpAddrs(&header);
1243 /* Follow the hash tables */
1244 FollowNameHash(&header);
1245 FollowIdHash(&header);
1247 /* Follow the chain of free entries */
1248 FollowFreeChain(&header);
1250 /* Now check the record we have been keeping for inconsistencies
1251 * For valid vlentries, also check that the server we point to is
1252 * valid (the serveraddrs array).
1255 quiet_println("Verify each volume entry\n");
1256 for (i = 0; i < maxentries; i++) {
1261 if (record[i].type == 0)
1264 /* If a vlentry, verify that its name is valid, its name and ids are
1265 * on the hash chains, and its server numbers are good.
1267 if (record[i].type & VL) {
1269 int foundbroken = 0;
1272 readentry(record[i].addr, &vlentry, &type);
1274 if (!(vlentry.flags & VLF_RWEXISTS))
1275 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has no RW volume\n",
1276 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1278 if (InvalidVolname(vlentry.name))
1279 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has an invalid name\n",
1280 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1282 if (vlentry.volumeId[0] == 0)
1283 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' (%u) has an invalid volume id\n",
1284 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0]);
1286 if (!(record[i].type & NH)) {
1287 hash = NameHash(vlentry.name);
1293 if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
1294 hash = IdHash(vlentry.volumeId[0]);
1296 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1300 if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
1301 hash = IdHash(vlentry.volumeId[1]);
1303 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1307 if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
1308 hash = IdHash(vlentry.volumeId[2]);
1310 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1314 if (!validVolumeAddr(vlentry.nextNameHash) ||
1315 record[ADDR(vlentry.nextNameHash)].type & MULTN) {
1316 hash = NameHash(vlentry.name);
1319 if (validVolumeAddr(vlentry.nextNameHash)) {
1320 readentry(vlentry.nextNameHash, &vlentry2, &type);
1321 nexthash = NameHash(vlentry2.name);
1323 nexthash = 0xFFFFFFFF;
1325 if (hash != nexthash)
1329 if (!validVolumeAddr(vlentry.nextIdHash[0]) ||
1330 record[ADDR(vlentry.nextIdHash[0])].type & MULTRW) {
1331 hash = IdHash(vlentry.volumeId[0]);
1333 sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
1334 if (validVolumeAddr(vlentry.nextIdHash[0])) {
1335 readentry(vlentry.nextIdHash[0], &vlentry2, &type);
1336 nexthash = IdHash(vlentry2.volumeId[0]);
1338 nexthash = 0xFFFFFFFF;
1340 if (hash != nexthash)
1344 if (!validVolumeAddr(vlentry.nextIdHash[1]) ||
1345 record[ADDR(vlentry.nextIdHash[1])].type & MULTRO) {
1346 hash = IdHash(vlentry.volumeId[1]);
1348 sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
1349 if (validVolumeAddr(vlentry.nextIdHash[1])) {
1350 readentry(vlentry.nextIdHash[1], &vlentry2, &type);
1351 nexthash = IdHash(vlentry2.volumeId[1]);
1353 nexthash = 0xFFFFFFFF;
1355 if (hash != nexthash)
1359 if (!validVolumeAddr(vlentry.nextIdHash[2]) ||
1360 record[ADDR(vlentry.nextIdHash[2])].type & MULTBK) {
1361 hash = IdHash(vlentry.volumeId[2]);
1363 sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
1364 if (validVolumeAddr(vlentry.nextIdHash[2])) {
1365 readentry(vlentry.nextIdHash[2], &vlentry2, &type);
1366 nexthash = IdHash(vlentry2.volumeId[2]);
1368 nexthash = 0xFFFFFFFF;
1370 if (hash != nexthash)
1375 log_error(VLDB_CHECK_ERROR,
1376 "address %u (offset 0x%0x): Volume '%s' %s forward link in %s hash chain is broken (hash %d != %d)\n",
1377 record[i].addr, OFFSET(record[i].addr),
1378 vlentry.name, volidbuf, which, hash, nexthash);
1379 } else if (foundbad) {
1380 log_error(VLDB_CHECK_ERROR,
1381 "address %u (offset 0x%0x): Volume '%s' %snot found in %s hash %d\n",
1382 record[i].addr, OFFSET(record[i].addr),
1383 vlentry.name, volidbuf, which, hash);
1386 for (j = 0; j < NMAXNSERVERS; j++) {
1387 if (vlentry.serverNumber[j] != BADSERVERID) {
1388 serverref[vlentry.serverNumber[j]] = 1;
1389 if (serveraddrs[vlentry.serverNumber[j]] == 0) {
1391 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s', index %d points to empty server entry %d\n",
1392 record[i].addr, OFFSET(record[i].addr), vlentry.name, j, vlentry.serverNumber[j]);
1393 } else if (serverxref[vlentry.serverNumber[j]] != BADSERVERID) {
1395 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s', index %d points to server entry %d, which is cross-linked by %d\n",
1396 record[i].addr, OFFSET(record[i].addr), vlentry.name, j, vlentry.serverNumber[j], serverxref[vlentry.serverNumber[j]]);
1401 if (record[i].type & 0xffff0f00)
1403 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Volume '%s' id %u also found on other chains (0x%x)\n",
1404 record[i].addr, OFFSET(record[i].addr), vlentry.name, vlentry.volumeId[0], record[i].type);
1407 } else if (record[i].type & FR) {
1408 if (!(record[i].type & FRC))
1409 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free vlentry not on free chain\n",
1410 record[i].addr, OFFSET(record[i].addr));
1412 if (record[i].type & 0xfffffdf0)
1414 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Free vlentry also found on other chains (0x%x)\n",
1415 record[i].addr, OFFSET(record[i].addr), record[i].type);
1417 /* A multihomed entry */
1418 } else if (record[i].type & MH) {
1419 if (!(record[i].type & MHC))
1420 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed block is orphaned\n",
1421 record[i].addr, OFFSET(record[i].addr));
1423 if (record[i].type & 0xfffffef0)
1425 (VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Multihomed block also found on other chains (0x%x)\n",
1426 record[i].addr, OFFSET(record[i].addr), record[i].type);
1429 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Unknown entry type 0x%x\n",
1430 record[i].addr, OFFSET(record[i].addr), record[i].type);
1436 * If we are fixing we will rebuild the free and hash lists from the ground up.
1438 header.vital_header.freePtr = 0;
1439 memcpy(oldnamehash, header.VolnameHash, sizeof(oldnamehash));
1440 memset(header.VolnameHash, 0, sizeof(header.VolnameHash));
1442 memcpy(oldidhash, header.VolidHash, sizeof(oldidhash));
1443 memset(header.VolidHash, 0, sizeof(header.VolidHash));
1444 quiet_println("Rebuilding %u entries\n", maxentries);
1446 quiet_println("Scanning %u entries for possible repairs\n", maxentries);
1448 for (i = 0; i < maxentries; i++) {
1450 if (record[i].type & VL) {
1451 readentry(record[i].addr, &vlentry, &type);
1452 if (!(record[i].type & REFN)) {
1453 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record is not in a name chain (type 0x%0x)\n",
1454 record[i].addr, OFFSET(record[i].addr), record[i].type);
1456 if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
1457 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a RW chain (type 0x%0x)\n",
1458 record[i].addr, OFFSET(record[i].addr), record[i].type);
1460 if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
1461 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a RO chain (type 0x%0x)\n",
1462 record[i].addr, OFFSET(record[i].addr), record[i].type);
1464 if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
1465 log_error(VLDB_CHECK_ERROR,"address %u (offset 0x%0x): Record not in a BK chain (type 0x%0x)\n",
1466 record[i].addr, OFFSET(record[i].addr), record[i].type);
1469 afs_uint32 oldhash, newhash;
1470 char oldNameBuffer[10 + VL_MAXNAMELEN];
1471 char newNameBuffer[10 + VL_MAXNAMELEN];
1472 char *oldname, *newname;
1474 /* Fix broken names and numbers so entries can be inspected and deleted. */
1475 if (InvalidVolname(vlentry.name)) {
1476 char bogus[VL_MAXNAMELEN];
1477 memset(bogus, 0, sizeof(bogus));
1478 snprintf(bogus, sizeof(bogus)-1, ".bogus.%ld", record[i].addr);
1479 strcpy(vlentry.name, bogus);
1480 quiet_println("FIX: Record %ld invalid volume name set to '%s'\n", record[i].addr, bogus);
1482 if (vlentry.volumeId[0] == 0) {
1483 afs_uint32 next_volid = header.vital_header.MaxVolumeId++;
1484 vlentry.volumeId[0] = next_volid;
1485 quiet_println("FIX: Record %ld invalid volume id set to %ld. New max volid is %ld\n",
1486 record[i].addr, next_volid, header.vital_header.MaxVolumeId);
1490 * Put the current hash table contexts into our 'next'
1491 * and our address into the hash table.
1493 hash = NameHash(vlentry.name);
1495 if (vlentry.nextNameHash != header.VolnameHash[hash]) {
1496 oldname = nameForAddr(vlentry.nextNameHash, MAXTYPES, &oldhash, oldNameBuffer);
1497 newname = nameForAddr(header.VolnameHash[hash], MAXTYPES, &newhash, newNameBuffer);
1498 if (verbose || ((oldhash != newhash) &&
1499 (0 != vlentry.nextNameHash) &&
1500 (0 != header.VolnameHash[hash]))) {
1502 * That is, only report if we are verbose
1503 * or the hash is changing (and one side wasn't NULL
1505 quiet_println("FIX: Name hash link for '%s' was %s, is now %s\n",
1506 vlentry.name, oldname, newname);
1510 vlentry.nextNameHash = header.VolnameHash[hash];
1511 header.VolnameHash[hash] = record[i].addr;
1513 for (j = 0; j < MAXTYPES; j++) {
1515 if (0 == vlentry.volumeId[j]) {
1517 * No volume of that type. Continue
1521 hash = IdHash(vlentry.volumeId[j]);
1523 if (vlentry.nextIdHash[j] != header.VolidHash[j][hash]) {
1524 oldname = nameForAddr(vlentry.nextIdHash[j], j, &oldhash, oldNameBuffer);
1525 newname = nameForAddr(header.VolidHash[j][hash], j, &newhash, newNameBuffer);
1526 if (verbose || ((oldhash != newhash) &&
1527 (0 != vlentry.nextIdHash[j]) &&
1528 (0 != header.VolidHash[j][hash]))) {
1529 quiet_println("FIX: %s hash link for '%s' was %s, is now %s\n",
1530 vtype(j), vlentry.name, oldname, newname);
1534 /* Consolidate server numbers which point to the same mh entry.
1535 * The serverref flags are not reset here, since we want to make
1536 * sure the data is actually written before the server number is
1537 * considered unreferenced. */
1538 for (k = 0; k < NMAXNSERVERS; k++) {
1539 if (vlentry.serverNumber[k] != BADSERVERID
1540 && serverxref[vlentry.serverNumber[k]] != BADSERVERID) {
1541 u_char oldsn = vlentry.serverNumber[k];
1542 u_char newsn = serverxref[oldsn];
1543 if (newsn == oldsn) {
1544 log_error(VLDB_CHECK_ERROR,
1545 "INTERNAL VLDB_CHECK_ERROR: serverxref points to self; index %d\n",
1547 } else if (header.IpMappedAddr[oldsn] == 0) {
1548 log_error(VLDB_CHECK_ERROR,
1549 "INTERNAL VLDB_CHECK_ERROR: serverxref; points to empty address; index %d, value %d\n",
1551 } else if (header.IpMappedAddr[newsn] != header.IpMappedAddr[oldsn]) {
1552 log_error(VLDB_CHECK_ERROR,
1553 "INTERNAL VLDB_CHECK_ERROR: invalid serverxref; index %d\n",
1557 ("FIX: Volume '%s', index %d, server number was %d, is now %d\n",
1558 vlentry.name, k, oldsn, newsn);
1559 vlentry.serverNumber[k] = newsn;
1564 vlentry.nextIdHash[j] = header.VolidHash[j][hash];
1565 header.VolidHash[j][hash] = record[i].addr;
1567 writeentry(record[i].addr, &vlentry);
1570 else if (record[i].type & MH) {
1572 char mhblock[VL_ADDREXTBLK_SIZE];
1573 struct extentaddr *MHblock = (struct extentaddr *)mhblock;
1576 for (block = 0; block < VL_MAX_ADDREXTBLKS; block++) {
1577 if (mhinfo[block].addr == record[i].addr)
1580 if (block == VL_MAX_ADDREXTBLKS) {
1581 continue; /* skip orphaned extent block */
1583 readMH(record[i].addr, block, MHblock);
1584 for (index = 0; index < VL_MHSRV_PERBLK; index++) {
1585 if (mhinfo[block].orphan[index]) {
1586 quiet_println("FIX: Removing unreferenced mh entry; block %d, index %d\n",
1588 memset(&(MHblock[index]), 0, sizeof(struct extentaddr));
1591 writeMH(record[i].addr, block, MHblock);
1593 } else if (record[i].type & FR) {
1595 readentry(record[i].addr, &vlentry, &type);
1596 vlentry.nextIdHash[0] = header.vital_header.freePtr;
1597 header.vital_header.freePtr = record[i].addr;
1598 if ((record[i].type & FRC) == 0) {
1600 ("FIX: Putting free entry on the free chain: addr=%lu (offset 0x%0x)\n",
1601 record[i].addr, OFFSET(record[i].addr));
1603 writeentry(record[i].addr, &vlentry);
1608 reportHashChanges(&header, oldnamehash, oldidhash);
1609 removeCrossLinkedAddresses(&header);
1610 writeheader(&header);
1619 main(int argc, char **argv)
1621 struct cmd_syndesc *ts;
1625 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "vldb check");
1626 cmd_AddParm(ts, "-database", CMD_SINGLE, CMD_REQUIRED, "vldb_file");
1627 cmd_AddParm(ts, "-uheader", CMD_FLAG, CMD_OPTIONAL,
1628 "Display UBIK header");
1629 cmd_AddParm(ts, "-vheader", CMD_FLAG, CMD_OPTIONAL,
1630 "Display VLDB header");
1631 cmd_AddParm(ts, "-servers", CMD_FLAG, CMD_OPTIONAL,
1632 "Display server list");
1633 cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
1634 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
1635 cmd_AddParm(ts, "-quiet", CMD_FLAG, CMD_OPTIONAL, "quiet");
1636 cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
1638 return cmd_Dispatch(argc, argv);