1*17527Ssam #ifndef lint 2*17527Ssam static char *sccsid = "@(#)tape.c 1.8 (Berkeley) 12/16/84"; 3*17527Ssam #endif 4*17527Ssam 51425Sroot #include "dump.h" 61425Sroot 710911Ssam char (*tblock)[TP_BSIZE]; /* Pointer to malloc()ed buffer for tape */ 810911Ssam int writesize; /* Size of malloc()ed buffer for tape */ 94774Smckusic int trecno = 0; 1010911Ssam extern int ntrec; /* blocking factor on tape */ 111425Sroot 1210911Ssam /* 1310911Ssam * Allocate the buffer for tape operations. 1410911Ssam * 1510911Ssam * Depends on global variable ntrec, set from 'b' option in command line. 1610911Ssam * Returns 1 if successful, 0 if failed. 1710911Ssam * 1810911Ssam * For later kernel performance improvement, this buffer should be allocated 1910911Ssam * on a page boundary. 2010911Ssam */ 2110911Ssam alloctape() 2210911Ssam { 2310911Ssam 2410911Ssam writesize = ntrec * TP_BSIZE; 2510911Ssam tblock = (char (*)[TP_BSIZE])malloc(writesize); 2610911Ssam return (tblock != NULL); 2710911Ssam } 2810911Ssam 2910911Ssam 301425Sroot taprec(dp) 315329Smckusic char *dp; 321425Sroot { 331425Sroot 34*17527Ssam bcopy(dp, tblock[trecno], TP_BSIZE); 351425Sroot trecno++; 361425Sroot spcl.c_tapea++; 3710911Ssam if(trecno >= ntrec) 381425Sroot flusht(); 391425Sroot } 401425Sroot 414774Smckusic dmpblk(blkno, size) 424774Smckusic daddr_t blkno; 434774Smckusic int size; 441425Sroot { 455329Smckusic int avail, tpblks, dblkno; 461425Sroot 475329Smckusic if (size % TP_BSIZE != 0) 484774Smckusic msg("bad size to dmpblk: %d\n", size); 4910911Ssam avail = ntrec - trecno; 505329Smckusic dblkno = fsbtodb(sblock, blkno); 515329Smckusic for (tpblks = size / TP_BSIZE; tpblks > avail; ) { 525329Smckusic bread(dblkno, tblock[trecno], TP_BSIZE * avail); 534774Smckusic trecno += avail; 544774Smckusic spcl.c_tapea += avail; 554774Smckusic flusht(); 565329Smckusic dblkno += avail * (TP_BSIZE / DEV_BSIZE); 575329Smckusic tpblks -= avail; 5810911Ssam avail = ntrec - trecno; 594774Smckusic } 605329Smckusic bread(dblkno, tblock[trecno], TP_BSIZE * tpblks); 615329Smckusic trecno += tpblks; 625329Smckusic spcl.c_tapea += tpblks; 6310911Ssam if(trecno >= ntrec) 641425Sroot flusht(); 651425Sroot } 661425Sroot 671425Sroot int nogripe = 0; 681425Sroot 691425Sroot flusht() 701425Sroot { 711425Sroot register i, si; 721425Sroot daddr_t d; 731425Sroot 741425Sroot trecno = 0; 7510911Ssam if (write(to, tblock[0], writesize) != writesize){ 7612331Smckusick if (pipeout) { 7712331Smckusick msg("Tape write error on %s\n", tape); 7812331Smckusick msg("Cannot recover\n"); 7912331Smckusick dumpabort(); 8012331Smckusick /* NOTREACHED */ 8112331Smckusick } 821425Sroot msg("Tape write error on tape %d\n", tapeno); 831425Sroot broadcast("TAPE ERROR!\n"); 841425Sroot if (query("Do you want to restart?")){ 851425Sroot msg("This tape will rewind. After it is rewound,\n"); 861425Sroot msg("replace the faulty tape with a new one;\n"); 871925Swnj msg("this dump volume will be rewritten.\n"); 881425Sroot /* 891425Sroot * Temporarily change the tapeno identification 901425Sroot */ 911425Sroot tapeno--; 921425Sroot nogripe = 1; 931425Sroot close_rewind(); 941425Sroot nogripe = 0; 951425Sroot tapeno++; 961425Sroot Exit(X_REWRITE); 971425Sroot } else { 981425Sroot dumpabort(); 991425Sroot /*NOTREACHED*/ 1001425Sroot } 1011425Sroot } 1021425Sroot 10310911Ssam asize += writesize/density; 1041425Sroot asize += 7; 10510911Ssam blockswritten += ntrec; 10612331Smckusick if (!pipeout && asize > tsize) { 1071425Sroot close_rewind(); 1081425Sroot otape(); 1091425Sroot } 1101425Sroot timeest(); 1111425Sroot } 1121425Sroot 1131425Sroot rewind() 1141425Sroot { 1151425Sroot int secs; 1163214Swnj int f; 11712331Smckusick 11812331Smckusick if (pipeout) 11912331Smckusick return; 1201425Sroot #ifdef DEBUG 1211425Sroot msg("Waiting 10 seconds to rewind.\n"); 1221425Sroot sleep(10); 1231425Sroot #else 1241425Sroot /* 1251425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 1261425Sroot */ 1273214Swnj msg("Tape rewinding\n", secs); 1283214Swnj close(to); 1293214Swnj while ((f = open(tape, 0)) < 0) 1303214Swnj sleep (10); 1313214Swnj close(f); 1321425Sroot #endif 1331425Sroot } 1341425Sroot 1351425Sroot close_rewind() 1361425Sroot { 13712331Smckusick 13812331Smckusick if (pipeout) 13912331Smckusick return; 1401425Sroot close(to); 1411425Sroot if (!nogripe){ 1421425Sroot rewind(); 1431425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 1441425Sroot broadcast("CHANGE TAPES!\7\7\n"); 1451425Sroot } 1461425Sroot do{ 1471425Sroot if (query ("Is the new tape mounted and ready to go?")) 1481425Sroot break; 1491425Sroot if (query ("Do you want to abort?")){ 1501425Sroot dumpabort(); 1511425Sroot /*NOTREACHED*/ 1521425Sroot } 1531425Sroot } while (1); 1541425Sroot } 1551425Sroot 1561425Sroot /* 1571425Sroot * We implement taking and restoring checkpoints on 1581425Sroot * the tape level. 1591425Sroot * When each tape is opened, a new process is created by forking; this 1601425Sroot * saves all of the necessary context in the parent. The child 1611425Sroot * continues the dump; the parent waits around, saving the context. 1621425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 1631425Sroot * this causes the parent to fork again, duplicating the context, and 1641425Sroot * everything continues as if nothing had happened. 1651425Sroot */ 1661425Sroot 1671425Sroot otape() 1681425Sroot { 1691425Sroot int parentpid; 1701425Sroot int childpid; 1711425Sroot int status; 1721425Sroot int waitpid; 1731425Sroot int sig_ign_parent(); 1741425Sroot int interrupt(); 1751425Sroot 1761425Sroot /* 1771425Sroot * Force the tape to be closed 1781425Sroot */ 1791425Sroot close(to); 1801425Sroot parentpid = getpid(); 1811425Sroot 1821425Sroot restore_check_point: 1831425Sroot signal(SIGINT, interrupt); 1841425Sroot /* 1851425Sroot * All signals are inherited... 1861425Sroot */ 1871425Sroot childpid = fork(); 1881425Sroot if (childpid < 0){ 1891425Sroot msg("Context save fork fails in parent %d\n", parentpid); 1901425Sroot Exit(X_ABORT); 1911425Sroot } 1921425Sroot if (childpid != 0){ 1931425Sroot /* 1941425Sroot * PARENT: 1951425Sroot * save the context by waiting 1961425Sroot * until the child doing all of the work returns. 1971425Sroot * don't catch the interrupt 1981425Sroot */ 1991425Sroot signal(SIGINT, SIG_IGN); 2001425Sroot #ifdef TDEBUG 2011425Sroot msg("Tape: %d; parent process: %d child process %d\n", 2021425Sroot tapeno+1, parentpid, childpid); 2031425Sroot #endif TDEBUG 2041425Sroot for (;;){ 2051425Sroot waitpid = wait(&status); 2061425Sroot if (waitpid != childpid){ 2071425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 2081425Sroot parentpid, childpid, waitpid); 2091425Sroot } else 2101425Sroot break; 2111425Sroot } 2121425Sroot if (status & 0xFF){ 2131425Sroot msg("Child %d returns LOB status %o\n", 2141425Sroot childpid, status&0xFF); 2151425Sroot } 2161425Sroot status = (status >> 8) & 0xFF; 2171425Sroot #ifdef TDEBUG 2181425Sroot switch(status){ 2191425Sroot case X_FINOK: 2201425Sroot msg("Child %d finishes X_FINOK\n", childpid); 2211425Sroot break; 2221425Sroot case X_ABORT: 2231425Sroot msg("Child %d finishes X_ABORT\n", childpid); 2241425Sroot break; 2251425Sroot case X_REWRITE: 2261425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 2271425Sroot break; 2281425Sroot default: 2291425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 2301425Sroot break; 2311425Sroot } 2321425Sroot #endif TDEBUG 2331425Sroot switch(status){ 2341425Sroot case X_FINOK: 2351425Sroot Exit(X_FINOK); 2361425Sroot case X_ABORT: 2371425Sroot Exit(X_ABORT); 2381425Sroot case X_REWRITE: 2391425Sroot goto restore_check_point; 2401425Sroot default: 2411425Sroot msg("Bad return code from dump: %d\n", status); 2421425Sroot Exit(X_ABORT); 2431425Sroot } 2441425Sroot /*NOTREACHED*/ 2451425Sroot } else { /* we are the child; just continue */ 2461425Sroot #ifdef TDEBUG 2471425Sroot sleep(4); /* allow time for parent's message to get out */ 2481425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 2491425Sroot tapeno+1, parentpid, getpid()); 2501425Sroot #endif 2511425Sroot do{ 25212331Smckusick if (pipeout) 25312331Smckusick to = 1; 25412331Smckusick else 25512331Smckusick to = creat(tape, 0666); 2561425Sroot if (to < 0) { 2571425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 2581425Sroot dumpabort(); 2591425Sroot } else break; 2601425Sroot } while (1); 2611425Sroot 2621425Sroot asize = 0; 2631425Sroot tapeno++; /* current tape sequence */ 2641425Sroot newtape++; /* new tape signal */ 2651425Sroot spcl.c_volume++; 2661425Sroot spcl.c_type = TS_TAPE; 2671425Sroot spclrec(); 2681425Sroot if (tapeno > 1) 2691425Sroot msg("Tape %d begins with blocks from ino %d\n", 2701425Sroot tapeno, ino); 2711425Sroot } 2721425Sroot } 2731425Sroot 2741425Sroot /* 2751425Sroot * The parent still catches interrupts, but does nothing with them 2761425Sroot */ 2771425Sroot sig_ign_parent() 2781425Sroot { 2791425Sroot msg("Waiting parent receives interrupt\n"); 2801425Sroot signal(SIGINT, sig_ign_parent); 2811425Sroot } 2821425Sroot 2831425Sroot dumpabort() 2841425Sroot { 2851925Swnj msg("The ENTIRE dump is aborted.\n"); 2861425Sroot Exit(X_ABORT); 2871425Sroot } 2881425Sroot 2891425Sroot Exit(status) 2901425Sroot { 2911425Sroot #ifdef TDEBUG 2921425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 2931425Sroot #endif TDEBUG 2941925Swnj exit(status); 2951425Sroot } 296