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>
23 #include <netinet/in.h>
24 #include <sys/param.h>
27 #include <sys/types.h>
42 #include "error_macros.h"
43 #include "budb_errs.h"
44 #include "afs/audit.h"
47 /* dump ubik database - routines to scan the database and dump all
51 /* -----------------------
52 * synchronization on pipe
53 * -----------------------
56 /* interlocking for database dump */
59 dumpSyncP dumpSyncPtr = &dumpSync;
63 * check if we should dump more of the database. Waits for the reader
64 * to drain the information before allowing the writer to proceed.
74 extern dumpSyncP dumpSyncPtr;
76 ObtainWriteLock(&dumpSyncPtr->ds_lock);
78 /* let the pipe drain */
79 while ( dumpSyncPtr->ds_bytes > 0 )
81 if ( dumpSyncPtr->ds_readerStatus == DS_WAITING )
83 dumpSyncPtr->ds_readerStatus = 0;
84 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
86 LogError(code, "canWrite: Signal delivery failed\n");
88 dumpSyncPtr->ds_writerStatus = DS_WAITING;
89 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
90 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
91 ObtainWriteLock(&dumpSyncPtr->ds_lock);
98 * record the fact that nbytes have been written. Signal the reader
99 * to proceed, and unlock.
108 extern dumpSyncP dumpSyncPtr;
110 dumpSyncPtr->ds_bytes += nbytes;
111 if ( dumpSyncPtr->ds_readerStatus == DS_WAITING )
113 dumpSyncPtr->ds_readerStatus = 0;
114 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
116 LogError(code, "haveWritten: Signal delivery failed\n");
118 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
122 * wait for the reader to drain all the information, and then set the
131 /* wait for the reader */
132 ObtainWriteLock(&dumpSyncPtr->ds_lock);
133 while ( dumpSyncPtr->ds_readerStatus != DS_WAITING )
135 LogDebug(4, "doneWriting: waiting for Reader\n");
136 dumpSyncPtr->ds_writerStatus = DS_WAITING;
137 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
138 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
139 ObtainWriteLock(&dumpSyncPtr->ds_lock);
142 LogDebug(4, "doneWriting: setting done\n");
144 /* signal that we are done */
145 if (error) dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
146 else dumpSyncPtr->ds_writerStatus = DS_DONE;
147 dumpSyncPtr->ds_readerStatus = 0;
148 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
150 LogError(code, "doneWriting: Signal delivery failed\n");
151 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
155 * ut - setup and pass down
159 * write header appropriate for requested structure type
163 writeStructHeader(fid, type)
167 struct structDumpHeader hostDumpHeader, netDumpHeader;
169 hostDumpHeader.type = type;
170 hostDumpHeader.structversion = 1;
176 hostDumpHeader.size = sizeof(struct DbHeader);
180 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
184 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
188 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
192 hostDumpHeader.size = 0;
196 LogError(0, "writeStructHeader: invalid type %d\n", type);
200 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
202 if ( canWrite(fid) <= 0 )
203 return(BUDB_DUMPFAILED);
204 if ( write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
205 sizeof(netDumpHeader) )
206 return(BUDB_DUMPFAILED);
207 haveWritten(sizeof(netDumpHeader));
213 * write header appropriate for requested structure type
217 writeTextHeader(fid, type)
221 struct structDumpHeader hostDumpHeader, netDumpHeader;
223 hostDumpHeader.structversion = 1;
227 case TB_DUMPSCHEDULE:
228 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
232 hostDumpHeader.type = SD_TEXT_VOLUMESET;
236 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
240 LogError(0, "writeTextHeader: invalid type %d\n", type);
244 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
245 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
247 if (canWrite(fid) <= 0)
248 return(BUDB_DUMPFAILED);
250 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) != sizeof(netDumpHeader))
251 return(BUDB_DUMPFAILED);
253 haveWritten(sizeof(netDumpHeader));
262 struct DbHeader header;
264 afs_int32 code = 0, tcode;
266 extern struct memoryDB db;
268 /* check the memory database header for integrity */
269 if ( db.h.version != db.h.checkVersion )
270 ERROR(BUDB_DATABASEINCONSISTENT);
274 /* copy selected fields. Source is in xdr format. */
275 header.dbversion = db.h.version;
276 header.created = htonl(curtime);
277 strcpy(header.cell, "");
278 header.lastDumpId = db.h.lastDumpId;
279 header.lastInstanceId = db.h.lastInstanceId;
280 header.lastTapeId = db.h.lastTapeId;
282 tcode = writeStructHeader(fid, SD_DBHEADER);
286 if (canWrite(fid) <= 0)
287 ERROR(BUDB_DUMPFAILED);
289 if (write(fid, &header, sizeof(header)) != sizeof(header))
290 ERROR(BUDB_DUMPFAILED);
292 haveWritten(sizeof(header));
299 * write out a dump entry structure
303 writeDump(fid, dumpPtr)
307 struct budb_dumpEntry dumpEntry;
308 afs_int32 code = 0, tcode;
310 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
314 writeStructHeader(fid, SD_DUMP);
316 if (canWrite(fid) <= 0)
317 ERROR(BUDB_DUMPFAILED);
319 if ( write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry) )
320 ERROR(BUDB_DUMPFAILED);
321 haveWritten(sizeof(dumpEntry));
328 writeTape(fid, tapePtr, dumpid)
330 struct tape *tapePtr;
333 struct budb_tapeEntry tapeEntry;
334 afs_int32 code = 0, tcode;
336 tcode = writeStructHeader(fid, SD_TAPE);
340 tapeToBudbTape(tapePtr, &tapeEntry);
342 tapeEntry.dump = htonl(dumpid);
344 if (canWrite(fid) <= 0)
345 ERROR(BUDB_DUMPFAILED);
347 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
348 ERROR(BUDB_DUMPFAILED);
350 haveWritten(sizeof(tapeEntry));
356 /* combines volFragment and volInfo */
359 writeVolume(ut, fid, volFragmentPtr, volInfoPtr, dumpid, tapeName)
360 struct ubik_trans *ut;
362 struct volFragment *volFragmentPtr;
363 struct volInfo *volInfoPtr;
367 struct budb_volumeEntry budbVolume;
370 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
372 budbVolume.dump = htonl(dumpid);
373 strcpy(budbVolume.tape, tapeName);
375 writeStructHeader(fid, SD_VOLUME);
377 if (canWrite(fid) <= 0)
378 ERROR(BUDB_DUMPFAILED);
380 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
381 ERROR(BUDB_DUMPFAILED);
383 haveWritten(sizeof(budbVolume));
389 /* -------------------
390 * handlers for the text blocks
391 * -------------------
395 * make sure a text lock is NOT held
407 if ( (textType < 0) || (textType > TB_NUM-1) )
408 return(BUDB_BADARGUMENT);
410 lockPtr = &db.h.textLocks[textType];
412 if ( lockPtr->lockState != 0 )
418 * check the integrity of the specified text type
421 checkText(ut, textType)
422 struct ubik_trans *ut;
425 struct textBlock *tbPtr;
426 afs_int32 nBytes = 0; /* accumulated actual size */
433 tbPtr = &db.h.textBlock[textType];
434 blockAddr = ntohl(tbPtr->textAddr);
435 size = ntohl(tbPtr->size);
437 while ( blockAddr != 0 )
440 code = cdbread(ut, text_BLOCK, blockAddr, (char *) &block, sizeof(block));
445 if ( block.h.type != text_BLOCK )
446 ERROR(BUDB_DATABASEINCONSISTENT);
448 /* add up the size */
449 nBytes += BLOCK_DATA_SIZE;
451 blockAddr = ntohl(block.h.next);
454 /* ensure that we have at least the expected amount of text */
456 ERROR(BUDB_DATABASEINCONSISTENT);
464 * textType - type of text block, e.g. TB_DUMPSCHEDULE
468 writeText(ut, fid, textType)
469 struct ubik_trans *ut;
473 struct textBlock *tbPtr;
474 afs_int32 textSize, writeSize;
479 /* check lock is free */
480 code = checkLock(textType);
484 /* ensure that this block has the correct type */
485 code = checkText(ut, textType);
487 LogError(0, "writeText: text type %d damaged\n", textType);
491 tbPtr = &db.h.textBlock[textType];
492 textSize = ntohl(tbPtr->size);
493 dbAddr = ntohl(tbPtr->textAddr);
496 goto error_exit; /* Don't save anything if no blocks */
498 writeTextHeader(fid, textType);
501 code = cdbread(ut, text_BLOCK, dbAddr, (char *) &block, sizeof(block));
505 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
509 if (canWrite(fid) <= 0)
510 ERROR(BUDB_DUMPFAILED);
512 if (write(fid, &block.a[0], writeSize) != writeSize)
515 haveWritten(writeSize);
516 textSize -= writeSize;
518 dbAddr = ntohl(block.h.next);
525 #define MAXAPPENDS 200
528 writeDatabase(ut, fid)
529 struct ubik_trans *ut;
532 dbadr dbAddr, dbAppAddr;
533 struct dump diskDump, apDiskDump;
535 struct tape diskTape;
537 struct volFragment diskVolFragment;
538 struct volInfo diskVolInfo;
542 afs_int32 code = 0, tcode;
543 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
545 struct memoryHashTable *mht;
547 LogDebug(4, "writeDatabase:\n");
549 /* write out a header identifying this database etc */
550 tcode = writeDbHeader(fid);
552 LogError(tcode, "writeDatabase: Can't write Header\n");
556 /* write out the tree of dump structures */
558 mht = ht_GetType (HT_dumpIden_FUNCTION, &entrySize);
560 LogError(tcode, "writeDatabase: Can't get dump type\n");
561 ERROR(BUDB_BADARGUMENT);
564 for (old = 0; old <= 1; old++) {
566 /* only two states, old or not old */
567 length = (old ? mht->oldLength : mht->length);
571 for (hash=0; hash<length; hash++) {
573 /* dump all the dumps in this hash bucket
575 for (dbAddr = ht_LookupBucket (ut, mht, hash, old);
577 dbAddr = ntohl(diskDump.idHashChain))
579 /* now check if this dump had any errors/inconsistencies.
580 * If so, don't dump it
582 if (badEntry(dbAddr)) {
583 LogError(0, "writeDatabase: Damaged dump entry at addr 0x%x\n", dbAddr);
584 Log (" Skipping remainder of dumps on hash chain %d\n", hash);
588 tcode = cdbread(ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
590 LogError(tcode, "writeDatabase: Can't read dump entry (addr 0x%x)\n", dbAddr);
591 Log (" Skipping remainder of dumps on hash chain %d\n", hash);
595 /* Skip appended dumps, only start with initial dumps */
596 if (diskDump.initialDumpID != 0)
599 /* Skip appended dumps, only start with initial dumps. Then
600 * follow the appended dump chain so they are in order for restore.
602 appcount = numaddrs = 0;
603 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
605 /* Check to see if we have a circular loop of appended dumps */
606 for (j=0; j<numaddrs; j++) {
607 if (appDumpAddrs[j] == dbAppAddr) break;/* circular loop */
609 if (j < numaddrs) { /* circular loop */
610 Log("writeDatabase: Circular loop found in appended dumps\n");
611 Log("Skipping rest of appended dumps of dumpID %u\n",
615 if (numaddrs >= MAXAPPENDS) numaddrs = MAXAPPENDS-1; /* don't overflow */
616 appDumpAddrs[numaddrs] = dbAppAddr;
619 /* If we dump a 1000 appended dumps, assume a loop */
620 if (appcount >= 5 * MAXAPPENDS) {
621 Log("writeDatabase: Potential circular loop of appended dumps\n");
622 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n",
623 ntohl(diskDump.id), appcount);
628 /* Read the dump entry */
629 if (dbAddr == dbAppAddr) {
630 /* First time through, don't need to read the dump entry again */
631 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
634 if (badEntry(dbAppAddr)) {
635 LogError(0, "writeDatabase: Damaged appended dump entry at addr 0x%x\n", dbAddr);
636 Log (" Skipping this and remainder of appended dumps of initial DumpID %u\n",
641 tcode = cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump, sizeof(apDiskDump));
643 LogError(tcode, "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
645 Log (" Skipping this and remainder of appended dumps of initial DumpID %u\n",
650 /* Verify that this appended dump points to the initial dump */
651 if (ntohl(apDiskDump.initialDumpID) != ntohl(diskDump.id)) {
652 LogError(0, "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
653 ntohl(apDiskDump.id), ntohl(diskDump.id));
654 Log (" Skipping this appended dump\n");
659 /* Save the dump entry */
660 tcode = writeDump(fid, &apDiskDump);
662 LogError(tcode, "writeDatabase: Can't write dump entry\n");
666 /* For each tape on this dump
668 for (tapeAddr = ntohl(apDiskDump.firstTape);
670 tapeAddr = ntohl(diskTape.nextTape))
672 /* read the tape entry */
673 tcode = cdbread(ut, tape_BLOCK, tapeAddr, &diskTape, sizeof(diskTape));
675 LogError(tcode, "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
676 tapeAddr, ntohl(apDiskDump.id));
677 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
681 /* Save the tape entry */
682 tcode = writeTape(fid, &diskTape, ntohl(apDiskDump.id));
684 LogError(tcode, "writeDatabase: Can't write tape entry\n");
688 /* For each volume on this tape.
690 for (volFragAddr = ntohl(diskTape.firstVol);
692 volFragAddr = ntohl(diskVolFragment.sameTapeChain))
694 /* Read the volume Fragment entry */
695 tcode = cdbread(ut, volFragment_BLOCK, volFragAddr,
696 &diskVolFragment, sizeof(diskVolFragment));
698 LogError(tcode, "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
699 volFragAddr, ntohl(apDiskDump.id));
700 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
704 /* Read the volume Info entry */
705 tcode = cdbread(ut, volInfo_BLOCK, ntohl(diskVolFragment.vol),
706 &diskVolInfo, sizeof(diskVolInfo));
708 LogError(tcode, "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
709 ntohl(diskVolFragment.vol), ntohl(apDiskDump.id));
710 Log(" Skipping volume on tape '%s'\n", diskTape.name);
714 /* Save the volume entry */
715 tcode = writeVolume(ut, fid, &diskVolFragment, &diskVolInfo,
716 ntohl(apDiskDump.id), diskTape.name);
718 LogError(tcode, "writeDatabase: Can't write volume entry\n");
728 /* write out the textual configuration information */
729 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
731 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
734 tcode = writeText(ut, fid, TB_VOLUMESET);
736 LogError(tcode, "writeDatabase: Can't write volume set\n");
739 tcode = writeText(ut, fid, TB_TAPEHOSTS);
741 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
745 tcode = writeStructHeader(fid, SD_END);
747 LogError(tcode, "writeDatabase: Can't write end savedb\n");
763 afs_int32 in, out, except;
774 code = IOMGR_Select(32, &in, &out, &except, &tp);