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>
22 #include <netinet/in.h>
23 #include <sys/param.h>
26 #include <sys/types.h>
34 #include "error_macros.h"
35 #include "budb_errs.h"
36 #include "budb_internal.h"
37 #include "afs/audit.h"
40 /* dump ubik database - routines to scan the database and dump all
44 /* -----------------------
45 * synchronization on pipe
46 * -----------------------
49 /* interlocking for database dump */
52 dumpSyncP dumpSyncPtr = &dumpSync;
56 * check if we should dump more of the database. Waits for the reader
57 * to drain the information before allowing the writer to proceed.
65 #ifndef AFS_PTHREAD_ENV
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 #ifdef AFS_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 #ifdef AFS_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.
107 haveWritten(afs_int32 nbytes)
109 #ifndef AFS_PTHREAD_ENV
112 extern dumpSyncP dumpSyncPtr;
114 dumpSyncPtr->ds_bytes += nbytes;
115 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
116 dumpSyncPtr->ds_readerStatus = 0;
117 #ifdef AFS_PTHREAD_ENV
118 assert(pthread_cond_broadcast(&dumpSyncPtr->ds_readerStatus_cond) == 0);
120 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
122 LogError(code, "haveWritten: Signal delivery failed\n");
125 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
129 * wait for the reader to drain all the information, and then set the
134 doneWriting(afs_int32 error)
136 #ifndef AFS_PTHREAD_ENV
140 /* wait for the reader */
141 ObtainWriteLock(&dumpSyncPtr->ds_lock);
142 while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
143 LogDebug(4, "doneWriting: waiting for Reader\n");
144 dumpSyncPtr->ds_writerStatus = DS_WAITING;
145 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
146 #ifdef AFS_PTHREAD_ENV
147 assert(pthread_mutex_lock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
148 assert(pthread_cond_wait(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex) == 0);
149 assert(pthread_mutex_unlock(&dumpSyncPtr->ds_writerStatus_mutex) == 0);
151 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
153 ObtainWriteLock(&dumpSyncPtr->ds_lock);
156 LogDebug(4, "doneWriting: setting done\n");
158 /* signal that we are done */
160 dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
162 dumpSyncPtr->ds_writerStatus = DS_DONE;
163 dumpSyncPtr->ds_readerStatus = 0;
164 #ifdef AFS_PTHREAD_ENV
165 assert(pthread_cond_broadcast(&dumpSyncPtr->ds_readerStatus_cond) == 0);
167 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
169 LogError(code, "doneWriting: Signal delivery failed\n");
171 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
175 * ut - setup and pass down
179 * write header appropriate for requested structure type
183 writeStructHeader(int fid, afs_int32 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(int fid, afs_int32 type)
236 struct structDumpHeader hostDumpHeader, netDumpHeader;
238 hostDumpHeader.structversion = 1;
241 case TB_DUMPSCHEDULE:
242 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
246 hostDumpHeader.type = SD_TEXT_VOLUMESET;
250 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
254 LogError(0, "writeTextHeader: invalid type %d\n", type);
258 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
259 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
261 if (canWrite(fid) <= 0)
262 return (BUDB_DUMPFAILED);
264 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
265 sizeof(netDumpHeader))
266 return (BUDB_DUMPFAILED);
268 haveWritten(sizeof(netDumpHeader));
274 writeDbHeader(int fid)
276 struct DbHeader header;
278 afs_int32 code = 0, tcode;
280 extern struct memoryDB db;
282 /* check the memory database header for integrity */
283 if (db.h.version != db.h.checkVersion)
284 ERROR(BUDB_DATABASEINCONSISTENT);
288 /* copy selected fields. Source is in xdr format. */
289 header.dbversion = db.h.version;
290 header.created = htonl(curtime);
291 strcpy(header.cell, "");
292 header.lastDumpId = db.h.lastDumpId;
293 header.lastInstanceId = db.h.lastInstanceId;
294 header.lastTapeId = db.h.lastTapeId;
296 tcode = writeStructHeader(fid, SD_DBHEADER);
300 if (canWrite(fid) <= 0)
301 ERROR(BUDB_DUMPFAILED);
303 if (write(fid, &header, sizeof(header)) != sizeof(header))
304 ERROR(BUDB_DUMPFAILED);
306 haveWritten(sizeof(header));
313 * write out a dump entry structure
317 writeDump(int fid, dbDumpP dumpPtr)
319 struct budb_dumpEntry dumpEntry;
320 afs_int32 code = 0, tcode;
322 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
326 writeStructHeader(fid, SD_DUMP);
328 if (canWrite(fid) <= 0)
329 ERROR(BUDB_DUMPFAILED);
331 if (write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry))
332 ERROR(BUDB_DUMPFAILED);
333 haveWritten(sizeof(dumpEntry));
340 writeTape(int fid, struct tape *tapePtr, afs_int32 dumpid)
342 struct budb_tapeEntry tapeEntry;
343 afs_int32 code = 0, tcode;
345 tcode = writeStructHeader(fid, SD_TAPE);
349 tapeToBudbTape(tapePtr, &tapeEntry);
351 tapeEntry.dump = htonl(dumpid);
353 if (canWrite(fid) <= 0)
354 ERROR(BUDB_DUMPFAILED);
356 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
357 ERROR(BUDB_DUMPFAILED);
359 haveWritten(sizeof(tapeEntry));
365 /* combines volFragment and volInfo */
368 writeVolume(struct ubik_trans *ut, int fid, struct volFragment *volFragmentPtr,
369 struct volInfo *volInfoPtr, afs_int32 dumpid, char *tapeName)
371 struct budb_volumeEntry budbVolume;
374 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
376 budbVolume.dump = htonl(dumpid);
377 strcpy(budbVolume.tape, tapeName);
379 writeStructHeader(fid, SD_VOLUME);
381 if (canWrite(fid) <= 0)
382 ERROR(BUDB_DUMPFAILED);
384 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
385 ERROR(BUDB_DUMPFAILED);
387 haveWritten(sizeof(budbVolume));
393 /* -------------------
394 * handlers for the text blocks
395 * -------------------
399 * make sure a text lock is NOT held
406 checkLock(afs_int32 textType)
410 if ((textType < 0) || (textType > TB_NUM - 1))
411 return (BUDB_BADARGUMENT);
413 lockPtr = &db.h.textLocks[textType];
415 if (lockPtr->lockState != 0)
416 return (BUDB_LOCKED);
421 * check the integrity of the specified text type
425 checkText(struct ubik_trans *ut, afs_int32 textType)
427 struct textBlock *tbPtr;
428 afs_int32 nBytes = 0; /* accumulated actual size */
435 tbPtr = &db.h.textBlock[textType];
436 blockAddr = ntohl(tbPtr->textAddr);
437 size = ntohl(tbPtr->size);
439 while (blockAddr != 0) {
442 cdbread(ut, text_BLOCK, blockAddr, (char *)&block, sizeof(block));
447 if (block.h.type != text_BLOCK)
448 ERROR(BUDB_DATABASEINCONSISTENT);
450 /* add up the size */
451 nBytes += BLOCK_DATA_SIZE;
453 blockAddr = ntohl(block.h.next);
456 /* ensure that we have at least the expected amount of text */
458 ERROR(BUDB_DATABASEINCONSISTENT);
466 * textType - type of text block, e.g. TB_DUMPSCHEDULE
470 writeText(struct ubik_trans *ut, int fid, int textType)
472 struct textBlock *tbPtr;
473 afs_int32 textSize, writeSize;
478 /* check lock is free */
479 code = checkLock(textType);
483 /* ensure that this block has the correct type */
484 code = checkText(ut, textType);
486 LogError(0, "writeText: text type %d damaged\n", textType);
490 tbPtr = &db.h.textBlock[textType];
491 textSize = ntohl(tbPtr->size);
492 dbAddr = ntohl(tbPtr->textAddr);
495 goto error_exit; /* Don't save anything if no blocks */
497 writeTextHeader(fid, textType);
500 code = cdbread(ut, text_BLOCK, dbAddr, (char *)&block, sizeof(block));
504 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
508 if (canWrite(fid) <= 0)
509 ERROR(BUDB_DUMPFAILED);
511 if (write(fid, &block.a[0], writeSize) != writeSize)
514 haveWritten(writeSize);
515 textSize -= writeSize;
517 dbAddr = ntohl(block.h.next);
524 #define MAXAPPENDS 200
527 writeDatabase(struct ubik_trans *ut, int fid)
529 dbadr dbAddr, dbAppAddr;
530 struct dump diskDump, apDiskDump;
532 struct tape diskTape;
534 struct volFragment diskVolFragment;
535 struct volInfo diskVolInfo;
539 afs_int32 code = 0, tcode;
540 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
542 struct memoryHashTable *mht;
544 LogDebug(4, "writeDatabase:\n");
546 /* write out a header identifying this database etc */
547 tcode = writeDbHeader(fid);
549 LogError(tcode, "writeDatabase: Can't write Header\n");
553 /* write out the tree of dump structures */
555 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
557 LogError(tcode, "writeDatabase: Can't get dump type\n");
558 ERROR(BUDB_BADARGUMENT);
561 for (old = 0; old <= 1; old++) {
563 /* only two states, old or not old */
564 length = (old ? mht->oldLength : mht->length);
568 for (hash = 0; hash < length; hash++) {
570 /* dump all the dumps in this hash bucket
572 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*initialDumps */
573 /* now check if this dump had any errors/inconsistencies.
574 * If so, don't dump it
576 if (badEntry(dbAddr)) {
578 "writeDatabase: Damaged dump entry at addr 0x%x\n",
580 Log(" Skipping remainder of dumps on hash chain %d\n",
586 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
590 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
592 Log(" Skipping remainder of dumps on hash chain %d\n",
597 /* Skip appended dumps, only start with initial dumps */
598 if (diskDump.initialDumpID != 0)
601 /* Skip appended dumps, only start with initial dumps. Then
602 * follow the appended dump chain so they are in order for restore.
604 appcount = numaddrs = 0;
605 for (dbAppAddr = dbAddr; dbAppAddr;
606 dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
608 /* Check to see if we have a circular loop of appended dumps */
609 for (j = 0; j < numaddrs; j++) {
610 if (appDumpAddrs[j] == dbAppAddr)
611 break; /* circular loop */
613 if (j < numaddrs) { /* circular loop */
614 Log("writeDatabase: Circular loop found in appended dumps\n");
615 Log("Skipping rest of appended dumps of dumpID %u\n",
619 if (numaddrs >= MAXAPPENDS)
620 numaddrs = MAXAPPENDS - 1; /* don't overflow */
621 appDumpAddrs[numaddrs] = dbAppAddr;
624 /* If we dump a 1000 appended dumps, assume a loop */
625 if (appcount >= 5 * MAXAPPENDS) {
626 Log("writeDatabase: Potential circular loop of appended dumps\n");
627 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
632 /* Read the dump entry */
633 if (dbAddr == dbAppAddr) {
634 /* First time through, don't need to read the dump entry again */
635 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
637 if (badEntry(dbAppAddr)) {
639 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
641 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
646 cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
650 "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
652 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
656 /* Verify that this appended dump points to the initial dump */
657 if (ntohl(apDiskDump.initialDumpID) !=
658 ntohl(diskDump.id)) {
660 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
661 ntohl(apDiskDump.id),
663 Log(" Skipping this appended dump\n");
668 /* Save the dump entry */
669 tcode = writeDump(fid, &apDiskDump);
672 "writeDatabase: Can't write dump entry\n");
676 /* For each tape on this dump
678 for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) { /*tapes */
679 /* read the tape entry */
681 cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
685 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
686 tapeAddr, ntohl(apDiskDump.id));
687 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
691 /* Save the tape entry */
693 writeTape(fid, &diskTape, ntohl(apDiskDump.id));
696 "writeDatabase: Can't write tape entry\n");
700 /* For each volume on this tape.
702 for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) { /*volumes */
703 /* Read the volume Fragment entry */
705 cdbread(ut, volFragment_BLOCK, volFragAddr,
707 sizeof(diskVolFragment));
710 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
711 volFragAddr, ntohl(apDiskDump.id));
712 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
716 /* Read the volume Info entry */
718 cdbread(ut, volInfo_BLOCK,
719 ntohl(diskVolFragment.vol),
720 &diskVolInfo, sizeof(diskVolInfo));
723 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
724 ntohl(diskVolFragment.vol),
725 ntohl(apDiskDump.id));
726 Log(" Skipping volume on tape '%s'\n",
731 /* Save the volume entry */
733 writeVolume(ut, fid, &diskVolFragment,
735 ntohl(apDiskDump.id),
739 "writeDatabase: Can't write volume entry\n");
749 /* write out the textual configuration information */
750 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
752 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
755 tcode = writeText(ut, fid, TB_VOLUMESET);
757 LogError(tcode, "writeDatabase: Can't write volume set\n");
760 tcode = writeText(ut, fid, TB_TAPEHOSTS);
762 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
766 tcode = writeStructHeader(fid, SD_END);
768 LogError(tcode, "writeDatabase: Can't write end savedb\n");
783 afs_int32 in, out, except;
794 code = IOMGR_Select(32, &in, &out, &except, &tp);