diff options
author | NeilBrown <neilb@suse.de> | 2011-04-05 13:43:52 +0200 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2011-04-05 13:43:52 +0200 |
commit | d47a29257a189ffb9a85a0c39df4873a306be385 (patch) | |
tree | 81a06b27acd3b12408041618aaedf4c56acbab60 /restripe.c | |
parent | Create: fix size after setting default chunk (diff) | |
download | mdadm-d47a29257a189ffb9a85a0c39df4873a306be385.tar.xz mdadm-d47a29257a189ffb9a85a0c39df4873a306be385.zip |
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>
Diffstat (limited to 'restripe.c')
-rw-r--r-- | restripe.c | 16 |
1 files changed, 13 insertions, 3 deletions
@@ -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); |