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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include "recover.h"
#include <errno.h>
#include <stdio.h>
#include <unistd.h> /* for usleep - to be removed */
// Main algorithm for recover datas
void recover(slices_evt_t *slicesEvt, char *src, char *dst, char *ddOpts) {
slice_t *sliceToRead;
address_t firstError=0, median, foundMax=0;
int res;
//sliceToRead=slicesEvt->data->first;
sliceToRead=slicesFindLargest(slicesEvt->data, S_UNKNOWN);
while (!end) {
// try to recover sliceToRead and split it if read error
switch ( tryRecoverUntilError(sliceToRead, &firstError, src, dst, ddOpts) ) {
case 0:
// slice recovery has been executed without read error
sliceToRead->status=S_RECOVERED;
break;
case EIO:
// slice recovery has encountered a readerror
res=sliceEvtSplit(slicesEvt, sliceToRead, firstError, S_RECOVERED, S_UNREADABLE, S_UNKNOWN);
if (res<1) {
//TODO
printf("sliceEvtSplit return %d\n", res);
exit(5);
}
break;
default:
exit(2); //TODO
}
/* Now, search the largest S_UNKNOWN zone
split it in two parts */
//sliceToRead=slicesFindLargest(slices, S_UNKNOWN);
sliceToRead=slicesFindLargestFast(slicesEvt->data, &foundMax, S_UNKNOWN, foundMax, sliceToRead->next);
if ( sliceToRead == NULL ) {
// There is nothing more to recover, bailout
end=1;
continue;
}
median=(sliceToRead->begin+sliceToRead->end)/2;
res=sliceEvtSplit(slicesEvt, sliceToRead, median, S_UNKNOWN, S_UNKNOWN, S_UNKNOWN);
switch (res) {
case 1:
// No split, try analyse this zone
// Should be a slice of length 1
break;
case 2:
/* After splitting an S_UNKNOWN zone in two parts
take the second for further analysis.
We already now that this first one is just preceded by
a read error, and errors are frequently grouped in zones,
so trying to read a sector just after a faulty sector is
most likely a waste of time.
*/
sliceToRead=sliceToRead->next;
break;
case 3:
// Internal error of sliceSlpit because this set of parameters prevent split by 3
exit(6); // TODO
break;
case -1:
// Memory error
exit(5); //TODO
break;
default:
// API error, all necessary cases are already listed
exit(7); // TODO
}
}
}
// Method tha read source (and clone to dest) until the first read error
int tryRecoverUntilError(slice_t *sliceToRead, address_t *firstError, char *src, char *dst, char*ddOpts) {
//TODO : implement realy that
//TODO : bail out hardly if WRITE error (on dest)
// char ddinvocation[256];
int res;
address_t seek, count;
seek=sliceToRead->begin;
count=sliceToRead->end - seek + 1;
// res=snprintf(ddinvocation, 255, "dd %s %s %s seek=%lld skip=%lld count=%lld", src, dst, ddOpts, seek, seek, count);
//TODO : listener to put that info on the interface puts(ddinvocation);
/*
// Simulate that we have systematically a read error at first sector
*firstError=sliceToRead->begin;
res=EIO;
*/
/*
// Simulate that we have systematically a read error at last sector
*firstError=sliceToRead->end;
res=EIO;
*/
/*
// Simulate that we have systematically a read error at first sector
// Simulate for each read, tha we have an error just in the middle if read for mor than one sector
if ( sliceToRead->begin == sliceToRead->end ) {
res=0;
} else {
*firstError=(sliceToRead->begin + sliceToRead->end)/2;
res=EIO;
}
*/
// Simulate for each read a pseudo random error position and generate some cases of full read without error
//address_t error=sliceToRead->begin + rand()%(count);
address_t error=sliceToRead->begin + rand()%(count/3);
if ( error % 42 == 0 ) {
res=0;
} else {
res=EIO;
*firstError=error;
}
// Keep things humanly understandable (to be removed when real reads will be done)
//usleep(10000);
return res;
}
|