summaryrefslogtreecommitdiff
path: root/restripe.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-04-05 21:43:52 +1000
committerNeilBrown <neilb@suse.de>2011-04-05 21:43:52 +1000
commitd47a29257a189ffb9a85a0c39df4873a306be385 (patch)
tree81a06b27acd3b12408041618aaedf4c56acbab60 /restripe.c
parent64385908bbec982d4d6cddd313c7594499087126 (diff)
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.c16
1 files 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);