Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / budb / ol_verify.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10/* ol_verify - online database verification */
11
12#include <afsconfig.h>
13#include <afs/param.h>
14#include <afs/stds.h>
15
16#include <roken.h>
17
18#include <lock.h>
19#include <ubik.h>
20#include <afs/cellconfig.h>
21#include <afs/audit.h>
22
23#include "database.h"
24#include "error_macros.h"
25#include "budb_errs.h"
26#include "budb_internal.h"
27
28#undef min
29#undef max
30
31/* notes
32 * 1) volInfo structures refering to a volume of the same name are
33 * chained together, i.e. the volumes described differ in volid, partition
34 * etc. The structure at the head of this list (the sameNameChain) is
35 * treated specially. When a delete volInfo request is processed, heads
36 * are not deleted unless all other items on the sameNameChain are gone.
37 *
38 * The result is that volInfo (head) structures may be present
39 * even if no tape structures refer to them. These structures are
40 * unreachable in a top-down tree walk.
41 * TO DO
42 * 1) make the verify tolerant of errors. Want to get a summary statistic
43 * indicating how may dumps are lost and how many text blocks lost
44 * 2) Make the recreation instructions write out whatever is good. This
45 * is only for the off-line case.
46 */
47
48/* flags associated with each structure. These are set and checked in
49 * the blockMap entries
50 */
51
52#define MAP_DUMPHASH 1 /* dump name hash checked */
53#define MAP_TAPEHASH 2 /* tape name hash checked */
54#define MAP_VOLHASH 4 /* volume name hash checked */
55#define MAP_IDHASH 8 /* dump id hash checked */
56
57#define MAP_HASHES (MAP_DUMPHASH | MAP_TAPEHASH | MAP_VOLHASH | MAP_IDHASH)
58
59#define MAP_FREE 0x10 /* item is free */
60#define MAP_RECREATE 0x20
61#define MAP_HTBLOCK 0x40 /* hash table block */
62#define MAP_TAPEONDUMP 0x100
63#define MAP_VOLFRAGONTAPE 0x200
64#define MAP_VOLFRAGONVOL 0x400
65#define MAP_VOLINFOONNAME 0x800
66#define MAP_VOLINFONAMEHEAD 0x1000
67#define MAP_TEXTBLOCK 0x2000 /* block of text */
68#define MAP_APPENDEDDUMP 0x4000
69
70/* one blockMap for every block in the database. Each element of the entries
71 * array describes the status of a data structure/entry in that block
72 */
73
74struct blockMap {
75 struct blockHeader header; /* copy of the block header */
76 char free; /* on free list */
77 int nEntries; /* size of the entries arrays */
78 afs_uint32 entries[1]; /* describes each entry */
79};
80
81/* status for verify call */
82struct dbStatus {
83 char hostname[64]; /* host on which checked */
84 afs_int32 status; /* ok, not ok */
85};
86
87int nBlocks; /* total number of blocks in db */
88
89struct misc_hash_stats { /* stats for hashing */
90 int max; /* longest chain length */
91 double avg; /* avg length */
92 double std_dev; /* standard deviation of length */
93};
94
95struct misc_data {
96 int errors; /* errors encountered */
97 int maxErrors; /* abort after this many errors */
98 int nBlocks; /* number of database blocks */
99 int nDump, nTape, nVolInfo, nVolFrag; /* counts of each type */
100 int nVolName; /* volInfos w/ head==0 */
101 int maxVolsPerVolInfo; /* maximum list lengths */
102 int maxVolsPerTape;
103 int maxVolsPerDump;
104 int maxVolInfosPerName;
105 int maxTapesPerDump;
106 int maxAppendsPerDump;
107 int freeLength[NBLOCKTYPES]; /* length of free lists */
108 int fullyFree[NBLOCKTYPES]; /* free blocks full of free entries */
109 int veryLongChain; /* length of chain to report */
110 int checkFragCount; /* report fragment count errors */
111 struct misc_hash_stats dumpName, dumpIden, tapeName, volName;
112 FILE *recreate; /* stream for recreate instructions */
113} miscData;
114struct misc_data *misc;
115
116struct blockMap **blockMap = 0; /* initial block map */
117
118/* describes number of entries for each type of block */
119
120int blockEntries[NBLOCKTYPES] = {
121 0 /* free_BLOCK */ ,
122 NvolFragmentS,
123 NvolInfoS,
124 NtapeS,
125 NdumpS,
126 1, /* hashTable_BLOCK */
127 1 /* text block */
128};
129
130int blockEntrySize[NBLOCKTYPES] = {
131 0 /* free */ ,
132 sizeof(struct vfBlock_frag),
133 sizeof(struct viBlock_info),
134 sizeof(struct tBlock_tape),
135 sizeof(struct dBlock_dump),
136 0,
137 0,
138};
139
140char *typeName[NBLOCKTYPES] = {
141 "free",
142 "volFragment",
143 "volInfo",
144 "tape",
145 "dump",
146 "hashTable",
147 "text"
148};
149
150int hashBlockType[HT_MAX_FUNCTION + 1] = {
151 0,
152 dump_BLOCK,
153 dump_BLOCK,
154 tape_BLOCK,
155 volInfo_BLOCK
156};
157
158/* Compatibility table for the bits in the blockMap. */
159
160struct mapCompatability {
161 short trigger; /* these bits trigger this element */
162} mapC[] = {
163 {MAP_FREE}, {MAP_HTBLOCK}, {MAP_DUMPHASH | MAP_IDHASH},
164 {MAP_TAPEHASH | MAP_TAPEONDUMP}, {MAP_VOLINFOONNAME},
165 {MAP_VOLINFONAMEHEAD | MAP_VOLHASH},
166 {MAP_VOLFRAGONTAPE | MAP_VOLFRAGONVOL}, {MAP_TEXTBLOCK}};
167
168/* no. of entries in the mapC array */
169int NMAPCs = (sizeof(mapC) / sizeof(mapC[0]));
170
171/* for identifying stored textual information */
172
173char *textName[TB_NUM] = {
174 "Dump Schedule\n",
175 "Volume Sets\n",
176 "Tape Hosts\n"
177};
178
179extern int sizeFunctions[];
180extern int nHTBuckets;
181
182afs_int32 DbVerify(struct rx_call *call, afs_int32 *status,
183 afs_int32 *orphans, afs_int32 *host);
184afs_int32 verifyTextChain(struct ubik_trans *ut, struct textBlock *tbPtr);
185
186
187#define DBBAD BUDB_DATABASEINCONSISTENT
188
189/* ------------------------------------
190 * supporting routines
191 * ------------------------------------
192 */
193
194/* BumpErrors
195 * increment the error count
196 * exit:
197 * 0 - continue
198 * 1 - maximum errors exceeded
199 */
200
201afs_int32
202BumpErrors(void)
203{
204 if (++miscData.errors >= miscData.maxErrors)
205 return (1);
206 else
207 return (0);
208}
209
210/* convertDiskAddress
211 * given a disk address, break it down into a block and entry index. These
212 * permit access to the block map information. The conversion process
213 * compares the supplied address with the alignment/type information
214 * stored in the block map.
215 * exit:
216 * 0 - ok
217 * BUDB_ADDR - address alignment checks failed
218 */
219
220afs_int32
221checkDiskAddress(unsigned long address, int type, int *blockIndexPtr,
222 int *entryIndexPtr)
223{
224 int index, offset;
225
226 if (blockIndexPtr)
227 *blockIndexPtr = -1;
228 if (entryIndexPtr)
229 *entryIndexPtr = -1;
230
231 /* This is safest way to handle totally bogus addresses (eg 0x80001234). */
232 if ((address < sizeof(db.h)) || (address >= ntohl(db.h.eofPtr)))
233 return BUDB_ADDR;
234
235 address -= sizeof(db.h);
236 index = address / BLOCKSIZE;
237 offset = address - (index * BLOCKSIZE);
238 if (offset % sizeof(afs_int32)) /* alignment check */
239 return BUDB_ADDR;
240 if (offset && (type > 0) && (type <= MAX_STRUCTURE_BLOCK_TYPE)) {
241 offset -= sizeof(struct blockHeader);
242 if ((offset < 0) || (offset % blockEntrySize[type]))
243 return BUDB_ADDR;
244 offset /= blockEntrySize[type];
245 if (offset >= blockEntries[type])
246 return BUDB_ADDR;
247 }
248 if (blockIndexPtr)
249 *blockIndexPtr = index;
250 if (entryIndexPtr)
251 *entryIndexPtr = offset;
252 return 0;
253}
254
255/* ConvertDiskAddress
256 * given a disk address, break it down into a block and entry index. These
257 * permit access to the block map information. The conversion process
258 * compares the supplied address with the alignment/type information
259 * stored in the block map.
260 * exit:
261 * 0 - ok
262 * BUDB_ADDR - address alignment checks failed
263 */
264
265afs_int32
266ConvertDiskAddress(afs_uint32 address, int *blockIndexPtr, int *entryIndexPtr)
267{
268 int index, type;
269 afs_int32 code;
270
271 index = (address - sizeof(db.h)) / BLOCKSIZE;
272 type = blockMap[index]->header.type;
273
274 code = checkDiskAddress(address, type, blockIndexPtr, entryIndexPtr);
275 return (code);
276}
277
278char *
279TypeName(int index)
280{
281 static char error[36];
282
283 if ((index < 0) || (index >= NBLOCKTYPES)) {
284 sprintf(error, "UNKNOWN_TYPE %d", index);
285 return (error);
286 }
287 return (typeName[index]);
288}
289
290int
291getDumpID(struct ubik_trans *ut,
292 struct tape *tapePtr,
293 afs_int32 *dumpID)
294{
295 struct dump d;
296 afs_int32 code;
297
298 *dumpID = 0;
299 code = dbread(ut, ntohl(tapePtr->dump), &d, sizeof(d));
300 if (!code)
301 *dumpID = ntohl(d.id);
302 return code;
303}
304
305/* ------------------------------------
306 * verification routines - structure specific
307 * ------------------------------------
308 */
309
310/* verifyDumpEntry
311 * Follow the tapes entries hanging off of a dump and verify they belong
312 * to the dump.
313 */
314afs_int32
315verifyDumpEntry(struct ubik_trans *ut, afs_int32 dumpAddr, int ai, int ao,
316 void *param)
317{
318 struct dump *dumpPtr = (struct dump *)param;
319
320 struct tape tape;
321 afs_int32 tapeAddr, tapeCount = 0, volCount = 0, appDumpCount = 0;
322 afs_int32 appDumpAddr, appDumpIndex, appDumpOffset;
323 struct dump appDump;
324 int tapeIndex, tapeOffset, ccheck = 1;
325 afs_int32 code = 0, tcode;
326 int dumpIndex, dumpOffset;
327
328 tcode = ConvertDiskAddress(dumpAddr, &dumpIndex, &dumpOffset);
329 if (tcode) {
330 Log("verifyDumpEntry: Invalid dump entry addr 0x%x\n", dumpAddr);
331 if (BumpErrors())
332 ERROR(DBBAD);
333 ERROR(0);
334 }
335
336 /* Step though list of tapes hanging off of this dump */
337 for (tapeAddr = ntohl(dumpPtr->firstTape); tapeAddr;
338 tapeAddr = ntohl(tape.nextTape)) {
339 tcode = ConvertDiskAddress(tapeAddr, &tapeIndex, &tapeOffset);
340 if (tcode) {
341 Log("verifyDumpEntry: Invalid tape entry addr 0x%x (on DumpID %u)\n", tapeAddr, ntohl(dumpPtr->id));
342 Log(" Skipping remainder of tapes in dump\n");
343 if (BumpErrors())
344 ERROR(DBBAD);
345 ccheck = 0;
346 break;
347 }
348
349 tcode = dbread(ut, tapeAddr, &tape, sizeof(tape));
350 if (tcode)
351 ERROR(BUDB_IO);
352
353 if (ntohl(tape.dump) != dumpAddr) {
354 afs_int32 did;
355
356 getDumpID(ut, &tape, &did);
357 Log("verifyDumpEntry: Tape '%s' (addr 0x%x) doesn't point to\n",
358 tape.name, tapeAddr);
359 Log(" dumpID %u (addr 0x%x). Points to DumpID %u (addr 0x%x)\n", ntohl(dumpPtr->id), dumpAddr, did, ntohl(tape.dump));
360 if (BumpErrors())
361 return (DBBAD);
362 }
363
364 /* Check if this tape entry has been examine already */
365 if (blockMap[tapeIndex]->entries[tapeOffset] & MAP_TAPEONDUMP) {
366 Log("verifyDumpEntry: Tape '%s' (addr 0x%x) on multiple dumps\n",
367 tape.name, tapeAddr);
368 if (BumpErrors())
369 return (DBBAD);
370 }
371 blockMap[tapeIndex]->entries[tapeOffset] |= MAP_TAPEONDUMP;
372
373 tapeCount++;
374 volCount += ntohl(tape.nVolumes);
375 }
376
377 if (ccheck && (ntohl(dumpPtr->nVolumes) != volCount)) {
378 Log("verifyDumpEntry: DumpID %u (addr 0x%x) volume count of %d is wrong (should be %d)\n", ntohl(dumpPtr->id), dumpAddr, ntohl(dumpPtr->nVolumes), volCount);
379 if (BumpErrors())
380 return (DBBAD);
381 }
382
383 if (volCount > misc->maxVolsPerDump)
384 misc->maxVolsPerDump = volCount;
385 if (tapeCount > misc->maxTapesPerDump)
386 misc->maxTapesPerDump = tapeCount;
387
388 /* If this is an initial dump, then step though list of appended dumps
389 * hanging off of this dump.
390 */
391 if (ntohl(dumpPtr->initialDumpID) == 0) {
392 for (appDumpAddr = ntohl(dumpPtr->appendedDumpChain); appDumpAddr;
393 appDumpAddr = ntohl(appDump.appendedDumpChain)) {
394
395 tcode =
396 ConvertDiskAddress(appDumpAddr, &appDumpIndex,
397 &appDumpOffset);
398 if (tcode) {
399 Log("verifyDumpEntry: Invalid appended dump entry addr 0x%x\n", appDumpAddr);
400 Log("Skipping remainder of appended dumps\n");
401 if (BumpErrors())
402 ERROR(DBBAD);
403 break;
404 }
405
406 /* Read the appended dump in */
407 tcode = dbread(ut, appDumpAddr, &appDump, sizeof(appDump));
408 if (tcode)
409 ERROR(BUDB_IO);
410
411 /* Verify that it points to the parent dump */
412 if (ntohl(appDump.initialDumpID) != ntohl(dumpPtr->id)) {
413 Log("verifyDumpEntry: DumpID %u (addr 0x%x) initial DumpID incorrect (is %u, should be %u)\n", ntohl(appDump.id), appDumpAddr, ntohl(appDump.initialDumpID), ntohl(dumpPtr->id));
414 if (BumpErrors())
415 return (DBBAD);
416 }
417
418 /* Check if this appended dump entry has been examined already */
419 if (blockMap[appDumpIndex]->
420 entries[appDumpOffset] & MAP_APPENDEDDUMP) {
421 Log("verifyDumpEntry: DumpID %u (addr %u) is on multiple appended dump chains\n", ntohl(appDump.id), appDumpAddr);
422 Log("Skipping remainder of appended dumps\n");
423 if (BumpErrors())
424 return (DBBAD);
425 break;
426 }
427 blockMap[appDumpIndex]->entries[appDumpOffset] |=
428 MAP_APPENDEDDUMP;
429
430 appDumpCount++;
431 }
432 }
433
434 if (appDumpCount > misc->maxAppendsPerDump)
435 misc->maxAppendsPerDump = appDumpCount;
436 misc->nDump++;
437
438 error_exit:
439 return (code);
440}
441
442/*
443 * verifyTapeEntry
444 * Follw the volume fragments hanging off of a tape entry and verify
445 * they belong to the tape.
446 */
447afs_int32
448verifyTapeEntry(struct ubik_trans *ut, afs_int32 tapeAddr, int ai, int ao,
449 void *param)
450{
451 struct tape *tapePtr = (struct tape *) param;
452 int volCount = 0, ccheck = 1;
453 afs_int32 volFragAddr;
454 int blockIndex, entryIndex;
455 struct volFragment volFragment;
456 afs_int32 code = 0, tcode;
457
458 for (volFragAddr = ntohl(tapePtr->firstVol); volFragAddr;
459 volFragAddr = ntohl(volFragment.sameTapeChain)) {
460 tcode = ConvertDiskAddress(volFragAddr, &blockIndex, &entryIndex);
461 if (tcode) {
462 afs_int32 did;
463
464 getDumpID(ut, tapePtr, &did);
465 Log("verifyTapeEntry: Invalid volFrag addr 0x%x (on tape '%s' DumpID %u)\n", volFragAddr, tapePtr->name, did);
466 Log(" Skipping remainder of volumes on tape\n");
467 if (BumpErrors())
468 ERROR(DBBAD);
469 ccheck = 0;
470 break;
471 }
472
473 tcode = dbread(ut, volFragAddr, &volFragment, sizeof(volFragment));
474 if (tcode)
475 ERROR(tcode);
476
477 if (ntohl(volFragment.tape) != tapeAddr) {
478 afs_int32 did;
479
480 getDumpID(ut, tapePtr, &did);
481 Log("verifyTapeEntry: VolFrag (addr 0x%x) doesn't point to \n",
482 volFragAddr);
483 Log(" tape '%s' DumpID %u (addr 0x%x). Points to addr 0x%x\n",
484 tapePtr->name, did, tapeAddr, ntohl(volFragment.tape));
485 if (BumpErrors())
486 ERROR(DBBAD);
487 }
488
489 /* Has this volume fragment already been examined */
490 if (blockMap[blockIndex]->entries[entryIndex] & MAP_VOLFRAGONTAPE) {
491 Log("verifyTapeEntry: VolFrag (addr %d) on multiple tapes\n",
492 volFragAddr);
493 if (BumpErrors())
494 ERROR(DBBAD);
495 }
496 blockMap[blockIndex]->entries[entryIndex] |= MAP_VOLFRAGONTAPE;
497
498 volCount++;
499 }
500
501 /* now check computed vs. recorded volume counts */
502 if (ccheck && (ntohl(tapePtr->nVolumes) != volCount)) {
503 afs_int32 did;
504
505 getDumpID(ut, tapePtr, &did);
506 Log("verifyTapeEntry: Tape '%s' DumpID %u (addr 0x%x) volFrag count of %d is wrong (should be %d)\n", tapePtr->name, did, tapeAddr, ntohl(tapePtr->nVolumes), volCount);
507 if (BumpErrors())
508 ERROR(DBBAD);
509 }
510
511 if (volCount > misc->maxVolsPerTape)
512 misc->maxVolsPerTape = volCount;
513 misc->nTape++;
514
515 error_exit:
516 return (code);
517}
518
519/*
520 * verifyVolFragEntry
521 * volume fragments are the lowest leaf describing a dump (nothing hangs off of it).
522 * So no check is done agaist it.
523 */
524afs_int32
525verifyVolFragEntry(struct ubik_trans *ut, afs_int32 va, int ai, int ao,
526 void *param)
527{
528 /* struct volFragment *v = (struct volFragment *)param; */
529 misc->nVolFrag++;
530 return 0;
531}
532
533/* verifyVolInfoEntry
534 * Follow the volume fragments hanging off of a volinfo structure and
535 * verify they belong to the volinfo structure.
536 * If the volinfo structure is at the head of the same name chain, then
537 * also verify all entries are also on the chain.
538 */
539afs_int32
540verifyVolInfoEntry(struct ubik_trans *ut, afs_int32 volInfoAddr, int ai,
541 int ao, void *param)
542{
543 struct volInfo *volInfo = (struct volInfo *) param;
544
545 int volCount = 0, ccheck = 1;
546 afs_int32 volFragAddr;
547 int blockIndex, entryIndex;
548 struct volFragment volFragment;
549 afs_int32 code = 0, tcode;
550
551 /* check each fragment attached to this volinfo structure */
552 for (volFragAddr = ntohl(volInfo->firstFragment); volFragAddr;
553 volFragAddr = ntohl(volFragment.sameNameChain)) {
554 tcode = ConvertDiskAddress(volFragAddr, &blockIndex, &entryIndex);
555 if (tcode) {
556 Log("verifyVolInfoEntry: Invalid volFrag entry addr 0x%x (on volume '%s')\n", volFragAddr, volInfo->name);
557 Log(" Skipping remainder of volumes on tape\n");
558 if (BumpErrors())
559 ERROR(DBBAD);
560 ccheck = 0;
561 break;
562 }
563
564 tcode = dbread(ut, volFragAddr, &volFragment, sizeof(volFragment));
565 if (tcode)
566 ERROR(tcode);
567
568 if (ntohl(volFragment.vol) != volInfoAddr) {
569 Log("verifyVolInfoEntry: volFrag (addr 0x%x) doesn't point to \n",
570 volFragAddr);
571 Log(" volInfo '%s' (addr 0x%x). Points to addr 0x%x\n",
572 volInfo->name, volInfoAddr, ntohl(volFragment.vol));
573 if (BumpErrors())
574 ERROR(DBBAD);
575 }
576
577 /* volume fragment already on a volinfo chain? */
578 if (blockMap[blockIndex]->entries[entryIndex] & MAP_VOLFRAGONVOL) {
579 Log("verifyVolInfoEntry: VolFrag (addr %d) on multiple volInfo chains\n", volFragAddr);
580 if (BumpErrors())
581 ERROR(DBBAD);
582 }
583 blockMap[blockIndex]->entries[entryIndex] |= MAP_VOLFRAGONVOL;
584
585 volCount++;
586 }
587
588 /* check computed vs. recorded number of fragments */
589 if (ccheck && misc->checkFragCount
590 && (ntohl(volInfo->nFrags) != volCount)) {
591 Log("verifyVolInfoEntry: VolInfo '%s' (addr 0x%x) volFrag count of %d is wrong (should be %d)\n", volInfo->name, volInfoAddr, ntohl(volInfo->nFrags), volCount);
592 if (BumpErrors())
593 ERROR(DBBAD);
594 }
595
596 if (volCount > misc->maxVolsPerVolInfo)
597 misc->maxVolsPerVolInfo = volCount;
598
599 /* Check that all volInfo structures with same name point to the same
600 * head. If sameNameHead == 0, this is the head structure so we check,
601 * otherwise ignore
602 */
603 if (volInfo->sameNameHead == 0) { /*i */
604 int viCount = 1; /* count this one */
605 struct volInfo tvi;
606 afs_int32 tviAddr;
607
608 for (tviAddr = ntohl(volInfo->sameNameChain); tviAddr;
609 tviAddr = ntohl(tvi.sameNameChain)) {
610 viCount++;
611 tcode = ConvertDiskAddress(tviAddr, &blockIndex, &entryIndex);
612 if (tcode) {
613 Log("verifyVolInfoEntry: Invalid volInfo entry %s addr 0x%x\n", volInfo->name, tviAddr);
614 Log(" Skipping remainder of volumes on same name chain\n");
615 if (BumpErrors())
616 ERROR(DBBAD);
617 code = 0;
618 break;
619 }
620
621 tcode = dbread(ut, tviAddr, &tvi, sizeof(tvi));
622 if (tcode)
623 ERROR(tcode);
624
625 if (ntohl(tvi.sameNameHead) != volInfoAddr) {
626 Log("verifyVolInfoEntry: VolInfo '%s' (addr 0x%x) doesn't point to \n", volInfo->name, tviAddr);
627 Log(" head of sameName volInfo (addr 0x%x). Points to addr 0x%x\n", volInfoAddr, ntohl(tvi.sameNameHead));
628 if (BumpErrors())
629 ERROR(DBBAD);
630 }
631
632 if (blockMap[blockIndex]->entries[entryIndex] & MAP_VOLINFOONNAME) {
633 Log("verifyVolInfoEntry: VolInfo (addr 0x%x) on multiple same name chains\n", tviAddr);
634 if (BumpErrors())
635 ERROR(DBBAD);
636 }
637 blockMap[blockIndex]->entries[entryIndex] |= MAP_VOLINFOONNAME;
638 }
639
640 /* select the passed in structure flags */
641 if (blockMap[ai]->entries[ao] & MAP_VOLINFONAMEHEAD) {
642 Log("verifyVolInfoEntry: VolInfo '%s' (addr 0x%x) is name head multiple times\n", volInfo->name, volInfoAddr);
643 if (BumpErrors())
644 ERROR(DBBAD);
645 }
646 blockMap[ai]->entries[ao] |= MAP_VOLINFONAMEHEAD;
647
648 if (viCount > misc->maxVolInfosPerName)
649 misc->maxVolInfosPerName = viCount;
650 misc->nVolName++;
651 }
652 /*i */
653 misc->nVolInfo++;
654
655 error_exit:
656 return (code);
657}
658
659
660/* ------------------------------------
661 * verification routines - general
662 * ------------------------------------
663 */
664
665/* verifyBlocks
666 * Read each block header of every 2K block and remember it in our global
667 * blockMap array. Also check that the type of block is good.
668 */
669afs_int32
670verifyBlocks(struct ubik_trans *ut)
671{
672 struct block block;
673 int blocktype;
674 afs_int32 blockAddr;
675 struct blockMap *ablockMap = 0;
676 int bmsize;
677 int i;
678 afs_int32 code = 0, tcode;
679
680 /* Remember every header of every block in the database */
681 for (i = 0; i < nBlocks; i++) {
682 /* To avoid the call from timing out, do a poll every 256 blocks */
683
684 /* read the block header */
685 blockAddr = sizeof(db.h) + (i * BLOCKSIZE);
686 tcode = dbread(ut, blockAddr, (char *)&block.h, sizeof(block.h));
687 if (tcode)
688 ERROR(tcode);
689
690 /* check the block type */
691 blocktype = block.h.type; /* char */
692 if ((blocktype < 0) || (blocktype >= NBLOCKTYPES)) {
693 Log("Block (index %d addr %d) has invalid type of %d\n", i,
694 blockAddr, blocktype);
695 ERROR(BUDB_BLOCKTYPE);
696 }
697
698 /* allocate the block map memory */
699 bmsize =
700 sizeof(*ablockMap) + (blockEntries[blocktype] -
701 1) * sizeof(ablockMap->entries[0]);
702 ablockMap = calloc(1, bmsize);
703 if (!ablockMap)
704 ERROR(BUDB_NOMEM);
705
706 ablockMap->nEntries = blockEntries[blocktype];
707
708 /* save the block header in the block map */
709 memcpy(&ablockMap->header, &block.h, sizeof(ablockMap->header));
710 blockMap[i] = ablockMap;
711 }
712
713 error_exit:
714 return (code);
715}
716
717int minvols, maxvols, ttlvols;
718
719/* verifyHashTableBlock
720 * Take a 2K hash table block and traverse its entries. Make sure each entry
721 * is of the correct type for the hash table, is hashed into the correct
722 * entry and is not threaded on multiple lists.
723 */
724afs_int32
725verifyHashTableBlock(struct ubik_trans *ut,
726 struct memoryHashTable *mhtPtr,
727 struct htBlock *htBlockPtr,
728 int old,
729 afs_int32 length, /* size of whole hash table */
730 int index, /* base index of this block */
731 int mapBit)
732{
733 int type; /* hash table type */
734 int entrySize; /* hashed entry size */
735 int blockType; /* block type for this hash table */
736 int blockIndex, entryIndex;
737 char entry[sizeof(struct block)];
738 dbadr entryAddr;
739 int hash; /* calculated hash value for entry */
740 int i, count;
741 afs_int32 code = 0, tcode;
742
743 type = ntohl(mhtPtr->ht->functionType);
744 entrySize = sizeFunctions[type];
745 blockType = hashBlockType[type];
746
747 /* step through this hash table block, being careful to stop
748 * before the end of the overall hash table
749 */
750
751 for (i = 0; (i < nHTBuckets) && (index < length); i++, index++) { /*f */
752 entryAddr = ntohl(htBlockPtr->bucket[i]);
753
754 /* if this is the old hash table, all entries below the progress mark
755 * should have been moved to the new hash table
756 */
757 if (old && (index < mhtPtr->progress) && entryAddr) {
758 Log("Old hash table not empty (entry %d) below progress (%d)\n",
759 i, mhtPtr->progress);
760 if (BumpErrors())
761 ERROR(DBBAD);
762 }
763
764 /* now walk down the chain of each bucket */
765 for (count = 0; entryAddr; count++) { /*w */
766 tcode = ConvertDiskAddress(entryAddr, &blockIndex, &entryIndex);
767 if (tcode) {
768 Log("verifyHashTableBlock: Invalid hash table chain addr 0x%x\n", entryAddr);
769 Log(" Skipping remainder of bucket %d\n", index);
770 if (BumpErrors())
771 ERROR(DBBAD);
772 code = 0;
773 break;
774 }
775
776 if (blockMap[blockIndex]->header.type != blockType) {
777 Log("Hash table chain (block index %d) incorrect\n",
778 blockIndex);
779 Log(" Table type %d traverses block type %d\n", blockType,
780 blockMap[blockIndex]->header.type);
781 Log(" Skipping remainder of bucket %d\n", index);
782 if (BumpErrors())
783 ERROR(DBBAD);
784 break;
785 }
786
787 if (dbread(ut, entryAddr, &entry[0], entrySize))
788 ERROR(DBBAD);
789
790 hash = ht_HashEntry(mhtPtr, &entry[0]) % length;
791 if (hash != index) { /* if it hashed to some other place */
792 Log("Entry (addr 0x%x) bucket %d, should be hashed into bucket %d\n", entryAddr, index, hash);
793 if (BumpErrors())
794 ERROR(DBBAD);
795 }
796
797 /* check if entry has been examined */
798 if (blockMap[blockIndex]->entries[entryIndex] & mapBit) {
799 Log("Entry (addr 0x%x) multiply referenced\n", entryAddr);
800 if (BumpErrors())
801 ERROR(DBBAD);
802 }
803 blockMap[blockIndex]->entries[entryIndex] |= mapBit;
804
805 entryAddr = ntohl(*((dbadr *) (entry + mhtPtr->threadOffset)));
806 } /*w */
807
808 /* Log("Bucket %4d contains %d entries\n", index+1, count); */
809 ttlvols += count;
810 if (count < minvols)
811 minvols = count;
812 if (count > maxvols)
813 maxvols = count;
814 } /*f */
815
816 error_exit:
817 return (code);
818}
819
820/* verifyHashTable
821 * Read each 2K block a hashtable has (both its old hastable and
822 * new hashtable) and verify the block has not been read before.
823 * Will also make call to verify entries within each 2K block of
824 * the hash table.
825 */
826afs_int32
827verifyHashTable(struct ubik_trans *ut, struct memoryHashTable *mhtPtr,
828 int mapBit)
829{
830 struct hashTable *htPtr = mhtPtr->ht;
831
832 struct htBlock hashTableBlock;
833 int tableLength; /* # entries */
834 int hashblocks; /* # blocks */
835 dbadr tableAddr; /* disk addr of hash block */
836 int blockIndex, entryIndex;
837 int old;
838 int i;
839 afs_int32 code = 0, tcode;
840
841 extern int nHTBuckets; /* # buckets in a hash table */
842
843 LogDebug(4, "Htable: length %d oldlength %d progress %d\n",
844 mhtPtr->length, mhtPtr->oldLength, mhtPtr->progress);
845
846 /* check both old and current tables */
847 for (old = 0; old <= 1; old++) { /*fo */
848 tableLength = (old ? mhtPtr->oldLength : mhtPtr->length);
849 if (tableLength == 0)
850 continue;
851 tableAddr = (old ? ntohl(htPtr->oldTable) : ntohl(htPtr->table));
852 minvols = 999999;
853 maxvols = ttlvols = 0;
854
855 /* follow the chain of hashtable blocks - avoid infinite loops */
856 hashblocks = ((tableLength - 1) / nHTBuckets) + 1; /* numb of 2K hashtable blocks */
857 for (i = 0; (tableAddr && (i < hashblocks + 5)); i++) {
858 tcode = ConvertDiskAddress(tableAddr, &blockIndex, &entryIndex);
859 if (tcode) {
860 Log("verifyHashTable: Invalid hash table chain addr 0x%x\n",
861 tableAddr);
862 Log(" Skipping remainder of hash table chain\n");
863 if (BumpErrors())
864 return (DBBAD);
865 code = 0;
866 break;
867 }
868
869 if (blockMap[blockIndex]->header.type != hashTable_BLOCK) {
870 Log("Hashtable block (index %d addr 0x%x) hashtype %d - type %d, expected type %d\n", i + 1, tableAddr, ntohl(htPtr->functionType), blockMap[blockIndex]->header.type, hashTable_BLOCK);
871 Log(" Skipping remainder of hash table chain\n");
872 if (BumpErrors())
873 ERROR(BUDB_BLOCKTYPE);
874 break;
875 }
876
877 /* check if we've examined this block before */
878 /* mark this (hash table) block as examined */
879 if (blockMap[blockIndex]->entries[entryIndex] & MAP_HTBLOCK) {
880 Log("Hash table block (index %d addr 0x%x) multiple ref\n",
881 i + 1, tableAddr);
882 if (BumpErrors())
883 ERROR(BUDB_DATABASEINCONSISTENT);
884 }
885 blockMap[blockIndex]->entries[entryIndex] |= MAP_HTBLOCK;
886
887 /* Read the actual hash table block */
888 tcode =
889 dbread(ut, tableAddr, &hashTableBlock,
890 sizeof(hashTableBlock));
891 if (tcode)
892 ERROR(tcode);
893
894 /* Verify its entries */
895 tcode =
896 verifyHashTableBlock(ut, mhtPtr, &hashTableBlock, old,
897 tableLength, (i * nHTBuckets), mapBit);
898 if (tcode)
899 ERROR(tcode);
900
901 tableAddr = ntohl(hashTableBlock.h.next);
902 }
903
904 /* Verify numb hash blocks is as it says */
905 if (i != hashblocks) {
906 Log("Incorrect number of hash chain blocks: %d (expected %d), hashtype %d\n", i, hashblocks, ntohl(htPtr->functionType));
907 if (BumpErrors())
908 ERROR(BUDB_DATABASEINCONSISTENT);
909 }
910
911 if (ttlvols)
912 Log("%d entries; %u buckets; min = %d; max = %d\n", ttlvols,
913 tableLength, minvols, maxvols);
914 } /*fo */
915
916 error_exit:
917 return (code);
918}
919
920/* verifyEntryChains
921 * do a linear walk of all the blocks. Check each block of structures
922 * to see if the actual free matches the recorded free. Also check
923 * the integrity of each allocated structure.
924 */
925afs_int32
926verifyEntryChains(struct ubik_trans *ut)
927{
928 afs_int32 code;
929 afs_int32 offset;
930 afs_int32 start;
931 int blockIndex, entryIndex;
932 char entry[sizeof(struct block)];
933 int entrySize;
934 int type;
935 int nFree;
936
937 static afs_int32(*checkEntry[NBLOCKTYPES]) (struct ubik_trans *,
938 afs_int32, int, int, void *)
939 = {
940 /* FIXME: this list does not match typeName[] and may be incorrect */
941 0, /* free block */
942 verifyVolFragEntry, verifyVolInfoEntry, verifyTapeEntry, verifyDumpEntry, 0 /* text block */
943 };
944
945 for (blockIndex = 0; blockIndex < nBlocks; blockIndex++) { /*f */
946 /* ignore non-structure or blocks with invalid type */
947 type = blockMap[blockIndex]->header.type;
948 if ((type <= 0) || (type > MAX_STRUCTURE_BLOCK_TYPE))
949 continue;
950
951 entrySize = blockEntrySize[type];
952 nFree = 0;
953
954 for (entryIndex = 0; entryIndex < blockMap[blockIndex]->nEntries; entryIndex++) { /*f */
955 offset =
956 sizeof(db.h) + (blockIndex * BLOCKSIZE) +
957 sizeof(struct blockHeader) + (entryIndex * entrySize);
958 if (dbread(ut, offset, &entry[0], entrySize))
959 return BUDB_IO;
960
961 /* check if entry is free by looking at the first "afs_int32" of the structure */
962 memcpy(&start, entry, sizeof(start));
963 if (start == 0) { /* zero is free */
964 /* Is it on any hash chain? */
965 if (blockMap[blockIndex]->entries[entryIndex] & MAP_HASHES) {
966 Log("Entry: blockindex %d, entryindex %d - marked free but hashed 0x%x\n", blockIndex, entryIndex, blockMap[blockIndex]->entries[entryIndex]);
967 if (BumpErrors())
968 return DBBAD;
969 }
970
971 blockMap[blockIndex]->entries[entryIndex] |= MAP_FREE;
972 nFree++;
973 } else {
974 /* check the entry itself for consistency */
975 code =
976 (*(checkEntry[type])) (ut, offset, blockIndex, entryIndex,
977 &entry[0]);
978 if (code)
979 return code;
980 }
981 } /*f */
982
983 /* check computed free with recorded free entries */
984 if (nFree != ntohs(blockMap[blockIndex]->header.nFree)) {
985 Log("Block (index %d) free count %d has %d free structs\n",
986 blockIndex, ntohs(blockMap[blockIndex]->header.nFree), nFree);
987 if (BumpErrors())
988 return DBBAD;
989 }
990 } /*f */
991
992 return 0;
993}
994
995
996afs_int32
997verifyFreeLists(void)
998{
999 int i;
1000 afs_int32 addr;
1001 int blockIndex, entryIndex;
1002 int nFree;
1003 afs_int32 code;
1004
1005 /* for each free list */
1006 for (i = 0; i < NBLOCKTYPES; i++) {
1007 misc->fullyFree[i] = misc->freeLength[i] = 0;
1008
1009 for (addr = ntohl(db.h.freePtrs[i]); addr;
1010 addr = ntohl(blockMap[blockIndex]->header.next)) {
1011 misc->freeLength[i]++;
1012
1013 code = ConvertDiskAddress(addr, &blockIndex, &entryIndex);
1014 if (code || (entryIndex != 0)) {
1015 Log("verifyFreeLists: Invalid free chain addr 0x%x in %s free chain\n", addr, TypeName(i));
1016 Log(" Skipping remainder of free chain\n");
1017 if (BumpErrors())
1018 return (DBBAD);
1019 break;
1020 }
1021
1022 /* check block type */
1023 if (blockMap[blockIndex]->header.type != i) {
1024 Log("verifyFreeLists: Found %s type in %s free chain (addr 0x%x)\n",
1025 TypeName(blockMap[blockIndex]->header.type), TypeName(i),
1026 addr);
1027 if (BumpErrors())
1028 return (DBBAD);
1029 }
1030
1031 /* If entire block isn't free, check if count of free entries is ok */
1032 nFree = ntohs(blockMap[blockIndex]->header.nFree);
1033 if (i != free_BLOCK) {
1034 if ((nFree <= 0) || (nFree > blockEntries[i])) {
1035 Log("verifyFreeLists: Illegal free count %d on %s free chain\n", nFree, TypeName(i));
1036 if (BumpErrors())
1037 return (DBBAD);
1038 } else if (nFree == blockEntries[i]) {
1039 misc->fullyFree[i]++;
1040 }
1041 }
1042
1043 /* Check if already examined the block */
1044 if (blockMap[blockIndex]->free) {
1045 Log("verifyFreeLists: %s free chain block at addr 0x%x multiply threaded\n", TypeName(i), addr);
1046 if (BumpErrors())
1047 return DBBAD;
1048 }
1049 blockMap[blockIndex]->free++;
1050 }
1051 }
1052
1053 return 0;
1054}
1055
1056/* verifyMapBits
1057 * Examines each entry to make sure it was traversed appropriately by
1058 * checking the bits for compatibility.
1059 */
1060afs_int32
1061verifyMapBits(void)
1062{
1063 int blockIndex, entryIndex, i, entrySize, type, bits;
1064 afs_int32 offset;
1065
1066 for (blockIndex = 0; blockIndex < nBlocks; blockIndex++) {
1067 /* If no entries in this block, then the block should be marked free */
1068 if ((blockMap[blockIndex]->nEntries == 0)
1069 && !blockMap[blockIndex]->free) {
1070 Log("verifyMapBits: Orphan free block (index %d)\n", blockIndex);
1071 if (BumpErrors())
1072 return DBBAD;
1073 }
1074
1075 /* check each entry */
1076 for (entryIndex = 0; entryIndex < blockMap[blockIndex]->nEntries; entryIndex++) { /*f */
1077#ifndef AFS_PTHREAD_ENV
1078 if ((entryIndex % 1024) == 0)
1079 IOMGR_Poll();
1080#endif
1081 bits = blockMap[blockIndex]->entries[entryIndex];
1082
1083 for (i = 0; i < NMAPCs; i++)
1084 if ((bits & mapC[i].trigger) == mapC[i].trigger)
1085 break;
1086
1087 if (i >= NMAPCs) {
1088 char logstr[256];
1089
1090 type = blockMap[blockIndex]->header.type;
1091 entrySize = blockEntrySize[type];
1092 offset =
1093 sizeof(db.h) + (blockIndex * BLOCKSIZE) +
1094 sizeof(struct blockHeader) + (entryIndex * entrySize);
1095
1096 sprintf(logstr, "%s entry Block %d, Entry %d, (addr 0x%x)",
1097 TypeName(type), blockIndex, entryIndex, offset);
1098
1099 if (!bits)
1100 strcat(logstr, ": An orphaned entry");
1101 if (bits & MAP_FREE)
1102 strcat(logstr, ": A valid free block");
1103 if (bits & MAP_HTBLOCK)
1104 strcat(logstr, ": A valid hash-table block");
1105 if (bits & MAP_TEXTBLOCK)
1106 strcat(logstr, ": A valid text block");
1107 if (bits & (MAP_DUMPHASH | MAP_IDHASH)) {
1108 if (!(bits & MAP_DUMPHASH))
1109 strcat(logstr,
1110 ": A dump not on dump-name hash-chain");
1111 else if (!(bits & MAP_IDHASH))
1112 strcat(logstr, ": A dump not on dump-id hash-chain");
1113 else
1114 strcat(logstr, ": A valid dump entry");
1115 }
1116 if (bits & (MAP_TAPEHASH | MAP_TAPEONDUMP)) {
1117 if (!(bits & MAP_TAPEHASH))
1118 strcat(logstr,
1119 ": A tape not on tape-name hash-chain");
1120 else if (!(bits & MAP_TAPEONDUMP))
1121 strcat(logstr, ": A tape not associated with a dump");
1122 else
1123 strcat(logstr, ": A valid tape entry");
1124 }
1125 if (bits & MAP_VOLINFOONNAME)
1126 strcat(logstr,
1127 ": A valid volInfo on a volume-name chain");
1128 if (bits & (MAP_VOLINFONAMEHEAD | MAP_VOLHASH)) {
1129 if (!(bits & MAP_VOLINFONAMEHEAD))
1130 strcat(logstr,
1131 ": A volInfo not the head of a volume-name hash-chain");
1132 else if (!(bits & MAP_VOLHASH))
1133 strcat(logstr,
1134 ": A volInfo not on volume-name hash-chain");
1135 else
1136 strcat(logstr,
1137 ": A valid volInfo in volume-name hash-chain");
1138 }
1139 if (bits & (MAP_VOLFRAGONTAPE | MAP_VOLFRAGONVOL)) {
1140 if (!(bits & MAP_VOLFRAGONTAPE))
1141 strcat(logstr,
1142 ": A volFrag not associated with a tape");
1143 else if (!(bits & MAP_VOLFRAGONVOL))
1144 strcat(logstr,
1145 ": A volFrag not associated with a volume");
1146 else
1147 strcat(logstr, ": A valid volFrag entry");
1148 }
1149 Log("%s\n", logstr);
1150
1151 if (BumpErrors())
1152 return DBBAD;
1153 }
1154 } /*f */
1155 }
1156
1157 return 0;
1158}
1159
1160afs_int32
1161verifyText(struct ubik_trans *ut)
1162{
1163 int i;
1164 afs_int32 code;
1165
1166 /* check each of the text types in use */
1167 for (i = 0; i < TB_NUM; i++) {
1168 Log("Verify Text: %s", textName[i]);
1169 code = verifyTextChain(ut, &db.h.textBlock[i]);
1170 if (code)
1171 return (code);
1172 }
1173 return (0);
1174}
1175
1176/* verifyTextChain
1177 * check the integrity of a text chain. Also checks the new chain.
1178 */
1179afs_int32
1180verifyTextChain(struct ubik_trans *ut, struct textBlock *tbPtr)
1181{
1182 dbadr blockAddr;
1183 int blockIndex, entryIndex;
1184 struct block block;
1185 afs_int32 size;
1186 int new;
1187 afs_int32 code = 0, tcode;
1188
1189 for (new = 0; new < 2; new++) {
1190 size = 0;
1191
1192 for (blockAddr =
1193 (new ? ntohl(tbPtr->newTextAddr) : ntohl(tbPtr->textAddr));
1194 blockAddr; blockAddr = ntohl(block.h.next)) {
1195 tcode = ConvertDiskAddress(blockAddr, &blockIndex, &entryIndex);
1196 if (tcode) {
1197 Log("verifyTextChain: Invalid %s text block addr 0x%x\n",
1198 (new ? "new" : ""), blockAddr);
1199 Log(" Skipping remainder of text chain\n");
1200 if (BumpErrors())
1201 ERROR(tcode);
1202 break;
1203 }
1204
1205 tcode = dbread(ut, blockAddr, &block, sizeof(block));
1206 if (tcode)
1207 ERROR(tcode);
1208
1209 if (blockMap[blockIndex]->entries[entryIndex] & MAP_TEXTBLOCK) {
1210 Log("verifyTextChain: Text block (addr 0x%x) multiply chained\n", blockAddr);
1211 if (BumpErrors())
1212 ERROR(DBBAD);
1213 }
1214 blockMap[blockIndex]->entries[entryIndex] |= MAP_TEXTBLOCK;
1215
1216 size += BLOCK_DATA_SIZE;
1217 }
1218
1219 if (ntohl(new ? tbPtr->newsize : tbPtr->size) > size) {
1220 Log("verifyTextChain: Text block %s size %d > computed capacity %d\n", (new ? "new" : ""), ntohl(new ? tbPtr->newsize : tbPtr->size), size);
1221 if (BumpErrors())
1222 ERROR(DBBAD);
1223 }
1224 }
1225
1226 error_exit:
1227 return (code);
1228}
1229
1230/* -----------------------------------------
1231 * verification driver routines
1232 * -----------------------------------------
1233 */
1234
1235/* verifyDatabase
1236 * Check the integrity of the database
1237 */
1238
1239afs_int32
1240verifyDatabase(struct ubik_trans *ut,
1241 FILE *recreateFile) /* not used */
1242{
1243 afs_int32 eof;
1244 int bmsize;
1245 afs_int32 code = 0, tcode = 0;
1246
1247 extern int nBlocks; /* no. blocks in database */
1248
1249 /* clear verification statistics */
1250 misc = &miscData;
1251 memset(&miscData, 0, sizeof(miscData));
1252
1253#ifdef PDEBUG
1254 miscData.maxErrors = 1000000;
1255#else
1256 miscData.maxErrors = 50; /* Catch the first 50 errors */
1257#endif
1258 miscData.veryLongChain = 0;
1259 miscData.checkFragCount = 1; /* check frags */
1260
1261 /* check eofPtr */
1262 eof = ntohl(db.h.eofPtr);
1263 eof -= sizeof(db.h); /* subtract header */
1264 nBlocks = eof / BLOCKSIZE;
1265
1266 Log("Verify of backup database started\n");
1267 Log("Database is %u. %d blocks of %d Bytes\n", eof, nBlocks, BLOCKSIZE);
1268
1269 if ((eof < 0) || (nBlocks * BLOCKSIZE != eof)) {
1270 Log("Database eofPtr (%d) bad, blocksize %d\n", eof, BLOCKSIZE);
1271 ERROR(DBBAD);
1272 }
1273
1274 /* set size of database */
1275 miscData.nBlocks = nBlocks;
1276
1277 if (nBlocks == 0)
1278 ERROR(0); /* Nothing to check? */
1279
1280 /* construct block map - first level is the array of pointers */
1281 bmsize = nBlocks * sizeof(struct blockMap *);
1282 blockMap = calloc(1, bmsize);
1283 if (!blockMap)
1284 ERROR(BUDB_NOMEM);
1285
1286 /* verify blocks and construct the block map */
1287 Log("Read header of every block\n");
1288 tcode = verifyBlocks(ut);
1289 if (tcode)
1290 ERROR(tcode);
1291
1292 /* check the various hash tables */
1293 Log("Verify volume name hash table\n");
1294 tcode = verifyHashTable(ut, &db.volName, MAP_VOLHASH);
1295 if (tcode)
1296 ERROR(tcode);
1297
1298 Log("Verify tape name hash table\n");
1299 tcode = verifyHashTable(ut, &db.tapeName, MAP_TAPEHASH);
1300 if (tcode)
1301 ERROR(tcode);
1302
1303 Log("Verify dump name hash table\n");
1304 tcode = verifyHashTable(ut, &db.dumpName, MAP_DUMPHASH);
1305 if (tcode)
1306 ERROR(tcode);
1307
1308 Log("Verify dump id hash table\n");
1309 tcode = verifyHashTable(ut, &db.dumpIden, MAP_IDHASH);
1310 if (tcode)
1311 ERROR(tcode);
1312
1313 /* check the entry chains */
1314 Log("Verify all blocks and entries\n");
1315 tcode = verifyEntryChains(ut);
1316 if (tcode)
1317 ERROR(tcode);
1318
1319 /* check text blocks - Log message in verifyText */
1320 tcode = verifyText(ut);
1321 if (tcode)
1322 ERROR(tcode);
1323
1324 /* check free list */
1325 Log("Verify Free Lists\n");
1326 tcode = verifyFreeLists();
1327 if (tcode)
1328 ERROR(tcode);
1329
1330 /* check entry map bit compatibility */
1331
1332 Log("Verify Map bits\n");
1333 tcode = verifyMapBits();
1334 if (tcode)
1335 ERROR(tcode);
1336
1337 error_exit:
1338 /* free the block map */
1339 if (blockMap != 0) {
1340 int i;
1341
1342 /* free all the individual maps */
1343 for (i = 0; i < nBlocks; i++) {
1344 if (blockMap[i])
1345 free(blockMap[i]);
1346 }
1347
1348 /* free the pointer array */
1349 free(blockMap);
1350 blockMap = 0;
1351 }
1352
1353 if (!tcode) {
1354 Log("# 2K database blocks = %d\n", miscData.nBlocks);
1355 Log("# Dump entries found = %d. 3 dumps per block\n",
1356 miscData.nDump);
1357 Log(" max tapes on a dump = %d\n", miscData.maxTapesPerDump);
1358 Log(" max volumes on a dump = %d\n", miscData.maxVolsPerDump);
1359 Log(" max appends on a dump = %d\n", miscData.maxAppendsPerDump);
1360 Log(" # Blocks with space = %d\n", miscData.freeLength[4]);
1361 Log(" # of those fully free = %d\n", miscData.fullyFree[4]);
1362 Log("# Tape entries found = %d. 20 tapes per block\n",
1363 miscData.nTape);
1364 Log(" max volumes on a tape = %d\n", miscData.maxVolsPerTape);
1365 Log(" # Blocks with space = %d\n", miscData.freeLength[3]);
1366 Log(" # of those fully free = %d\n", miscData.fullyFree[3]);
1367 Log("# VolInfo entries found = %d. 20 volInfos per block\n",
1368 miscData.nVolInfo);
1369 Log(" # head of sameNameCh = %d\n", miscData.nVolName);
1370 Log(" max on a sameNameCh = %d\n", miscData.maxVolInfosPerName);
1371 Log(" max VolFrags on chain = %d\n", miscData.maxVolsPerVolInfo);
1372 Log(" # Blocks with space = %d\n", miscData.freeLength[2]);
1373 Log(" # of those fully free = %d\n", miscData.fullyFree[2]);
1374 Log("# VolFrag entries found = %d. 45 VolFrags per block\n",
1375 miscData.nVolFrag);
1376 Log(" # Blocks with space = %d\n", miscData.freeLength[1]);
1377 Log(" # of those fully free = %d\n", miscData.fullyFree[1]);
1378 Log("# free blocks = %d\n", miscData.freeLength[0]);
1379 }
1380
1381 Log("Verify of database completed. %d errors found\n", miscData.errors);
1382
1383 if (miscData.errors && !code)
1384 code = DBBAD;
1385 return (code);
1386}
1387
1388
1389/* -----------------------------
1390 * interface routines
1391 * -----------------------------
1392 */
1393
1394/* BUDB_DbVerify
1395 * check the integrity of the database
1396 * exit:
1397 * status - integrity: 0, ok; n, not ok (error value)
1398 * orphans - no. of orphan blocks
1399 * host - address of host that did verification
1400 */
1401afs_int32
1402SBUDB_DbVerify(struct rx_call *call, afs_int32 *status, afs_int32 *orphans,
1403 afs_int32 *host)
1404{
1405 afs_int32 code;
1406
1407 code = DbVerify(call, status, orphans, host);
1408 osi_auditU(call, BUDB_DBVfyEvent, code, AUD_END);
1409 return code;
1410}
1411
1412afs_int32
1413DbVerify(struct rx_call *call, afs_int32 *status, afs_int32 *orphans,
1414 afs_int32 *host)
1415{
1416 struct ubik_trans *ut = 0;
1417 afs_int32 code = 0, tcode;
1418 char hostname[64];
1419 struct hostent *th;
1420
1421 if (callPermitted(call) == 0)
1422 ERROR(BUDB_NOTPERMITTED);
1423
1424 tcode = InitRPC(&ut, LOCKREAD, 1);
1425 if (tcode)
1426 ERROR(tcode);
1427
1428 tcode = verifyDatabase(ut, 0); /* check the database */
1429 if (tcode)
1430 ERROR(tcode);
1431
1432 error_exit:
1433 if (ut) {
1434 if (code)
1435 ubik_AbortTrans(ut);
1436 else
1437 code = ubik_EndTrans(ut);
1438 }
1439
1440 *status = code;
1441 *orphans = 0;
1442
1443 gethostname(hostname, sizeof(hostname));
1444 th = gethostbyname(hostname);
1445 if (!th)
1446 *host = 0;
1447 else {
1448 memcpy(host, th->h_addr, sizeof(afs_int32));
1449 *host = ntohl(*host);
1450 }
1451
1452 return (0);
1453}
1454
1455/* ----------------------
1456 * debug support
1457 * ----------------------
1458 */
1459
1460/* check_header
1461 * do a simple sanity check on the database header
1462 */
1463void
1464check_header(char *callerst)
1465{
1466 static int iteration_count = 0;
1467 afs_int32 eof;
1468
1469 eof = ntohl(db.h.eofPtr);
1470 if ((eof == 0) || (eof < 0)) {
1471 Log("Eof check failed, caller %s, eof 0x%x\n", callerst, eof);
1472 }
1473
1474 eof -= sizeof(db.h);
1475 if (eof < 0) {
1476 Log("Adjusted Eof check failed, caller %s, eof 0x%x\n", callerst,
1477 eof);
1478 }
1479
1480 iteration_count++;
1481 if (iteration_count >= 10) {
1482 Log("Eof ptr is 0x%x\n", eof);
1483 iteration_count = 0;
1484 }
1485}