|
|
1.1.1.2 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)dumptape.c 5.2 (Berkeley) 8/5/85"; ! 9: #endif not lint ! 10: 1.1 root 11: #include "dump.h" 1.1.1.2 ! root 12: #include <sys/file.h> 1.1 root 13: 14: char (*tblock)[TP_BSIZE]; /* Pointer to malloc()ed buffer for tape */ 15: int writesize; /* Size of malloc()ed buffer for tape */ 16: int trecno = 0; 1.1.1.2 ! root 17: extern int ntrec; /* blocking factor on tape */ ! 18: extern int cartridge; ! 19: int tenths; /* length of tape used per block written */ 1.1 root 20: 21: /* 1.1.1.2 ! root 22: * Concurrent dump mods (Caltech) - disk block reading and tape writing ! 23: * are exported to several slave processes. While one slave writes the ! 24: * tape, the others read disk blocks; they pass control of the tape in ! 25: * a ring via flock(). The parent process traverses the filesystem and ! 26: * sends spclrec()'s and lists of daddr's to each slave via pipes. 1.1 root 27: * 1.1.1.2 ! root 28: * from "@(#)dumptape.c 2.1 (Berkeley+Caltech mods) 4/7/85"; ! 29: */ ! 30: struct req { /* instruction packets sent to slaves */ ! 31: daddr_t dblk; ! 32: int count; ! 33: } *req; ! 34: int reqsiz; ! 35: ! 36: #define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */ ! 37: int slavepid[SLAVES]; ! 38: int slavefd[SLAVES]; /* Pipes from master to each slave */ ! 39: int rotor; /* Current slave number */ ! 40: int master; /* Pid of master, for sending error signals */ ! 41: int trace = 0; /* Protocol trace; easily patchable with adb */ ! 42: #define tmsg if (trace) msg ! 43: ! 44: /* ! 45: /* Allocate tape buffer contiguous with the array of instruction ! 46: * packets, so flusht() can write them together with one write(). ! 47: * Align tape buffer on page boundary to speed up tape write(). 1.1 root 48: */ 49: alloctape() 50: { 51: 1.1.1.2 ! root 52: int pgoff = getpagesize() - 1; 1.1 root 53: writesize = ntrec * TP_BSIZE; 1.1.1.2 ! root 54: /* ! 55: * 92185 NEEDS 0.4"; 92181 NEEDS 0.8" to start/stop (see TU80 manual) ! 56: */ ! 57: tenths = writesize/density + (cartridge ? 16 : density == 625 ? 4 : 8); 1.1 root 58: 1.1.1.2 ! root 59: reqsiz = ntrec * sizeof(struct req); ! 60: req = (struct req *)malloc(reqsiz + writesize + pgoff); ! 61: if (req == NULL) ! 62: return(0); ! 63: tblock = (char (*)[TP_BSIZE]) (((long)&req[ntrec] + pgoff) &~ pgoff); ! 64: req = (struct req *)tblock; ! 65: req = &req[-ntrec]; /* Cmd packets go in front of tape buffer */ ! 66: return(1); ! 67: } 1.1 root 68: 1.1.1.2 ! root 69: /* ! 70: * Make copy of spclrec, to later send to tape writer. ! 71: */ 1.1 root 72: taprec(dp) 73: char *dp; 74: { 75: 1.1.1.2 ! root 76: tmsg("taprec %d\n", trecno); ! 77: req[trecno].dblk = (daddr_t)0; ! 78: req[trecno].count = 1; ! 79: *(union u_spcl *)(*tblock++) = *(union u_spcl *)dp; /* movc3 */ 1.1 root 80: trecno++; 81: spcl.c_tapea++; 82: if(trecno >= ntrec) 83: flusht(); 84: } 85: 86: dmpblk(blkno, size) 87: daddr_t blkno; 88: int size; 89: { 1.1.1.2 ! root 90: int tpblks, dblkno; ! 91: register int avail; 1.1 root 92: 93: dblkno = fsbtodb(sblock, blkno); 1.1.1.2 ! root 94: tpblks = size / TP_BSIZE; ! 95: while ((avail = MIN(tpblks, ntrec - trecno)) > 0) { ! 96: tmsg("dmpblk %d\n", avail); ! 97: req[trecno].dblk = dblkno; ! 98: req[trecno].count = avail; 1.1 root 99: spcl.c_tapea += avail; 1.1.1.2 ! root 100: if ((trecno += avail) >= ntrec) ! 101: flusht(); 1.1 root 102: dblkno += avail * (TP_BSIZE / DEV_BSIZE); 103: tpblks -= avail; 104: } 105: } 106: 107: int nogripe = 0; 108: 1.1.1.2 ! root 109: tperror() { ! 110: if (pipeout) { ! 111: msg("Tape write error on %s\n", tape); ! 112: msg("Cannot recover\n"); ! 113: dumpabort(); ! 114: /* NOTREACHED */ ! 115: } ! 116: msg("Tape write error on tape %d\n", tapeno); ! 117: broadcast("TAPE ERROR!\n"); ! 118: if (!query("Do you want to restart?")) ! 119: dumpabort(); ! 120: msg("This tape will rewind. After it is rewound,\n"); ! 121: msg("replace the faulty tape with a new one;\n"); ! 122: msg("this dump volume will be rewritten.\n"); ! 123: killall(); ! 124: nogripe = 1; ! 125: close_rewind(); ! 126: Exit(X_REWRITE); ! 127: } ! 128: ! 129: #ifdef RDUMP ! 130: tflush(cnt) ! 131: int cnt; ! 132: { ! 133: int i; ! 134: ! 135: for (i = 0; i < ntrec; i++) ! 136: spclrec(); ! 137: } ! 138: #endif RDUMP ! 139: 1.1 root 140: flusht() 141: { 1.1.1.2 ! root 142: int sig, siz = (char *)tblock - (char *)req; 1.1 root 143: 1.1.1.2 ! root 144: tmsg("flusht %d\n", siz); ! 145: sig = sigblock(1 << SIGINT-1); /* Don't abort pipe write */ ! 146: if (write(slavefd[rotor], req, siz) != siz) { ! 147: perror(" DUMP: pipe error in command to slave"); ! 148: dumpabort(); 1.1 root 149: } 1.1.1.2 ! root 150: sigsetmask(sig); ! 151: if (++rotor >= SLAVES) rotor = 0; ! 152: tblock = (char (*)[TP_BSIZE]) &req[ntrec]; ! 153: trecno = 0; ! 154: asize += tenths; 1.1 root 155: blockswritten += ntrec; 156: if (!pipeout && asize > tsize) { 157: close_rewind(); 158: otape(); 159: } 160: timeest(); 161: } 162: 163: tape_rewind() 164: { 165: int f; 166: 167: if (pipeout) 168: return; 1.1.1.2 ! root 169: for (f = 0; f < SLAVES; f++) ! 170: close(slavefd[f]); ! 171: while (wait(NULL) >= 0) ; /* wait for any signals from slaves */ ! 172: msg("Tape rewinding\n"); ! 173: #ifdef RDUMP ! 174: rmtclose(); ! 175: while (rmtopen(tape, 0) < 0) ! 176: sleep(10); ! 177: rmtclose(); 1.1 root 178: #else 179: close(to); 180: while ((f = open(tape, 0)) < 0) 181: sleep (10); 182: close(f); 1.1.1.2 ! root 183: #endif RDUMP 1.1 root 184: } 185: 186: close_rewind() 187: { 1.1.1.2 ! root 188: tape_rewind(); ! 189: if (!nogripe) { 1.1 root 190: msg("Change Tapes: Mount tape #%d\n", tapeno+1); 191: broadcast("CHANGE TAPES!\7\7\n"); 192: } 1.1.1.2 ! root 193: while (!query("Is the new tape mounted and ready to go?")) ! 194: if (query("Do you want to abort?")) 1.1 root 195: dumpabort(); 196: } 197: 198: /* 1.1.1.2 ! root 199: * We implement taking and restoring checkpoints on the tape level. 1.1 root 200: * When each tape is opened, a new process is created by forking; this 201: * saves all of the necessary context in the parent. The child 202: * continues the dump; the parent waits around, saving the context. 203: * If the child returns X_REWRITE, then it had problems writing that tape; 204: * this causes the parent to fork again, duplicating the context, and 205: * everything continues as if nothing had happened. 206: */ 207: 208: otape() 209: { 210: int parentpid; 211: int childpid; 212: int status; 213: int waitpid; 1.1.1.2 ! root 214: int (*interrupt)(); 1.1 root 215: 216: parentpid = getpid(); 217: 218: restore_check_point: 1.1.1.2 ! root 219: interrupt = signal(SIGINT, SIG_IGN); 1.1 root 220: childpid = fork(); 1.1.1.2 ! root 221: if (childpid < 0) { 1.1 root 222: msg("Context save fork fails in parent %d\n", parentpid); 223: Exit(X_ABORT); 224: } 1.1.1.2 ! root 225: if (childpid != 0) { 1.1 root 226: /* 227: * PARENT: 228: * save the context by waiting 229: * until the child doing all of the work returns. 1.1.1.2 ! root 230: * don't catch the interrupt 1.1 root 231: */ 232: #ifdef TDEBUG 233: msg("Tape: %d; parent process: %d child process %d\n", 234: tapeno+1, parentpid, childpid); 235: #endif TDEBUG 1.1.1.2 ! root 236: while ((waitpid = wait(&status)) != childpid) ! 237: msg("Parent %d waiting for child %d has another child %d return\n", ! 238: parentpid, childpid, waitpid); ! 239: if (status & 0xFF) { 1.1 root 240: msg("Child %d returns LOB status %o\n", 241: childpid, status&0xFF); 242: } 243: status = (status >> 8) & 0xFF; 244: #ifdef TDEBUG 1.1.1.2 ! root 245: switch(status) { 1.1 root 246: case X_FINOK: 247: msg("Child %d finishes X_FINOK\n", childpid); 248: break; 249: case X_ABORT: 250: msg("Child %d finishes X_ABORT\n", childpid); 251: break; 252: case X_REWRITE: 253: msg("Child %d finishes X_REWRITE\n", childpid); 254: break; 255: default: 1.1.1.2 ! root 256: msg("Child %d finishes unknown %d\n", ! 257: childpid, status); 1.1 root 258: break; 259: } 260: #endif TDEBUG 1.1.1.2 ! root 261: switch(status) { 1.1 root 262: case X_FINOK: 263: Exit(X_FINOK); 264: case X_ABORT: 265: Exit(X_ABORT); 266: case X_REWRITE: 267: goto restore_check_point; 268: default: 269: msg("Bad return code from dump: %d\n", status); 270: Exit(X_ABORT); 271: } 272: /*NOTREACHED*/ 273: } else { /* we are the child; just continue */ 274: #ifdef TDEBUG 275: sleep(4); /* allow time for parent's message to get out */ 276: msg("Child on Tape %d has parent %d, my pid = %d\n", 277: tapeno+1, parentpid, getpid()); 278: #endif 1.1.1.2 ! root 279: signal(SIGINT, interrupt); ! 280: #ifdef RDUMP ! 281: while ((to = rmtopen(tape, 2)) < 0) ! 282: #else ! 283: while ((to = pipeout ? 1 : creat(tape, 0666)) < 0) ! 284: #endif RDUMP ! 285: if (!query("Cannot open tape. Do you want to retry the open?")) ! 286: dumpabort(); ! 287: ! 288: enslave(); /* Share open tape file descriptor with slaves */ 1.1 root 289: 290: asize = 0; 291: tapeno++; /* current tape sequence */ 292: newtape++; /* new tape signal */ 293: spcl.c_volume++; 294: spcl.c_type = TS_TAPE; 295: spclrec(); 296: if (tapeno > 1) 297: msg("Tape %d begins with blocks from ino %d\n", 298: tapeno, ino); 299: } 300: } 301: 302: dumpabort() 303: { 1.1.1.2 ! root 304: if (master != 0 && master != getpid()) ! 305: kill(master, SIGPIPE); ! 306: else { ! 307: killall(); ! 308: msg("The ENTIRE dump is aborted.\n"); ! 309: } 1.1 root 310: Exit(X_ABORT); 311: } 312: 313: Exit(status) 314: { 315: #ifdef TDEBUG 316: msg("pid = %d exits with status %d\n", getpid(), status); 317: #endif TDEBUG 318: exit(status); 319: } 1.1.1.2 ! root 320: ! 321: /* ! 322: * prefer pipe(), but flock() barfs on them ! 323: */ ! 324: lockfile(fd) ! 325: int fd[2]; ! 326: { ! 327: char tmpname[20]; ! 328: ! 329: strcpy(tmpname, "/tmp/dumplockXXXXXX"); ! 330: mktemp(tmpname); ! 331: if ((fd[1] = creat(tmpname, 0400)) < 0) ! 332: return(fd[1]); ! 333: fd[0] = open(tmpname, 0); ! 334: unlink(tmpname); ! 335: return (fd[0] < 0 ? fd[0] : 0); ! 336: } ! 337: ! 338: enslave() ! 339: { ! 340: int first[2], prev[2], next[2], cmd[2]; /* file descriptors */ ! 341: register int i, j; ! 342: ! 343: master = getpid(); ! 344: signal(SIGPIPE, dumpabort); /* Slave quit/died/killed -> abort */ ! 345: signal(SIGIOT, tperror); /* SIGIOT -> restart from checkpoint */ ! 346: lockfile(first); ! 347: for (i = 0; i < SLAVES; i++) { ! 348: if (i == 0) { ! 349: prev[0] = first[1]; ! 350: prev[1] = first[0]; ! 351: } else { ! 352: prev[0] = next[0]; ! 353: prev[1] = next[1]; ! 354: flock(prev[1], LOCK_EX); ! 355: } ! 356: next[0] = first[0]; ! 357: next[1] = first[1]; /* Last slave loops back */ ! 358: if ((i < SLAVES-1 && lockfile(next) < 0) || pipe(cmd) < 0 ! 359: || (slavepid[i] = fork()) < 0) { ! 360: perror(" DUMP: too many slaves (recompile smaller)"); ! 361: dumpabort(); ! 362: } ! 363: slavefd[i] = cmd[1]; ! 364: if (slavepid[i] == 0) { /* Slave starts up here */ ! 365: for (j = 0; j <= i; j++) ! 366: close(slavefd[j]); ! 367: signal(SIGINT, SIG_IGN); /* Master handles these */ ! 368: signal(SIGTERM, SIG_IGN); ! 369: doslave(i, cmd[0], prev, next); ! 370: Exit(X_FINOK); ! 371: } ! 372: close(cmd[0]); ! 373: if (i > 0) { ! 374: close(prev[0]); ! 375: close(prev[1]); ! 376: } ! 377: } ! 378: close(first[0]); ! 379: close(first[1]); ! 380: master = 0; rotor = 0; ! 381: } ! 382: ! 383: killall() ! 384: { ! 385: register int i; ! 386: ! 387: for (i = 0; i < SLAVES; i++) ! 388: if (slavepid[i] > 0) ! 389: kill(slavepid[i], SIGKILL); ! 390: } ! 391: ! 392: /* ! 393: * Synchronization - each process has a lockfile, and shares file ! 394: * descriptors to the following process's lockfile. When our write ! 395: * completes, we release our lock on the following process's lock- ! 396: * file, allowing the following process to lock it and proceed. We ! 397: * get the lock back for the next cycle by swapping descriptors. ! 398: */ ! 399: doslave(mynum,cmd,prev,next) ! 400: int mynum, cmd, prev[2], next[2]; ! 401: { ! 402: register int toggle = 0, firstdone = mynum; ! 403: ! 404: tmsg("slave %d\n", mynum); ! 405: close(fi); ! 406: if ((fi = open(disk, 0)) < 0) { /* Need our own seek pointer */ ! 407: perror(" DUMP: slave couldn't reopen disk"); ! 408: kill(master, SIGPIPE); /* dumpabort */ ! 409: Exit(X_ABORT); ! 410: } ! 411: /* ! 412: * Get list of blocks to dump ! 413: */ ! 414: while (readpipe(cmd, req, reqsiz) > 0) { ! 415: register struct req *p = req; ! 416: for (trecno = 0; trecno < ntrec; trecno += p->count, p += p->count) { ! 417: if (p->dblk) { ! 418: tmsg("%d READS %d\n", mynum, p->count); ! 419: bread(p->dblk, tblock[trecno], ! 420: p->count * TP_BSIZE); ! 421: } else { ! 422: tmsg("%d PIPEIN %d\n", mynum, p->count); ! 423: if (p->count != 1 || ! 424: readpipe(cmd, tblock[trecno], TP_BSIZE) <= 0) { ! 425: msg("Master/slave protocol botched"); ! 426: dumpabort(); ! 427: } ! 428: } ! 429: } ! 430: flock(prev[toggle], LOCK_EX); /* Wait our turn */ ! 431: tmsg("%d WRITE\n", mynum); ! 432: #ifdef RDUMP ! 433: #ifndef sun /* Defer checking first write until next one is started */ ! 434: rmtwrite0(writesize); ! 435: rmtwrite1(tblock[0],writesize); ! 436: if (firstdone == 0) firstdone = -1; ! 437: else if (rmtwrite2() != writesize) { ! 438: rmtwrite2(); /* Don't care if another err */ ! 439: #else ! 440: /* Asynchronous writes can hang Suns; do it synchronously */ ! 441: if (rmtwrite(tblock[0],writesize) != writesize) { ! 442: #endif sun ! 443: #else /* Local tape drive */ ! 444: if (write(to,tblock[0],writesize) != writesize) { ! 445: perror(tape); ! 446: #endif RDUMP ! 447: kill(master, SIGIOT); /* restart from checkpoint */ ! 448: for (;;) sigpause(0); ! 449: } ! 450: toggle ^= 1; ! 451: flock(next[toggle], LOCK_UN); /* Next slave's turn */ ! 452: } /* Also jolts him awake */ ! 453: #ifdef RDUMP /* One more time around, to check last write */ ! 454: #ifndef sun ! 455: flock(prev[toggle], LOCK_EX); ! 456: tmsg("%d LAST\n", mynum); ! 457: if (firstdone < 0 && rmtwrite2() != writesize) { ! 458: kill(master, SIGIOT); ! 459: for (;;) ! 460: sigpause(0); ! 461: } ! 462: toggle ^= 1; ! 463: flock(next[toggle], LOCK_UN); ! 464: #endif sun ! 465: #endif RDUMP ! 466: } ! 467: ! 468: /* ! 469: * Since a read from a pipe may not return all we asked for ! 470: * we must loop until we get all we need ! 471: */ ! 472: readpipe(fd, buf, cnt) ! 473: int fd; ! 474: char *buf; ! 475: int cnt; ! 476: { ! 477: int rd, got; ! 478: ! 479: for (rd = cnt; rd > 0; rd -= got) { ! 480: got = read(fd, buf, rd); ! 481: if (got <= 0) { ! 482: if (rd == cnt && got == 0) ! 483: return (0); /* Normal EOF */ ! 484: msg("short pipe read"); ! 485: dumpabort(); ! 486: } ! 487: buf += got; ! 488: } ! 489: return (cnt); ! 490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.