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 #if defined(AFS_PTHREAD_ENV) && defined(UBIK_PTHREAD_ENV)
77 assert(pthread_cond_broadcast(&dumpSyncPtr->ds_readerStatus_cond) == 0);
79 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
81 LogError(code, "canWrite: Signal delivery failed\n");
84 dumpSyncPtr->ds_writerStatus = DS_WAITING;
85 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
86 #if defined(AFS_PTHREAD_ENV) && defined(UBIK_PTHREAD_ENV)
87 assert(pthread_mutex_lock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
88 assert(pthread_cond_wait(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex) == 0);
89 assert(pthread_mutex_unlock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
91 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
93 ObtainWriteLock(&dumpSyncPtr->ds_lock);
100 * record the fact that nbytes have been written. Signal the reader
101 * to proceed, and unlock.
111 extern dumpSyncP dumpSyncPtr;
113 dumpSyncPtr->ds_bytes += nbytes;
114 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
115 dumpSyncPtr->ds_readerStatus = 0;
116 #if defined(AFS_PTHREAD_ENV) && defined(UBIK_PTHREAD_ENV)
117 assert(pthread_cond_broadcast(&dumpSyncPtr->ds_readerStatus_cond) == 0);
119 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
121 LogError(code, "haveWritten: Signal delivery failed\n");
124 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
128 * wait for the reader to drain all the information, and then set the
138 /* wait for the reader */
139 ObtainWriteLock(&dumpSyncPtr->ds_lock);
140 while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
141 LogDebug(4, "doneWriting: waiting for Reader\n");
142 dumpSyncPtr->ds_writerStatus = DS_WAITING;
143 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
144 #if defined(AFS_PTHREAD_ENV) && defined(UBIK_PTHREAD_ENV)
145 assert(pthread_mutex_lock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
146 assert(pthread_cond_wait(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex) == 0);
147 assert(pthread_mutex_unlock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
149 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
151 ObtainWriteLock(&dumpSyncPtr->ds_lock);
154 LogDebug(4, "doneWriting: setting done\n");
156 /* signal that we are done */
158 dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
160 dumpSyncPtr->ds_writerStatus = DS_DONE;
161 dumpSyncPtr->ds_readerStatus = 0;
162 #if defined(AFS_PTHREAD_ENV) && defined(UBIK_PTHREAD_ENV)
163 assert(pthread_cond_broadcast(&dumpSyncPtr->ds_readerStatus_cond) == 0);
165 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
167 LogError(code, "doneWriting: Signal delivery failed\n");
169 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
173 * ut - setup and pass down
177 * write header appropriate for requested structure type
181 writeStructHeader(fid, type)
185 struct structDumpHeader hostDumpHeader, netDumpHeader;
187 hostDumpHeader.type = type;
188 hostDumpHeader.structversion = 1;
193 hostDumpHeader.size = sizeof(struct DbHeader);
197 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
201 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
205 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
209 hostDumpHeader.size = 0;
213 LogError(0, "writeStructHeader: invalid type %d\n", type);
217 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
219 if (canWrite(fid) <= 0)
220 return (BUDB_DUMPFAILED);
221 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
222 sizeof(netDumpHeader))
223 return (BUDB_DUMPFAILED);
224 haveWritten(sizeof(netDumpHeader));
230 * write header appropriate for requested structure type
234 writeTextHeader(fid, type)
238 struct structDumpHeader hostDumpHeader, netDumpHeader;
240 hostDumpHeader.structversion = 1;
243 case TB_DUMPSCHEDULE:
244 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
248 hostDumpHeader.type = SD_TEXT_VOLUMESET;
252 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
256 LogError(0, "writeTextHeader: invalid type %d\n", type);
260 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
261 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
263 if (canWrite(fid) <= 0)
264 return (BUDB_DUMPFAILED);
266 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
267 sizeof(netDumpHeader))
268 return (BUDB_DUMPFAILED);
270 haveWritten(sizeof(netDumpHeader));
279 struct DbHeader header;
281 afs_int32 code = 0, tcode;
283 extern struct memoryDB db;
285 /* check the memory database header for integrity */
286 if (db.h.version != db.h.checkVersion)
287 ERROR(BUDB_DATABASEINCONSISTENT);
291 /* copy selected fields. Source is in xdr format. */
292 header.dbversion = db.h.version;
293 header.created = htonl(curtime);
294 strcpy(header.cell, "");
295 header.lastDumpId = db.h.lastDumpId;
296 header.lastInstanceId = db.h.lastInstanceId;
297 header.lastTapeId = db.h.lastTapeId;
299 tcode = writeStructHeader(fid, SD_DBHEADER);
303 if (canWrite(fid) <= 0)
304 ERROR(BUDB_DUMPFAILED);
306 if (write(fid, &header, sizeof(header)) != sizeof(header))
307 ERROR(BUDB_DUMPFAILED);
309 haveWritten(sizeof(header));
316 * write out a dump entry structure
320 writeDump(fid, dumpPtr)
324 struct budb_dumpEntry dumpEntry;
325 afs_int32 code = 0, tcode;
327 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
331 writeStructHeader(fid, SD_DUMP);
333 if (canWrite(fid) <= 0)
334 ERROR(BUDB_DUMPFAILED);
336 if (write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry))
337 ERROR(BUDB_DUMPFAILED);
338 haveWritten(sizeof(dumpEntry));
345 writeTape(fid, tapePtr, dumpid)
347 struct tape *tapePtr;
350 struct budb_tapeEntry tapeEntry;
351 afs_int32 code = 0, tcode;
353 tcode = writeStructHeader(fid, SD_TAPE);
357 tapeToBudbTape(tapePtr, &tapeEntry);
359 tapeEntry.dump = htonl(dumpid);
361 if (canWrite(fid) <= 0)
362 ERROR(BUDB_DUMPFAILED);
364 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
365 ERROR(BUDB_DUMPFAILED);
367 haveWritten(sizeof(tapeEntry));
373 /* combines volFragment and volInfo */
376 writeVolume(ut, fid, volFragmentPtr, volInfoPtr, dumpid, tapeName)
377 struct ubik_trans *ut;
379 struct volFragment *volFragmentPtr;
380 struct volInfo *volInfoPtr;
384 struct budb_volumeEntry budbVolume;
387 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
389 budbVolume.dump = htonl(dumpid);
390 strcpy(budbVolume.tape, tapeName);
392 writeStructHeader(fid, SD_VOLUME);
394 if (canWrite(fid) <= 0)
395 ERROR(BUDB_DUMPFAILED);
397 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
398 ERROR(BUDB_DUMPFAILED);
400 haveWritten(sizeof(budbVolume));
406 /* -------------------
407 * handlers for the text blocks
408 * -------------------
412 * make sure a text lock is NOT held
424 if ((textType < 0) || (textType > TB_NUM - 1))
425 return (BUDB_BADARGUMENT);
427 lockPtr = &db.h.textLocks[textType];
429 if (lockPtr->lockState != 0)
430 return (BUDB_LOCKED);
435 * check the integrity of the specified text type
438 checkText(ut, textType)
439 struct ubik_trans *ut;
442 struct textBlock *tbPtr;
443 afs_int32 nBytes = 0; /* accumulated actual size */
450 tbPtr = &db.h.textBlock[textType];
451 blockAddr = ntohl(tbPtr->textAddr);
452 size = ntohl(tbPtr->size);
454 while (blockAddr != 0) {
457 cdbread(ut, text_BLOCK, blockAddr, (char *)&block, sizeof(block));
462 if (block.h.type != text_BLOCK)
463 ERROR(BUDB_DATABASEINCONSISTENT);
465 /* add up the size */
466 nBytes += BLOCK_DATA_SIZE;
468 blockAddr = ntohl(block.h.next);
471 /* ensure that we have at least the expected amount of text */
473 ERROR(BUDB_DATABASEINCONSISTENT);
481 * textType - type of text block, e.g. TB_DUMPSCHEDULE
485 writeText(ut, fid, textType)
486 struct ubik_trans *ut;
490 struct textBlock *tbPtr;
491 afs_int32 textSize, writeSize;
496 /* check lock is free */
497 code = checkLock(textType);
501 /* ensure that this block has the correct type */
502 code = checkText(ut, textType);
504 LogError(0, "writeText: text type %d damaged\n", textType);
508 tbPtr = &db.h.textBlock[textType];
509 textSize = ntohl(tbPtr->size);
510 dbAddr = ntohl(tbPtr->textAddr);
513 goto error_exit; /* Don't save anything if no blocks */
515 writeTextHeader(fid, textType);
518 code = cdbread(ut, text_BLOCK, dbAddr, (char *)&block, sizeof(block));
522 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
526 if (canWrite(fid) <= 0)
527 ERROR(BUDB_DUMPFAILED);
529 if (write(fid, &block.a[0], writeSize) != writeSize)
532 haveWritten(writeSize);
533 textSize -= writeSize;
535 dbAddr = ntohl(block.h.next);
542 #define MAXAPPENDS 200
545 writeDatabase(ut, fid)
546 struct ubik_trans *ut;
549 dbadr dbAddr, dbAppAddr;
550 struct dump diskDump, apDiskDump;
552 struct tape diskTape;
554 struct volFragment diskVolFragment;
555 struct volInfo diskVolInfo;
559 afs_int32 code = 0, tcode;
560 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
562 struct memoryHashTable *mht;
564 LogDebug(4, "writeDatabase:\n");
566 /* write out a header identifying this database etc */
567 tcode = writeDbHeader(fid);
569 LogError(tcode, "writeDatabase: Can't write Header\n");
573 /* write out the tree of dump structures */
575 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
577 LogError(tcode, "writeDatabase: Can't get dump type\n");
578 ERROR(BUDB_BADARGUMENT);
581 for (old = 0; old <= 1; old++) {
583 /* only two states, old or not old */
584 length = (old ? mht->oldLength : mht->length);
588 for (hash = 0; hash < length; hash++) {
590 /* dump all the dumps in this hash bucket
592 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*initialDumps */
593 /* now check if this dump had any errors/inconsistencies.
594 * If so, don't dump it
596 if (badEntry(dbAddr)) {
598 "writeDatabase: Damaged dump entry at addr 0x%x\n",
600 Log(" Skipping remainder of dumps on hash chain %d\n",
606 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
610 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
612 Log(" Skipping remainder of dumps on hash chain %d\n",
617 /* Skip appended dumps, only start with initial dumps */
618 if (diskDump.initialDumpID != 0)
621 /* Skip appended dumps, only start with initial dumps. Then
622 * follow the appended dump chain so they are in order for restore.
624 appcount = numaddrs = 0;
625 for (dbAppAddr = dbAddr; dbAppAddr;
626 dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
628 /* Check to see if we have a circular loop of appended dumps */
629 for (j = 0; j < numaddrs; j++) {
630 if (appDumpAddrs[j] == dbAppAddr)
631 break; /* circular loop */
633 if (j < numaddrs) { /* circular loop */
634 Log("writeDatabase: Circular loop found in appended dumps\n");
635 Log("Skipping rest of appended dumps of dumpID %u\n",
639 if (numaddrs >= MAXAPPENDS)
640 numaddrs = MAXAPPENDS - 1; /* don't overflow */
641 appDumpAddrs[numaddrs] = dbAppAddr;
644 /* If we dump a 1000 appended dumps, assume a loop */
645 if (appcount >= 5 * MAXAPPENDS) {
646 Log("writeDatabase: Potential circular loop of appended dumps\n");
647 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
652 /* Read the dump entry */
653 if (dbAddr == dbAppAddr) {
654 /* First time through, don't need to read the dump entry again */
655 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
657 if (badEntry(dbAppAddr)) {
659 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
661 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
666 cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
670 "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
672 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
676 /* Verify that this appended dump points to the initial dump */
677 if (ntohl(apDiskDump.initialDumpID) !=
678 ntohl(diskDump.id)) {
680 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
681 ntohl(apDiskDump.id),
683 Log(" Skipping this appended dump\n");
688 /* Save the dump entry */
689 tcode = writeDump(fid, &apDiskDump);
692 "writeDatabase: Can't write dump entry\n");
696 /* For each tape on this dump
698 for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) { /*tapes */
699 /* read the tape entry */
701 cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
705 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
706 tapeAddr, ntohl(apDiskDump.id));
707 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
711 /* Save the tape entry */
713 writeTape(fid, &diskTape, ntohl(apDiskDump.id));
716 "writeDatabase: Can't write tape entry\n");
720 /* For each volume on this tape.
722 for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) { /*volumes */
723 /* Read the volume Fragment entry */
725 cdbread(ut, volFragment_BLOCK, volFragAddr,
727 sizeof(diskVolFragment));
730 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
731 volFragAddr, ntohl(apDiskDump.id));
732 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
736 /* Read the volume Info entry */
738 cdbread(ut, volInfo_BLOCK,
739 ntohl(diskVolFragment.vol),
740 &diskVolInfo, sizeof(diskVolInfo));
743 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
744 ntohl(diskVolFragment.vol),
745 ntohl(apDiskDump.id));
746 Log(" Skipping volume on tape '%s'\n",
751 /* Save the volume entry */
753 writeVolume(ut, fid, &diskVolFragment,
755 ntohl(apDiskDump.id),
759 "writeDatabase: Can't write volume entry\n");
769 /* write out the textual configuration information */
770 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
772 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
775 tcode = writeText(ut, fid, TB_VOLUMESET);
777 LogError(tcode, "writeDatabase: Can't write volume set\n");
780 tcode = writeText(ut, fid, TB_TAPEHOSTS);
782 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
786 tcode = writeStructHeader(fid, SD_END);
788 LogError(tcode, "writeDatabase: Can't write end savedb\n");
804 afs_int32 in, out, except;
815 code = IOMGR_Select(32, &in, &out, &except, &tp);