]> git.wh0rd.org - dump.git/blob - dump/tape.c
Regenerate configure.
[dump.git] / dump / tape.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <stelian@popies.net>, 1999-2000
6 * Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
7 */
8
9 /*-
10 * Copyright (c) 1980, 1991, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #ifndef lint
39 static const char rcsid[] =
40 "$Id: tape.c,v 1.96 2011/06/10 13:41:41 stelian Exp $";
41 #endif /* not lint */
42
43 #include <config.h>
44 #include <compatlfs.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <setjmp.h>
48 #include <signal.h>
49 #include <stdio.h>
50 #include <compaterr.h>
51 #include <system.h>
52 #ifdef __STDC__
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #else
57 int write(), read();
58 #endif
59
60 #ifdef __linux__
61 #include <sys/types.h>
62 #include <sys/time.h>
63 #include <sys/ioctl.h>
64 #include <sys/mount.h> /* for definition of BLKFLSBUF */
65 #ifndef BLKFLSBUF /* last resort... */
66 #define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
67 #endif
68 #include <time.h>
69 #endif
70 #include <sys/param.h>
71 #include <sys/socket.h>
72 #include <sys/wait.h>
73 #include <sys/mtio.h>
74 #ifdef __linux__
75 #ifdef HAVE_EXT2FS_EXT2_FS_H
76 #include <ext2fs/ext2_fs.h>
77 #else
78 #include <linux/ext2_fs.h>
79 #endif
80 #include <ext2fs/ext2fs.h>
81 #include <sys/stat.h>
82 #include <bsdcompat.h>
83 #elif defined sunos
84 #include <sys/vnode.h>
85
86 #include <ufs/fs.h>
87 #include <ufs/inode.h>
88 #else
89 #include <ufs/ufs/dinode.h>
90 #include <ufs/ffs/fs.h>
91 #endif /* __linux__ */
92
93 #include <protocols/dumprestore.h>
94
95 #include "dump.h"
96 #include "indexer.h"
97 #include "slave.h"
98
99 int writesize; /* size of malloc()ed buffer for tape */
100 long lastspclrec = -1; /* tape block number of last written header */
101 int trecno = 0; /* next record to write in current block */
102 extern long *blocksperfiles; /* number of blocks per output file(s) */
103 long blocksperfiles_current; /* current position in blocksperfiles */
104 long blocksthisvol; /* number of blocks on current output file */
105 extern int ntrec; /* blocking factor on tape */
106 extern int cartridge;
107 char *nexttape;
108 extern pid_t rshpid;
109 int eot_code = 1;
110 long long tapea_bytes = 0; /* bytes_written at start of current volume */
111 static int magtapeout; /* output is really a tape */
112
113 static ssize_t dump_atomic_read __P((int, char *, size_t));
114 static ssize_t dump_atomic_write __P((int, const char *, size_t));
115 #ifdef WRITEDEBUG
116 static void doslave __P((int, int, int));
117 #else
118 static void doslave __P((int, int));
119 #endif
120 static void enslave __P((void));
121 static void flushtape __P((void));
122 static void killall __P((void));
123 static void rollforward __P((void));
124
125 int reqsiz;
126
127 struct slave_results {
128 ssize_t unclen; /* uncompressed length */
129 ssize_t clen; /* compressed length */
130 };
131
132 struct slave slaves[SLAVES+1];
133 struct slave *slp;
134
135 char (*nextblock)[TP_BSIZE];
136
137 static time_t tstart_volume; /* time of volume start */
138 static int tapea_volume; /* value of spcl.c_tapea at volume start */
139
140 int master; /* pid of master, for sending error signals */
141 int tenths; /* length of tape overhead per block written */
142 static int caught1; /* have we caught the signal to proceed? */
143 static int ready1; /* have we reached the lock point without having */
144 /* received the SIGUSR2 signal from the prev slave? */
145 static sigjmp_buf jmpbuf1; /* where to jump to if we are ready when the */
146 /* SIGUSR1 arrives from the previous slave */
147 static int caught2; /* have we caught the signal to proceed? */
148 static int ready2; /* have we reached the lock point without having */
149 /* received the SIGUSR2 signal from the prev slave? */
150 static sigjmp_buf jmpbuf2; /* where to jump to if we are ready when the */
151 /* SIGUSR2 arrives from the previous slave */
152
153 /*
154 * Determine if we can use Linux' clone system call. If so, call it
155 * with the CLONE_IO flag so that all processes will share the same I/O
156 * context, allowing the I/O schedulers to make better scheduling decisions.
157 */
158 #ifdef __linux__
159 /* first, pull in the header files that define sys_clone and CLONE_IO */
160 #include <syscall.h>
161 #define _GNU_SOURCE
162 #include <sched.h>
163 #include <unistd.h>
164 #undef _GNU_SOURCE
165
166 /* If either is not present, fall back on the fork behaviour */
167 #if ! defined(SYS_clone) || ! defined (CLONE_IO)
168 #define fork_clone_io fork
169 #else /* SYS_clone */
170 /* CLONE_IO is available, determine which version of sys_clone to use */
171 #include <linux/version.h>
172 /*
173 * Kernel 2.5.49 introduced two extra parameters to the clone system call.
174 * Neither is useful in our case, so this is easy to handle.
175 */
176 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,49)
177 /*
178 * Parameters of the sys_clone syscall are
179 * clone_flags, child_stack, parent_tidptr, child_tidptr
180 * on all architectures except s390 and s390x
181 * s390* have child_stack, clone_flags, parent_tidptr, child_tidptr
182 */
183 #if defined(__s390__) || defined(__s390x__)
184 #define CLONE_ARGS 0, SIGCHLD|CLONE_IO, NULL, NULL
185 #else
186 #define CLONE_ARGS SIGCHLD|CLONE_IO, 0, NULL, NULL
187 #endif
188 #else
189 #define CLONE_ARGS SIGCHLD|CLONE_IO, 0
190 #endif /* LINUX_VERSION_CODE */
191 pid_t fork_clone_io(void);
192 #endif /* SYS_clone */
193 #else /* __linux__ not defined */
194 #define fork_clone_io fork
195 #endif /* __linux__ */
196
197 int
198 alloctape(void)
199 {
200 int pgoff = getpagesize() - 1;
201 char *buf;
202 int i;
203
204 writesize = ntrec * TP_BSIZE;
205 reqsiz = (ntrec + 1) * sizeof(struct req);
206 /*
207 * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
208 * (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
209 * repositioning after stopping, i.e, streaming mode, where the gap is
210 * variable, 0.30" to 0.45". The gap is maximal when the tape stops.
211 */
212 if (!blocksperfiles && !unlimited)
213 tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
214 else {
215 tenths = 0;
216 density = 1;
217 }
218 /*
219 * Allocate tape buffer contiguous with the array of instruction
220 * packets, so flushtape() can write them together with one write().
221 * Align tape buffer on page boundary to speed up tape write().
222 */
223 for (i = 0; i <= SLAVES; i++) {
224 buf = (char *)
225 malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
226 if (buf == NULL)
227 return(0);
228 slaves[i].tblock = (char (*)[TP_BSIZE])
229 #ifdef __linux__
230 (((long)&buf[reqsiz] + pgoff) &~ pgoff);
231 #else
232 (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
233 #endif
234 slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
235 }
236 slp = &slaves[0];
237 slp->count = 1;
238 slp->tapea = 0;
239 slp->firstrec = 0;
240 nextblock = slp->tblock;
241 return(1);
242 }
243
244 void
245 writerec(const void *dp, int isspcl)
246 {
247 slp->req[trecno].dblk = (ext2_loff_t)0;
248 slp->req[trecno].count = 1;
249 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
250 *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp;
251
252 /* Need to write it to the archive file */
253 indexer->writerec(dp, isspcl);
254
255 nextblock++;
256 if (isspcl)
257 lastspclrec = spcl.c_tapea;
258 trecno++;
259 spcl.c_tapea++;
260 if (trecno >= ntrec)
261 flushtape();
262 }
263
264 void
265 dumpblock(blk_t blkno, int size)
266 {
267 int avail, tpblks;
268 ext2_loff_t dblkno;
269
270 dblkno = fsbtodb(sblock, blkno);
271 tpblks = size >> tp_bshift;
272 while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
273 slp->req[trecno].dblk = dblkno;
274 slp->req[trecno].count = avail;
275 trecno += avail;
276 spcl.c_tapea += avail;
277 if (trecno >= ntrec)
278 flushtape();
279 dblkno += avail << (tp_bshift - dev_bshift);
280 tpblks -= avail;
281 }
282 }
283
284 int nogripe = 0;
285
286 static void
287 tperror(int errnum)
288 {
289
290 if (pipeout) {
291 msg("write error on %s: %s\n", tape, strerror(errnum));
292 quit("Cannot recover\n");
293 /* NOTREACHED */
294 }
295 msg("write error %d blocks into volume %d: %s\n",
296 blocksthisvol, tapeno, strerror(errnum));
297 broadcast("DUMP WRITE ERROR!\n");
298 if (query("Do you want to rewrite this volume?")) {
299 msg("Closing this volume. Prepare to restart with new media;\n");
300 msg("this dump volume will be rewritten.\n");
301 killall();
302 nogripe = 1;
303 close_rewind();
304 Exit(X_REWRITE);
305 }
306 if (query("Do you want to start the next tape?"))
307 return;
308 dumpabort(0);
309 }
310
311 static void
312 sigpipe(UNUSED(int signo))
313 {
314
315 quit("Broken pipe\n");
316 }
317
318 /*
319 * do_stats --
320 * Update xferrate stats
321 */
322 time_t
323 do_stats(void)
324 {
325 time_t tnow, ttaken;
326 int blocks;
327
328 tnow = time(NULL);
329 ttaken = tnow - tstart_volume;
330 blocks = spcl.c_tapea - tapea_volume;
331 msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
332 if (! compressed)
333 msg("Volume %d %ld blocks (%.2fMB)\n", tapeno,
334 blocks, ((double)blocks * TP_BSIZE / 1048576));
335 if (ttaken > 0) {
336 long volkb = (bytes_written - tapea_bytes) / 1024;
337 long txfrate = volkb / ttaken;
338 msg("Volume %d took %d:%02d:%02d\n", tapeno,
339 ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
340 msg("Volume %d transfer rate: %ld kB/s\n", tapeno,
341 txfrate);
342 xferrate += txfrate;
343 if (compressed) {
344 double rate = .0005 + (double) blocks / (double) volkb;
345 msg("Volume %d %ldkB uncompressed, %ldkB compressed,"
346 " %1.3f:1\n",
347 tapeno, blocks, volkb, rate);
348 }
349 }
350 return(tnow);
351 }
352
353 char *
354 mktimeest(time_t tnow)
355 {
356 static char msgbuf[128];
357 time_t deltat;
358
359 msgbuf[0] = '\0';
360
361 if (blockswritten < 500)
362 return NULL;
363 if (blockswritten > tapesize)
364 tapesize = blockswritten;
365 deltat = tstart_writing - tnow + (1.0 * (tnow - tstart_writing))
366 / blockswritten * tapesize;
367 if (tnow > tstart_volume)
368 (void)snprintf(msgbuf, sizeof(msgbuf),
369 "%3.2f%% done at %ld kB/s, finished in %d:%02d\n",
370 (blockswritten * 100.0) / tapesize,
371 (spcl.c_tapea - tapea_volume) / (tnow - tstart_volume),
372 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
373 else
374 (void)snprintf(msgbuf, sizeof(msgbuf),
375 "%3.2f%% done, finished in %d:%02d\n",
376 (blockswritten * 100.0) / tapesize,
377 (int)(deltat / 3600), (int)((deltat % 3600) / 60));
378
379 return msgbuf;
380 }
381
382 #if defined(SIGINFO)
383 /*
384 * statussig --
385 * information message upon receipt of SIGINFO
386 */
387 void
388 statussig(int notused)
389 {
390 int save_errno = errno;
391 char *buf;
392
393 buf = mktimeest(time(NULL));
394 if (buf)
395 write(STDERR_FILENO, buf, strlen(buf));
396 errno = save_errno;
397 }
398 #endif
399
400 static void
401 flushtape(void)
402 {
403 int i, blks, got;
404 long lastfirstrec;
405 struct slave_results returned;
406
407 int siz = (char *)nextblock - (char *)slp->req;
408
409 /* make sure returned has sane values in case we don't read
410 * them from the slave in this pass */
411 returned.unclen = returned.clen = writesize;
412
413 slp->req[trecno].count = 0; /* Sentinel */
414
415 if (dump_atomic_write( slp->fd, (char *)slp->req, siz) != siz)
416 quit("error writing command pipe: %s\n", strerror(errno));
417 slp->sent = 1; /* we sent a request, read the response later */
418
419 lastfirstrec = slp->firstrec;
420
421 if (++slp >= &slaves[SLAVES])
422 slp = &slaves[0];
423
424 /* Read results back from next slave */
425 if (slp->sent) {
426 if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
427 != sizeof returned) {
428 perror(" DUMP: error reading command pipe in master");
429 dumpabort(0);
430 }
431 got = returned.unclen;
432 bytes_written += returned.clen;
433 if (returned.unclen == returned.clen)
434 uncomprblks++;
435 slp->sent = 0;
436
437 /* Check for errors or end of tape */
438 if (got <= 0) {
439 /* Check for errors */
440 if (got < 0)
441 tperror(-got);
442 else
443 msg("End of tape detected\n");
444
445 /*
446 * Drain the results, don't care what the values were.
447 * If we read them here then trewind won't...
448 */
449 for (i = 0; i < SLAVES; i++) {
450 if (slaves[i].sent) {
451 if (dump_atomic_read( slaves[i].fd,
452 (char *)&returned, sizeof returned)
453 != sizeof returned) {
454 perror(" DUMP: error reading command pipe in master");
455 dumpabort(0);
456 }
457 slaves[i].sent = 0;
458 }
459 }
460
461 close_rewind();
462 rollforward();
463 return;
464 }
465 }
466
467 blks = 0;
468 if (spcl.c_type == TS_CLRI || spcl.c_type == TS_BITS)
469 blks = spcl.c_count;
470 else {
471 if (spcl.c_type != TS_END) {
472 for (i = 0; i < spcl.c_count; i++)
473 if (spcl.c_addr[i] != 0)
474 blks++;
475 }
476 }
477 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
478 slp->tapea = spcl.c_tapea;
479 slp->firstrec = lastfirstrec + ntrec;
480 slp->inode = curino;
481 nextblock = slp->tblock;
482 trecno = 0;
483 asize += tenths + returned.clen / density;
484 blockswritten += ntrec;
485 blocksthisvol += ntrec;
486 if (!pipeout && !unlimited) {
487 if (blocksperfiles && blocksperfiles[blocksperfiles_current]) {
488 if ( compressed ? (bytes_written - tapea_bytes + SLAVES * (writesize + sizeof(struct tapebuf))) >= (((long long)blocksperfiles[blocksperfiles_current]) * 1024)
489 : blocksthisvol >= blocksperfiles[blocksperfiles_current] ) {
490 close_rewind();
491 startnewtape(0);
492 }
493 }
494 else if (asize > tsize) {
495 close_rewind();
496 startnewtape(0);
497 }
498 }
499 timeest();
500 }
501
502 time_t
503 trewind(void)
504 {
505 int f;
506 int got;
507 struct slave_results returned;
508
509 for (f = 0; f < SLAVES; f++) {
510 /*
511 * Drain the results, but unlike EOT we DO (or should) care
512 * what the return values were, since if we detect EOT after
513 * we think we've written the last blocks to the tape anyway,
514 * we have to replay those blocks with rollforward.
515 *
516 * fixme: punt for now.
517 */
518 if (slaves[f].sent) {
519 if (dump_atomic_read( slaves[f].fd, (char *)&returned, sizeof returned)
520 != sizeof returned) {
521 perror(" DUMP: error reading command pipe in master");
522 dumpabort(0);
523 }
524 got = returned.unclen;
525 bytes_written += returned.clen;
526 if (returned.unclen == returned.clen)
527 uncomprblks++;
528 slaves[f].sent = 0;
529
530 if (got < 0)
531 tperror(-got);
532
533 if (got == 0) {
534 msg("EOT detected in last 2 tape records!\n");
535 msg("Use a longer tape, decrease the size estimate\n");
536 quit("or use no size estimate at all.\n");
537 }
538 }
539 (void) close(slaves[f].fd);
540 }
541 while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
542 /* void */;
543
544 if (!pipeout) {
545
546 msg("Closing %s\n", tape);
547
548 #ifdef RDUMP
549 if (host) {
550 rmtclose();
551 while (rmtopen(tape, O_RDONLY) < 0)
552 sleep(10);
553 rmtclose();
554 }
555 else
556 #endif
557 {
558 (void) close(tapefd);
559 if (!fifoout) {
560 while ((f = OPEN(tape, O_RDONLY)) < 0)
561 sleep (10);
562 (void) close(f);
563 }
564 }
565 }
566 return do_stats();
567 }
568
569
570 void
571 close_rewind(void)
572 {
573 int eot_code = 1;
574 (void)trewind();
575 if (eot_script) {
576 msg("Launching %s\n", eot_script);
577 eot_code = system_command(eot_script, tape, tapeno);
578 }
579 if (eot_code != 0 && eot_code != 1) {
580 msg("Dump aborted by the end of tape script\n");
581 dumpabort(0);
582 }
583 if (eot_code == 0)
584 return;
585 if (nexttape || Mflag)
586 return;
587 if (!nogripe) {
588 msg("Change Volumes: Mount volume #%d\n", tapeno+1);
589 broadcast("CHANGE DUMP VOLUMES!\7\7\n");
590 }
591 while (!query("Is the new volume mounted and ready to go?"))
592 if (query("Do you want to abort?")) {
593 dumpabort(0);
594 /*NOTREACHED*/
595 }
596 }
597
598 void
599 rollforward(void)
600 {
601 struct req *p, *q = NULL, *prev;
602 struct slave *tslp;
603 int i, size, savedtapea, got;
604 union u_spcl *ntb, *otb;
605 struct slave_results returned;
606 #ifdef __linux__
607 int blks;
608 long lastfirstrec;
609 #endif
610 tslp = &slaves[SLAVES];
611 ntb = (union u_spcl *)tslp->tblock[1];
612
613 /* make sure returned has sane values in case we don't read
614 * them from the slave in this pass */
615 returned.unclen = returned.clen = writesize;
616
617 /*
618 * Each of the N slaves should have requests that need to
619 * be replayed on the next tape. Use the extra slave buffers
620 * (slaves[SLAVES]) to construct request lists to be sent to
621 * each slave in turn.
622 */
623 for (i = 0; i < SLAVES; i++) {
624 q = &tslp->req[1];
625 otb = (union u_spcl *)slp->tblock;
626
627 /*
628 * For each request in the current slave, copy it to tslp.
629 */
630
631 prev = NULL;
632 for (p = slp->req; p->count > 0; p += p->count) {
633 *q = *p;
634 if (p->dblk == 0)
635 *ntb++ = *otb++; /* copy the datablock also */
636 prev = q;
637 q += q->count;
638 }
639 if (prev == NULL)
640 quit("rollforward: protocol botch");
641 if (prev->dblk != 0)
642 prev->count -= 1;
643 else
644 ntb--;
645 q -= 1;
646 q->count = 0;
647 q = &tslp->req[0];
648 if (i == 0) {
649 q->dblk = 0;
650 q->count = 1;
651 trecno = 0;
652 nextblock = tslp->tblock;
653 savedtapea = spcl.c_tapea;
654 spcl.c_tapea = slp->tapea;
655 startnewtape(0);
656 spcl.c_tapea = savedtapea;
657 lastspclrec = savedtapea - 1;
658 }
659 size = (char *)ntb - (char *)q;
660 if (dump_atomic_write( slp->fd, (char *)q, size) != size) {
661 perror(" DUMP: error writing command pipe");
662 dumpabort(0);
663 }
664 slp->sent = 1;
665 #ifdef __linux__
666 lastfirstrec = slp->firstrec;
667 #endif
668 if (++slp >= &slaves[SLAVES])
669 slp = &slaves[0];
670
671 q->count = 1;
672
673 if (prev->dblk != 0) {
674 /*
675 * If the last one was a disk block, make the
676 * first of this one be the last bit of that disk
677 * block...
678 */
679 q->dblk = prev->dblk +
680 prev->count * (TP_BSIZE / DEV_BSIZE);
681 ntb = (union u_spcl *)tslp->tblock;
682 } else {
683 /*
684 * It wasn't a disk block. Copy the data to its
685 * new location in the buffer.
686 */
687 q->dblk = 0;
688 *((union u_spcl *)tslp->tblock) = *ntb;
689 ntb = (union u_spcl *)tslp->tblock[1];
690 }
691 }
692 slp->req[0] = *q;
693 nextblock = slp->tblock;
694 if (q->dblk == 0) {
695 #ifdef __linux__
696 /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */
697 *(union u_spcl *)(*nextblock) = *(union u_spcl *)tslp->tblock;
698 #endif
699 nextblock++;
700 }
701 trecno = 1;
702
703 /*
704 * Clear the first slaves' response. One hopes that it
705 * worked ok, otherwise the tape is much too short!
706 */
707 if (slp->sent) {
708 if (dump_atomic_read( slp->fd, (char *)&returned, sizeof returned)
709 != sizeof returned) {
710 perror(" DUMP: error reading command pipe in master");
711 dumpabort(0);
712 }
713 got = returned.unclen;
714 bytes_written += returned.clen;
715 if (returned.clen == returned.unclen)
716 uncomprblks++;
717 slp->sent = 0;
718
719 if (got < 0)
720 tperror(-got);
721
722 if (got == 0) {
723 quit("EOT detected at start of the tape!\n");
724 }
725 }
726
727 #ifdef __linux__
728 blks = 0;
729 if (spcl.c_type != TS_END) {
730 for (i = 0; i < spcl.c_count; i++)
731 if (spcl.c_addr[i] != 0)
732 blks++;
733 }
734
735 slp->firstrec = lastfirstrec + ntrec;
736 slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
737 slp->inode = curino;
738 asize += tenths + returned.clen / density;
739 blockswritten += ntrec;
740 blocksthisvol += ntrec;
741 #endif
742 }
743
744 #ifdef __linux__
745 #if defined(SYS_clone) && defined(CLONE_IO)
746 pid_t
747 fork_clone_io(void)
748 {
749 return syscall(SYS_clone, CLONE_ARGS);
750 }
751 #endif
752 #endif
753
754 /*
755 * We implement taking and restoring checkpoints on the tape level.
756 * When each tape is opened, a new process is created by forking; this
757 * saves all of the necessary context in the parent. The child
758 * continues the dump; the parent waits around, saving the context.
759 * If the child returns X_REWRITE, then it had problems writing that tape;
760 * this causes the parent to fork again, duplicating the context, and
761 * everything continues as if nothing had happened.
762 */
763 void
764 startnewtape(int top)
765 {
766 int parentpid;
767 int childpid;
768 int status;
769 int waitpid;
770 char *p;
771
772 #ifdef __linux__
773 sigset_t sigs;
774 sigemptyset(&sigs);
775 sigaddset(&sigs, SIGINT);
776 sigprocmask(SIG_BLOCK, &sigs, NULL);
777 #else /* __linux__ */
778 #ifdef sunos
779 void (*interrupt_save)();
780 #else
781 sig_t interrupt_save;
782 #endif
783 interrupt_save = signal(SIGINT, SIG_IGN);
784 #endif /* __linux__ */
785
786 parentpid = getpid();
787 tapea_volume = spcl.c_tapea;
788 tapea_bytes = bytes_written;
789 tstart_volume = time(NULL);
790
791 restore_check_point:
792 #ifdef __linux__
793 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
794 #else
795 (void)signal(SIGINT, interrupt_save);
796 #endif
797 /*
798 * All signals are inherited...
799 */
800 childpid = fork_clone_io();
801 if (childpid < 0) {
802 msg("Context save fork fails in parent %d\n", parentpid);
803 Exit(X_ABORT);
804 }
805 if (childpid != 0) {
806 /*
807 * PARENT:
808 * save the context by waiting
809 * until the child doing all of the work returns.
810 * don't catch the interrupt
811 */
812 #ifdef __linux__
813 sigprocmask(SIG_BLOCK, &sigs, NULL);
814 #else
815 signal(SIGINT, SIG_IGN);
816 #endif
817 #ifdef TDEBUG
818 msg("Tape: %d; parent process: %d child process %d\n",
819 tapeno+1, parentpid, childpid);
820 #endif /* TDEBUG */
821 while ((waitpid = wait(&status)) != childpid)
822 if (waitpid != rshpid)
823 msg("Parent %d waiting for child %d has another child %d return\n",
824 parentpid, childpid, waitpid);
825 if (status & 0xFF) {
826 msg("Child %d returns LOB status %o\n",
827 childpid, status&0xFF);
828 }
829 status = (status >> 8) & 0xFF;
830 #ifdef TDEBUG
831 switch(status) {
832 case X_FINOK:
833 msg("Child %d finishes X_FINOK\n", childpid);
834 break;
835 case X_ABORT:
836 msg("Child %d finishes X_ABORT\n", childpid);
837 break;
838 case X_REWRITE:
839 msg("Child %d finishes X_REWRITE\n", childpid);
840 break;
841 default:
842 msg("Child %d finishes unknown %d\n",
843 childpid, status);
844 break;
845 }
846 #endif /* TDEBUG */
847 switch(status) {
848 case X_FINOK:
849 Exit(X_FINOK);
850 case X_ABORT:
851 Exit(X_ABORT);
852 case X_REWRITE:
853 goto restore_check_point;
854 default:
855 msg("Bad return code from dump: %d\n", status);
856 Exit(X_ABORT);
857 }
858 /*NOTREACHED*/
859 } else { /* we are the child; just continue */
860 #ifdef TDEBUG
861 sleep(4); /* allow time for parent's message to get out */
862 msg("Child on Tape %d has parent %d, my pid = %d\n",
863 tapeno+1, parentpid, getpid());
864 #endif /* TDEBUG */
865 /*
866 * If we have a name like "/dev/rmt0,/dev/rmt1",
867 * use the name before the comma first, and save
868 * the remaining names for subsequent volumes.
869 */
870 tapeno++; /* current tape sequence */
871 if (Mflag) {
872 snprintf(tape, MAXPATHLEN, "%s%03d", tapeprefix, tapeno);
873 tape[MAXPATHLEN - 1] = '\0';
874 msg("Dumping volume %d on %s\n", tapeno, tape);
875 }
876 else if (nexttape || strchr(tapeprefix, ',')) {
877 if (nexttape && *nexttape)
878 tapeprefix = nexttape;
879 if ((p = strchr(tapeprefix, ',')) != NULL) {
880 *p = '\0';
881 nexttape = p + 1;
882 } else
883 nexttape = NULL;
884 strncpy(tape, tapeprefix, MAXPATHLEN);
885 tape[MAXPATHLEN - 1] = '\0';
886 msg("Dumping volume %d on %s\n", tapeno, tape);
887 }
888 if (blocksperfiles && blocksperfiles_current < *blocksperfiles)
889 blocksperfiles_current++;
890 #ifdef RDUMP
891 while ((tapefd = (host ? rmtopen(tape, O_WRONLY|O_CREAT|O_TRUNC) : pipeout ?
892 fileno(stdout) :
893 OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
894 #else
895 while ((tapefd = (pipeout ? fileno(stdout) :
896 OPEN(tape, O_WRONLY|O_CREAT|O_TRUNC, 0666))) < 0)
897 #endif
898 {
899 msg("Cannot open output \"%s\": %s\n", tape,
900 strerror(errno));
901 if (!query("Do you want to retry the open?"))
902 dumpabort(0);
903 }
904 #ifdef RDUMP
905 if (!host)
906 #endif
907 {
908 struct mtget mt_stat;
909 magtapeout = ioctl(tapefd, MTIOCGET, (char *)&mt_stat) == 0;
910 /*
911 msg("Output is to %s\n",
912 magtapeout ? "tape" : "file/pipe");
913 */
914 }
915
916 enslave(); /* Share open tape file descriptor with slaves */
917
918 asize = 0;
919 blocksthisvol = 0;
920 if (top)
921 newtape++; /* new tape signal */
922 spcl.c_count = slp->count;
923 /*
924 * measure firstrec in TP_BSIZE units since restore doesn't
925 * know the correct ntrec value...
926 */
927 spcl.c_firstrec = slp->firstrec;
928 spcl.c_volume++;
929 spcl.c_type = TS_TAPE;
930 spcl.c_flags |= DR_NEWHEADER;
931 spcl.c_ntrec = ntrec;
932 if (compressed)
933 spcl.c_flags |= DR_COMPRESSED;
934 writeheader((dump_ino_t)slp->inode);
935 spcl.c_flags &=~ DR_NEWHEADER;
936 msg("Volume %d started with block %ld at: %s", tapeno,
937 spcl.c_tapea, ctime(&tstart_volume));
938 if (tapeno > 1)
939 msg("Volume %d begins with blocks from inode %d\n",
940 tapeno, slp->inode);
941 if (tapeno < (int)TP_NINOS)
942 volinfo[tapeno] = slp->inode;
943 transformation->startNewTape(transformation, NULL, 0);
944 }
945 }
946
947 void
948 dumpabort(UNUSED(int signo))
949 {
950
951 if (master != 0 && master != getpid())
952 /* Signals master to call dumpabort */
953 (void) kill(master, SIGTERM);
954 else {
955 killall();
956 msg("The ENTIRE dump is aborted.\n");
957 }
958 #ifdef RDUMP
959 rmtclose();
960 #endif
961 Exit(X_ABORT);
962 }
963
964 void
965 Exit(int status)
966 {
967
968 #ifdef TDEBUG
969 msg("pid = %d exits with status %d\n", getpid(), status);
970 #endif /* TDEBUG */
971 exit(status);
972 }
973
974 /*
975 * proceed - handler for SIGUSR1, used to synchronize IO between the slaves.
976 */
977 static void
978 proceed1(UNUSED(int signo))
979 {
980 if (ready1)
981 siglongjmp(jmpbuf1, 1);
982 caught1++;
983 }
984
985 /*
986 * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
987 */
988 static void
989 proceed2(UNUSED(int signo))
990 {
991 if (ready2)
992 siglongjmp(jmpbuf2, 1);
993 caught2++;
994 }
995
996 void
997 enslave(void)
998 {
999 int cmd[2];
1000 #ifdef LINUX_FORK_BUG
1001 int i, j;
1002 #else
1003 int i, j;
1004 #endif
1005
1006 master = getpid();
1007
1008 { struct sigaction sa;
1009 memset(&sa, 0, sizeof sa);
1010 sigemptyset(&sa.sa_mask);
1011 sa.sa_handler = dumpabort;
1012 sigaction(SIGTERM, &sa, NULL); /* Slave sends SIGTERM on dumpabort() */
1013 sa.sa_handler = sigpipe;
1014 sigaction(SIGPIPE, &sa, NULL);
1015 sa.sa_handler = proceed1;
1016 sa.sa_flags = SA_RESTART;
1017 sigaction(SIGUSR1, &sa, NULL); /* Slave sends SIGUSR1 to next slave */
1018 sa.sa_handler = proceed2;
1019 sa.sa_flags = SA_RESTART;
1020 sigaction(SIGUSR2, &sa, NULL); /* Slave sends SIGUSR2 to next slave */
1021 }
1022
1023 for (i = 0; i < SLAVES; i++) {
1024 if (i == slp - &slaves[0]) {
1025 caught1 = 1;
1026 caught2 = 1;
1027 } else {
1028 caught1 = 0;
1029 caught2 = 0;
1030 }
1031
1032 if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
1033 (slaves[i].pid = fork_clone_io()) < 0)
1034 quit("too many slaves, %d (recompile smaller): %s\n",
1035 i, strerror(errno));
1036
1037 slaves[i].fd = cmd[1];
1038 slaves[i].sent = 0;
1039 if (slaves[i].pid == 0) { /* Slave starts up here */
1040 sigset_t sigs;
1041 for (j = 0; j <= i; j++)
1042 (void) close(slaves[j].fd);
1043 sigemptyset(&sigs);
1044 sigaddset(&sigs, SIGINT); /* Master handles this */
1045 #if defined(SIGINFO)
1046 sigaddset(&sigs, SIGINFO);
1047 #endif
1048 sigprocmask(SIG_BLOCK, &sigs, NULL);
1049
1050 #ifdef LINUX_FORK_BUG
1051 if (dump_atomic_write( cmd[0], (char *) &i, sizeof i)
1052 != sizeof i)
1053 quit("master/slave protocol botched 3\n");
1054 #endif
1055 doslave(cmd[0],
1056 #ifdef WRITEDEBUG
1057 i,
1058 #endif
1059 (slaves[i].pid == slp->pid));
1060 Exit(X_FINOK);
1061 }
1062 else
1063 close(cmd[0]);
1064 }
1065
1066 #ifdef LINUX_FORK_BUG
1067 /*
1068 * Wait for all slaves to _actually_ start to circumvent a bug in
1069 * Linux kernels >= 2.1.3 where a signal sent to a child that hasn't
1070 * returned from fork() causes a SEGV in the child process
1071 */
1072 for (i = 0; i < SLAVES; i++)
1073 if (dump_atomic_read( slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
1074 quit("master/slave protocol botched 4\n");
1075 #endif
1076
1077 for (i = 0; i < SLAVES; i++)
1078 (void) dump_atomic_write( slaves[i].fd,
1079 (char *) &slaves[(i + 1) % SLAVES].pid,
1080 sizeof slaves[0].pid);
1081
1082 master = 0;
1083 }
1084
1085 void
1086 killall(void)
1087 {
1088 int i;
1089
1090 for (i = 0; i < SLAVES; i++)
1091 if (slaves[i].pid > 0) {
1092 (void) kill(slaves[i].pid, SIGKILL);
1093 slaves[i].sent = 0;
1094 }
1095 }
1096
1097 /*
1098 * Synchronization - each process waits for a SIGUSR2 from the
1099 * previous process before writing to the tape, and sends SIGUSR2
1100 * to the next process when the tape write completes. On tape errors
1101 * a SIGUSR1 is sent to the master which then terminates all of the
1102 * slaves. Each process sends SIGUSR1 to the next to signal that it
1103 * is time to start reading from the disk, after it finishes reading
1104 * and moves to the compression phase.
1105 */
1106 static void
1107 doslave(int cmd,
1108 #ifdef WRITEDEBUG
1109 int slave_number,
1110 #endif
1111 int first)
1112 {
1113 int nread;
1114 int nextslave;
1115 volatile int wrote = 0, size, eot_count, bufsize;
1116 char * volatile buffer;
1117 #if defined(HAVE_BLOCK_TRANSFORMATION)
1118 struct tapebuf * volatile comp_buf = NULL;
1119 int compresult;
1120 volatile int do_compress = !first;
1121 unsigned long worklen;
1122 #endif /* HAVE_BLOCK_TRANSFORMATION */
1123
1124 struct slave_results returns;
1125 #ifdef __linux__
1126 errcode_t retval;
1127 #endif
1128 #ifdef USE_QFA
1129 QFA_State qfa_state;
1130 #endif /* USE_QFA */
1131 sigset_t set;
1132
1133 sigemptyset(&set);
1134 sigaddset(&set, SIGUSR1);
1135 sigaddset(&set, SIGUSR2);
1136 sigprocmask(SIG_BLOCK, &set, NULL);
1137 sigemptyset(&set);
1138
1139 #ifdef HAVE_BLOCK_TRANSFORMATION
1140 transformation->startDiskIOProcess(transformation);
1141 #endif /* HAVE_BLOCK_TRANSFORMATION */
1142
1143 indexer->openQfaState(&qfa_state);
1144
1145 /*
1146 * Need our own seek pointer.
1147 */
1148 (void) close(diskfd);
1149 if ((diskfd = OPEN(disk, O_RDONLY)) < 0)
1150 quit("slave couldn't reopen disk: %s\n", strerror(errno));
1151 #ifdef __linux__
1152 #ifdef BLKFLSBUF
1153 (void)ioctl(diskfd, BLKFLSBUF, 0);
1154 #endif
1155 ext2fs_close(fs);
1156 retval = dump_fs_open(disk, &fs);
1157 if (retval)
1158 quit("slave couldn't reopen disk: %s\n", error_message(retval));
1159 #endif /* __linux__ */
1160
1161 /*
1162 * Need the pid of the next slave in the loop...
1163 */
1164 if ((nread = dump_atomic_read( cmd, (char *)&nextslave, sizeof nextslave))
1165 != sizeof nextslave) {
1166 quit("master/slave protocol botched - didn't get pid of next slave.\n");
1167 }
1168
1169 #if defined(HAVE_BLOCK_TRANSFORMATION)
1170 /* if we're doing a compressed dump, allocate the compress buffer */
1171 if (compressed) {
1172 int bsiz = sizeof(struct tapebuf) + writesize;
1173 /* Add extra space to deal with compression or encryption enlarging the buffer */
1174 if (TP_BSIZE > writesize/16 + 200)
1175 bsiz += TP_BSIZE;
1176 else
1177 bsiz += writesize/16 + 200;
1178 comp_buf = malloc(bsiz);
1179 if (comp_buf == NULL)
1180 quit("couldn't allocate a compress buffer.\n");
1181 transformation->initialize(transformation, 1);
1182 if (zipflag == COMPRESS_ZLIB)
1183 comp_buf->flags = COMPRESS_ZLIB;
1184 else if (zipflag == COMPRESS_BZLIB)
1185 comp_buf->flags = COMPRESS_BZLIB;
1186 else if (zipflag == COMPRESS_LZO)
1187 comp_buf->flags = COMPRESS_LZO;
1188 else
1189 quit("internal error - unknown compression method: %d\n", zipflag);
1190 }
1191 #endif /* HAVE_BLOCK_TRANSFORMATION */
1192
1193 /*
1194 * Get list of blocks to dump, read the blocks into tape buffer
1195 */
1196 while ((nread = dump_atomic_read( cmd, (char *)slp->req, reqsiz)) == reqsiz) {
1197 struct req *p = slp->req;
1198
1199 /* wait for previous slave to finish reading */
1200 if (sigsetjmp(jmpbuf1, 1) == 0) {
1201 ready1 = 1;
1202 if (!caught1)
1203 sigsuspend(&set);
1204 }
1205 ready1 = 0;
1206 caught1 = 0;
1207
1208 for (trecno = 0; trecno < ntrec;
1209 trecno += p->count, p += p->count) {
1210
1211 if (p->dblk) { /* read a disk block */
1212 bread(p->dblk, slp->tblock[trecno],
1213 p->count * TP_BSIZE);
1214 } else { /* read record from pipe */
1215 if (p->count != 1 || dump_atomic_read( cmd,
1216 (char *)slp->tblock[trecno],
1217 TP_BSIZE) != TP_BSIZE)
1218 quit("master/slave protocol botched.\n");
1219 }
1220 }
1221 /* signal next slave to start reading */
1222 (void) kill(nextslave, SIGUSR1);
1223
1224 /* Try to write the data... */
1225 wrote = 0;
1226 eot_count = 0;
1227 size = 0;
1228 buffer = (char *) slp->tblock[0]; /* set write pointer */
1229 bufsize = writesize; /* length to write */
1230 returns.clen = returns.unclen = bufsize;
1231
1232 #if defined(HAVE_BLOCK_TRANSFORMATION)
1233 /*
1234 * When writing a compressed dump, each block except
1235 * the first one on each tape is written
1236 * from struct tapebuf with an 4 byte prefix
1237 * followed by the data. This can be less than
1238 * writesize. Restore, on a short read, can compare the
1239 * length read to the compressed length in the header
1240 * to verify that the read was good. Blocks which don't
1241 * compress well are written uncompressed.
1242 * The first block written by each slave is not compressed
1243 * and does not have a prefix.
1244 */
1245 if (compressed && do_compress) {
1246 comp_buf->length = bufsize;
1247 worklen = TP_BSIZE + writesize;
1248 compresult = 1;
1249
1250 // tapebuf: compressed, flags, length
1251 compresult = transformation->compress(transformation, comp_buf,
1252 &worklen, slp->tblock[0], writesize);
1253
1254 if (compresult && worklen <= ((unsigned long)writesize - 16)) {
1255 /* write the compressed buffer */
1256 comp_buf->length = worklen;
1257 comp_buf->compressed = 1;
1258 buffer = (char *) comp_buf;
1259 returns.clen = bufsize = worklen + sizeof(struct tapebuf);
1260 }
1261 else {
1262 /* write the data uncompressed */
1263 comp_buf->length = writesize;
1264 comp_buf->compressed = 0;
1265 buffer = (char *) comp_buf;
1266 returns.clen = bufsize = writesize + sizeof(struct tapebuf);
1267 returns.unclen = returns.clen;
1268 memcpy(comp_buf->buf, (char *)slp->tblock[0], writesize);
1269 }
1270 }
1271 /* compress the remaining blocks if we're compressing */
1272 do_compress = compressed;
1273 #endif /* HAVE_BLOCK_TRANSFORMATION */
1274
1275 if (sigsetjmp(jmpbuf2, 1) == 0) {
1276 ready2 = 1;
1277 if (!caught2)
1278 sigsuspend(&set);
1279 }
1280 ready2 = 0;
1281 caught2 = 0;
1282
1283 indexer->updateQfa(&qfa_state);
1284
1285 while (eot_count < 10 && size < bufsize) {
1286 #ifdef RDUMP
1287 if (host)
1288 wrote = rmtwrite(buffer + size, bufsize - size);
1289 else
1290 #endif
1291 wrote = write(tapefd, buffer + size, bufsize - size);
1292 #ifdef WRITEDEBUG
1293 printf("slave %d wrote %d\n", slave_number, wrote);
1294 #endif
1295 if (wrote < 0 && errno != ENOSPC)
1296 break;
1297 if (wrote == 0 || (wrote < 0 && errno == ENOSPC))
1298 eot_count++;
1299 else
1300 size += wrote;
1301 }
1302
1303 #ifdef WRITEDEBUG
1304 if (size != bufsize)
1305 printf("slave %d only wrote %d out of %d bytes and gave up.\n",
1306 slave_number, size, bufsize);
1307 #endif
1308
1309 /*
1310 * Handle ENOSPC as an EOT condition.
1311 */
1312 if (wrote < 0 && errno == ENOSPC) {
1313 wrote = 0;
1314 eot_count++;
1315 }
1316
1317 if (eot_count > 0)
1318 returns.clen = returns.unclen = 0;
1319
1320 /*
1321 * pass errno back to master for special handling
1322 */
1323 if (wrote < 0)
1324 returns.unclen = -errno;
1325
1326 /*
1327 * pass size of data and size of write back to master
1328 * (for EOT handling)
1329 */
1330 (void) dump_atomic_write( cmd, (char *)&returns, sizeof returns);
1331
1332 /*
1333 * Signal the next slave to go.
1334 */
1335 (void) kill(nextslave, SIGUSR2);
1336
1337 indexer->updateQfaState(&qfa_state);
1338 }
1339
1340 #ifdef HAVE_BLOCK_TRANSFORMATION
1341 transformation->endDiskIOProcess(transformation);
1342 #endif /* HAVE_BLOCK_TRANSFORMATION */
1343
1344 if (nread != 0)
1345 quit("error reading command pipe: %s\n", strerror(errno));
1346 }
1347
1348 /*
1349 * Since a read from a pipe may not return all we asked for,
1350 * or a write may not write all we ask if we get a signal,
1351 * loop until the count is satisfied (or error).
1352 */
1353 static ssize_t
1354 dump_atomic_read(int fd, char *buf, size_t count)
1355 {
1356 int got, need = count;
1357
1358 do {
1359 while ((got = read(fd, buf, need)) > 0 && (need -= got) > 0)
1360 buf += got;
1361 } while (got == -1 && errno == EINTR);
1362 return (got < 0 ? got : (ssize_t)count - need);
1363 }
1364
1365 /*
1366 * Since a read from a pipe may not return all we asked for,
1367 * or a write may not write all we ask if we get a signal,
1368 * loop until the count is satisfied (or error).
1369 */
1370 static ssize_t
1371 dump_atomic_write(int fd, const char *buf, size_t count)
1372 {
1373 int got, need = count;
1374
1375 do {
1376 while ((got = write(fd, buf, need)) > 0 && (need -= got) > 0)
1377 buf += got;
1378 } while (got == -1 && errno == EINTR);
1379 return (got < 0 ? got : (ssize_t)count - need);
1380 }
1381
1382
1383 /*
1384 int
1385 SetLogicalPos(void)
1386 {
1387 int err = 0;
1388 struct mt_pos buf;
1389
1390 buf.mt_op = MTSETDRVBUFFER;
1391 buf.mt_count = MT_ST_BOOLEANS | MT_ST_SCSI2LOGICAL;
1392 if (ioctl(tapefd, MTIOCTOP, &buf) == -1) {
1393 err = errno;
1394 msg("[%ld] error: %d (setting logical)\n",
1395 (unsigned long)getpid(), err);
1396 }
1397 return err;
1398 }
1399 */