From d47a29257a189ffb9a85a0c39df4873a306be385 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 5 Apr 2011 21:43:52 +1000 Subject: [PATCH] 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 --- restripe.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) 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); -- 2.39.2