Пример #1
0
/* Recover failure of one data block plus the P block */
void raid6_datap_recov(int disks, size_t bytes, int faila, uint8_t **ptrs,
		       int neg_offset)
{
	uint8_t *p, *q, *dq;
	const uint8_t *qmul;		/* Q multiplier table */

	if (neg_offset) {
		p = ptrs[-1];
		q = ptrs[-2];
	} else {
		p = ptrs[disks-2];
		q = ptrs[disks-1];
	}

	/* Compute syndrome with zero for the missing data page
	   Use the dead data page as temporary storage for delta q */
	dq = ptrs[faila];
	ptrs[faila] = zero;

	qsyndrome(p, dq, ptrs, disks-2, bytes);

	/* Restore pointer table */
	ptrs[faila]   = dq;

	/* Now, pick the proper data tables */
	qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];

	/* Now do it... */
	while ( bytes-- ) {
		*p++ ^= *dq = qmul[*q ^ *dq];
		q++; dq++;
	}
}
Пример #2
0
void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
		       uint8_t **ptrs, int neg_offset)
{
	uint8_t *p, *q, *dp, *dq;
	uint8_t px, qx, db;
	const uint8_t *pbmul;	/* P multiplier table for B data */
	const uint8_t *qmul;		/* Q multiplier table (for both) */

	if (faila > failb) {
		int t = faila;
		faila = failb;
		failb = t;
	}

	if (neg_offset) {
		p = ptrs[-1];
		q = ptrs[-2];
	} else {
		p = ptrs[disks-2];
		q = ptrs[disks-1];
	}

	/* Compute syndrome with zero for the missing data pages
	   Use the dead data pages as temporary storage for
	   delta p and delta q */
	dp = ptrs[faila];
	ptrs[faila] = zero;
	dq = ptrs[failb];
	ptrs[failb] = zero;

	qsyndrome(dp, dq, ptrs, disks-2, bytes);

	/* Restore pointer table */
	ptrs[faila]   = dp;
	ptrs[failb]   = dq;

	/* Now, pick the proper data tables */
	pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
	qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];

	/* Now do it... */
	while ( bytes-- ) {
		px    = *p ^ *dp;
		qx    = qmul[*q ^ *dq];
		*dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
		*dp++ = db ^ px; /* Reconstructed A */
		p++; q++;
	}
}
Пример #3
0
int test_stripes(int *source, unsigned long long *offsets,
		 int raid_disks, int chunk_size, int level, int layout,
		 unsigned long long start, unsigned long long length)
{
	/* ready the data and p (and q) blocks, and check we got them right */
	char *stripe_buf = xmalloc(raid_disks * chunk_size);
	char **stripes = xmalloc(raid_disks * sizeof(char*));
	char **blocks = xmalloc(raid_disks * sizeof(char*));
	char *p = xmalloc(chunk_size);
	char *q = xmalloc(chunk_size);

	int i;
	int diskP, diskQ;
	int data_disks = raid_disks - (level == 5 ? 1: 2);

	if (!tables_ready)
		make_tables();

	for ( i = 0 ; i < raid_disks ; i++)
		stripes[i] = stripe_buf + i * chunk_size;

	while (length > 0) {
		int disk;

		for (i = 0 ; i < raid_disks ; i++) {
			lseek64(source[i], offsets[i]+start, 0);
			read(source[i], stripes[i], chunk_size);
		}
		for (i = 0 ; i < data_disks ; i++) {
			int disk = geo_map(i, start/chunk_size, raid_disks,
					   level, layout);
			blocks[i] = stripes[disk];
			printf("%d->%d\n", i, disk);
		}
		switch(level) {
		case 6:
			qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size);
			diskP = geo_map(-1, start/chunk_size, raid_disks,
				       level, layout);
			if (memcmp(p, stripes[diskP], chunk_size) != 0) {
				printf("P(%d) wrong at %llu\n", diskP,
				       start / chunk_size);
			}
			diskQ = geo_map(-2, start/chunk_size, raid_disks,
				       level, layout);
			if (memcmp(q, stripes[diskQ], chunk_size) != 0) {
				printf("Q(%d) wrong at %llu\n", diskQ,
				       start / chunk_size);
			}
			disk = raid6_check_disks(data_disks, start, chunk_size,
						 level, layout, diskP, diskQ,
						 p, q, stripes);
			if(disk >= 0) {
			  printf("Possible failed disk: %d\n", disk);
			}
			if(disk == -2) {
			  printf("Failure detected, but disk unknown\n");
			}
			break;
		}
		length -= chunk_size;
		start += chunk_size;
	}
	return 0;
}
Пример #4
0
/* Restore data:
 * We are given:
 *  A list of 'fds' of the active disks. Some may be '-1' for not-available.
 *  A geometry: raid_disks, chunk_size, level, layout
 *  An 'fd' to read from.  It is already seeked to the right (Read) location.
 *  A start and length.
 * The length must be a multiple of the stripe size.
 *
 * We build a full stripe in memory and then write it out.
 * We assume that there are enough working devices.
 */
int restore_stripes(int *dest, unsigned long long *offsets,
		    int raid_disks, int chunk_size, int level, int layout,
		    int source, unsigned long long read_offset,
		    unsigned long long start, unsigned long long length,
		    char *src_buf)
{
	char *stripe_buf;
	char **stripes = xmalloc(raid_disks * sizeof(char*));
	char **blocks = xmalloc(raid_disks * sizeof(char*));
	int i;
	int rv;

	int data_disks = raid_disks - (level == 0 ? 0 : level <= 5 ? 1 : 2);

	if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size))
		stripe_buf = NULL;

	if (zero == NULL || chunk_size > zero_size) {
		if (zero)
			free(zero);
		zero = xcalloc(1, chunk_size);
		zero_size = chunk_size;
	}

	if (stripe_buf == NULL || stripes == NULL || blocks == NULL
	    || zero == NULL) {
		rv = -2;
		goto abort;
	}
	for (i = 0; i < raid_disks; i++)
		stripes[i] = stripe_buf + i * chunk_size;
	while (length > 0) {
		unsigned int len = data_disks * chunk_size;
		unsigned long long offset;
		int disk, qdisk;
		int syndrome_disks;
		if (length < len) {
			rv = -3;
			goto abort;
		}
		for (i = 0; i < data_disks; i++) {
			int disk = geo_map(i, start/chunk_size/data_disks,
					   raid_disks, level, layout);
			if (src_buf == NULL) {
				/* read from file */
				if (lseek64(source, read_offset, 0) !=
					 (off64_t)read_offset) {
					rv = -1;
					goto abort;
				}
				if (read(source,
					 stripes[disk],
					 chunk_size) != chunk_size) {
					rv = -1;
					goto abort;
				}
			} else {
				/* read from input buffer */
				memcpy(stripes[disk],
				       src_buf + read_offset,
				       chunk_size);
			}
			read_offset += chunk_size;
		}
		/* We have the data, now do the parity */
		offset = (start/chunk_size/data_disks) * chunk_size;
		switch (level) {
		case 4:
		case 5:
			disk = geo_map(-1, start/chunk_size/data_disks,
					   raid_disks, level, layout);
			for (i = 0; i < data_disks; i++)
				blocks[i] = stripes[(disk+1+i) % raid_disks];
			xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
			break;
		case 6:
			disk = geo_map(-1, start/chunk_size/data_disks,
				       raid_disks, level, layout);
			qdisk = geo_map(-2, start/chunk_size/data_disks,
				       raid_disks, level, layout);
			if (is_ddf(layout)) {
				/* q over 'raid_disks' blocks, in device order.
				 * 'p' and 'q' get to be all zero
				 */
				for (i = 0; i < raid_disks; i++)
					if (i == disk || i == qdisk)
						blocks[i] = (char*)zero;
					else
						blocks[i] = stripes[i];
				syndrome_disks = raid_disks;
			} else {
				/* for md, q is over 'data_disks' blocks,
				 * starting immediately after 'q'
				 */
				for (i = 0; i < data_disks; i++)
					blocks[i] = stripes[(qdisk+1+i) % raid_disks];

				syndrome_disks = data_disks;
			}
			qsyndrome((uint8_t*)stripes[disk],
				  (uint8_t*)stripes[qdisk],
				  (uint8_t**)blocks,
				  syndrome_disks, chunk_size);
			break;
		}
		for (i=0; i < raid_disks ; i++)
			if (dest[i] >= 0) {
				if (lseek64(dest[i],
					 offsets[i]+offset, 0) < 0) {
					rv = -1;
					goto abort;
				}
				if (write(dest[i], stripes[i],
					 chunk_size) != chunk_size) {
					rv = -1;
					goto abort;
				}
			}
		length -= len;
		start += len;
	}
	rv = 0;

abort:
	free(stripe_buf);
	free(stripes);
	free(blocks);
	return rv;
}
Пример #5
0
int check_stripes(struct mdinfo *info, int *source, unsigned long long *offsets,
		  int raid_disks, int chunk_size, int level, int layout,
		  unsigned long long start, unsigned long long length, char *name[],
		  int repair, int failed_disk1, int failed_disk2)
{
	/* read the data and p and q blocks, and check we got them right */
	char *stripe_buf = xmalloc(raid_disks * chunk_size);
	char **stripes = xmalloc(raid_disks * sizeof(char*));
	char **blocks = xmalloc(raid_disks * sizeof(char*));
	int *block_index_for_slot = xmalloc(raid_disks * sizeof(int));
	uint8_t *p = xmalloc(chunk_size);
	uint8_t *q = xmalloc(chunk_size);
	int *results = xmalloc(chunk_size * sizeof(int));
	sighandler_t *sig = xmalloc(3 * sizeof(sighandler_t));

	int i;
	int diskP, diskQ;
	int data_disks = raid_disks - 2;
	int err = 0;

	extern int tables_ready;

	if (!tables_ready)
		make_tables();

	for ( i = 0 ; i < raid_disks ; i++)
		stripes[i] = stripe_buf + i * chunk_size;

	while (length > 0) {
		int disk;

		printf("pos --> %llu\n", start);

		err = lock_stripe(info, start, chunk_size, data_disks, sig);
		if(err != 0) {
			if (err != 2)
				unlock_all_stripes(info, sig);
			goto exitCheck;
		}
		for (i = 0 ; i < raid_disks ; i++) {
			lseek64(source[i], offsets[i] + start * chunk_size, 0);
			read(source[i], stripes[i], chunk_size);
		}
		err = unlock_all_stripes(info, sig);
		if(err != 0)
			goto exitCheck;

		for (i = 0 ; i < data_disks ; i++) {
			int disk = geo_map(i, start, raid_disks, level, layout);
			blocks[i] = stripes[disk];
			block_index_for_slot[disk] = i;
			printf("%d->%d\n", i, disk);
		}

		qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size);
		diskP = geo_map(-1, start, raid_disks, level, layout);
		diskQ = geo_map(-2, start, raid_disks, level, layout);
		blocks[data_disks] = stripes[diskP];
		block_index_for_slot[diskP] = data_disks;
		blocks[data_disks+1] = stripes[diskQ];
		block_index_for_slot[diskQ] = data_disks+1;

		if (memcmp(p, stripes[diskP], chunk_size) != 0) {
			printf("P(%d) wrong at %llu\n", diskP, start);
		}
		if (memcmp(q, stripes[diskQ], chunk_size) != 0) {
			printf("Q(%d) wrong at %llu\n", diskQ, start);
		}
		raid6_collect(chunk_size, p, q, stripes[diskP], stripes[diskQ], results);
		disk = raid6_stats(results, raid_disks, chunk_size);

		if(disk >= -2) {
			disk = geo_map(disk, start, raid_disks, level, layout);
		}
		if(disk >= 0) {
			printf("Error detected at %llu: possible failed disk slot: %d --> %s\n",
				start, disk, name[disk]);
		}
		if(disk == -65535) {
			printf("Error detected at %llu: disk slot unknown\n", start);
		}
		if(repair == 1) {
			printf("Repairing stripe %llu\n", start);
			printf("Assuming slots %d (%s) and %d (%s) are incorrect\n",
			       failed_disk1, name[failed_disk1],
			       failed_disk2, name[failed_disk2]);

			if (failed_disk1 == diskQ || failed_disk2 == diskQ) {
				char *all_but_failed_blocks[data_disks];
				int failed_data_or_p;
				int failed_block_index;

				if (failed_disk1 == diskQ)
					failed_data_or_p = failed_disk2;
				else
					failed_data_or_p = failed_disk1;
				printf("Repairing D/P(%d) and Q\n", failed_data_or_p);
				failed_block_index = block_index_for_slot[failed_data_or_p];
				for (i=0; i < data_disks; i++)
					if (failed_block_index == i)
						all_but_failed_blocks[i] = stripes[diskP];
					else
						all_but_failed_blocks[i] = blocks[i];
				xor_blocks(stripes[failed_data_or_p],
					all_but_failed_blocks, data_disks, chunk_size);
				qsyndrome(p, (uint8_t*)stripes[diskQ], (uint8_t**)blocks, data_disks, chunk_size);
			} else {
				ensure_zero_has_size(chunk_size);
				if (failed_disk1 == diskP || failed_disk2 == diskP) {
					int failed_data, failed_block_index;
					if (failed_disk1 == diskP)
						failed_data = failed_disk2;
					else
						failed_data = failed_disk1;
					failed_block_index = block_index_for_slot[failed_data];
					printf("Repairing D(%d) and P\n", failed_data);
					raid6_datap_recov(raid_disks, chunk_size, failed_block_index, (uint8_t**)blocks);
				} else {
					printf("Repairing D and D\n");
					int failed_block_index1 = block_index_for_slot[failed_disk1];
					int failed_block_index2 = block_index_for_slot[failed_disk2];
					if (failed_block_index1 > failed_block_index2) {
						int t = failed_block_index1;
						failed_block_index1 = failed_block_index2;
						failed_block_index2 = t;
					}
					raid6_2data_recov(raid_disks, chunk_size, failed_block_index1, failed_block_index2, (uint8_t**)blocks);
				}
			}

			err = lock_stripe(info, start, chunk_size, data_disks, sig);
			if(err != 0) {
				if (err != 2)
					unlock_all_stripes(info, sig);
				goto exitCheck;
			}

			lseek64(source[failed_disk1], offsets[failed_disk1] + start * chunk_size, 0);
			write(source[failed_disk1], stripes[failed_disk1], chunk_size);
			lseek64(source[failed_disk2], offsets[failed_disk2] + start * chunk_size, 0);
			write(source[failed_disk2], stripes[failed_disk2], chunk_size);

			err = unlock_all_stripes(info, sig);
			if(err != 0)
				goto exitCheck;
		} else if (disk >= 0 && repair == 2) {
			printf("Auto-repairing slot %d (%s)\n", disk, name[disk]);
			if (disk == diskQ) {
				qsyndrome(p, (uint8_t*)stripes[diskQ], (uint8_t**)blocks, data_disks, chunk_size);
			} else {
				char *all_but_failed_blocks[data_disks];
				int failed_block_index = block_index_for_slot[disk];
				for (i=0; i < data_disks; i++)
					if (failed_block_index == i)
						all_but_failed_blocks[i] = stripes[diskP];
					else
						all_but_failed_blocks[i] = blocks[i];
				xor_blocks(stripes[disk],
					all_but_failed_blocks, data_disks, chunk_size);
			}

			err = lock_stripe(info, start, chunk_size, data_disks, sig);
			if(err != 0) {
				if (err != 2)
					unlock_all_stripes(info, sig);
				goto exitCheck;
			}

			lseek64(source[disk], offsets[disk] + start * chunk_size, 0);
			write(source[disk], stripes[disk], chunk_size);

			err = unlock_all_stripes(info, sig);
			if(err != 0)
				goto exitCheck;
		}


		length--;
		start++;
	}

exitCheck:

	free(stripe_buf);
	free(stripes);
	free(blocks);
	free(p);
	free(q);
	free(results);

	return err;
}