This source file includes following definitions.
- ftape_validate_label
- find_end_of_eof_list
- reset_eof_list
- check_for_eof
- clear_eof_mark_if_set
- put_file_mark_in_map
- ftape_weof
- ftape_erase
- extract_file_marks
- update_failed_sector_log
- ftape_seek_eom
- ftape_seek_eof
- ftape_file_no
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <linux/module.h>
31 #include <linux/ftape.h>
32 #include <linux/string.h>
33 #include <linux/errno.h>
34
35 #include "tracing.h"
36 #include "ftape-eof.h"
37 #include "ftape-write.h"
38 #include "ftape-read.h"
39 #include "ftape-rw.h"
40 #include "ftape-ctl.h"
41 #include "ftape-bsm.h"
42
43
44
45 int failed_sector_log_changed = 0;
46 int eof_mark = 0;
47
48
49
50 static struct failed_sector_entry {
51 unsigned short segment;
52 unsigned short sector;
53 } *eof_mark_ptr;
54
55 typedef union {
56 struct failed_sector_entry mark;
57 unsigned long entry;
58 } eof_mark_union;
59
60
61
62 static eof_mark_union eof_map[(2048 - 256) / 4];
63
64
65
66 static int eof_index;
67
68
69
70 static int nr_of_eof_marks = -1;
71
72 static char linux_tape_label[] = "Linux raw format V";
73 enum {
74 min_fmt_version = 1, max_fmt_version = 2
75 };
76 static unsigned ftape_fmt_version = 0;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 int ftape_validate_label(char *label)
116 {
117 TRACE_FUN(8, "ftape_validate_label");
118 int result = 0;
119
120 TRACEx1(4, "tape label = `%s'", label);
121 ftape_fmt_version = 0;
122 if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) {
123 int pos = strlen(linux_tape_label);
124 while (label[pos] >= '0' && label[pos] <= '9') {
125 ftape_fmt_version *= 10;
126 ftape_fmt_version = label[pos++] - '0';
127 }
128 result = (ftape_fmt_version >= min_fmt_version &&
129 ftape_fmt_version <= max_fmt_version);
130 }
131 TRACEx1(4, "format version = %d", ftape_fmt_version);
132 TRACE_EXIT;
133 return result;
134 }
135
136 static byte *
137 find_end_of_eof_list(byte * ptr, byte * limit)
138 {
139 while (ptr + 3 < limit) {
140 if (*(unsigned long *) ptr) {
141 ++(unsigned long *) ptr;
142 } else {
143 return ptr;
144 }
145 }
146 return NULL;
147 }
148
149 void reset_eof_list(void)
150 {
151 TRACE_FUN(8, "reset_eof_list");
152
153 eof_mark_ptr = &eof_map[0].mark;
154 eof_index = 0;
155 eof_mark = 0;
156 TRACE_EXIT;
157 }
158
159
160
161
162 int check_for_eof(unsigned segment)
163 {
164 TRACE_FUN(8, "check_for_eof");
165 static unsigned last_reference = INT_MAX;
166 int result;
167
168 if (segment < last_reference) {
169 reset_eof_list();
170 }
171 last_reference = segment;
172 while (eof_index < nr_of_eof_marks && segment > eof_mark_ptr->segment) {
173 ++eof_mark_ptr;
174 ++eof_index;
175 }
176 if (eof_index < nr_of_eof_marks && segment == eof_mark_ptr->segment) {
177 TRACEx3(5, "hit mark %d/%d at index %d",
178 eof_map[eof_index].mark.segment, eof_map[eof_index].mark.sector,
179 eof_index);
180 if (eof_mark_ptr->sector >= SECTORS_PER_SEGMENT) {
181 TRACEx2(-1, "Bad file mark detected: %d/%d",
182 eof_mark_ptr->segment, eof_mark_ptr->sector);
183 result = 0;
184 } else {
185 result = eof_mark_ptr->sector;
186 }
187 } else {
188 result = 0;
189 }
190 TRACE_EXIT;
191 return result;
192 }
193
194 void clear_eof_mark_if_set(unsigned segment, unsigned byte_count)
195 {
196 TRACE_FUN(5, "clear_eof_mark_if_set");
197 if (ftape_fmt_version != 0 &&
198 check_for_eof(segment) > 0 &&
199 byte_count >= eof_mark_ptr->sector * SECTOR_SIZE) {
200 TRACEx3(5, "clearing mark %d/%d at index %d",
201 eof_mark_ptr->segment, eof_mark_ptr->sector, eof_index);
202 memmove(&eof_map[eof_index], &eof_map[eof_index + 1],
203 (nr_of_eof_marks - eof_index) * sizeof(*eof_map));
204 --nr_of_eof_marks;
205 failed_sector_log_changed = 1;
206 }
207 TRACE_EXIT;
208 }
209
210 void put_file_mark_in_map(unsigned segment, unsigned sector)
211 {
212 TRACE_FUN(8, "put_file_mark_in_map");
213 eof_mark_union new;
214 int index;
215 eof_mark_union *ptr;
216
217 if (ftape_fmt_version != 0) {
218 new.mark.segment = segment;
219 new.mark.sector = sector;
220 for (index = 0, ptr = &eof_map[0];
221 index < nr_of_eof_marks && ptr->mark.segment < segment;
222 ++index, ++ptr) {
223 }
224 if (index < nr_of_eof_marks) {
225 if (ptr->mark.segment == segment) {
226
227 if (ptr->mark.sector == sector) {
228 TRACEx2(5, "mark %d/%d already exists",
229 new.mark.segment, new.mark.sector);
230 } else {
231 TRACEx5(5, "overwriting %d/%d at index %d with %d/%d",
232 ptr->mark.segment, ptr->mark.sector, index,
233 new.mark.segment, new.mark.sector);
234 ptr->entry = new.entry;
235 failed_sector_log_changed = 1;
236 }
237 } else {
238
239 TRACEx5(5, "inserting %d/%d at index %d before %d/%d",
240 new.mark.segment, new.mark.sector, index,
241 ptr->mark.segment, ptr->mark.sector);
242 memmove(ptr + 1, ptr, (nr_of_eof_marks - index) * sizeof(*eof_map));
243 ptr->entry = new.entry;
244 ++nr_of_eof_marks;
245 failed_sector_log_changed = 1;
246 }
247 } else {
248
249 TRACEx3(5, "appending %d/%d at index %d",
250 new.mark.segment, new.mark.sector, index);
251 ptr->entry = new.entry;
252 ++nr_of_eof_marks;
253 failed_sector_log_changed = 1;
254 }
255 }
256 TRACE_EXIT;
257 }
258
259
260
261
262
263 int ftape_weof(unsigned count, unsigned segment, unsigned sector)
264 {
265 TRACE_FUN(5, "ftape_weof");
266 int result = 0;
267 unsigned long mask = get_bad_sector_entry(segment);
268 unsigned sector_nr = 0;
269
270 if (ftape_fmt_version != 0) {
271 if (sector < 1 || sector > 29 ||
272 segment + count >= ftape_last_segment.id) {
273 TRACEx3(5, "parameter out of range: %d, %d, %d", count, segment, sector);
274 result = -EIO;
275 } else {
276 while (count-- > 0) {
277 do {
278 do {
279 while (mask & 1) {
280 ++sector_nr;
281 mask >>= 1;
282 }
283 if (sector_nr >= 29) {
284 if (++segment >= ftape_last_segment.id) {
285 TRACEx1(5, "segment out of range: %d", segment);
286 result = -EIO;
287 break;
288 }
289 mask = get_bad_sector_entry(segment);
290 sector_nr = 0;
291 }
292 } while (mask & 1);
293 ++sector_nr;
294 mask >>= 1;
295 } while (--sector);
296 if (result >= 0) {
297 TRACEx2(5, "writing filemark %d/%d", segment, sector_nr);
298 put_file_mark_in_map(segment, sector_nr);
299 ++segment;
300 sector_nr = 0;
301 sector = 1;
302 }
303 }
304 }
305 } else {
306 result = -EPERM;
307 }
308 TRACE_EXIT;
309 return result;
310 }
311
312 int ftape_erase(void)
313 {
314 TRACE_FUN(5, "ftape_erase");
315 int result = 0;
316 int i;
317 unsigned long now = 0;
318 byte *buffer = deblock_buffer;
319
320 if (write_protected) {
321 result = -EROFS;
322 } else {
323 result = read_header_segment(buffer);
324 if (result >= 0) {
325
326
327 TRACEx1(5, "old label: `%s'", (char *) (buffer + 30));
328 if (!ftape_validate_label((char *) &buffer[30])) {
329 TRACE(5, "invalid label, overwriting with new");
330 memset(buffer + 30, 0, 44);
331 memcpy(buffer + 30, linux_tape_label, strlen(linux_tape_label));
332 buffer[30 + strlen(linux_tape_label)] = '2';
333 TRACEx1(5, "new label: `%s'", (char *) (buffer + 30));
334 PUT4(buffer, 74, now);
335 if (format_code != 4) {
336 for (i = 0; i < nr_of_eof_marks; ++i) {
337 unsigned failing_segment = eof_map[i].mark.segment;
338
339 if (!valid_segment_no(failing_segment)) {
340 TRACEi(4, "bad entry in failed sector log:", failing_segment);
341 } else {
342 put_bad_sector_entry(failing_segment, EMPTY_SEGMENT);
343 TRACEx2(4, "moved entry %d from failed sector log (%d)",
344 i, failing_segment);
345 }
346 }
347 }
348 }
349
350
351 failed_sector_log_changed = 1;
352 memset(eof_map, 0, sizeof(eof_map));
353 nr_of_eof_marks = 0;
354 ftape_fmt_version = max_fmt_version;
355 #if 0
356 fix_tape(buffer);
357 #endif
358 result = ftape_update_header_segments(buffer, 1);
359 prevent_flush();
360 reset_eof_list();
361 }
362 }
363 TRACE_EXIT;
364 return result;
365 }
366
367 void extract_file_marks(byte * address)
368 {
369 TRACE_FUN(8, "extract_file_marks");
370 int i;
371
372 if (format_code == 4) {
373 byte *end;
374 byte *start = find_end_of_bsm_list(address + 256,
375 address + 29 * SECTOR_SIZE);
376
377 memset(eof_map, 0, sizeof(eof_map));
378 nr_of_eof_marks = 0;
379 if (start) {
380 start += 3;
381 end = find_end_of_eof_list(start, address + 29 * SECTOR_SIZE);
382 if (end && end - start <= sizeof(eof_map)) {
383 nr_of_eof_marks = (end - start) / sizeof(unsigned long);
384 memcpy(eof_map, start, end - start);
385 } else {
386 TRACE(1, "File Mark List is too long or damaged !");
387 }
388 } else {
389 TRACE(1, "Bad Sector List is too long or damaged !");
390 }
391 } else {
392 memcpy(eof_map, address + 256, sizeof(eof_map));
393 nr_of_eof_marks = GET2(address, 144);
394 }
395 TRACEi(4, "number of file marks:", nr_of_eof_marks);
396 if (ftape_fmt_version == 1) {
397 TRACE(-1, "swapping version 1 fields");
398
399
400 for (i = 0; i < nr_of_eof_marks; ++i) {
401 unsigned short tmp = eof_map[i].mark.segment;
402 eof_map[i].mark.segment = eof_map[i].mark.sector;
403 eof_map[i].mark.sector = tmp;
404 }
405 }
406 for (i = 0; i < nr_of_eof_marks; ++i) {
407 TRACEx2(4, "eof mark: %5d/%2d",
408 eof_map[i].mark.segment, eof_map[i].mark.sector);
409 }
410 reset_eof_list();
411 TRACE_EXIT;
412 }
413
414 int update_failed_sector_log(byte * buffer)
415 {
416 TRACE_FUN(8, "update_failed_sector_log");
417
418 if (ftape_fmt_version != 0 && failed_sector_log_changed) {
419 if (ftape_fmt_version == 1) {
420 TRACE(-1, "upgrading version 1 format to version 2");
421
422
423 buffer[30 + strlen(linux_tape_label)] = '2';
424 ftape_fmt_version = 2;
425 TRACEx1(-1, "new tape label = \"%s\"", &buffer[30]);
426 }
427 if (format_code == 4) {
428 byte *dest = find_end_of_bsm_list(buffer + 256,
429 buffer + 29 * SECTOR_SIZE) + 3;
430
431 if (dest) {
432 TRACEx2(4, "eof_map at byte offset %6d, size %d",
433 dest - buffer - 256, nr_of_eof_marks * sizeof(unsigned long));
434 memcpy(dest, eof_map, nr_of_eof_marks * sizeof(unsigned long));
435 PUT4(dest, nr_of_eof_marks * sizeof(unsigned long), 0);
436 }
437 } else {
438 memcpy(buffer + 256, eof_map, sizeof(eof_map));
439 PUT2(buffer, 144, nr_of_eof_marks);
440 }
441 failed_sector_log_changed = 0;
442 return 1;
443 }
444 TRACE_EXIT;
445 return 0;
446 }
447
448 int ftape_seek_eom(void)
449 {
450 TRACE_FUN(5, "ftape_seek_eom");
451 int result = 0;
452 unsigned eom;
453
454 if (first_data_segment == -1) {
455 result = read_header_segment(deblock_buffer);
456 }
457 if (result >= 0 && ftape_fmt_version != 0) {
458 eom = first_data_segment;
459 eof_index = 0;
460 eof_mark_ptr = &eof_map[0].mark;
461
462
463
464 for (eof_index = 1, eof_mark_ptr = &eof_map[1].mark;
465 eof_index < nr_of_eof_marks; ++eof_index, ++eof_mark_ptr) {
466
467
468
469 if (eof_mark_ptr->sector == 1) {
470 if (eof_mark_ptr->segment == (eof_mark_ptr - 1)->segment + 1) {
471 eom = eof_mark_ptr->segment;
472 break;
473 }
474 }
475 }
476 ftape_seg_pos = eom;
477 TRACEx1(5, "eom found at segment %d", eom);
478 } else {
479 TRACE(5, "Couldn't get eof mark table");
480 result = -EIO;
481 }
482 TRACE_EXIT;
483 return result;
484 }
485
486 int ftape_seek_eof(unsigned count)
487 {
488 TRACE_FUN(5, "ftape_seek_eof");
489 int result = 0;
490 enum {
491 not = 0, begin, end
492 } bad_seek = not;
493
494 if (first_data_segment == -1) {
495 result = read_header_segment(deblock_buffer);
496 }
497 TRACEx1(5, "tape positioned at segment %d", ftape_seg_pos);
498 if (ftape_fmt_version == 0) {
499 result = -1;
500 }
501 if (result >= 0 && count != 0) {
502 for (eof_index = 0; eof_index <= nr_of_eof_marks; ++eof_index) {
503 if (eof_index == nr_of_eof_marks ||
504 ftape_seg_pos <= eof_map[eof_index].mark.segment) {
505 eof_index += count;
506 if (eof_index < 1) {
507 ftape_seg_pos = first_data_segment;
508 if (eof_index < 0) {
509 eof_index = 0;
510 bad_seek = begin;
511 }
512 } else if (eof_index >= nr_of_eof_marks) {
513 ftape_seg_pos = segments_per_track * tracks_per_tape;
514 if (eof_index > nr_of_eof_marks) {
515 eof_index = nr_of_eof_marks;
516 bad_seek = end;
517 }
518 } else {
519 ftape_seg_pos = eof_map[eof_index - 1].mark.segment + 1;
520 }
521 eof_mark_ptr = &eof_map[eof_index].mark;
522 break;
523 }
524 }
525 }
526 if (result < 0) {
527 TRACE(5, "Couldn't get eof mark table");
528 result = -EIO;
529 } else if (bad_seek != not) {
530 TRACEx1(1, "seek reached %s of tape",
531 (bad_seek == begin) ? "begin" : "end");
532 result = -EIO;
533 } else {
534 TRACEx1(5, "tape repositioned to segment %d", ftape_seg_pos);
535 }
536 TRACE_EXIT;
537 return result;
538 }
539
540 int ftape_file_no(daddr_t * f_no, daddr_t * b_no)
541 {
542 TRACE_FUN(5, "ftape_file_no");
543 int result = 0;
544 int i;
545
546 *f_no = eof_index;
547 *b_no = ftape_seg_pos;
548 TRACEi(4, "number of file marks:", nr_of_eof_marks);
549 for (i = 0; i < nr_of_eof_marks; ++i) {
550 TRACEx2(4, "eof mark: %5d/%2d",
551 eof_map[i].mark.segment, eof_map[i].mark.sector);
552 }
553 TRACE_EXIT;
554 return result;
555 }