|
|
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 1.1 root 10: 11: #include "dump.h" 1.1.1.2 ! root 12: #include <sys/file.h> ! 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; ! 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. ! 27: * ! 28: * from "@(#)dumptape.c 2.1 (Berkeley+Caltech mods) 4/7/85"; 1.1 root 29: */ 1.1.1.2 ! root 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 1.1 root 43: 44: /* 1.1.1.2 ! root 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); ! 58: ! 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); 1.1 root 67: } 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 */ ! 80: trecno++; 1.1 root 81: spcl.c_tapea++; 1.1.1.2 ! root 82: if(trecno >= ntrec) 1.1 root 83: flusht(); 84: } 85: 86: dmpblk(blkno, size) 87: daddr_t blkno; 88: int size; 89: { 90: int tpblks, dblkno; 1.1.1.2 ! root 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; ! 99: spcl.c_tapea += avail; ! 100: if ((trecno += avail) >= ntrec) ! 101: flusht(); ! 102: dblkno += avail * (TP_BSIZE / DEV_BSIZE); ! 103: tpblks -= avail; 1.1 root 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 */ 1.1 root 115: } 1.1.1.2 ! root 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); 1.1 root 127: } 128: 1.1.1.2 ! root 129: #ifdef RDUMP ! 130: tflush(cnt) ! 131: int cnt; 1.1 root 132: { 1.1.1.2 ! root 133: int i; 1.1 root 134: 1.1.1.2 ! root 135: for (i = 0; i < ntrec; i++) ! 136: spclrec(); 1.1 root 137: } 1.1.1.2 ! root 138: #endif RDUMP 1.1 root 139: 1.1.1.2 ! root 140: flusht() 1.1 root 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(); ! 149: } ! 150: sigsetmask(sig); ! 151: if (++rotor >= SLAVES) rotor = 0; ! 152: tblock = (char (*)[TP_BSIZE]) &req[ntrec]; ! 153: trecno = 0; ! 154: asize += tenths; ! 155: blockswritten += ntrec; ! 156: if (!pipeout && asize > tsize) { ! 157: close_rewind(); ! 158: otape(); ! 159: } ! 160: timeest(); 1.1 root 161: } 162: 1.1.1.2 ! root 163: tape_rewind() 1.1 root 164: { 1.1.1.2 ! root 165: int f; 1.1 root 166: 1.1.1.2 ! root 167: if (pipeout) 1.1 root 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(); ! 178: #else ! 179: close(to); ! 180: while ((f = open(tape, 0)) < 0) ! 181: sleep (10); ! 182: close(f); ! 183: #endif RDUMP 1.1 root 184: } 185: 1.1.1.2 ! root 186: close_rewind() 1.1 root 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?")) ! 195: dumpabort(); 1.1 root 196: } 197: 1.1.1.2 ! root 198: /* ! 199: * We implement taking and restoring checkpoints on the tape level. ! 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: */ 1.1 root 207: 1.1.1.2 ! root 208: otape() ! 209: { ! 210: int parentpid; ! 211: int childpid; ! 212: int status; ! 213: int waitpid; ! 214: int (*interrupt)(); ! 215: ! 216: parentpid = getpid(); ! 217: ! 218: restore_check_point: ! 219: interrupt = signal(SIGINT, SIG_IGN); ! 220: childpid = fork(); ! 221: if (childpid < 0) { ! 222: msg("Context save fork fails in parent %d\n", parentpid); ! 223: Exit(X_ABORT); ! 224: } ! 225: if (childpid != 0) { ! 226: /* ! 227: * PARENT: ! 228: * save the context by waiting ! 229: * until the child doing all of the work returns. ! 230: * don't catch the interrupt ! 231: */ ! 232: #ifdef TDEBUG ! 233: msg("Tape: %d; parent process: %d child process %d\n", ! 234: tapeno+1, parentpid, childpid); ! 235: #endif TDEBUG ! 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) { ! 240: msg("Child %d returns LOB status %o\n", ! 241: childpid, status&0xFF); ! 242: } ! 243: status = (status >> 8) & 0xFF; ! 244: #ifdef TDEBUG ! 245: switch(status) { ! 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: ! 256: msg("Child %d finishes unknown %d\n", ! 257: childpid, status); ! 258: break; ! 259: } ! 260: #endif TDEBUG ! 261: switch(status) { ! 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 ! 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 */ ! 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); 1.1 root 299: } 300: } 301: 1.1.1.2 ! root 302: dumpabort() 1.1 root 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: } ! 310: Exit(X_ABORT); 1.1 root 311: } 312: 1.1.1.2 ! root 313: Exit(status) 1.1 root 314: { 1.1.1.2 ! root 315: #ifdef TDEBUG ! 316: msg("pid = %d exits with status %d\n", getpid(), status); ! 317: #endif TDEBUG ! 318: exit(status); 1.1 root 319: } 320: 1.1.1.2 ! root 321: /* ! 322: * prefer pipe(), but flock() barfs on them ! 323: */ ! 324: lockfile(fd) ! 325: int fd[2]; 1.1 root 326: { 1.1.1.2 ! root 327: char tmpname[20]; 1.1 root 328: 1.1.1.2 ! root 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); 1.1 root 355: } 1.1.1.2 ! root 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)"); 1.1 root 361: dumpabort(); 1.1.1.2 ! root 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: } 1.1 root 377: } 1.1.1.2 ! root 378: close(first[0]); ! 379: close(first[1]); ! 380: master = 0; rotor = 0; 1.1 root 381: } 382: 1.1.1.2 ! root 383: killall() 1.1 root 384: { 1.1.1.2 ! root 385: register int i; 1.1 root 386: 1.1.1.2 ! root 387: for (i = 0; i < SLAVES; i++) ! 388: if (slavepid[i] > 0) ! 389: kill(slavepid[i], SIGKILL); 1.1 root 390: } 391: 1.1.1.2 ! root 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]; 1.1 root 401: { 1.1.1.2 ! root 402: register int toggle = 0, firstdone = mynum; 1.1 root 403: 1.1.1.2 ! root 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); 1.1 root 490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.