Annotation of cci/usr/src/etc/dump/dumprtape.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.