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 #ifdef AFS_PTHREAD_ENV
24 # include <opr/lock.h>
28 #include <afs/audit.h>
33 #include "error_macros.h"
34 #include "budb_errs.h"
35 #include "budb_internal.h"
38 /* dump ubik database - routines to scan the database and dump all
42 /* -----------------------
43 * synchronization on pipe
44 * -----------------------
47 /* interlocking for database dump */
50 dumpSyncP dumpSyncPtr
= &dumpSync
;
54 * check if we should dump more of the database. Waits for the reader
55 * to drain the information before allowing the writer to proceed.
63 #ifndef AFS_PTHREAD_ENV
66 extern dumpSyncP dumpSyncPtr
;
68 ObtainWriteLock(&dumpSyncPtr
->ds_lock
);
70 /* let the pipe drain */
71 while (dumpSyncPtr
->ds_bytes
> 0) {
72 if (dumpSyncPtr
->ds_readerStatus
== DS_WAITING
) {
73 dumpSyncPtr
->ds_readerStatus
= 0;
74 #ifdef AFS_PTHREAD_ENV
75 opr_cv_broadcast(&dumpSyncPtr
->ds_readerStatus_cond
);
77 code
= LWP_SignalProcess(&dumpSyncPtr
->ds_readerStatus
);
79 LogError(code
, "canWrite: Signal delivery failed\n");
82 dumpSyncPtr
->ds_writerStatus
= DS_WAITING
;
83 ReleaseWriteLock(&dumpSyncPtr
->ds_lock
);
84 #ifdef AFS_PTHREAD_ENV
85 MUTEX_ENTER(&dumpSyncPtr
->ds_writerStatus_mutex
);
86 opr_cv_wait(&dumpSyncPtr
->ds_writerStatus_cond
, &dumpSyncPtr
->ds_writerStatus_mutex
);
87 MUTEX_EXIT(&dumpSyncPtr
->ds_writerStatus_mutex
);
89 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.
105 haveWritten(afs_int32 nbytes
)
107 #ifndef AFS_PTHREAD_ENV
110 extern dumpSyncP dumpSyncPtr
;
112 dumpSyncPtr
->ds_bytes
+= nbytes
;
113 if (dumpSyncPtr
->ds_readerStatus
== DS_WAITING
) {
114 dumpSyncPtr
->ds_readerStatus
= 0;
115 #ifdef AFS_PTHREAD_ENV
116 opr_cv_broadcast(&dumpSyncPtr
->ds_readerStatus_cond
);
118 code
= LWP_SignalProcess(&dumpSyncPtr
->ds_readerStatus
);
120 LogError(code
, "haveWritten: Signal delivery failed\n");
123 ReleaseWriteLock(&dumpSyncPtr
->ds_lock
);
127 * wait for the reader to drain all the information, and then set the
132 doneWriting(afs_int32 error
)
134 #ifndef AFS_PTHREAD_ENV
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 #ifdef AFS_PTHREAD_ENV
145 MUTEX_ENTER(&dumpSyncPtr
->ds_writerStatus_mutex
);
146 opr_cv_wait(&dumpSyncPtr
->ds_writerStatus_cond
, &dumpSyncPtr
->ds_writerStatus_mutex
);
147 MUTEX_EXIT(&dumpSyncPtr
->ds_writerStatus_mutex
);
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 #ifdef AFS_PTHREAD_ENV
163 opr_cv_broadcast(&dumpSyncPtr
->ds_readerStatus_cond
);
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(int fid
, afs_int32 type
)
183 struct structDumpHeader hostDumpHeader
, netDumpHeader
;
185 hostDumpHeader
.type
= type
;
186 hostDumpHeader
.structversion
= 1;
191 hostDumpHeader
.size
= sizeof(struct DbHeader
);
195 hostDumpHeader
.size
= sizeof(struct budb_dumpEntry
);
199 hostDumpHeader
.size
= sizeof(struct budb_tapeEntry
);
203 hostDumpHeader
.size
= sizeof(struct budb_volumeEntry
);
207 hostDumpHeader
.size
= 0;
211 LogError(0, "writeStructHeader: invalid type %d\n", type
);
215 structDumpHeader_hton(&hostDumpHeader
, &netDumpHeader
);
217 if (canWrite(fid
) <= 0)
218 return (BUDB_DUMPFAILED
);
219 if (write(fid
, &netDumpHeader
, sizeof(netDumpHeader
)) !=
220 sizeof(netDumpHeader
))
221 return (BUDB_DUMPFAILED
);
222 haveWritten(sizeof(netDumpHeader
));
228 * write header appropriate for requested structure type
232 writeTextHeader(int fid
, afs_int32 type
)
234 struct structDumpHeader hostDumpHeader
, netDumpHeader
;
236 hostDumpHeader
.structversion
= 1;
239 case TB_DUMPSCHEDULE
:
240 hostDumpHeader
.type
= SD_TEXT_DUMPSCHEDULE
;
244 hostDumpHeader
.type
= SD_TEXT_VOLUMESET
;
248 hostDumpHeader
.type
= SD_TEXT_TAPEHOSTS
;
252 LogError(0, "writeTextHeader: invalid type %d\n", type
);
256 hostDumpHeader
.size
= ntohl(db
.h
.textBlock
[type
].size
);
257 structDumpHeader_hton(&hostDumpHeader
, &netDumpHeader
);
259 if (canWrite(fid
) <= 0)
260 return (BUDB_DUMPFAILED
);
262 if (write(fid
, &netDumpHeader
, sizeof(netDumpHeader
)) !=
263 sizeof(netDumpHeader
))
264 return (BUDB_DUMPFAILED
);
266 haveWritten(sizeof(netDumpHeader
));
272 writeDbHeader(int fid
)
274 struct DbHeader header
;
276 afs_int32 code
= 0, tcode
;
278 extern struct memoryDB db
;
280 /* check the memory database header for integrity */
281 if (db
.h
.version
!= db
.h
.checkVersion
)
282 ERROR(BUDB_DATABASEINCONSISTENT
);
286 /* copy selected fields. Source is in xdr format. */
287 header
.dbversion
= db
.h
.version
;
288 header
.created
= htonl(curtime
);
289 strcpy(header
.cell
, "");
290 header
.lastDumpId
= db
.h
.lastDumpId
;
291 header
.lastInstanceId
= db
.h
.lastInstanceId
;
292 header
.lastTapeId
= db
.h
.lastTapeId
;
294 tcode
= writeStructHeader(fid
, SD_DBHEADER
);
298 if (canWrite(fid
) <= 0)
299 ERROR(BUDB_DUMPFAILED
);
301 if (write(fid
, &header
, sizeof(header
)) != sizeof(header
))
302 ERROR(BUDB_DUMPFAILED
);
304 haveWritten(sizeof(header
));
311 * write out a dump entry structure
315 writeDump(int fid
, dbDumpP dumpPtr
)
317 struct budb_dumpEntry dumpEntry
;
318 afs_int32 code
= 0, tcode
;
320 tcode
= dumpToBudbDump(dumpPtr
, &dumpEntry
);
324 writeStructHeader(fid
, SD_DUMP
);
326 if (canWrite(fid
) <= 0)
327 ERROR(BUDB_DUMPFAILED
);
329 if (write(fid
, &dumpEntry
, sizeof(dumpEntry
)) != sizeof(dumpEntry
))
330 ERROR(BUDB_DUMPFAILED
);
331 haveWritten(sizeof(dumpEntry
));
338 writeTape(int fid
, struct tape
*tapePtr
, afs_int32 dumpid
)
340 struct budb_tapeEntry tapeEntry
;
341 afs_int32 code
= 0, tcode
;
343 tcode
= writeStructHeader(fid
, SD_TAPE
);
347 tapeToBudbTape(tapePtr
, &tapeEntry
);
349 tapeEntry
.dump
= htonl(dumpid
);
351 if (canWrite(fid
) <= 0)
352 ERROR(BUDB_DUMPFAILED
);
354 if (write(fid
, &tapeEntry
, sizeof(tapeEntry
)) != sizeof(tapeEntry
))
355 ERROR(BUDB_DUMPFAILED
);
357 haveWritten(sizeof(tapeEntry
));
363 /* combines volFragment and volInfo */
366 writeVolume(struct ubik_trans
*ut
, int fid
, struct volFragment
*volFragmentPtr
,
367 struct volInfo
*volInfoPtr
, afs_int32 dumpid
, char *tapeName
)
369 struct budb_volumeEntry budbVolume
;
372 volsToBudbVol(volFragmentPtr
, volInfoPtr
, &budbVolume
);
374 budbVolume
.dump
= htonl(dumpid
);
375 strcpy(budbVolume
.tape
, tapeName
);
377 writeStructHeader(fid
, SD_VOLUME
);
379 if (canWrite(fid
) <= 0)
380 ERROR(BUDB_DUMPFAILED
);
382 if (write(fid
, &budbVolume
, sizeof(budbVolume
)) != sizeof(budbVolume
))
383 ERROR(BUDB_DUMPFAILED
);
385 haveWritten(sizeof(budbVolume
));
391 /* -------------------
392 * handlers for the text blocks
393 * -------------------
397 * make sure a text lock is NOT held
404 checkLock(afs_int32 textType
)
408 if ((textType
< 0) || (textType
> TB_NUM
- 1))
409 return (BUDB_BADARGUMENT
);
411 lockPtr
= &db
.h
.textLocks
[textType
];
413 if (lockPtr
->lockState
!= 0)
414 return (BUDB_LOCKED
);
419 * check the integrity of the specified text type
423 checkText(struct ubik_trans
*ut
, afs_int32 textType
)
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 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(struct ubik_trans
*ut
, int fid
, int textType
)
470 struct textBlock
*tbPtr
;
471 afs_int32 textSize
, writeSize
;
476 /* check lock is free */
477 code
= checkLock(textType
);
481 /* ensure that this block has the correct type */
482 code
= checkText(ut
, textType
);
484 LogError(0, "writeText: text type %d damaged\n", textType
);
488 tbPtr
= &db
.h
.textBlock
[textType
];
489 textSize
= ntohl(tbPtr
->size
);
490 dbAddr
= ntohl(tbPtr
->textAddr
);
493 goto error_exit
; /* Don't save anything if no blocks */
495 writeTextHeader(fid
, textType
);
498 code
= cdbread(ut
, text_BLOCK
, dbAddr
, (char *)&block
, sizeof(block
));
502 writeSize
= min(textSize
, BLOCK_DATA_SIZE
);
506 if (canWrite(fid
) <= 0)
507 ERROR(BUDB_DUMPFAILED
);
509 if (write(fid
, &block
.a
[0], writeSize
) != writeSize
)
512 haveWritten(writeSize
);
513 textSize
-= writeSize
;
515 dbAddr
= ntohl(block
.h
.next
);
522 #define MAXAPPENDS 200
525 writeDatabase(struct ubik_trans
*ut
, int fid
)
527 dbadr dbAddr
, dbAppAddr
;
528 struct dump diskDump
, apDiskDump
;
530 struct tape diskTape
;
532 struct volFragment diskVolFragment
;
533 struct volInfo diskVolInfo
;
537 afs_int32 code
= 0, tcode
;
538 afs_int32 appDumpAddrs
[MAXAPPENDS
], numaddrs
, appcount
, j
;
540 struct memoryHashTable
*mht
;
542 LogDebug(4, "writeDatabase:\n");
544 /* write out a header identifying this database etc */
545 tcode
= writeDbHeader(fid
);
547 LogError(tcode
, "writeDatabase: Can't write Header\n");
551 /* write out the tree of dump structures */
553 mht
= ht_GetType(HT_dumpIden_FUNCTION
, &entrySize
);
555 LogError(tcode
, "writeDatabase: Can't get dump type\n");
556 ERROR(BUDB_BADARGUMENT
);
559 for (old
= 0; old
<= 1; old
++) {
561 /* only two states, old or not old */
562 length
= (old
? mht
->oldLength
: mht
->length
);
566 for (hash
= 0; hash
< length
; hash
++) {
568 /* dump all the dumps in this hash bucket
570 for (dbAddr
= ht_LookupBucket(ut
, mht
, hash
, old
); dbAddr
; dbAddr
= ntohl(diskDump
.idHashChain
)) { /*initialDumps */
571 /* now check if this dump had any errors/inconsistencies.
572 * If so, don't dump it
574 if (badEntry(dbAddr
)) {
576 "writeDatabase: Damaged dump entry at addr 0x%x\n",
578 Log(" Skipping remainder of dumps on hash chain %d\n",
584 cdbread(ut
, dump_BLOCK
, dbAddr
, &diskDump
,
588 "writeDatabase: Can't read dump entry (addr 0x%x)\n",
590 Log(" Skipping remainder of dumps on hash chain %d\n",
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
;
604 dbAppAddr
= ntohl(apDiskDump
.appendedDumpChain
)) {
606 /* Check to see if we have a circular loop of appended dumps */
607 for (j
= 0; j
< numaddrs
; j
++) {
608 if (appDumpAddrs
[j
] == dbAppAddr
)
609 break; /* circular loop */
611 if (j
< numaddrs
) { /* circular loop */
612 Log("writeDatabase: Circular loop found in appended dumps\n");
613 Log("Skipping rest of appended dumps of dumpID %u\n",
617 if (numaddrs
>= MAXAPPENDS
)
618 numaddrs
= MAXAPPENDS
- 1; /* don't overflow */
619 appDumpAddrs
[numaddrs
] = dbAppAddr
;
622 /* If we dump a 1000 appended dumps, assume a loop */
623 if (appcount
>= 5 * MAXAPPENDS
) {
624 Log("writeDatabase: Potential circular loop of appended dumps\n");
625 Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump
.id
), appcount
);
630 /* Read the dump entry */
631 if (dbAddr
== dbAppAddr
) {
632 /* First time through, don't need to read the dump entry again */
633 memcpy(&apDiskDump
, &diskDump
, sizeof(diskDump
));
635 if (badEntry(dbAppAddr
)) {
637 "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
639 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump
.id
));
644 cdbread(ut
, dump_BLOCK
, dbAppAddr
, &apDiskDump
,
648 "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
650 Log(" Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump
.id
));
654 /* Verify that this appended dump points to the initial dump */
655 if (ntohl(apDiskDump
.initialDumpID
) !=
656 ntohl(diskDump
.id
)) {
658 "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
659 ntohl(apDiskDump
.id
),
661 Log(" Skipping this appended dump\n");
666 /* Save the dump entry */
667 tcode
= writeDump(fid
, &apDiskDump
);
670 "writeDatabase: Can't write dump entry\n");
674 /* For each tape on this dump
676 for (tapeAddr
= ntohl(apDiskDump
.firstTape
); tapeAddr
; tapeAddr
= ntohl(diskTape
.nextTape
)) { /*tapes */
677 /* read the tape entry */
679 cdbread(ut
, tape_BLOCK
, tapeAddr
, &diskTape
,
683 "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
684 tapeAddr
, ntohl(apDiskDump
.id
));
685 Log(" Skipping this and remaining tapes in the dump (and all their volumes)\n");
689 /* Save the tape entry */
691 writeTape(fid
, &diskTape
, ntohl(apDiskDump
.id
));
694 "writeDatabase: Can't write tape entry\n");
698 /* For each volume on this tape.
700 for (volFragAddr
= ntohl(diskTape
.firstVol
); volFragAddr
; volFragAddr
= ntohl(diskVolFragment
.sameTapeChain
)) { /*volumes */
701 /* Read the volume Fragment entry */
703 cdbread(ut
, volFragment_BLOCK
, volFragAddr
,
705 sizeof(diskVolFragment
));
708 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
709 volFragAddr
, ntohl(apDiskDump
.id
));
710 Log(" Skipping this and remaining volumes on tape '%s'\n", diskTape
.name
);
714 /* Read the volume Info entry */
716 cdbread(ut
, volInfo_BLOCK
,
717 ntohl(diskVolFragment
.vol
),
718 &diskVolInfo
, sizeof(diskVolInfo
));
721 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
722 ntohl(diskVolFragment
.vol
),
723 ntohl(apDiskDump
.id
));
724 Log(" Skipping volume on tape '%s'\n",
729 /* Save the volume entry */
731 writeVolume(ut
, fid
, &diskVolFragment
,
733 ntohl(apDiskDump
.id
),
737 "writeDatabase: Can't write volume entry\n");
747 /* write out the textual configuration information */
748 tcode
= writeText(ut
, fid
, TB_DUMPSCHEDULE
);
750 LogError(tcode
, "writeDatabase: Can't write dump schedule\n");
753 tcode
= writeText(ut
, fid
, TB_VOLUMESET
);
755 LogError(tcode
, "writeDatabase: Can't write volume set\n");
758 tcode
= writeText(ut
, fid
, TB_TAPEHOSTS
);
760 LogError(tcode
, "writeDatabase: Can't write tape hosts\n");
764 tcode
= writeStructHeader(fid
, SD_END
);
766 LogError(tcode
, "writeDatabase: Can't write end savedb\n");
781 afs_int32 in
, out
, except
;
792 code
= IOMGR_Select(32, &in
, &out
, &except
, &tp
);