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