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

📄 tape.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
			startnewtape(0);			spcl.c_tapea = savedtapea;			lastspclrec = savedtapea - 1;		}		size = (char *)ntb - (char *)q;		if (atomic(write, slp->fd, (char *)q, size) != size) {			perror("  DUMP: error writing command pipe");			dumpabort(0);		}		slp->sent = 1;		if (++slp >= &slaves[SLAVES])			slp = &slaves[0];		q->count = 1;		if (prev->dblk != 0) {			/*			 * If the last one was a disk block, make the 			 * first of this one be the last bit of that disk 			 * block...			 */			q->dblk = prev->dblk +				prev->count * (TP_BSIZE / DEV_BSIZE);			ntb = (union u_spcl *)tslp->tblock;		} else {			/*			 * It wasn't a disk block.  Copy the data to its 			 * new location in the buffer.			 */			q->dblk = 0;			*((union u_spcl *)tslp->tblock) = *ntb;			ntb = (union u_spcl *)tslp->tblock[1];		}	}	slp->req[0] = *q;	nextblock = slp->tblock;	if (q->dblk == 0)		nextblock++;	trecno = 1;	/*	 * Clear the first slaves' response.  One hopes that it	 * worked ok, otherwise the tape is much too short!	 */	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;		if (got != writesize) {			quit("EOT detected at start of the tape!\n");		}	}}/* * We implement taking and restoring checkpoints on the tape level. * When each tape is opened, a new process is created by forking; this * saves all of the necessary context in the parent.  The child * continues the dump; the parent waits around, saving the context. * If the child returns X_REWRITE, then it had problems writing that tape; * this causes the parent to fork again, duplicating the context, and * everything continues as if nothing had happened. */voidstartnewtape(top)	int top;{	int	parentpid;	int	childpid;	int	status;	int	waitpid;	char	*p;#ifdef sunos	void	(*interrupt_save)();#else	sig_t	interrupt_save;#endif	interrupt_save = signal(SIGINT, SIG_IGN);	parentpid = getpid();restore_check_point:	(void)signal(SIGINT, interrupt_save);	/*	 *	All signals are inherited...	 */	childpid = fork();	if (childpid < 0) {		msg("Context save fork fails in parent %d\n", parentpid);		Exit(X_ABORT);	}	if (childpid != 0) {		/*		 *	PARENT:		 *	save the context by waiting		 *	until the child doing all of the work returns.		 *	don't catch the interrupt		 */		signal(SIGINT, SIG_IGN);#ifdef TDEBUG		msg("Tape: %d; parent process: %d child process %d\n",			tapeno+1, parentpid, childpid);#endif /* TDEBUG */		while ((waitpid = wait(&status)) != childpid)			msg("Parent %d waiting for child %d has another child %d return\n",				parentpid, childpid, waitpid);		if (status & 0xFF) {			msg("Child %d returns LOB status %o\n",				childpid, status&0xFF);		}		status = (status >> 8) & 0xFF;#ifdef TDEBUG		switch(status) {			case X_FINOK:				msg("Child %d finishes X_FINOK\n", childpid);				break;			case X_ABORT:					msg("Child %d finishes X_ABORT\n", childpid);				break;			case X_REWRITE:				msg("Child %d finishes X_REWRITE\n", childpid);				break;			default:				msg("Child %d finishes unknown %d\n",					childpid, status);				break;		}#endif /* TDEBUG */		switch(status) {			case X_FINOK:				Exit(X_FINOK);			case X_ABORT:				Exit(X_ABORT);			case X_REWRITE:				goto restore_check_point;			default:				msg("Bad return code from dump: %d\n", status);				Exit(X_ABORT);		}		/*NOTREACHED*/	} else {	/* we are the child; just continue */#ifdef TDEBUG		sleep(4);	/* allow time for parent's message to get out */		msg("Child on Tape %d has parent %d, my pid = %d\n",			tapeno+1, parentpid, getpid());#endif /* TDEBUG */		/*		 * If we have a name like "/dev/rmt0,/dev/rmt1",		 * use the name before the comma first, and save		 * the remaining names for subsequent volumes.		 */		tapeno++;               /* current tape sequence */		if (nexttape || index(tape, ',')) {			if (nexttape && *nexttape)				tape = nexttape;			if ((p = index(tape, ',')) != NULL) {				*p = '\0';				nexttape = p + 1;			} else				nexttape = NULL;			msg("Dumping volume %d on %s\n", tapeno, tape);		}#ifdef RDUMP		while ((tapefd = (host ? rmtopen(tape, 2) :			pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)#else		while ((tapefd = (pipeout ? 1 : 				  open(tape, O_WRONLY|O_CREAT, 0666))) < 0)#endif		    {			msg("Cannot open output \"%s\".\n", tape);			if (!query("Do you want to retry the open?"))				dumpabort(0);		}		enslave();  /* Share open tape file descriptor with slaves */		asize = 0;		blocksthisvol = 0;		if (top)			newtape++;		/* new tape signal */		spcl.c_count = slp->count; 		/*		 * measure firstrec in TP_BSIZE units since restore doesn't		 * know the correct ntrec value...		 */		spcl.c_firstrec = slp->firstrec;		spcl.c_volume++;		spcl.c_type = TS_TAPE;		spcl.c_flags |= DR_NEWHEADER;		writeheader((ino_t)slp->inode);		spcl.c_flags &=~ DR_NEWHEADER;		if (tapeno > 1)			msg("Volume %d begins with blocks from inode %d\n",				tapeno, slp->inode);	}}voiddumpabort(signo)	int signo;{	if (master != 0 && master != getpid())		/* Signals master to call dumpabort */		(void) kill(master, SIGTERM);	else {		killall();		msg("The ENTIRE dump is aborted.\n");	}#ifdef RDUMP	rmtclose();#endif	Exit(X_ABORT);}__dead voidExit(status)	int status;{#ifdef TDEBUG	msg("pid = %d exits with status %d\n", getpid(), status);#endif /* TDEBUG */	exit(status);}/* * proceed - handler for SIGUSR2, used to synchronize IO between the slaves. */voidproceed(signo)	int signo;{	if (ready)		longjmp(jmpbuf, 1);	caught++;}voidenslave(){	int cmd[2];	register int i, j;	master = getpid();	signal(SIGTERM, dumpabort);  /* Slave sends SIGTERM on dumpabort() */	signal(SIGPIPE, sigpipe);	signal(SIGUSR1, tperror);    /* Slave sends SIGUSR1 on tape errors */	signal(SIGUSR2, proceed);    /* Slave sends SIGUSR2 to next slave */	for (i = 0; i < SLAVES; i++) {		if (i == slp - &slaves[0]) {			caught = 1;		} else {			caught = 0;		}		if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||		    (slaves[i].pid = fork()) < 0)			quit("too many slaves, %d (recompile smaller): %s\n",			    i, strerror(errno));		slaves[i].fd = cmd[1];		slaves[i].sent = 0;		if (slaves[i].pid == 0) { 	    /* Slave starts up here */			for (j = 0; j <= i; j++)			        (void) close(slaves[j].fd);			signal(SIGINT, SIG_IGN);    /* Master handles this */			doslave(cmd[0], i);			Exit(X_FINOK);		}	}		for (i = 0; i < SLAVES; i++)		(void) atomic(write, slaves[i].fd, 			      (char *) &slaves[(i + 1) % SLAVES].pid, 		              sizeof slaves[0].pid);			master = 0; }voidkillall(){	register int i;	for (i = 0; i < SLAVES; i++)		if (slaves[i].pid > 0)			(void) kill(slaves[i].pid, SIGKILL);}/* * Synchronization - each process has a lockfile, and shares file * descriptors to the following process's lockfile.  When our write * completes, we release our lock on the following process's lock- * file, allowing the following process to lock it and proceed. We * get the lock back for the next cycle by swapping descriptors. */static voiddoslave(cmd, slave_number)	register int cmd;        int slave_number;{	register int nread;	int nextslave, size, wrote, eot_count;	/*	 * Need our own seek pointer.	 */	(void) close(diskfd);	if ((diskfd = open(disk, O_RDONLY)) < 0)		quit("slave couldn't reopen disk: %s\n", strerror(errno));	/*	 * Need the pid of the next slave in the loop...	 */	if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave))	    != sizeof nextslave) {		quit("master/slave protocol botched - didn't get pid of next slave.\n");	}	/*	 * Get list of blocks to dump, read the blocks into tape buffer	 */	while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {		register struct req *p = slp->req;		for (trecno = 0; trecno < ntrec;		     trecno += p->count, p += p->count) {			if (p->dblk) {				bread(p->dblk, slp->tblock[trecno],					p->count * TP_BSIZE);			} else {				if (p->count != 1 || atomic(read, cmd,				    (char *)slp->tblock[trecno], 				    TP_BSIZE) != TP_BSIZE)				       quit("master/slave protocol botched.\n");			}		}		if (setjmp(jmpbuf) == 0) {			ready = 1;			if (!caught)				(void) pause();		}		ready = 0;		caught = 0;		/* Try to write the data... */		eot_count = 0;		size = 0;		while (eot_count < 10 && size < writesize) {#ifdef RDUMP			if (host)				wrote = rmtwrite(slp->tblock[0]+size,				    writesize-size);			else#endif				wrote = write(tapefd, slp->tblock[0]+size,				    writesize-size);#ifdef WRITEDEBUG			printf("slave %d wrote %d\n", slave_number, wrote);#endif			if (wrote < 0) 				break;			if (wrote == 0)				eot_count++;			size += wrote;		}#ifdef WRITEDEBUG		if (size != writesize) 		 printf("slave %d only wrote %d out of %d bytes and gave up.\n",		     slave_number, size, writesize);#endif		if (eot_count > 0)			size = 0;		/*		 * fixme: Pyramids running OSx return ENOSPC		 * at EOT on 1/2 inch drives.		 */		if (size < 0) {			(void) kill(master, SIGUSR1);			for (;;)				(void) sigpause(0);		} else {			/*			 * pass size of write back to master			 * (for EOT handling)			 */			(void) atomic(write, cmd, (char *)&size, sizeof size);		} 		/*		 * If partial write, don't want next slave to go.		 * Also jolts him awake.		 */		(void) kill(nextslave, SIGUSR2);	}	if (nread != 0)		quit("error reading command pipe: %s\n", strerror(errno));}/* * Since a read from a pipe may not return all we asked for, * or a write may not write all we ask if we get a signal, * loop until the count is satisfied (or error). */static intatomic(func, fd, buf, count)	int (*func)(), fd;	char *buf;	int count;{	int got, need = count;	while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)		buf += got;	return (got < 0 ? got : count - need);}

⌨️ 快捷键说明

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