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 <afs/audit.h>
28 #include "error_macros.h"
29 #include "budb_errs.h"
30 #include "budb_internal.h"
33 /* dump ubik database - routines to scan the database and dump all
37 /* -----------------------
38 * synchronization on pipe
39 * -----------------------
42 /* interlocking for database dump */
45 dumpSyncP dumpSyncPtr = &dumpSync;
49 * check if we should dump more of the database. Waits for the reader
50 * to drain the information before allowing the writer to proceed.
58 #ifndef AFS_PTHREAD_ENV
61 extern dumpSyncP dumpSyncPtr;
63 ObtainWriteLock(&dumpSyncPtr->ds_lock);
65 /* let the pipe drain */
66 while (dumpSyncPtr->ds_bytes > 0) {
67 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
68 dumpSyncPtr->ds_readerStatus = 0;
69 #ifdef AFS_PTHREAD_ENV
70 CV_BROADCAST(&dumpSyncPtr->ds_readerStatus_cond);
72 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
74 LogError(code, "canWrite: Signal delivery failed\n");
77 dumpSyncPtr->ds_writerStatus = DS_WAITING;
78 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
79 #ifdef AFS_PTHREAD_ENV
80 MUTEX_ENTER(&dumpSyncPtr->ds_writerStatus_mutex);
81 CV_WAIT(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex);
82 MUTEX_EXIT(&dumpSyncPtr->ds_writerStatus_mutex);
84 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
86 ObtainWriteLock(&dumpSyncPtr->ds_lock);
93 * record the fact that nbytes have been written. Signal the reader
94 * to proceed, and unlock.
100 haveWritten(afs_int32 nbytes)
102 #ifndef AFS_PTHREAD_ENV
105 extern dumpSyncP dumpSyncPtr;
107 dumpSyncPtr->ds_bytes += nbytes;
108 if (dumpSyncPtr->ds_readerStatus == DS_WAITING) {
109 dumpSyncPtr->ds_readerStatus = 0;
110 #ifdef AFS_PTHREAD_ENV
111 CV_BROADCAST(&dumpSyncPtr->ds_readerStatus_cond);
113 code = LWP_SignalProcess(&dumpSyncPtr->ds_readerStatus);
115 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
127 doneWriting(afs_int32 error)
129 #ifndef AFS_PTHREAD_ENV
133 /* wait for the reader */
134 ObtainWriteLock(&dumpSyncPtr->ds_lock);
135 while (dumpSyncPtr->ds_readerStatus != DS_WAITING) {
136 LogDebug(4, "doneWriting: waiting for Reader\n");
137 dumpSyncPtr->ds_writerStatus = DS_WAITING;
138 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
139 #ifdef AFS_PTHREAD_ENV
140 MUTEX_ENTER(&dumpSyncPtr->ds_writerStatus_mutex);
141 CV_WAIT(&dumpSyncPtr->ds_writerStatus_cond, &dumpSyncPtr->ds_writerStatus_mutex);
142 MUTEX_EXIT(&dumpSyncPtr->ds_writerStatus_mutex);
144 LWP_WaitProcess(&dumpSyncPtr->ds_writerStatus);
146 ObtainWriteLock(&dumpSyncPtr->ds_lock);
149 LogDebug(4, "doneWriting: setting done\n");
151 /* signal that we are done */
153 dumpSyncPtr->ds_writerStatus = DS_DONE_ERROR;
155 dumpSyncPtr->ds_writerStatus = DS_DONE;
156 dumpSyncPtr->ds_readerStatus = 0;
157 #ifdef AFS_PTHREAD_ENV
158 CV_BROADCAST(&dumpSyncPtr->ds_readerStatus_cond);
160 code = LWP_NoYieldSignal(&dumpSyncPtr->ds_readerStatus);
162 LogError(code, "doneWriting: Signal delivery failed\n");
164 ReleaseWriteLock(&dumpSyncPtr->ds_lock);
168 * ut - setup and pass down
172 * write header appropriate for requested structure type
176 writeStructHeader(int fid, afs_int32 type)
178 struct structDumpHeader hostDumpHeader, netDumpHeader;
180 hostDumpHeader.type = type;
181 hostDumpHeader.structversion = 1;
186 hostDumpHeader.size = sizeof(struct DbHeader);
190 hostDumpHeader.size = sizeof(struct budb_dumpEntry);
194 hostDumpHeader.size = sizeof(struct budb_tapeEntry);
198 hostDumpHeader.size = sizeof(struct budb_volumeEntry);
202 hostDumpHeader.size = 0;
206 LogError(0, "writeStructHeader: invalid type %d\n", type);
210 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
212 if (canWrite(fid) <= 0)
213 return (BUDB_DUMPFAILED);
214 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
215 sizeof(netDumpHeader))
216 return (BUDB_DUMPFAILED);
217 haveWritten(sizeof(netDumpHeader));
223 * write header appropriate for requested structure type
227 writeTextHeader(int fid, afs_int32 type)
229 struct structDumpHeader hostDumpHeader, netDumpHeader;
231 hostDumpHeader.structversion = 1;
234 case TB_DUMPSCHEDULE:
235 hostDumpHeader.type = SD_TEXT_DUMPSCHEDULE;
239 hostDumpHeader.type = SD_TEXT_VOLUMESET;
243 hostDumpHeader.type = SD_TEXT_TAPEHOSTS;
247 LogError(0, "writeTextHeader: invalid type %d\n", type);
251 hostDumpHeader.size = ntohl(db.h.textBlock[type].size);
252 structDumpHeader_hton(&hostDumpHeader, &netDumpHeader);
254 if (canWrite(fid) <= 0)
255 return (BUDB_DUMPFAILED);
257 if (write(fid, &netDumpHeader, sizeof(netDumpHeader)) !=
258 sizeof(netDumpHeader))
259 return (BUDB_DUMPFAILED);
261 haveWritten(sizeof(netDumpHeader));
267 writeDbHeader(int fid)
269 struct DbHeader header;
271 afs_int32 code = 0, tcode;
273 extern struct memoryDB db;
275 /* check the memory database header for integrity */
276 if (db.h.version != db.h.checkVersion)
277 ERROR(BUDB_DATABASEINCONSISTENT);
281 /* copy selected fields. Source is in xdr format. */
282 header.dbversion = db.h.version;
283 header.created = htonl(curtime);
284 strcpy(header.cell, "");
285 header.lastDumpId = db.h.lastDumpId;
286 header.lastInstanceId = db.h.lastInstanceId;
287 header.lastTapeId = db.h.lastTapeId;
289 tcode = writeStructHeader(fid, SD_DBHEADER);
293 if (canWrite(fid) <= 0)
294 ERROR(BUDB_DUMPFAILED);
296 if (write(fid, &header, sizeof(header)) != sizeof(header))
297 ERROR(BUDB_DUMPFAILED);
299 haveWritten(sizeof(header));
306 * write out a dump entry structure
310 writeDump(int fid, dbDumpP dumpPtr)
312 struct budb_dumpEntry dumpEntry;
313 afs_int32 code = 0, tcode;
315 tcode = dumpToBudbDump(dumpPtr, &dumpEntry);
319 writeStructHeader(fid, SD_DUMP);
321 if (canWrite(fid) <= 0)
322 ERROR(BUDB_DUMPFAILED);
324 if (write(fid, &dumpEntry, sizeof(dumpEntry)) != sizeof(dumpEntry))
325 ERROR(BUDB_DUMPFAILED);
326 haveWritten(sizeof(dumpEntry));
333 writeTape(int fid, struct tape *tapePtr, afs_int32 dumpid)
335 struct budb_tapeEntry tapeEntry;
336 afs_int32 code = 0, tcode;
338 tcode = writeStructHeader(fid, SD_TAPE);
342 tapeToBudbTape(tapePtr, &tapeEntry);
344 tapeEntry.dump = htonl(dumpid);
346 if (canWrite(fid) <= 0)
347 ERROR(BUDB_DUMPFAILED);
349 if (write(fid, &tapeEntry, sizeof(tapeEntry)) != sizeof(tapeEntry))
350 ERROR(BUDB_DUMPFAILED);
352 haveWritten(sizeof(tapeEntry));
358 /* combines volFragment and volInfo */
361 writeVolume(struct ubik_trans *ut, int fid, struct volFragment *volFragmentPtr,
362 struct volInfo *volInfoPtr, afs_int32 dumpid, char *tapeName)
364 struct budb_volumeEntry budbVolume;
367 volsToBudbVol(volFragmentPtr, volInfoPtr, &budbVolume);
369 budbVolume.dump = htonl(dumpid);
370 strcpy(budbVolume.tape, tapeName);
372 writeStructHeader(fid, SD_VOLUME);
374 if (canWrite(fid) <= 0)
375 ERROR(BUDB_DUMPFAILED);
377 if (write(fid, &budbVolume, sizeof(budbVolume)) != sizeof(budbVolume))
378 ERROR(BUDB_DUMPFAILED);
380 haveWritten(sizeof(budbVolume));
386 /* -------------------
387 * handlers for the text blocks
388 * -------------------
392 * make sure a text lock is NOT held
399 checkLock(afs_int32 textType)
403 if ((textType < 0) || (textType > TB_NUM - 1))
404 return (BUDB_BADARGUMENT);
406 lockPtr = &db.h.textLocks[textType];
408 if (lockPtr->lockState != 0)
409 return (BUDB_LOCKED);
414 * check the integrity of the specified text type
418 checkText(struct ubik_trans *ut, afs_int32 textType)
420 struct textBlock *tbPtr;
421 afs_int32 nBytes = 0; /* accumulated actual size */
428 tbPtr = &db.h.textBlock[textType];
429 blockAddr = ntohl(tbPtr->textAddr);
430 size = ntohl(tbPtr->size);
432 while (blockAddr != 0) {
435 cdbread(ut, text_BLOCK, blockAddr, (char *)&block, sizeof(block));
440 if (block.h.type != text_BLOCK)
441 ERROR(BUDB_DATABASEINCONSISTENT);
443 /* add up the size */
444 nBytes += BLOCK_DATA_SIZE;
446 blockAddr = ntohl(block.h.next);
449 /* ensure that we have at least the expected amount of text */
451 ERROR(BUDB_DATABASEINCONSISTENT);
459 * textType - type of text block, e.g. TB_DUMPSCHEDULE
463 writeText(struct ubik_trans *ut, int fid, int textType)
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(struct ubik_trans *ut, int fid)
522 dbadr dbAddr, dbAppAddr;
523 struct dump diskDump, apDiskDump;
525 struct tape diskTape;
527 struct volFragment diskVolFragment;
528 struct volInfo diskVolInfo;
532 afs_int32 code = 0, tcode;
533 afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;
535 struct memoryHashTable *mht;
537 LogDebug(4, "writeDatabase:\n");
539 /* write out a header identifying this database etc */
540 tcode = writeDbHeader(fid);
542 LogError(tcode, "writeDatabase: Can't write Header\n");
546 /* write out the tree of dump structures */
548 mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
550 LogError(tcode, "writeDatabase: Can't get dump type\n");
551 ERROR(BUDB_BADARGUMENT);
554 for (old = 0; old <= 1; old++) {
556 /* only two states, old or not old */
557 length = (old ? mht->oldLength : mht->length);
561 for (hash = 0; hash < length; hash++) {
563 /* dump all the dumps in this hash bucket
565 for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) { /*initialDumps */
566 /* now check if this dump had any errors/inconsistencies.
567 * If so, don't dump it
569 if (badEntry(dbAddr)) {
571 "writeDatabase: Damaged dump entry at addr 0x%x\n",
573 Log(" Skipping remainder of dumps on hash chain %d\n",
579 cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
583 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
585 Log(" Skipping remainder of dumps on hash chain %d\n",
590 /* Skip appended dumps, only start with initial dumps */
591 if (diskDump.initialDumpID != 0)
594 /* Skip appended dumps, only start with initial dumps. Then
595 * follow the appended dump chain so they are in order for restore.
597 appcount = numaddrs = 0;
598 for (dbAppAddr = dbAddr; dbAppAddr;
599 dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
601 /* Check to see if we have a circular loop of appended dumps */
602 for (j = 0; j < numaddrs; j++) {
603 if (appDumpAddrs[j] == dbAppAddr)
604 break; /* circular loop */
606 if (j < numaddrs) { /* circular loop */
607 Log("writeDatabase: Circular loop found in appended dumps\n");
608 Log("Skipping rest of appended dumps of dumpID %u\n",
612 if (numaddrs >= MAXAPPENDS)
613 numaddrs = MAXAPPENDS - 1; /* don't overflow */
614 appDumpAddrs[numaddrs] = dbAppAddr;
617 /* If we dump a 1000 appended dumps, assume a loop */
618 if (appcount >= 5 * MAXAPPENDS) {
619 Log("writeDatabase: Potential circular loop of appended dumps\n");
620 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
625 /* Read the dump entry */
626 if (dbAddr == dbAppAddr) {
627 /* First time through, don't need to read the dump entry again */
628 memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
630 if (badEntry(dbAppAddr)) {
632 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
634 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
639 cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
643 "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", ntohl(diskDump.id));
649 /* Verify that this appended dump points to the initial dump */
650 if (ntohl(apDiskDump.initialDumpID) !=
651 ntohl(diskDump.id)) {
653 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
654 ntohl(apDiskDump.id),
656 Log(" Skipping this appended dump\n");
661 /* Save the dump entry */
662 tcode = writeDump(fid, &apDiskDump);
665 "writeDatabase: Can't write dump entry\n");
669 /* For each tape on this dump
671 for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) { /*tapes */
672 /* read the tape entry */
674 cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
678 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
679 tapeAddr, ntohl(apDiskDump.id));
680 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
684 /* Save the tape entry */
686 writeTape(fid, &diskTape, ntohl(apDiskDump.id));
689 "writeDatabase: Can't write tape entry\n");
693 /* For each volume on this tape.
695 for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) { /*volumes */
696 /* Read the volume Fragment entry */
698 cdbread(ut, volFragment_BLOCK, volFragAddr,
700 sizeof(diskVolFragment));
703 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
704 volFragAddr, ntohl(apDiskDump.id));
705 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
709 /* Read the volume Info entry */
711 cdbread(ut, volInfo_BLOCK,
712 ntohl(diskVolFragment.vol),
713 &diskVolInfo, sizeof(diskVolInfo));
716 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
717 ntohl(diskVolFragment.vol),
718 ntohl(apDiskDump.id));
719 Log(" Skipping volume on tape '%s'\n",
724 /* Save the volume entry */
726 writeVolume(ut, fid, &diskVolFragment,
728 ntohl(apDiskDump.id),
732 "writeDatabase: Can't write volume entry\n");
742 /* write out the textual configuration information */
743 tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
745 LogError(tcode, "writeDatabase: Can't write dump schedule\n");
748 tcode = writeText(ut, fid, TB_VOLUMESET);
750 LogError(tcode, "writeDatabase: Can't write volume set\n");
753 tcode = writeText(ut, fid, TB_TAPEHOSTS);
755 LogError(tcode, "writeDatabase: Can't write tape hosts\n");
759 tcode = writeStructHeader(fid, SD_END);
761 LogError(tcode, "writeDatabase: Can't write end savedb\n");
776 afs_int32 in, out, except;
787 code = IOMGR_Select(32, &in, &out, &except, &tp);