restripe: make sure zero buffer is always large enough.
If restripe is called to restore stripes of one size and then save stripes with a larger chunk size, the 'zero' buffer will not be large enough and a double-degraded RAID6 will over-run the buffer. So record the current size of the zero buffer and use it when deciding if we need to allocate a new buffer. Reported-by: Brad Campbell <lists2009@fnarfbargle.com> Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
64385908bb
commit
d47a29257a
16
restripe.c
16
restripe.c
|
@ -334,6 +334,7 @@ void make_tables(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *zero;
|
uint8_t *zero;
|
||||||
|
int zero_size;
|
||||||
/* Following was taken from linux/drivers/md/raid6recov.c */
|
/* Following was taken from linux/drivers/md/raid6recov.c */
|
||||||
|
|
||||||
/* Recover two failed data blocks. */
|
/* Recover two failed data blocks. */
|
||||||
|
@ -490,9 +491,13 @@ int save_stripes(int *source, unsigned long long *offsets,
|
||||||
if (!tables_ready)
|
if (!tables_ready)
|
||||||
make_tables();
|
make_tables();
|
||||||
|
|
||||||
if (zero == NULL) {
|
if (zero == NULL || chunk_size > zero_size) {
|
||||||
|
if (zero)
|
||||||
|
free(zero);
|
||||||
zero = malloc(chunk_size);
|
zero = malloc(chunk_size);
|
||||||
memset(zero, 0, chunk_size);
|
if (zero)
|
||||||
|
memset(zero, 0, chunk_size);
|
||||||
|
zero_size = chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = data_disks * chunk_size;
|
len = data_disks * chunk_size;
|
||||||
|
@ -651,11 +656,16 @@ int restore_stripes(int *dest, unsigned long long *offsets,
|
||||||
|
|
||||||
if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size))
|
if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size))
|
||||||
stripe_buf = NULL;
|
stripe_buf = NULL;
|
||||||
if (zero == NULL) {
|
|
||||||
|
if (zero == NULL || chunk_size > zero_size) {
|
||||||
|
if (zero)
|
||||||
|
free(zero);
|
||||||
zero = malloc(chunk_size);
|
zero = malloc(chunk_size);
|
||||||
if (zero)
|
if (zero)
|
||||||
memset(zero, 0, chunk_size);
|
memset(zero, 0, chunk_size);
|
||||||
|
zero_size = chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stripe_buf == NULL || stripes == NULL || blocks == NULL
|
if (stripe_buf == NULL || stripes == NULL || blocks == NULL
|
||||||
|| zero == NULL) {
|
|| zero == NULL) {
|
||||||
free(stripe_buf);
|
free(stripe_buf);
|
||||||
|
|
Loading…
Reference in New Issue