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
11 * Dump is made to a local file. Structures are dumped in network byte order
12 * for transportability between hosts
15 #include <afsconfig.h>
16 #include <afs/param.h>
24 #include <netinet/in.h>
25 #include <sys/param.h>
28 #include <sys/types.h>
36 #include "error_macros.h"
37 #include "budb_errs.h"
38 #include "afs/audit.h"
41 /* dump ubik database - routines to scan the database and dump all
45 /* -----------------------
46 * synchronization on pipe
47 * -----------------------
50 /* interlocking for database dump */
53 dumpSyncP dumpSyncPtr = &dumpSync;
57 * check if we should dump more of the database. Waits for the reader
58 * to drain the information before allowing the writer to proceed.
68 extern dumpSyncP dumpSyncPtr;
70 ObtainWriteLock(&dumpSyncPtr->ds_lock);
72 /* let the pipe drain */
73 while (dumpSyncPtr->ds_bytes > 0) {
74 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
75 dumpSyncPtr->ds_readerStatus = 0;
76 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
78 LogError(code, "canWrite: Signal delivery failed\n");
80 dumpSyncPtr->ds_writerStatus = DS_WAITING;
81 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
82 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
83 ObtainWriteLock(&dumpSyncPtr->ds_lock);
90 * record the fact that nbytes have been written. Signal the reader
91 * to proceed, and unlock.
100 extern dumpSyncP dumpSyncPtr;
102 dumpSyncPtr->ds_bytes += nbytes;
103 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
104 dumpSyncPtr->ds_readerStatus = 0;
105 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
107 LogError(code, "haveWritten: Signal delivery failed\n");
109 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
113 * wait for the reader to drain all the information, and then set the
122 /* wait for the reader */
123 ObtainWriteLock(&dumpSyncPtr->ds_lock);
124 while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
125 LogDebug(4, "doneWriting: waiting for Reader\n");
126 dumpSyncPtr->ds_writerStatus = DS_WAITING;
127 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
128 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
129 ObtainWriteLock(&dumpSyncPtr->ds_lock);
132 LogDebug(4, "doneWriting: setting done\n");
134 /* signal that we are done */
136 dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
138 dumpSyncPtr->ds_writerStatus = DS_DONE;
139 dumpSyncPtr->ds_readerStatus = 0;
140 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
142 LogError(code, "doneWriting: Signal delivery failed\n");
143 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
147 * ut - setup and pass down
151 * write header appropriate for requested structure type
155 writeStructHeader(fid, type)
159 struct structDumpHeader hostDumpHeader, netDumpHeader;
161 hostDumpHeader.type = type;
162 hostDumpHeader.structversion = 1;
167 hostDumpHeader.size = sizeof(struct DbHeader);
171 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
175 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
179 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
183 hostDumpHeader.size = 0;
187 LogError(0, "writeStructHeader: invalid type %d\n", type);
191 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
193 if (canWrite(fid) <= 0)
194 return (BUDB_DUMPFAILED);
195 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
196 sizeof(netDumpHeader))
197 return (BUDB_DUMPFAILED);
198 haveWritten(sizeof(netDumpHeader));
204 * write header appropriate for requested structure type
208 writeTextHeader(fid, type)
212 struct structDumpHeader hostDumpHeader, netDumpHeader;
214 hostDumpHeader.structversion = 1;
217 case TB_DUMPSCHEDULE:
218 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
222 hostDumpHeader.type = SD_TEXT_VOLUMESET;
226 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
230 LogError(0, "writeTextHeader: invalid type %d\n", type);
234 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
235 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
237 if (canWrite(fid) <= 0)
238 return (BUDB_DUMPFAILED);
240 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
241 sizeof(netDumpHeader))
242 return (BUDB_DUMPFAILED);
244 haveWritten(sizeof(netDumpHeader));
253 struct DbHeader header;
255 afs_int32 code = 0, tcode;
257 extern struct memoryDB db;
259 /* check the memory database header for integrity */
260 if (db.h.version != db.h.checkVersion)
261 ERROR(BUDB_DATABASEINCONSISTENT);
265 /* copy selected fields. Source is in xdr format. */
266 header.dbversion = db.h.version;
267 header.created = htonl(curtime);
268 strcpy(header.cell, "");
269 header.lastDumpId = db.h.lastDumpId;
270 header.lastInstanceId = db.h.lastInstanceId;
271 header.lastTapeId = db.h.lastTapeId;
273 tcode = writeStructHeader(fid, SD_DBHEADER);
277 if (canWrite(fid) <= 0)
278 ERROR(BUDB_DUMPFAILED);
280 if (write(fid, &header, sizeof(header)) != sizeof(header))
281 ERROR(BUDB_DUMPFAILED);
283 haveWritten(sizeof(header));
290 * write out a dump entry structure
294 writeDump(fid, dumpPtr)
298 struct budb_dumpEntry dumpEntry;
299 afs_int32 code = 0, tcode;
301 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
305 writeStructHeader(fid, SD_DUMP);
307 if (canWrite(fid) <= 0)
308 ERROR(BUDB_DUMPFAILED);
310 if (write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry))
311 ERROR(BUDB_DUMPFAILED);
312 haveWritten(sizeof(dumpEntry));
319 writeTape(fid, tapePtr, dumpid)
321 struct tape *tapePtr;
324 struct budb_tapeEntry tapeEntry;
325 afs_int32 code = 0, tcode;
327 tcode = writeStructHeader(fid, SD_TAPE);
331 tapeToBudbTape(tapePtr, &tapeEntry);
333 tapeEntry.dump = htonl(dumpid);
335 if (canWrite(fid) <= 0)
336 ERROR(BUDB_DUMPFAILED);
338 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
339 ERROR(BUDB_DUMPFAILED);
341 haveWritten(sizeof(tapeEntry));
347 /* combines volFragment and volInfo */
350 writeVolume(ut, fid, volFragmentPtr, volInfoPtr, dumpid, tapeName)
351 struct ubik_trans *ut;
353 struct volFragment *volFragmentPtr;
354 struct volInfo *volInfoPtr;
358 struct budb_volumeEntry budbVolume;
361 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
363 budbVolume.dump = htonl(dumpid);
364 strcpy(budbVolume.tape, tapeName);
366 writeStructHeader(fid, SD_VOLUME);
368 if (canWrite(fid) <= 0)
369 ERROR(BUDB_DUMPFAILED);
371 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
372 ERROR(BUDB_DUMPFAILED);
374 haveWritten(sizeof(budbVolume));
380 /* -------------------
381 * handlers for the text blocks
382 * -------------------
386 * make sure a text lock is NOT held
398 if ((textType < 0) || (textType > TB_NUM - 1))
399 return (BUDB_BADARGUMENT);
401 lockPtr = &db.h.textLocks[textType];
403 if (lockPtr->lockState != 0)
404 return (BUDB_LOCKED);
409 * check the integrity of the specified text type
412 checkText(ut, textType)
413 struct ubik_trans *ut;
416 struct textBlock *tbPtr;
417 afs_int32 nBytes = 0; /* accumulated actual size */
424 tbPtr = &db.h.textBlock[textType];
425 blockAddr = ntohl(tbPtr->textAddr);
426 size = ntohl(tbPtr->size);
428 while (blockAddr != 0) {
431 cdbread(ut, text_BLOCK, blockAddr, (char *)&block, sizeof(block));
436 if (block.h.type != text_BLOCK)
437 ERROR(BUDB_DATABASEINCONSISTENT);
439 /* add up the size */
440 nBytes += BLOCK_DATA_SIZE;
442 blockAddr = ntohl(block.h.next);
445 /* ensure that we have at least the expected amount of text */
447 ERROR(BUDB_DATABASEINCONSISTENT);
455 * textType - type of text block, e.g. TB_DUMPSCHEDULE
459 writeText(ut, fid, textType)
460 struct ubik_trans *ut;
464 struct textBlock *tbPtr;
465 afs_int32 textSize, writeSize;
470 /* check lock is free */
471 code = checkLock(textType);
475 /* ensure that this block has the correct type */
476 code = checkText(ut, textType);
478 LogError(0, "writeText: text type %d damaged\n", textType);
482 tbPtr = &db.h.textBlock[textType];
483 textSize = ntohl(tbPtr->size);
484 dbAddr = ntohl(tbPtr->textAddr);
487 goto error_exit; /* Don't save anything if no blocks */
489 writeTextHeader(fid, textType);
492 code = cdbread(ut, text_BLOCK, dbAddr, (char *)&block, sizeof(block));
496 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
500 if (canWrite(fid) <= 0)
501 ERROR(BUDB_DUMPFAILED);
503 if (write(fid, &block.a[0], writeSize) != writeSize)
506 haveWritten(writeSize);
507 textSize -= writeSize;
509 dbAddr = ntohl(block.h.next);
516 #define MAXAPPENDS 200
519 writeDatabase(ut, fid)
520 struct ubik_trans *ut;
523 dbadr dbAddr, dbAppAddr;
524 struct dump diskDump, apDiskDump;
526 struct tape diskTape;
528 struct volFragment diskVolFragment;
529 struct volInfo diskVolInfo;
533 afs_int32 code = 0, tcode;
534 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
536 struct memoryHashTable *mht;
538 LogDebug(4, "writeDatabase:\n");
540 /* write out a header identifying this database etc */
541 tcode = writeDbHeader(fid);
543 LogError(tcode, "writeDatabase: Can't write Header\n");
547 /* write out the tree of dump structures */
549 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
551 LogError(tcode, "writeDatabase: Can't get dump type\n");
552 ERROR(BUDB_BADARGUMENT);
555 for (old = 0; old <= 1; old++) {
557 /* only two states, old or not old */
558 length = (old ? mht->oldLength : mht->length);
562 for (hash = 0; hash < length; hash++) {
564 /* dump all the dumps in this hash bucket
566 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*initialDumps */
567 /* now check if this dump had any errors/inconsistencies.
568 * If so, don't dump it
570 if (badEntry(dbAddr)) {
572 "writeDatabase: Damaged dump entry at addr 0x%x\n",
574 Log(" Skipping remainder of dumps on hash chain %d\n",
580 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
584 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
586 Log(" Skipping remainder of dumps on hash chain %d\n",
591 /* Skip appended dumps, only start with initial dumps */
592 if (diskDump.initialDumpID != 0)
595 /* Skip appended dumps, only start with initial dumps. Then
596 * follow the appended dump chain so they are in order for restore.
598 appcount = numaddrs = 0;
599 for (dbAppAddr = dbAddr; dbAppAddr;
600 dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
602 /* Check to see if we have a circular loop of appended dumps */
603 for (j = 0; j < numaddrs; j++) {
604 if (appDumpAddrs[j] == dbAppAddr)
605 break; /* circular loop */
607 if (j < numaddrs) { /* circular loop */
608 Log("writeDatabase: Circular loop found in appended dumps\n");
609 Log("Skipping rest of appended dumps of dumpID %u\n",
613 if (numaddrs >= MAXAPPENDS)
614 numaddrs = MAXAPPENDS - 1; /* don't overflow */
615 appDumpAddrs[numaddrs] = dbAppAddr;
618 /* If we dump a 1000 appended dumps, assume a loop */
619 if (appcount >= 5 * MAXAPPENDS) {
620 Log("writeDatabase: Potential circular loop of appended dumps\n");
621 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
626 /* Read the dump entry */
627 if (dbAddr == dbAppAddr) {
628 /* First time through, don't need to read the dump entry again */
629 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
631 if (badEntry(dbAppAddr)) {
633 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
635 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
640 cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
644 "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
646 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
650 /* Verify that this appended dump points to the initial dump */
651 if (ntohl(apDiskDump.initialDumpID) !=
652 ntohl(diskDump.id)) {
654 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
655 ntohl(apDiskDump.id),
657 Log(" Skipping this appended dump\n");
662 /* Save the dump entry */
663 tcode = writeDump(fid, &apDiskDump);
666 "writeDatabase: Can't write dump entry\n");
670 /* For each tape on this dump
672 for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) { /*tapes */
673 /* read the tape entry */
675 cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
679 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
680 tapeAddr, ntohl(apDiskDump.id));
681 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
685 /* Save the tape entry */
687 writeTape(fid, &diskTape, ntohl(apDiskDump.id));
690 "writeDatabase: Can't write tape entry\n");
694 /* For each volume on this tape.
696 for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) { /*volumes */
697 /* Read the volume Fragment entry */
699 cdbread(ut, volFragment_BLOCK, volFragAddr,
701 sizeof(diskVolFragment));
704 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
705 volFragAddr, ntohl(apDiskDump.id));
706 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
710 /* Read the volume Info entry */
712 cdbread(ut, volInfo_BLOCK,
713 ntohl(diskVolFragment.vol),
714 &diskVolInfo, sizeof(diskVolInfo));
717 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
718 ntohl(diskVolFragment.vol),
719 ntohl(apDiskDump.id));
720 Log(" Skipping volume on tape '%s'\n",
725 /* Save the volume entry */
727 writeVolume(ut, fid, &diskVolFragment,
729 ntohl(apDiskDump.id),
733 "writeDatabase: Can't write volume entry\n");
743 /* write out the textual configuration information */
744 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
746 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
749 tcode = writeText(ut, fid, TB_VOLUMESET);
751 LogError(tcode, "writeDatabase: Can't write volume set\n");
754 tcode = writeText(ut, fid, TB_TAPEHOSTS);
756 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
760 tcode = writeStructHeader(fid, SD_END);
762 LogError(tcode, "writeDatabase: Can't write end savedb\n");
778 afs_int32 in, out, except;
789 code = IOMGR_Select(32, &in, &out, &except, &tp);