Commit | Line | Data |
---|---|---|
a47b7e40 | 1 | static char *sccsid = "@(#)tape.c 1.7 (Berkeley) %G%"; |
ae4b153c BJ |
2 | #include "dump.h" |
3 | ||
1ddebffe SL |
4 | char (*tblock)[TP_BSIZE]; /* Pointer to malloc()ed buffer for tape */ |
5 | int writesize; /* Size of malloc()ed buffer for tape */ | |
f5bba473 | 6 | int trecno = 0; |
1ddebffe SL |
7 | extern int ntrec; /* blocking factor on tape */ |
8 | ||
9 | /* | |
10 | * Allocate the buffer for tape operations. | |
11 | * | |
12 | * Depends on global variable ntrec, set from 'b' option in command line. | |
13 | * Returns 1 if successful, 0 if failed. | |
14 | * | |
15 | * For later kernel performance improvement, this buffer should be allocated | |
16 | * on a page boundary. | |
17 | */ | |
18 | alloctape() | |
19 | { | |
20 | ||
21 | writesize = ntrec * TP_BSIZE; | |
22 | tblock = (char (*)[TP_BSIZE])malloc(writesize); | |
23 | return (tblock != NULL); | |
24 | } | |
25 | ||
ae4b153c BJ |
26 | |
27 | taprec(dp) | |
b6407c9d | 28 | char *dp; |
ae4b153c BJ |
29 | { |
30 | register i; | |
31 | ||
b6407c9d | 32 | for (i=0; i < TP_BSIZE; i++) |
ae4b153c | 33 | tblock[trecno][i] = *dp++; |
ae4b153c BJ |
34 | trecno++; |
35 | spcl.c_tapea++; | |
1ddebffe | 36 | if(trecno >= ntrec) |
ae4b153c BJ |
37 | flusht(); |
38 | } | |
39 | ||
f5bba473 KM |
40 | dmpblk(blkno, size) |
41 | daddr_t blkno; | |
42 | int size; | |
ae4b153c | 43 | { |
b6407c9d | 44 | int avail, tpblks, dblkno; |
f5bba473 | 45 | |
b6407c9d | 46 | if (size % TP_BSIZE != 0) |
f5bba473 | 47 | msg("bad size to dmpblk: %d\n", size); |
1ddebffe | 48 | avail = ntrec - trecno; |
b6407c9d KM |
49 | dblkno = fsbtodb(sblock, blkno); |
50 | for (tpblks = size / TP_BSIZE; tpblks > avail; ) { | |
51 | bread(dblkno, tblock[trecno], TP_BSIZE * avail); | |
f5bba473 KM |
52 | trecno += avail; |
53 | spcl.c_tapea += avail; | |
54 | flusht(); | |
b6407c9d KM |
55 | dblkno += avail * (TP_BSIZE / DEV_BSIZE); |
56 | tpblks -= avail; | |
1ddebffe | 57 | avail = ntrec - trecno; |
f5bba473 | 58 | } |
b6407c9d KM |
59 | bread(dblkno, tblock[trecno], TP_BSIZE * tpblks); |
60 | trecno += tpblks; | |
61 | spcl.c_tapea += tpblks; | |
1ddebffe | 62 | if(trecno >= ntrec) |
ae4b153c BJ |
63 | flusht(); |
64 | } | |
65 | ||
66 | int nogripe = 0; | |
67 | ||
68 | flusht() | |
69 | { | |
70 | register i, si; | |
71 | daddr_t d; | |
72 | ||
ae4b153c | 73 | trecno = 0; |
1ddebffe | 74 | if (write(to, tblock[0], writesize) != writesize){ |
a47b7e40 KM |
75 | if (pipeout) { |
76 | msg("Tape write error on %s\n", tape); | |
77 | msg("Cannot recover\n"); | |
78 | dumpabort(); | |
79 | /* NOTREACHED */ | |
80 | } | |
ae4b153c BJ |
81 | msg("Tape write error on tape %d\n", tapeno); |
82 | broadcast("TAPE ERROR!\n"); | |
83 | if (query("Do you want to restart?")){ | |
84 | msg("This tape will rewind. After it is rewound,\n"); | |
85 | msg("replace the faulty tape with a new one;\n"); | |
ed7c701e | 86 | msg("this dump volume will be rewritten.\n"); |
ae4b153c BJ |
87 | /* |
88 | * Temporarily change the tapeno identification | |
89 | */ | |
90 | tapeno--; | |
91 | nogripe = 1; | |
92 | close_rewind(); | |
93 | nogripe = 0; | |
94 | tapeno++; | |
95 | Exit(X_REWRITE); | |
96 | } else { | |
97 | dumpabort(); | |
98 | /*NOTREACHED*/ | |
99 | } | |
100 | } | |
101 | ||
1ddebffe | 102 | asize += writesize/density; |
ae4b153c | 103 | asize += 7; |
1ddebffe | 104 | blockswritten += ntrec; |
a47b7e40 | 105 | if (!pipeout && asize > tsize) { |
ae4b153c BJ |
106 | close_rewind(); |
107 | otape(); | |
108 | } | |
109 | timeest(); | |
110 | } | |
111 | ||
112 | rewind() | |
113 | { | |
114 | int secs; | |
be3f486f | 115 | int f; |
a47b7e40 KM |
116 | |
117 | if (pipeout) | |
118 | return; | |
ae4b153c BJ |
119 | #ifdef DEBUG |
120 | msg("Waiting 10 seconds to rewind.\n"); | |
121 | sleep(10); | |
122 | #else | |
123 | /* | |
124 | * It takes about 3 minutes, 25secs to rewind 2300' of tape | |
125 | */ | |
be3f486f BJ |
126 | msg("Tape rewinding\n", secs); |
127 | close(to); | |
128 | while ((f = open(tape, 0)) < 0) | |
129 | sleep (10); | |
130 | close(f); | |
ae4b153c BJ |
131 | #endif |
132 | } | |
133 | ||
134 | close_rewind() | |
135 | { | |
a47b7e40 KM |
136 | |
137 | if (pipeout) | |
138 | return; | |
ae4b153c BJ |
139 | close(to); |
140 | if (!nogripe){ | |
141 | rewind(); | |
142 | msg("Change Tapes: Mount tape #%d\n", tapeno+1); | |
143 | broadcast("CHANGE TAPES!\7\7\n"); | |
144 | } | |
145 | do{ | |
146 | if (query ("Is the new tape mounted and ready to go?")) | |
147 | break; | |
148 | if (query ("Do you want to abort?")){ | |
149 | dumpabort(); | |
150 | /*NOTREACHED*/ | |
151 | } | |
152 | } while (1); | |
153 | } | |
154 | ||
155 | /* | |
156 | * We implement taking and restoring checkpoints on | |
157 | * the tape level. | |
158 | * When each tape is opened, a new process is created by forking; this | |
159 | * saves all of the necessary context in the parent. The child | |
160 | * continues the dump; the parent waits around, saving the context. | |
161 | * If the child returns X_REWRITE, then it had problems writing that tape; | |
162 | * this causes the parent to fork again, duplicating the context, and | |
163 | * everything continues as if nothing had happened. | |
164 | */ | |
165 | ||
166 | otape() | |
167 | { | |
168 | int parentpid; | |
169 | int childpid; | |
170 | int status; | |
171 | int waitpid; | |
172 | int sig_ign_parent(); | |
173 | int interrupt(); | |
174 | ||
175 | /* | |
176 | * Force the tape to be closed | |
177 | */ | |
178 | close(to); | |
179 | parentpid = getpid(); | |
180 | ||
181 | restore_check_point: | |
182 | signal(SIGINT, interrupt); | |
183 | /* | |
184 | * All signals are inherited... | |
185 | */ | |
186 | childpid = fork(); | |
187 | if (childpid < 0){ | |
188 | msg("Context save fork fails in parent %d\n", parentpid); | |
189 | Exit(X_ABORT); | |
190 | } | |
191 | if (childpid != 0){ | |
192 | /* | |
193 | * PARENT: | |
194 | * save the context by waiting | |
195 | * until the child doing all of the work returns. | |
196 | * don't catch the interrupt | |
197 | */ | |
198 | signal(SIGINT, SIG_IGN); | |
199 | #ifdef TDEBUG | |
200 | msg("Tape: %d; parent process: %d child process %d\n", | |
201 | tapeno+1, parentpid, childpid); | |
202 | #endif TDEBUG | |
203 | for (;;){ | |
204 | waitpid = wait(&status); | |
205 | if (waitpid != childpid){ | |
206 | msg("Parent %d waiting for child %d has another child %d return\n", | |
207 | parentpid, childpid, waitpid); | |
208 | } else | |
209 | break; | |
210 | } | |
211 | if (status & 0xFF){ | |
212 | msg("Child %d returns LOB status %o\n", | |
213 | childpid, status&0xFF); | |
214 | } | |
215 | status = (status >> 8) & 0xFF; | |
216 | #ifdef TDEBUG | |
217 | switch(status){ | |
218 | case X_FINOK: | |
219 | msg("Child %d finishes X_FINOK\n", childpid); | |
220 | break; | |
221 | case X_ABORT: | |
222 | msg("Child %d finishes X_ABORT\n", childpid); | |
223 | break; | |
224 | case X_REWRITE: | |
225 | msg("Child %d finishes X_REWRITE\n", childpid); | |
226 | break; | |
227 | default: | |
228 | msg("Child %d finishes unknown %d\n", childpid,status); | |
229 | break; | |
230 | } | |
231 | #endif TDEBUG | |
232 | switch(status){ | |
233 | case X_FINOK: | |
234 | Exit(X_FINOK); | |
235 | case X_ABORT: | |
236 | Exit(X_ABORT); | |
237 | case X_REWRITE: | |
238 | goto restore_check_point; | |
239 | default: | |
240 | msg("Bad return code from dump: %d\n", status); | |
241 | Exit(X_ABORT); | |
242 | } | |
243 | /*NOTREACHED*/ | |
244 | } else { /* we are the child; just continue */ | |
245 | #ifdef TDEBUG | |
246 | sleep(4); /* allow time for parent's message to get out */ | |
247 | msg("Child on Tape %d has parent %d, my pid = %d\n", | |
248 | tapeno+1, parentpid, getpid()); | |
249 | #endif | |
250 | do{ | |
a47b7e40 KM |
251 | if (pipeout) |
252 | to = 1; | |
253 | else | |
254 | to = creat(tape, 0666); | |
ae4b153c BJ |
255 | if (to < 0) { |
256 | if (!query("Cannot open tape. Do you want to retry the open?")) | |
257 | dumpabort(); | |
258 | } else break; | |
259 | } while (1); | |
260 | ||
261 | asize = 0; | |
262 | tapeno++; /* current tape sequence */ | |
263 | newtape++; /* new tape signal */ | |
264 | spcl.c_volume++; | |
265 | spcl.c_type = TS_TAPE; | |
266 | spclrec(); | |
267 | if (tapeno > 1) | |
268 | msg("Tape %d begins with blocks from ino %d\n", | |
269 | tapeno, ino); | |
270 | } | |
271 | } | |
272 | ||
273 | /* | |
274 | * The parent still catches interrupts, but does nothing with them | |
275 | */ | |
276 | sig_ign_parent() | |
277 | { | |
278 | msg("Waiting parent receives interrupt\n"); | |
279 | signal(SIGINT, sig_ign_parent); | |
280 | } | |
281 | ||
282 | dumpabort() | |
283 | { | |
ed7c701e | 284 | msg("The ENTIRE dump is aborted.\n"); |
ae4b153c BJ |
285 | Exit(X_ABORT); |
286 | } | |
287 | ||
288 | Exit(status) | |
289 | { | |
290 | #ifdef TDEBUG | |
291 | msg("pid = %d exits with status %d\n", getpid(), status); | |
292 | #endif TDEBUG | |
ed7c701e | 293 | exit(status); |
ae4b153c | 294 | } |