/* Calculate the XOR of all the disks besides the one passed at the block given Return -1 if one of the disks required to calculate the xor is failed or if any invalid arg is passed the XOR'ed value is returned in the xorBlock, which is assumed to be of size BLOCK_SIZE As a note, this method uses additive method to calculate the parity bit @param int diskToSkip - either parity disk or failed disk @param int blockToRead - which block we want to calculate parity for @param char *xorBlock - pass by reference the xorBlock that will be used @return int - 0 on success, -1 on failure */ int calculateXOR(int diskToSkip, int blockToRead, char* xorBlock) { int i; for (i = 0; i < BLOCK_SIZE; i++) { xorBlock[i] = 0; } //The disk to skip does not exist if (diskToSkip >= disks) { return -1; } //Check to make sure blockToRead is within range char temp[BLOCK_SIZE]; for(i=0; i < disks; i++) { //Skip this diskToSkip if (i == diskToSkip) { continue; } if (disk_array_read(diskArray, i, blockToRead, temp) != 0) { return -1; } int j; for (j = 0; j < BLOCK_SIZE; j++) { xorBlock[j] = xorBlock[j] ^ temp[j]; } } return 0; }
/* This function will recover the disk and then attempt to put any recovered data on that recovered disk @param int disk - disk to recover @return void */ void recoverDisk(int disk){ // If RAID 0 do nothing besides calling the recover function disk_array_recover_disk(diskArray, disk); //Level 10 if (level == 10){ int diskToCopyFrom; // To determine if recovered disk is first or second in a pair of mirrored disks if (disk % 2){ diskToCopyFrom = disk - 1; } else{ diskToCopyFrom = disk + 1; } int i; for (i = 0; i < blockSize; i++){ char buffer[BLOCK_SIZE]; disk_array_read(diskArray, diskToCopyFrom, i, buffer); disk_array_write(diskArray, disk, i, buffer); } } //Level 4 or 5 do the same attempts at recovery else if (level == 4 || level == 5){ int i; char missingData [BLOCK_SIZE]; for (i = 0; i < blockSize; i++){ if(calculateXOR(disk,i, missingData) == -1){ return; } disk_array_write(diskArray, disk, i, missingData); } } }
/** * This function handles striping across the disks */ static int stripper(int size, int lba, char* value, short isWrite) { int rc = 0; short startFound = 0; int diskIndex = 0; int blockIndex = 0; //index of block within disk int i; short write_error = 0; //loop until address reached for(i = 0; i < size + lba; i++){ if(i == lba){ startFound = 1; } //if address reached perform read or write if(startFound == 1){ if(isWrite == 1){ //has the disk failed? if(disk_active[diskIndex] == 0) { write_error = 1; } disk_array_write(_da, diskIndex, blockIndex, value); } //Read operation else { disk_array_read(_da, diskIndex, blockIndex, buffer); //if bad disk print error message if(!disk_active[diskIndex]) { printf("ERROR "); } else { printf("%d ", *((int*)buffer)); //print output from read } } } //end if start found //if reached end of strip change disk if(++blockIndex % _strip == 0) { diskIndex += 1; if(diskIndex % _disk == 0) { diskIndex = 0; } else { blockIndex -= _strip; } } } //end size+lba for loop diskIndex = diskIndex % _disk; //inform user of write error if(write_error){ printf("ERROR "); write_error = 0; } return rc; }
/* This function will write to the disk array starting at lba, for size, and will write the pattern in the buff passed into the block @param int lba - logical block address @param int size - size of the write @param char *buff - buffer to write to each block of the disk array @return void */ void writeToArray(int lba, int size, char * buff){ //Level 0 if (level == 0) { int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); //successfulWrite should be 0 after all writing is complete, otherwise print error //Only want to print error once int successfulWrite = 0; while (size > 0) { successfulWrite += disk_array_write(diskArray, currentDisk, currentBlock, buff); lba ++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); size --; } if (successfulWrite != 0) { fprintf(stdout, "ERROR "); } } //Level 10 else if(level == 10){ int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); currentDisk *= 2; //successfulWrite should be 0 after all writing is complete // Only want to print error once int successfulWrite = 0; while (size > 0) { // Status keeps track of if write to disk succeded // If we fail both, status will equal -2 int status = disk_array_write(diskArray, currentDisk, currentBlock, buff); status += disk_array_write(diskArray, currentDisk + 1, currentBlock, buff); if (status == -2){ successfulWrite = -1; } lba ++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); currentDisk *= 2; size--; } if (successfulWrite != 0) { fprintf(stdout, "ERROR "); } } //Level 4 else if(level == 4){ // successfulWrite should be 0 after all writing is complete // Only want to print error once int successfulWrite = 0; int currentDisk, currentBlock; int stripeLength =(disks - 1)*strip; int i, j, k; char temp[BLOCK_SIZE]; char parityChange[BLOCK_SIZE]; while (size > 0) { int whereInStripe = lba % stripeLength; int startOfThisStripe = lba - whereInStripe; int blockOffsetOfThisStripe = (startOfThisStripe)/(disks-1); int coverTo = whereInStripe + size; int tempNum; for(i = 0; i < strip; i ++){ for (j = 0; j < BLOCK_SIZE; j++) { parityChange[j] = 0; } tempNum = i; //printf("i: %i\n", i); currentBlock = i + blockOffsetOfThisStripe; while(tempNum < stripeLength){ //printf("temp: %i\n", tempNum); currentDisk = tempNum / strip; if(tempNum >= whereInStripe && tempNum < coverTo){ if (disk_array_write(diskArray, currentDisk, currentBlock, buff)){ successfulWrite --; //write failed } for (k = 0; k < BLOCK_SIZE; k++) { parityChange[k] = parityChange[k] ^ buff[k]; } } else{ if (disk_array_read(diskArray, currentDisk, currentBlock, temp) != 0) { //error reading old data, which means we cannot update parity for this block } else{ for (k = 0; k < BLOCK_SIZE; k++) { parityChange[k] = parityChange[k] ^ temp[k]; } } } tempNum += strip; } disk_array_write(diskArray, disks-1, currentBlock, parityChange); //printf("parity %i is %i\n", i, *((int*)parityChange)); } int next = startOfThisStripe + stripeLength; size -= next - lba; lba = next; } if (successfulWrite != 0) { fprintf(stdout, "ERROR "); } } //Level 5 else if(level == 5){ // successfulWrite should be 0 after all writing is complete // Only want to print error once int successfulWrite = 0; int currentDisk, currentBlock; int stripeLength =(disks - 1)*strip; int i, j, k; int currentParityDisk; char temp[BLOCK_SIZE]; char parityChange[BLOCK_SIZE]; while (size > 0) { int whereInStripe = lba % stripeLength; int startOfThisStripe = lba - whereInStripe; int blockOffsetOfThisStripe = (startOfThisStripe)/(disks-1); int coverTo = whereInStripe + size; int tempNum; for(i = 0; i < strip; i ++){ for (j = 0; j < BLOCK_SIZE; j++) { parityChange[j] = 0; } tempNum = i; //printf("i: %i\n", i); currentBlock = i + blockOffsetOfThisStripe; currentParityDisk = (currentBlock/strip) % disks; while(tempNum < stripeLength){ //printf("temp: %i\n", tempNum); currentDisk = tempNum / strip; if (currentDisk >= currentParityDisk) { currentDisk ++; } if(tempNum >= whereInStripe && tempNum < coverTo){ if (disk_array_write(diskArray, currentDisk, currentBlock, buff)){ successfulWrite --; //write failed } for (k = 0; k < BLOCK_SIZE; k++) { parityChange[k] = parityChange[k] ^ buff[k]; } } else{ if (disk_array_read(diskArray, currentDisk, currentBlock, temp) != 0) { //error reading old data, which means we cannot update parity for this block } else{ for (k = 0; k < BLOCK_SIZE; k++) { parityChange[k] = parityChange[k] ^ temp[k]; } } } tempNum += strip; } disk_array_write(diskArray, currentParityDisk, currentBlock, parityChange); //printf("parity %i is %i\n", i, *((int*)parityChange)); } int next = startOfThisStripe + stripeLength; size -= next - lba; lba = next; } if (successfulWrite != 0) { fprintf(stdout, "ERROR "); } } //Error else{ errorMsgParse(); } }
/* This function will read from the disk array starting at lba for size @param int lba - logical block address @param int size - size of the read @return void */ void readFromArray(int lba, int size){ //Level 0 if (level == 0) { int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); while (size > 0) { char buffer[BLOCK_SIZE]; // If read succeeds print out the value if(disk_array_read(diskArray, currentDisk, currentBlock, buffer) == 0){ int* firstValue = (int*)buffer; fprintf(stdout, "%i ", *firstValue); }else{ fprintf(stdout, "ERROR "); } lba ++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); size --; } } //Level 10 else if(level == 10){ int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); currentDisk *= 2; while (size > 0){ char buffer[BLOCK_SIZE]; // Need to check if 1st disk in mirrored is valid if (disk_array_read(diskArray, currentDisk, currentBlock, buffer) == 0){ int* firstValue = (int *)buffer; fprintf(stdout, "%i ", *firstValue); } // Need to check if 2nd disk in mirrored is valid else if (disk_array_read(diskArray, currentDisk + 1, currentBlock, buffer) == 0){ int* firstValue = (int *)buffer; fprintf(stdout, "%i ", *firstValue); } // Otherwise value read else { fprintf(stdout, "ERROR "); } lba++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); currentDisk *= 2; size --; } } //Level 4 else if(level == 4){ int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); while (size > 0) { char buffer[BLOCK_SIZE]; // If read succeeds print out value if(disk_array_read(diskArray, currentDisk, currentBlock, buffer) == 0){ int* firstValue = (int *)buffer; printf("%i ", *firstValue); }else{ //Try to recover disk on read fail using parity if (calculateXOR(currentDisk,currentBlock,buffer) == -1){ printf("ERROR "); } else{ int* firstValue = (int *)buffer; printf("%i ", *firstValue); } } lba ++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); size --; } } //Level 5 else if(level == 5){ int currentDisk, currentBlock; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); int currentParityDisk = (currentBlock/strip) % disks;; if (currentDisk >= currentParityDisk) { currentDisk ++; } while (size > 0) { char buffer[BLOCK_SIZE]; // If read succeeds print out value if(disk_array_read(diskArray, currentDisk, currentBlock, buffer) == 0){ int* firstValue = (int *)buffer; printf("%i ", *firstValue); }else{ //Try to recover disk on read fail using parity if (calculateXOR(currentDisk,currentBlock,buffer) == -1){ printf("ERROR "); } else{ int* firstValue = (int *)buffer; printf("%i ", *firstValue); } } lba ++; getPhysicalBlock(disks, lba, ¤tDisk, ¤tBlock); currentParityDisk = (currentBlock/strip) % disks;; if (currentDisk >= currentParityDisk) { currentDisk ++; } size --; } } //Error else{ errorMsgParse(); } }