/* Comile with -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 */ #ifdef LINUXSTATIC #include "lib.h" #else #include #include #include #include #include #include #include #include #include #endif #include "util.h" #define MAXDISKS 12 #define DEFSTRIPE 64 #define DEFWINDOW 128 const char *diskname[MAXDISKS], *progname="raidextract"; char *window[MAXDISKS][2]; int windowalt=1, failed=-1; int diskfd[MAXDISKS], request[MAXDISKS], reply[MAXDISKS]; off_t windowstart, windowend, windowcyl, stripecyl, raidstart=0, raidlen=0; int disks=0, diskstart, datasize=0, rotate=0, stripesize=DEFSTRIPE*1024, windowsize=DEFWINDOW*1024; int noparity = 0; void usage(int status) { fprintf(status? stderr:stdout, "Usage: %s [options] disks...\n" " --stripe " " Set stripe size in K (default: %i)\n" " --window " " Set I/O window size in K (default: %i)\n" " --start " " Skip to given output position in bytes (default: 0)\n" " --length " " Length of output (no default)\n" " --rotate " " Rotate parity disk position (default: 0)\n" " --noparity " " There is no parity, it's not raid5\n" " --failed " " Ignore data on disk at index n as failed (default: none)\n", progname, DEFSTRIPE, DEFWINDOW); exit(status); } void diskhelper(int i, int rd, int wr) { int bytes, dummy, datalen; while (1) { char *ptr; int len=windowsize; windowalt=!windowalt; ptr=window[i][windowalt]; while (len) { bytes=read(diskfd[i], ptr, windowsize); if (bytes==-1 && errno==EINTR) continue; if (bytes==-1) die("read (child %i, file %s): %s\n", i, diskname[i], strerror(errno)); if (bytes==0) break; ptr+=bytes; len-=bytes; } datalen=windowsize-len; msync(window[i][windowalt], windowsize, MS_SYNC | MS_INVALIDATE); len=sizeof(datalen); ptr=(char *)&datalen; while (len) { bytes=write(wr, ptr, len); if (bytes==-1 && errno==EINTR) continue; if (bytes==-1) die("write (child %i): %s\n", i, strerror(errno)); len-=bytes; ptr+=bytes; } while ((bytes=read(rd, &dummy, 1))!=1) { if (bytes==-1 && errno==EINTR) continue; if (bytes==-1) die("read (child %i): %s\n", i, strerror(errno)); if (bytes==0) exit(0); } } } void parseopts(int argc, char *argv[]) { int i, optparsing=1; if (argc) setprogname(argv[0]); if (argc<=1) usage(1); for (i=1; i= disks) die("Invalid failed disk\n"); if (windowsize % stripesize) die("Window size must be a multiple of stripe size\n"); if (raidlen <= 0) die("Need to specify mandatory argument: --length\n"); } void starthelpers(void) { int i; for (i=0; i returned) ret=returned; while ((bytes=write(request[i], &dummy, 1))!=1) { if (bytes==-1 && errno==EINTR) continue; die("write: %s\n", strerror(errno)); } } ret=(ret/stripesize) * stripesize; windowstart += datasize; datasize = ret; windowend = windowstart + ret-1; windowalt = !windowalt; return ret; } void verifychecksum(void) { int i, a; int lastwarn=-stripesize; if (noparity) return; if (failed==-1) { for (a=0; a=stripesize) { warn("Parity check failed at disk positition %lld\n", (long long)(windowstart+a)); lastwarn=a; } } xor ^= *(uint32_t *)(window[failed][windowalt]+a); *(uint32_t *)(window[failed][windowalt]+a) = xor; } } } void printpartial(void) { off_t windowoffset = raidstart - windowstart*(disks-(!noparity)); int stripe=raidstart/stripesize; int offset=raidstart%stripesize; off_t winoffset = (windowoffset/stripecyl)*stripesize+offset; int disk=stripe % (disks-(!noparity)); int paritydisk=(stripe / (disks-1) + rotate) % disks; int len=stripesize-offset; int bytes; char *ptr; if (!noparity && paritydisk <= disk) disk++; if (len>raidlen) len=raidlen; if (winoffset+len > datasize) len=datasize-winoffset; if (!len) die("Input ended with %llu output bytes unwritten\n", raidlen); /* fprintf(stderr, "\nraidlen=%lli\n", raidlen); */ /* fprintf(stderr, "raidstart=%llu\n", (long long)raidstart); */ /* fprintf(stderr, "windowstart=%llu\n", (long long)windowstart); */ /* fprintf(stderr, "windowoffset=%llu\n", (long long)windowoffset); */ /* fprintf(stderr, "stripe=%i\n", stripe); */ /* fprintf(stderr, "disk=%i\n", disk); */ /* fprintf(stderr, "paritydisk=%i\n", paritydisk); */ /* fprintf(stderr, "len=%i\n", len); */ /* fprintf(stderr, "print data [%lli] [%i..%i]\n", windowoffset/stripecyl, offset, offset+len-1); */ raidstart+=len; raidlen-=len; ptr=window[disk][windowalt]+winoffset; while (len) { bytes=write(STDOUT_FILENO, ptr, len); if (bytes==-1 && errno==EINTR) continue; if (bytes==-1) die("write: %s\n", strerror(errno)); len-=bytes; ptr+=bytes; } } int main(int argc, char *argv[]) { parseopts(argc, argv); windowcyl = windowsize * (disks-(!noparity)); stripecyl = stripesize * (disks-(!noparity)); windowstart = (raidstart/windowcyl) * windowsize; starthelpers(); getnextwindow(); verifychecksum(); while (raidlen) { off_t nextwindow = (raidstart/windowcyl) * windowsize; if (windowstart != nextwindow) { getnextwindow(); verifychecksum(); } printpartial(); } return 0; }