+/* Autorepair */
+int autorepair(int *disk, unsigned long long start, int chunk_size,
+ char *name[], int raid_disks, int syndrome_disks, char **blocks_page,
+ char **blocks, uint8_t *p, int *block_index_for_slot,
+ int *source, unsigned long long *offsets)
+{
+ int i, j;
+ int pages_to_write_count = 0;
+ int page_to_write[chunk_size >> CHECK_PAGE_BITS];
+ for(j = 0; j < (chunk_size >> CHECK_PAGE_BITS); j++) {
+ if (disk[j] >= -2 && block_index_for_slot[disk[j]] >= 0) {
+ int slot = block_index_for_slot[disk[j]];
+ printf("Auto-repairing slot %d (%s)\n", slot, name[slot]);
+ pages_to_write_count++;
+ page_to_write[j] = 1;
+ for(i = -2; i < syndrome_disks; i++) {
+ blocks_page[i] = blocks[i] + j * CHECK_PAGE_SIZE;
+ }
+ if (disk[j] == -2) {
+ qsyndrome(p, (uint8_t*)blocks_page[-2],
+ (uint8_t**)blocks_page,
+ syndrome_disks, CHECK_PAGE_SIZE);
+ }
+ else {
+ char *all_but_failed_blocks[syndrome_disks];
+ for(i = 0; i < syndrome_disks; i++) {
+ if (i == disk[j])
+ all_but_failed_blocks[i] = blocks_page[-1];
+ else
+ all_but_failed_blocks[i] = blocks_page[i];
+ }
+ xor_blocks(blocks_page[disk[j]],
+ all_but_failed_blocks, syndrome_disks,
+ CHECK_PAGE_SIZE);
+ }
+ }
+ else {
+ page_to_write[j] = 0;
+ }
+ }
+
+ if(pages_to_write_count > 0) {
+ int write_res = 0;
+ for(j = 0; j < (chunk_size >> CHECK_PAGE_BITS); j++) {
+ if(page_to_write[j] == 1) {
+ int slot = block_index_for_slot[disk[j]];
+ lseek64(source[slot], offsets[slot] + start * chunk_size + j * CHECK_PAGE_SIZE, SEEK_SET);
+ write_res += write(source[slot],
+ blocks[disk[j]] + j * CHECK_PAGE_SIZE,
+ CHECK_PAGE_SIZE);
+ }
+ }
+
+ if (write_res != (CHECK_PAGE_SIZE * pages_to_write_count)) {
+ fprintf(stderr, "Failed to write a full chunk.\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Manual repair */
+int manual_repair(int chunk_size, int syndrome_disks,
+ int failed_slot1, int failed_slot2,
+ unsigned long long start, int *block_index_for_slot,
+ char *name[], char **stripes, char **blocks, uint8_t *p,
+ int *source, unsigned long long *offsets)
+{
+ int i;
+ int fd1 = block_index_for_slot[failed_slot1];
+ int fd2 = block_index_for_slot[failed_slot2];
+ printf("Repairing stripe %llu\n", start);
+ printf("Assuming slots %d (%s) and %d (%s) are incorrect\n",
+ fd1, name[fd1],
+ fd2, name[fd2]);
+
+ if (failed_slot1 == -2 || failed_slot2 == -2) {
+ char *all_but_failed_blocks[syndrome_disks];
+ int failed_data_or_p;
+
+ if (failed_slot1 == -2)
+ failed_data_or_p = failed_slot2;
+ else
+ failed_data_or_p = failed_slot1;
+
+ printf("Repairing D/P(%d) and Q\n", failed_data_or_p);
+
+ for (i = 0; i < syndrome_disks; i++) {
+ if (i == failed_data_or_p)
+ all_but_failed_blocks[i] = blocks[-1];
+ else
+ all_but_failed_blocks[i] = blocks[i];
+ }
+ xor_blocks(blocks[failed_data_or_p],
+ all_but_failed_blocks, syndrome_disks, chunk_size);
+ qsyndrome(p, (uint8_t*)blocks[-2], (uint8_t**)blocks,
+ syndrome_disks, chunk_size);
+ } else {
+ ensure_zero_has_size(chunk_size);
+ if (failed_slot1 == -1 || failed_slot2 == -1) {
+ int failed_data;
+ if (failed_slot1 == -1)
+ failed_data = failed_slot2;
+ else
+ failed_data = failed_slot1;
+
+ printf("Repairing D(%d) and P\n", failed_data);
+ raid6_datap_recov(syndrome_disks+2, chunk_size,
+ failed_data, (uint8_t**)blocks, 1);
+ } else {
+ printf("Repairing D and D\n");
+ raid6_2data_recov(syndrome_disks+2, chunk_size,
+ failed_slot1, failed_slot2,
+ (uint8_t**)blocks, 1);
+ }
+ }
+
+ int write_res1, write_res2;
+ off64_t seek_res;
+
+ seek_res = lseek64(source[fd1],
+ offsets[fd1] + start * chunk_size, SEEK_SET);
+ if (seek_res < 0) {
+ fprintf(stderr, "lseek failed for failed_disk1\n");
+ return -1;
+ }
+ write_res1 = write(source[fd1], blocks[failed_slot1], chunk_size);
+
+ seek_res = lseek64(source[fd2],
+ offsets[fd2] + start * chunk_size, SEEK_SET);
+ if (seek_res < 0) {
+ fprintf(stderr, "lseek failed for failed_disk2\n");
+ return -1;
+ }
+ write_res2 = write(source[fd2], blocks[failed_slot2], chunk_size);
+
+ if (write_res1 != chunk_size || write_res2 != chunk_size) {
+ fprintf(stderr, "Failed to write a complete chunk.\n");
+ return -2;
+ }
+
+ return 0;
+}
+