#include "recover.h" #include #include #include /* 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; }