From: NeilBrown Date: Tue, 5 Apr 2011 11:43:52 +0000 (+1000) Subject: restripe: make sure zero buffer is always large enough. X-Git-Tag: mdadm-3.2.2~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d47a29257a189ffb9a85a0c39df4873a306be385;p=thirdparty%2Fmdadm.git 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 Signed-off-by: NeilBrown --- diff --git a/restripe.c b/restripe.c index 906788c4..63a2a64c 100644 --- a/restripe.c +++ b/restripe.c @@ -334,6 +334,7 @@ void make_tables(void) } uint8_t *zero; +int zero_size; /* Following was taken from linux/drivers/md/raid6recov.c */ /* Recover two failed data blocks. */ @@ -490,9 +491,13 @@ int save_stripes(int *source, unsigned long long *offsets, if (!tables_ready) make_tables(); - if (zero == NULL) { + if (zero == NULL || chunk_size > zero_size) { + if (zero) + free(zero); 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; @@ -651,11 +656,16 @@ int restore_stripes(int *dest, unsigned long long *offsets, if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size)) stripe_buf = NULL; - if (zero == NULL) { + + if (zero == NULL || chunk_size > zero_size) { + if (zero) + free(zero); zero = malloc(chunk_size); if (zero) memset(zero, 0, chunk_size); + zero_size = chunk_size; } + if (stripe_buf == NULL || stripes == NULL || blocks == NULL || zero == NULL) { free(stripe_buf);