1*10911Ssam static char *sccsid = "@(#)tape.c 1.6 (Berkeley) 02/11/83"; 21425Sroot #include "dump.h" 31425Sroot 4*10911Ssam char (*tblock)[TP_BSIZE]; /* Pointer to malloc()ed buffer for tape */ 5*10911Ssam int writesize; /* Size of malloc()ed buffer for tape */ 64774Smckusic int trecno = 0; 7*10911Ssam extern int ntrec; /* blocking factor on tape */ 81425Sroot 9*10911Ssam /* 10*10911Ssam * Allocate the buffer for tape operations. 11*10911Ssam * 12*10911Ssam * Depends on global variable ntrec, set from 'b' option in command line. 13*10911Ssam * Returns 1 if successful, 0 if failed. 14*10911Ssam * 15*10911Ssam * For later kernel performance improvement, this buffer should be allocated 16*10911Ssam * on a page boundary. 17*10911Ssam */ 18*10911Ssam alloctape() 19*10911Ssam { 20*10911Ssam 21*10911Ssam writesize = ntrec * TP_BSIZE; 22*10911Ssam tblock = (char (*)[TP_BSIZE])malloc(writesize); 23*10911Ssam return (tblock != NULL); 24*10911Ssam } 25*10911Ssam 26*10911Ssam 271425Sroot taprec(dp) 285329Smckusic char *dp; 291425Sroot { 301425Sroot register i; 311425Sroot 325329Smckusic for (i=0; i < TP_BSIZE; i++) 331425Sroot tblock[trecno][i] = *dp++; 341425Sroot trecno++; 351425Sroot spcl.c_tapea++; 36*10911Ssam if(trecno >= ntrec) 371425Sroot flusht(); 381425Sroot } 391425Sroot 404774Smckusic dmpblk(blkno, size) 414774Smckusic daddr_t blkno; 424774Smckusic int size; 431425Sroot { 445329Smckusic int avail, tpblks, dblkno; 451425Sroot 465329Smckusic if (size % TP_BSIZE != 0) 474774Smckusic msg("bad size to dmpblk: %d\n", size); 48*10911Ssam avail = ntrec - trecno; 495329Smckusic dblkno = fsbtodb(sblock, blkno); 505329Smckusic for (tpblks = size / TP_BSIZE; tpblks > avail; ) { 515329Smckusic bread(dblkno, tblock[trecno], TP_BSIZE * avail); 524774Smckusic trecno += avail; 534774Smckusic spcl.c_tapea += avail; 544774Smckusic flusht(); 555329Smckusic dblkno += avail * (TP_BSIZE / DEV_BSIZE); 565329Smckusic tpblks -= avail; 57*10911Ssam avail = ntrec - trecno; 584774Smckusic } 595329Smckusic bread(dblkno, tblock[trecno], TP_BSIZE * tpblks); 605329Smckusic trecno += tpblks; 615329Smckusic spcl.c_tapea += tpblks; 62*10911Ssam if(trecno >= ntrec) 631425Sroot flusht(); 641425Sroot } 651425Sroot 661425Sroot int nogripe = 0; 671425Sroot 681425Sroot flusht() 691425Sroot { 701425Sroot register i, si; 711425Sroot daddr_t d; 721425Sroot 731425Sroot trecno = 0; 74*10911Ssam if (write(to, tblock[0], writesize) != writesize){ 751425Sroot msg("Tape write error on tape %d\n", tapeno); 761425Sroot broadcast("TAPE ERROR!\n"); 771425Sroot if (query("Do you want to restart?")){ 781425Sroot msg("This tape will rewind. After it is rewound,\n"); 791425Sroot msg("replace the faulty tape with a new one;\n"); 801925Swnj msg("this dump volume will be rewritten.\n"); 811425Sroot /* 821425Sroot * Temporarily change the tapeno identification 831425Sroot */ 841425Sroot tapeno--; 851425Sroot nogripe = 1; 861425Sroot close_rewind(); 871425Sroot nogripe = 0; 881425Sroot tapeno++; 891425Sroot Exit(X_REWRITE); 901425Sroot } else { 911425Sroot dumpabort(); 921425Sroot /*NOTREACHED*/ 931425Sroot } 941425Sroot } 951425Sroot 96*10911Ssam asize += writesize/density; 971425Sroot asize += 7; 98*10911Ssam blockswritten += ntrec; 991425Sroot if (asize > tsize) { 1001425Sroot close_rewind(); 1011425Sroot otape(); 1021425Sroot } 1031425Sroot timeest(); 1041425Sroot } 1051425Sroot 1061425Sroot rewind() 1071425Sroot { 1081425Sroot int secs; 1093214Swnj int f; 1101425Sroot #ifdef DEBUG 1111425Sroot msg("Waiting 10 seconds to rewind.\n"); 1121425Sroot sleep(10); 1131425Sroot #else 1141425Sroot /* 1151425Sroot * It takes about 3 minutes, 25secs to rewind 2300' of tape 1161425Sroot */ 1173214Swnj msg("Tape rewinding\n", secs); 1183214Swnj close(to); 1193214Swnj while ((f = open(tape, 0)) < 0) 1203214Swnj sleep (10); 1213214Swnj close(f); 1221425Sroot #endif 1231425Sroot } 1241425Sroot 1251425Sroot close_rewind() 1261425Sroot { 1271425Sroot close(to); 1281425Sroot if (!nogripe){ 1291425Sroot rewind(); 1301425Sroot msg("Change Tapes: Mount tape #%d\n", tapeno+1); 1311425Sroot broadcast("CHANGE TAPES!\7\7\n"); 1321425Sroot } 1331425Sroot do{ 1341425Sroot if (query ("Is the new tape mounted and ready to go?")) 1351425Sroot break; 1361425Sroot if (query ("Do you want to abort?")){ 1371425Sroot dumpabort(); 1381425Sroot /*NOTREACHED*/ 1391425Sroot } 1401425Sroot } while (1); 1411425Sroot } 1421425Sroot 1431425Sroot /* 1441425Sroot * We implement taking and restoring checkpoints on 1451425Sroot * the tape level. 1461425Sroot * When each tape is opened, a new process is created by forking; this 1471425Sroot * saves all of the necessary context in the parent. The child 1481425Sroot * continues the dump; the parent waits around, saving the context. 1491425Sroot * If the child returns X_REWRITE, then it had problems writing that tape; 1501425Sroot * this causes the parent to fork again, duplicating the context, and 1511425Sroot * everything continues as if nothing had happened. 1521425Sroot */ 1531425Sroot 1541425Sroot otape() 1551425Sroot { 1561425Sroot int parentpid; 1571425Sroot int childpid; 1581425Sroot int status; 1591425Sroot int waitpid; 1601425Sroot int sig_ign_parent(); 1611425Sroot int interrupt(); 1621425Sroot 1631425Sroot /* 1641425Sroot * Force the tape to be closed 1651425Sroot */ 1661425Sroot close(to); 1671425Sroot parentpid = getpid(); 1681425Sroot 1691425Sroot restore_check_point: 1701425Sroot signal(SIGINT, interrupt); 1711425Sroot /* 1721425Sroot * All signals are inherited... 1731425Sroot */ 1741425Sroot childpid = fork(); 1751425Sroot if (childpid < 0){ 1761425Sroot msg("Context save fork fails in parent %d\n", parentpid); 1771425Sroot Exit(X_ABORT); 1781425Sroot } 1791425Sroot if (childpid != 0){ 1801425Sroot /* 1811425Sroot * PARENT: 1821425Sroot * save the context by waiting 1831425Sroot * until the child doing all of the work returns. 1841425Sroot * don't catch the interrupt 1851425Sroot */ 1861425Sroot signal(SIGINT, SIG_IGN); 1871425Sroot #ifdef TDEBUG 1881425Sroot msg("Tape: %d; parent process: %d child process %d\n", 1891425Sroot tapeno+1, parentpid, childpid); 1901425Sroot #endif TDEBUG 1911425Sroot for (;;){ 1921425Sroot waitpid = wait(&status); 1931425Sroot if (waitpid != childpid){ 1941425Sroot msg("Parent %d waiting for child %d has another child %d return\n", 1951425Sroot parentpid, childpid, waitpid); 1961425Sroot } else 1971425Sroot break; 1981425Sroot } 1991425Sroot if (status & 0xFF){ 2001425Sroot msg("Child %d returns LOB status %o\n", 2011425Sroot childpid, status&0xFF); 2021425Sroot } 2031425Sroot status = (status >> 8) & 0xFF; 2041425Sroot #ifdef TDEBUG 2051425Sroot switch(status){ 2061425Sroot case X_FINOK: 2071425Sroot msg("Child %d finishes X_FINOK\n", childpid); 2081425Sroot break; 2091425Sroot case X_ABORT: 2101425Sroot msg("Child %d finishes X_ABORT\n", childpid); 2111425Sroot break; 2121425Sroot case X_REWRITE: 2131425Sroot msg("Child %d finishes X_REWRITE\n", childpid); 2141425Sroot break; 2151425Sroot default: 2161425Sroot msg("Child %d finishes unknown %d\n", childpid,status); 2171425Sroot break; 2181425Sroot } 2191425Sroot #endif TDEBUG 2201425Sroot switch(status){ 2211425Sroot case X_FINOK: 2221425Sroot Exit(X_FINOK); 2231425Sroot case X_ABORT: 2241425Sroot Exit(X_ABORT); 2251425Sroot case X_REWRITE: 2261425Sroot goto restore_check_point; 2271425Sroot default: 2281425Sroot msg("Bad return code from dump: %d\n", status); 2291425Sroot Exit(X_ABORT); 2301425Sroot } 2311425Sroot /*NOTREACHED*/ 2321425Sroot } else { /* we are the child; just continue */ 2331425Sroot #ifdef TDEBUG 2341425Sroot sleep(4); /* allow time for parent's message to get out */ 2351425Sroot msg("Child on Tape %d has parent %d, my pid = %d\n", 2361425Sroot tapeno+1, parentpid, getpid()); 2371425Sroot #endif 2381425Sroot do{ 2391425Sroot to = creat(tape, 0666); 2401425Sroot if (to < 0) { 2411425Sroot if (!query("Cannot open tape. Do you want to retry the open?")) 2421425Sroot dumpabort(); 2431425Sroot } else break; 2441425Sroot } while (1); 2451425Sroot 2461425Sroot asize = 0; 2471425Sroot tapeno++; /* current tape sequence */ 2481425Sroot newtape++; /* new tape signal */ 2491425Sroot spcl.c_volume++; 2501425Sroot spcl.c_type = TS_TAPE; 2511425Sroot spclrec(); 2521425Sroot if (tapeno > 1) 2531425Sroot msg("Tape %d begins with blocks from ino %d\n", 2541425Sroot tapeno, ino); 2551425Sroot } 2561425Sroot } 2571425Sroot 2581425Sroot /* 2591425Sroot * The parent still catches interrupts, but does nothing with them 2601425Sroot */ 2611425Sroot sig_ign_parent() 2621425Sroot { 2631425Sroot msg("Waiting parent receives interrupt\n"); 2641425Sroot signal(SIGINT, sig_ign_parent); 2651425Sroot } 2661425Sroot 2671425Sroot dumpabort() 2681425Sroot { 2691925Swnj msg("The ENTIRE dump is aborted.\n"); 2701425Sroot Exit(X_ABORT); 2711425Sroot } 2721425Sroot 2731425Sroot Exit(status) 2741425Sroot { 2751425Sroot #ifdef TDEBUG 2761425Sroot msg("pid = %d exits with status %d\n", getpid(), status); 2771425Sroot #endif TDEBUG 2781925Swnj exit(status); 2791425Sroot } 280