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 <afs/param.h>
16 #include <afsconfig.h>
23 #include <netinet/in.h>
24 #include <sys/param.h>
27 #include <sys/types.h>
34 #include "error_macros.h"
35 #include "budb_errs.h"
36 #include "afs/audit.h"
39 /* dump ubik database - routines to scan the database and dump all
43 /* -----------------------
44 * synchronization on pipe
45 * -----------------------
48 /* interlocking for database dump */
51 dumpSyncP dumpSyncPtr = &dumpSync;
55 * check if we should dump more of the database. Waits for the reader
56 * to drain the information before allowing the writer to proceed.
66 extern dumpSyncP dumpSyncPtr;
68 ObtainWriteLock(&dumpSyncPtr->ds_lock);
70 /* let the pipe drain */
71 while ( dumpSyncPtr->ds_bytes > 0 )
73 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 )
105 dumpSyncPtr->ds_readerStatus = 0;
106 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
108 LogError(code, "haveWritten: Signal delivery failed\n");
110 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
114 * wait for the reader to drain all the information, and then set the
123 /* wait for the reader */
124 ObtainWriteLock(&dumpSyncPtr->ds_lock);
125 while ( dumpSyncPtr->ds_readerStatus != DS_WAITING )
127 LogDebug(4, "doneWriting: waiting for Reader\n");
128 dumpSyncPtr->ds_writerStatus = DS_WAITING;
129 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
130 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
131 ObtainWriteLock(&dumpSyncPtr->ds_lock);
134 LogDebug(4, "doneWriting: setting done\n");
136 /* signal that we are done */
137 if (error) dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
138 else 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;
168 hostDumpHeader.size = sizeof(struct DbHeader);
172 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
176 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
180 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
184 hostDumpHeader.size = 0;
188 LogError(0, "writeStructHeader: invalid type %d\n", type);
192 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
194 if ( canWrite(fid) <= 0 )
195 return(BUDB_DUMPFAILED);
196 if ( write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
197 sizeof(netDumpHeader) )
198 return(BUDB_DUMPFAILED);
199 haveWritten(sizeof(netDumpHeader));
205 * write header appropriate for requested structure type
209 writeTextHeader(fid, type)
213 struct structDumpHeader hostDumpHeader, netDumpHeader;
215 hostDumpHeader.structversion = 1;
219 case TB_DUMPSCHEDULE:
220 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
224 hostDumpHeader.type = SD_TEXT_VOLUMESET;
228 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
232 LogError(0, "writeTextHeader: invalid type %d\n", type);
236 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
237 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
239 if (canWrite(fid) <= 0)
240 return(BUDB_DUMPFAILED);
242 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) != sizeof(netDumpHeader))
243 return(BUDB_DUMPFAILED);
245 haveWritten(sizeof(netDumpHeader));
254 struct DbHeader header;
256 afs_int32 code = 0, tcode;
258 extern struct memoryDB db;
260 /* check the memory database header for integrity */
261 if ( db.h.version != db.h.checkVersion )
262 ERROR(BUDB_DATABASEINCONSISTENT);
266 /* copy selected fields. Source is in xdr format. */
267 header.dbversion = db.h.version;
268 header.created = htonl(curtime);
269 strcpy(header.cell, "");
270 header.lastDumpId = db.h.lastDumpId;
271 header.lastInstanceId = db.h.lastInstanceId;
272 header.lastTapeId = db.h.lastTapeId;
274 tcode = writeStructHeader(fid, SD_DBHEADER);
278 if (canWrite(fid) <= 0)
279 ERROR(BUDB_DUMPFAILED);
281 if (write(fid, &header, sizeof(header)) != sizeof(header))
282 ERROR(BUDB_DUMPFAILED);
284 haveWritten(sizeof(header));
291 * write out a dump entry structure
295 writeDump(fid, dumpPtr)
299 struct budb_dumpEntry dumpEntry;
300 afs_int32 code = 0, tcode;
302 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
306 writeStructHeader(fid, SD_DUMP);
308 if (canWrite(fid) <= 0)
309 ERROR(BUDB_DUMPFAILED);
311 if ( write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry) )
312 ERROR(BUDB_DUMPFAILED);
313 haveWritten(sizeof(dumpEntry));
320 writeTape(fid, tapePtr, dumpid)
322 struct tape *tapePtr;
325 struct budb_tapeEntry tapeEntry;
326 afs_int32 code = 0, tcode;
328 tcode = writeStructHeader(fid, SD_TAPE);
332 tapeToBudbTape(tapePtr, &tapeEntry);
334 tapeEntry.dump = htonl(dumpid);
336 if (canWrite(fid) <= 0)
337 ERROR(BUDB_DUMPFAILED);
339 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
340 ERROR(BUDB_DUMPFAILED);
342 haveWritten(sizeof(tapeEntry));
348 /* combines volFragment and volInfo */
351 writeVolume(ut, fid, volFragmentPtr, volInfoPtr, dumpid, tapeName)
352 struct ubik_trans *ut;
354 struct volFragment *volFragmentPtr;
355 struct volInfo *volInfoPtr;
359 struct budb_volumeEntry budbVolume;
362 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
364 budbVolume.dump = htonl(dumpid);
365 strcpy(budbVolume.tape, tapeName);
367 writeStructHeader(fid, SD_VOLUME);
369 if (canWrite(fid) <= 0)
370 ERROR(BUDB_DUMPFAILED);
372 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
373 ERROR(BUDB_DUMPFAILED);
375 haveWritten(sizeof(budbVolume));
381 /* -------------------
382 * handlers for the text blocks
383 * -------------------
387 * make sure a text lock is NOT held
399 if ( (textType < 0) || (textType > TB_NUM-1) )
400 return(BUDB_BADARGUMENT);
402 lockPtr = &db.h.textLocks[textType];
404 if ( lockPtr->lockState != 0 )
410 * check the integrity of the specified text type
413 checkText(ut, textType)
414 struct ubik_trans *ut;
417 struct textBlock *tbPtr;
418 afs_int32 nBytes = 0; /* accumulated actual size */
425 tbPtr = &db.h.textBlock[textType];
426 blockAddr = ntohl(tbPtr->textAddr);
427 size = ntohl(tbPtr->size);
429 while ( blockAddr != 0 )
432 code = cdbread(ut, text_BLOCK, blockAddr, (char *) &block, sizeof(block));
437 if ( block.h.type != text_BLOCK )
438 ERROR(BUDB_DATABASEINCONSISTENT);
440 /* add up the size */
441 nBytes += BLOCK_DATA_SIZE;
443 blockAddr = ntohl(block.h.next);
446 /* ensure that we have at least the expected amount of text */
448 ERROR(BUDB_DATABASEINCONSISTENT);
456 * textType - type of text block, e.g. TB_DUMPSCHEDULE
460 writeText(ut, fid, textType)
461 struct ubik_trans *ut;
465 struct textBlock *tbPtr;
466 afs_int32 textSize, writeSize;
471 /* check lock is free */
472 code = checkLock(textType);
476 /* ensure that this block has the correct type */
477 code = checkText(ut, textType);
479 LogError(0, "writeText: text type %d damaged\n", textType);
483 tbPtr = &db.h.textBlock[textType];
484 textSize = ntohl(tbPtr->size);
485 dbAddr = ntohl(tbPtr->textAddr);
488 goto error_exit; /* Don't save anything if no blocks */
490 writeTextHeader(fid, textType);
493 code = cdbread(ut, text_BLOCK, dbAddr, (char *) &block, sizeof(block));
497 writeSize = MIN(textSize, BLOCK_DATA_SIZE);
501 if (canWrite(fid) <= 0)
502 ERROR(BUDB_DUMPFAILED);
504 if (write(fid, &block.a[0], writeSize) != writeSize)
507 haveWritten(writeSize);
508 textSize -= writeSize;
510 dbAddr = ntohl(block.h.next);
517 #define MAXAPPENDS 200
520 writeDatabase(ut, fid)
521 struct ubik_trans *ut;
524 dbadr dbAddr, dbAppAddr;
525 struct dump diskDump, apDiskDump;
527 struct tape diskTape;
529 struct volFragment diskVolFragment;
530 struct volInfo diskVolInfo;
534 afs_int32 code = 0, tcode;
535 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
537 struct memoryHashTable *mht;
539 LogDebug(4, "writeDatabase:\n");
541 /* write out a header identifying this database etc */
542 tcode = writeDbHeader(fid);
544 LogError(tcode, "writeDatabase: Can't write Header\n");
548 /* write out the tree of dump structures */
550 mht = ht_GetType (HT_dumpIden_FUNCTION, &entrySize);
552 LogError(tcode, "writeDatabase: Can't get dump type\n");
553 ERROR(BUDB_BADARGUMENT);
556 for (old = 0; old <= 1; old++) {
558 /* only two states, old or not old */
559 length = (old ? mht->oldLength : mht->length);
563 for (hash=0; hash<length; hash++) {
565 /* dump all the dumps in this hash bucket
567 for (dbAddr = ht_LookupBucket (ut, mht, hash, old);
569 dbAddr = ntohl(diskDump.idHashChain))
571 /* now check if this dump had any errors/inconsistencies.
572 * If so, don't dump it
574 if (badEntry(dbAddr)) {
575 LogError(0, "writeDatabase: Damaged dump entry at addr 0x%x\n", dbAddr);
576 Log (" Skipping remainder of dumps on hash chain %d\n", hash);
580 tcode = cdbread(ut, dump_BLOCK, dbAddr, &diskDump, sizeof(diskDump));
582 LogError(tcode, "writeDatabase: Can't read dump entry (addr 0x%x)\n", dbAddr);
583 Log (" Skipping remainder of dumps on hash chain %d\n", hash);
587 /* Skip appended dumps, only start with initial dumps */
588 if (diskDump.initialDumpID != 0)
591 /* Skip appended dumps, only start with initial dumps. Then
592 * follow the appended dump chain so they are in order for restore.
594 appcount = numaddrs = 0;
595 for (dbAppAddr=dbAddr; dbAppAddr; dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
597 /* Check to see if we have a circular loop of appended dumps */
598 for (j=0; j<numaddrs; j++) {
599 if (appDumpAddrs[j] == dbAppAddr) break;/* circular loop */
601 if (j < numaddrs) { /* circular loop */
602 Log("writeDatabase: Circular loop found in appended dumps\n");
603 Log("Skipping rest of appended dumps of dumpID %u\n",
607 if (numaddrs >= MAXAPPENDS) numaddrs = MAXAPPENDS-1; /* don't overflow */
608 appDumpAddrs[numaddrs] = dbAppAddr;
611 /* If we dump a 1000 appended dumps, assume a loop */
612 if (appcount >= 5 * MAXAPPENDS) {
613 Log("writeDatabase: Potential circular loop of appended dumps\n");
614 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n",
615 ntohl(diskDump.id), appcount);
620 /* Read the dump entry */
621 if (dbAddr == dbAppAddr) {
622 /* First time through, don't need to read the dump entry again */
623 bcopy(&diskDump, &apDiskDump, sizeof(diskDump));
626 if (badEntry(dbAppAddr)) {
627 LogError(0, "writeDatabase: Damaged appended dump entry at addr 0x%x\n", dbAddr);
628 Log (" Skipping this and remainder of appended dumps of initial DumpID %u\n",
633 tcode = cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump, sizeof(apDiskDump));
635 LogError(tcode, "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
637 Log (" Skipping this and remainder of appended dumps of initial DumpID %u\n",
642 /* Verify that this appended dump points to the initial dump */
643 if (ntohl(apDiskDump.initialDumpID) != ntohl(diskDump.id)) {
644 LogError(0, "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
645 ntohl(apDiskDump.id), ntohl(diskDump.id));
646 Log (" Skipping this appended dump\n");
651 /* Save the dump entry */
652 tcode = writeDump(fid, &apDiskDump);
654 LogError(tcode, "writeDatabase: Can't write dump entry\n");
658 /* For each tape on this dump
660 for (tapeAddr = ntohl(apDiskDump.firstTape);
662 tapeAddr = ntohl(diskTape.nextTape))
664 /* read the tape entry */
665 tcode = cdbread(ut, tape_BLOCK, tapeAddr, &diskTape, sizeof(diskTape));
667 LogError(tcode, "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
668 tapeAddr, ntohl(apDiskDump.id));
669 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
673 /* Save the tape entry */
674 tcode = writeTape(fid, &diskTape, ntohl(apDiskDump.id));
676 LogError(tcode, "writeDatabase: Can't write tape entry\n");
680 /* For each volume on this tape.
682 for (volFragAddr = ntohl(diskTape.firstVol);
684 volFragAddr = ntohl(diskVolFragment.sameTapeChain))
686 /* Read the volume Fragment entry */
687 tcode = cdbread(ut, volFragment_BLOCK, volFragAddr,
688 &diskVolFragment, sizeof(diskVolFragment));
690 LogError(tcode, "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
691 volFragAddr, ntohl(apDiskDump.id));
692 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
696 /* Read the volume Info entry */
697 tcode = cdbread(ut, volInfo_BLOCK, ntohl(diskVolFragment.vol),
698 &diskVolInfo, sizeof(diskVolInfo));
700 LogError(tcode, "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
701 ntohl(diskVolFragment.vol), ntohl(apDiskDump.id));
702 Log(" Skipping volume on tape '%s'\n", diskTape.name);
706 /* Save the volume entry */
707 tcode = writeVolume(ut, fid, &diskVolFragment, &diskVolInfo,
708 ntohl(apDiskDump.id), diskTape.name);
710 LogError(tcode, "writeDatabase: Can't write volume entry\n");
720 /* write out the textual configuration information */
721 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
723 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
726 tcode = writeText(ut, fid, TB_VOLUMESET);
728 LogError(tcode, "writeDatabase: Can't write volume set\n");
731 tcode = writeText(ut, fid, TB_TAPEHOSTS);
733 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
737 tcode = writeStructHeader(fid, SD_END);
739 LogError(tcode, "writeDatabase: Can't write end savedb\n");
755 afs_int32 in, out, except;
766 code = IOMGR_Select(32, &in, &out, &except, &tp);