⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tape.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1980, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)tape.c	8.2 (Berkeley) 3/17/94";#endif /* not lint */#include <sys/param.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#ifdef sunos#include <sys/vnode.h>#include <ufs/fs.h>#include <ufs/inode.h>#else#include <ufs/ffs/fs.h>#include <ufs/ufs/dinode.h>#endif#include <protocols/dumprestore.h>#include <errno.h>#include <fcntl.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#ifdef __STDC__#include <stdlib.h>#include <string.h>#include <unistd.h>#elseint	write(), read();#endif#include "dump.h"#include "pathnames.h"int	writesize;		/* size of malloc()ed buffer for tape */long	lastspclrec = -1;	/* tape block number of last written header */int	trecno = 0;		/* next record to write in current block */extern	long blocksperfile;	/* number of blocks per output file */long	blocksthisvol;		/* number of blocks on current output file */extern	int ntrec;		/* blocking factor on tape */extern	int cartridge;extern	char *host;char	*nexttape;static	int atomic __P((int (*)(), int, char *, int));static	void doslave __P((int, int));static	void enslave __P((void));static	void flushtape __P((void));static	void killall __P((void));static	void rollforward __P((void));/* * Concurrent dump mods (Caltech) - disk block reading and tape writing * are exported to several slave processes.  While one slave writes the * tape, the others read disk blocks; they pass control of the tape in * a ring via signals. The parent process traverses the filesystem and * sends writeheader()'s and lists of daddr's to the slaves via pipes. * The following structure defines the instruction packets sent to slaves. */struct req {	daddr_t dblk;	int count;};int reqsiz;#define SLAVES 3		/* 1 slave writing, 1 reading, 1 for slack */struct slave {	int tapea;		/* header number at start of this chunk */	int count;		/* count to next header (used for TS_TAPE */				/* after EOT) */	int inode;		/* inode that we are currently dealing with */	int fd;			/* FD for this slave */	int pid;		/* PID for this slave */	int sent;		/* 1 == we've sent this slave requests */	int firstrec;		/* record number of this block */	char (*tblock)[TP_BSIZE]; /* buffer for data blocks */	struct req *req;	/* buffer for requests */} slaves[SLAVES+1];struct slave *slp;char	(*nextblock)[TP_BSIZE];int master;		/* pid of master, for sending error signals */int tenths;		/* length of tape used per block written */static int caught;	/* have we caught the signal to proceed? */static int ready;	/* have we reached the lock point without having */			/* received the SIGUSR2 signal from the prev slave? */static jmp_buf jmpbuf;	/* where to jump to if we are ready when the */			/* SIGUSR2 arrives from the previous slave */intalloctape(){	int pgoff = getpagesize() - 1;	char *buf;	int i;	writesize = ntrec * TP_BSIZE;	reqsiz = (ntrec + 1) * sizeof(struct req);	/*	 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode	 * (see DEC TU80 User's Guide).  The shorter gaps of 6250-bpi require	 * repositioning after stopping, i.e, streaming mode, where the gap is	 * variable, 0.30" to 0.45".  The gap is maximal when the tape stops.	 */	if (blocksperfile == 0)		tenths = writesize / density +		    (cartridge ? 16 : density == 625 ? 5 : 8);	/*	 * Allocate tape buffer contiguous with the array of instruction	 * packets, so flushtape() can write them together with one write().	 * Align tape buffer on page boundary to speed up tape write().	 */	for (i = 0; i <= SLAVES; i++) {		buf = (char *)		    malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));		if (buf == NULL)			return(0);		slaves[i].tblock = (char (*)[TP_BSIZE])		    (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);		slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;	}	slp = &slaves[0];	slp->count = 1;	slp->tapea = 0;	slp->firstrec = 0;	nextblock = slp->tblock;	return(1);}voidwriterec(dp, isspcl)	char *dp;	int isspcl;{	slp->req[trecno].dblk = (daddr_t)0;	slp->req[trecno].count = 1;	*(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;	if (isspcl)		lastspclrec = spcl.c_tapea;	trecno++;	spcl.c_tapea++;	if (trecno >= ntrec)		flushtape();}voiddumpblock(blkno, size)	daddr_t blkno;	int size;{	int avail, tpblks, dblkno;	dblkno = fsbtodb(sblock, blkno);	tpblks = size >> tp_bshift;	while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {		slp->req[trecno].dblk = dblkno;		slp->req[trecno].count = avail;		trecno += avail;		spcl.c_tapea += avail;		if (trecno >= ntrec)			flushtape();		dblkno += avail << (tp_bshift - dev_bshift);		tpblks -= avail;	}}int	nogripe = 0;voidtperror(signo)	int signo;{	if (pipeout) {		msg("write error on %s\n", tape);		quit("Cannot recover\n");		/* NOTREACHED */	}	msg("write error %d blocks into volume %d\n", blocksthisvol, tapeno);	broadcast("DUMP WRITE ERROR!\n");	if (!query("Do you want to restart?"))		dumpabort(0);	msg("Closing this volume.  Prepare to restart with new media;\n");	msg("this dump volume will be rewritten.\n");	killall();	nogripe = 1;	close_rewind();	Exit(X_REWRITE);}voidsigpipe(signo)	int signo;{	quit("Broken pipe\n");}static voidflushtape(){	int i, blks, got;	long lastfirstrec;	int siz = (char *)nextblock - (char *)slp->req;	slp->req[trecno].count = 0;			/* Sentinel */	if (atomic(write, slp->fd, (char *)slp->req, siz) != siz)		quit("error writing command pipe: %s\n", strerror(errno));	slp->sent = 1; /* we sent a request, read the response later */	lastfirstrec = slp->firstrec;	if (++slp >= &slaves[SLAVES])		slp = &slaves[0];	/* Read results back from next slave */	if (slp->sent) {		if (atomic(read, slp->fd, (char *)&got, sizeof got)		    != sizeof got) {			perror("  DUMP: error reading command pipe in master");			dumpabort(0);		}		slp->sent = 0;		/* Check for end of tape */		if (got < writesize) {			msg("End of tape detected\n");			/*			 * Drain the results, don't care what the values were.			 * If we read them here then trewind won't...			 */			for (i = 0; i < SLAVES; i++) {				if (slaves[i].sent) {					if (atomic(read, slaves[i].fd,					    (char *)&got, sizeof got)					    != sizeof got) {						perror("  DUMP: error reading command pipe in master");						dumpabort(0);					}					slaves[i].sent = 0;				}			}			close_rewind();			rollforward();			return;		}	}	blks = 0;	if (spcl.c_type != TS_END) {		for (i = 0; i < spcl.c_count; i++)			if (spcl.c_addr[i] != 0)				blks++;	}	slp->count = lastspclrec + blks + 1 - spcl.c_tapea;	slp->tapea = spcl.c_tapea;	slp->firstrec = lastfirstrec + ntrec;	slp->inode = curino;	nextblock = slp->tblock;	trecno = 0;	asize += tenths;	blockswritten += ntrec;	blocksthisvol += ntrec;	if (!pipeout && (blocksperfile ?	    (blocksthisvol >= blocksperfile) : (asize > tsize))) {		close_rewind();		startnewtape(0);	}	timeest();}voidtrewind(){	int f;	int got;	for (f = 0; f < SLAVES; f++) {		/*		 * Drain the results, but unlike EOT we DO (or should) care 		 * what the return values were, since if we detect EOT after 		 * we think we've written the last blocks to the tape anyway, 		 * we have to replay those blocks with rollforward.		 *		 * fixme: punt for now.  		 */		if (slaves[f].sent) {			if (atomic(read, slaves[f].fd, (char *)&got, sizeof got)			    != sizeof got) {				perror("  DUMP: error reading command pipe in master");				dumpabort(0);			}			slaves[f].sent = 0;			if (got != writesize) {				msg("EOT detected in last 2 tape records!\n");				msg("Use a longer tape, decrease the size estimate\n");				quit("or use no size estimate at all.\n");			}		}		(void) close(slaves[f].fd);	}	while (wait((int *)NULL) >= 0)	/* wait for any signals from slaves */		/* void */;	if (pipeout)		return;	msg("Closing %s\n", tape);#ifdef RDUMP	if (host) {		rmtclose();		while (rmtopen(tape, 0) < 0)			sleep(10);		rmtclose();		return;	}#endif	(void) close(tapefd);	while ((f = open(tape, 0)) < 0)		sleep (10);	(void) close(f);}voidclose_rewind(){	trewind();	if (nexttape)		return;	if (!nogripe) {		msg("Change Volumes: Mount volume #%d\n", tapeno+1);		broadcast("CHANGE DUMP VOLUMES!\7\7\n");	}	while (!query("Is the new volume mounted and ready to go?"))		if (query("Do you want to abort?")) {			dumpabort(0);			/*NOTREACHED*/		}}voidrollforward(){	register struct req *p, *q, *prev;	register struct slave *tslp;	int i, size, savedtapea, got;	union u_spcl *ntb, *otb;	tslp = &slaves[SLAVES];	ntb = (union u_spcl *)tslp->tblock[1];	/*	 * Each of the N slaves should have requests that need to 	 * be replayed on the next tape.  Use the extra slave buffers 	 * (slaves[SLAVES]) to construct request lists to be sent to 	 * each slave in turn.	 */	for (i = 0; i < SLAVES; i++) {		q = &tslp->req[1];		otb = (union u_spcl *)slp->tblock;		/*		 * For each request in the current slave, copy it to tslp. 		 */		prev = NULL;		for (p = slp->req; p->count > 0; p += p->count) {			*q = *p;			if (p->dblk == 0)				*ntb++ = *otb++; /* copy the datablock also */			prev = q;			q += q->count;		}		if (prev == NULL)			quit("rollforward: protocol botch");		if (prev->dblk != 0)			prev->count -= 1;		else			ntb--;		q -= 1;		q->count = 0;		q = &tslp->req[0];		if (i == 0) {			q->dblk = 0;			q->count = 1;			trecno = 0;			nextblock = tslp->tblock;			savedtapea = spcl.c_tapea;			spcl.c_tapea = slp->tapea;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -