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>
43 #include "error_macros.h"
44 #include "budb_errs.h"
45 #include "afs/audit.h"
48 /* dump ubik database - routines to scan the database and dump all
52 /* -----------------------
53 * synchronization on pipe
54 * -----------------------
57 /* interlocking for database dump */
60 dumpSyncP dumpSyncPtr = &dumpSync;
64 * check if we should dump more of the database. Waits for the reader
65 * to drain the information before allowing the writer to proceed.
75 extern dumpSyncP dumpSyncPtr;
77 ObtainWriteLock(&dumpSyncPtr->ds_lock);
79 /* let the pipe drain */
80 while (dumpSyncPtr->ds_bytes > 0) {
81 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
82 dumpSyncPtr->ds_readerStatus = 0;
83 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
85 LogError(code, "canWrite: Signal delivery failed\n");
87 dumpSyncPtr->ds_writerStatus = DS_WAITING;
88 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
89 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
90 ObtainWriteLock(&dumpSyncPtr->ds_lock);
97 * record the fact that nbytes have been written. Signal the reader
98 * to proceed, and unlock.
107 extern dumpSyncP dumpSyncPtr;
109 dumpSyncPtr->ds_bytes += nbytes;
110 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
111 dumpSyncPtr->ds_readerStatus = 0;
112 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
114 LogError(code, "haveWritten: Signal delivery failed\n");
116 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
120 * wait for the reader to drain all the information, and then set the
129 /* wait for the reader */
130 ObtainWriteLock(&dumpSyncPtr->ds_lock);
131 while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
132 LogDebug(4, "doneWriting: waiting for Reader\n");
133 dumpSyncPtr->ds_writerStatus = DS_WAITING;
134 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
135 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
136 ObtainWriteLock(&dumpSyncPtr->ds_lock);
139 LogDebug(4, "doneWriting: setting done\n");
141 /* signal that we are done */
143 dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
145 dumpSyncPtr->ds_writerStatus = DS_DONE;
146 dumpSyncPtr->ds_readerStatus = 0;
147 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
149 LogError(code, "doneWriting: Signal delivery failed\n");
150 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
154 * ut - setup and pass down
158 * write header appropriate for requested structure type
162 writeStructHeader(fid, type)
166 struct structDumpHeader hostDumpHeader, netDumpHeader;
168 hostDumpHeader.type = type;
169 hostDumpHeader.structversion = 1;
174 hostDumpHeader.size = sizeof(struct DbHeader);
178 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
182 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
186 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
190 hostDumpHeader.size = 0;
194 LogError(0, "writeStructHeader: invalid type %d\n", type);
198 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
200 if (canWrite(fid) <= 0)
201 return (BUDB_DUMPFAILED);
202 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
203 sizeof(netDumpHeader))
204 return (BUDB_DUMPFAILED);
205 haveWritten(sizeof(netDumpHeader));
211 * write header appropriate for requested structure type
215 writeTextHeader(fid, type)
219 struct structDumpHeader hostDumpHeader, netDumpHeader;
221 hostDumpHeader.structversion = 1;
224 case TB_DUMPSCHEDULE:
225 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
229 hostDumpHeader.type = SD_TEXT_VOLUMESET;
233 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
237 LogError(0, "writeTextHeader: invalid type %d\n", type);
241 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
242 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
244 if (canWrite(fid) <= 0)
245 return (BUDB_DUMPFAILED);
247 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
248 sizeof(netDumpHeader))
249 return (BUDB_DUMPFAILED);
251 haveWritten(sizeof(netDumpHeader));
260 struct DbHeader header;
262 afs_int32 code = 0, tcode;
264 extern struct memoryDB db;
266 /* check the memory database header for integrity */
267 if (db.h.version != db.h.checkVersion)
268 ERROR(BUDB_DATABASEINCONSISTENT);
272 /* copy selected fields. Source is in xdr format. */
273 header.dbversion = db.h.version;
274 header.created = htonl(curtime);
275 strcpy(header.cell, "");
276 header.lastDumpId = db.h.lastDumpId;
277 header.lastInstanceId = db.h.lastInstanceId;
278 header.lastTapeId = db.h.lastTapeId;
280 tcode = writeStructHeader(fid, SD_DBHEADER);
284 if (canWrite(fid) <= 0)
285 ERROR(BUDB_DUMPFAILED);
287 if (write(fid, &header, sizeof(header)) != sizeof(header))
288 ERROR(BUDB_DUMPFAILED);
290 haveWritten(sizeof(header));
297 * write out a dump entry structure
301 writeDump(fid, dumpPtr)
305 struct budb_dumpEntry dumpEntry;
306 afs_int32 code = 0, tcode;
308 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
312 writeStructHeader(fid, SD_DUMP);
314 if (canWrite(fid) <= 0)
315 ERROR(BUDB_DUMPFAILED);
317 if (write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry))
318 ERROR(BUDB_DUMPFAILED);
319 haveWritten(sizeof(dumpEntry));
326 writeTape(fid, tapePtr, dumpid)
328 struct tape *tapePtr;
331 struct budb_tapeEntry tapeEntry;
332 afs_int32 code = 0, tcode;
334 tcode = writeStructHeader(fid, SD_TAPE);
338 tapeToBudbTape(tapePtr, &tapeEntry);
340 tapeEntry.dump = htonl(dumpid);
342 if (canWrite(fid) <= 0)
343 ERROR(BUDB_DUMPFAILED);
345 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
346 ERROR(BUDB_DUMPFAILED);
348 haveWritten(sizeof(tapeEntry));
354 /* combines volFragment and volInfo */
357 writeVolume(ut, fid, volFragmentPtr, volInfoPtr, dumpid, tapeName)
358 struct ubik_trans *ut;
360 struct volFragment *volFragmentPtr;
361 struct volInfo *volInfoPtr;
365 struct budb_volumeEntry budbVolume;
368 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
370 budbVolume.dump = htonl(dumpid);
371 strcpy(budbVolume.tape, tapeName);
373 writeStructHeader(fid, SD_VOLUME);
375 if (canWrite(fid) <= 0)
376 ERROR(BUDB_DUMPFAILED);
378 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
379 ERROR(BUDB_DUMPFAILED);
381 haveWritten(sizeof(budbVolume));
387 /* -------------------
388 * handlers for the text blocks
389 * -------------------
393 * make sure a text lock is NOT held
405 if ((textType < 0) || (textType > TB_NUM - 1))
406 return (BUDB_BADARGUMENT);
408 lockPtr = &db.h.textLocks[textType];
410 if (lockPtr->lockState != 0)
411 return (BUDB_LOCKED);
416 * check the integrity of the specified text type
419 checkText(ut, textType)
420 struct ubik_trans *ut;
423 struct textBlock *tbPtr;
424 afs_int32 nBytes = 0; /* accumulated actual size */
431 tbPtr = &db.h.textBlock[textType];
432 blockAddr = ntohl(tbPtr->textAddr);
433 size = ntohl(tbPtr->size);
435 while (blockAddr != 0) {
438 cdbread(ut, text_BLOCK, blockAddr, (char *)&block, sizeof(block));
443 if (block.h.type != text_BLOCK)
444 ERROR(BUDB_DATABASEINCONSISTENT);
446 /* add up the size */
447 nBytes += BLOCK_DATA_SIZE;
449 blockAddr = ntohl(block.h.next);
452 /* ensure that we have at least the expected amount of text */
454 ERROR(BUDB_DATABASEINCONSISTENT);
462 * textType - type of text block, e.g. TB_DUMPSCHEDULE
466 writeText(ut, fid, textType)
467 struct ubik_trans *ut;
471 struct textBlock *tbPtr;
472 afs_int32 textSize, writeSize;
477 /* check lock is free */
478 code = checkLock(textType);
482 /* ensure that this block has the correct type */
483 code = checkText(ut, textType);
485 LogError(0, "writeText: text type %d damaged\n", textType);
489 tbPtr = &db.h.textBlock[textType];
490 textSize = ntohl(tbPtr->size);
491 dbAddr = ntohl(tbPtr->textAddr);
494 goto error_exit; /* Don't save anything if no blocks */
496 writeTextHeader(fid, textType);
499 code = cdbread(ut, text_BLOCK, dbAddr, (char *)&block, sizeof(block));
503 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
507 if (canWrite(fid) <= 0)
508 ERROR(BUDB_DUMPFAILED);
510 if (write(fid, &block.a[0], writeSize) != writeSize)
513 haveWritten(writeSize);
514 textSize -= writeSize;
516 dbAddr = ntohl(block.h.next);
523 #define MAXAPPENDS 200
526 writeDatabase(ut, fid)
527 struct ubik_trans *ut;
530 dbadr dbAddr, dbAppAddr;
531 struct dump diskDump, apDiskDump;
533 struct tape diskTape;
535 struct volFragment diskVolFragment;
536 struct volInfo diskVolInfo;
540 afs_int32 code = 0, tcode;
541 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
543 struct memoryHashTable *mht;
545 LogDebug(4, "writeDatabase:\n");
547 /* write out a header identifying this database etc */
548 tcode = writeDbHeader(fid);
550 LogError(tcode, "writeDatabase: Can't write Header\n");
554 /* write out the tree of dump structures */
556 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
558 LogError(tcode, "writeDatabase: Can't get dump type\n");
559 ERROR(BUDB_BADARGUMENT);
562 for (old = 0; old <= 1; old++) {
564 /* only two states, old or not old */
565 length = (old ? mht->oldLength : mht->length);
569 for (hash = 0; hash < length; hash++) {
571 /* dump all the dumps in this hash bucket
573 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*initialDumps */
574 /* now check if this dump had any errors/inconsistencies.
575 * If so, don't dump it
577 if (badEntry(dbAddr)) {
579 "writeDatabase: Damaged dump entry at addr 0x%x\n",
581 Log(" Skipping remainder of dumps on hash chain %d\n",
587 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
591 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
593 Log(" Skipping remainder of dumps on hash chain %d\n",
598 /* Skip appended dumps, only start with initial dumps */
599 if (diskDump.initialDumpID != 0)
602 /* Skip appended dumps, only start with initial dumps. Then
603 * follow the appended dump chain so they are in order for restore.
605 appcount = numaddrs = 0;
606 for (dbAppAddr = dbAddr; dbAppAddr;
607 dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
609 /* Check to see if we have a circular loop of appended dumps */
610 for (j = 0; j < numaddrs; j++) {
611 if (appDumpAddrs[j] == dbAppAddr)
612 break; /* circular loop */
614 if (j < numaddrs) { /* circular loop */
615 Log("writeDatabase: Circular loop found in appended dumps\n");
616 Log("Skipping rest of appended dumps of dumpID %u\n",
620 if (numaddrs >= MAXAPPENDS)
621 numaddrs = MAXAPPENDS - 1; /* don't overflow */
622 appDumpAddrs[numaddrs] = dbAppAddr;
625 /* If we dump a 1000 appended dumps, assume a loop */
626 if (appcount >= 5 * MAXAPPENDS) {
627 Log("writeDatabase: Potential circular loop of appended dumps\n");
628 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
633 /* Read the dump entry */
634 if (dbAddr == dbAppAddr) {
635 /* First time through, don't need to read the dump entry again */
636 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
638 if (badEntry(dbAppAddr)) {
640 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
642 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
647 cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
651 "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
653 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
657 /* Verify that this appended dump points to the initial dump */
658 if (ntohl(apDiskDump.initialDumpID) !=
659 ntohl(diskDump.id)) {
661 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
662 ntohl(apDiskDump.id),
664 Log(" Skipping this appended dump\n");
669 /* Save the dump entry */
670 tcode = writeDump(fid, &apDiskDump);
673 "writeDatabase: Can't write dump entry\n");
677 /* For each tape on this dump
679 for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) { /*tapes */
680 /* read the tape entry */
682 cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
686 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
687 tapeAddr, ntohl(apDiskDump.id));
688 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
692 /* Save the tape entry */
694 writeTape(fid, &diskTape, ntohl(apDiskDump.id));
697 "writeDatabase: Can't write tape entry\n");
701 /* For each volume on this tape.
703 for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) { /*volumes */
704 /* Read the volume Fragment entry */
706 cdbread(ut, volFragment_BLOCK, volFragAddr,
708 sizeof(diskVolFragment));
711 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
712 volFragAddr, ntohl(apDiskDump.id));
713 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
717 /* Read the volume Info entry */
719 cdbread(ut, volInfo_BLOCK,
720 ntohl(diskVolFragment.vol),
721 &diskVolInfo, sizeof(diskVolInfo));
724 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
725 ntohl(diskVolFragment.vol),
726 ntohl(apDiskDump.id));
727 Log(" Skipping volume on tape '%s'\n",
732 /* Save the volume entry */
734 writeVolume(ut, fid, &diskVolFragment,
736 ntohl(apDiskDump.id),
740 "writeDatabase: Can't write volume entry\n");
750 /* write out the textual configuration information */
751 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
753 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
756 tcode = writeText(ut, fid, TB_VOLUMESET);
758 LogError(tcode, "writeDatabase: Can't write volume set\n");
761 tcode = writeText(ut, fid, TB_TAPEHOSTS);
763 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
767 tcode = writeStructHeader(fid, SD_END);
769 LogError(tcode, "writeDatabase: Can't write end savedb\n");
785 afs_int32 in, out, except;
796 code = IOMGR_Select(32, &in, &out, &except, &tp);