]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
restripe: make sure zero buffer is always large enough.
authorNeilBrown <neilb@suse.de>
Tue, 5 Apr 2011 11:43:52 +0000 (21:43 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 5 Apr 2011 11:43:52 +0000 (21:43 +1000)
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>
restripe.c

index 906788c4c94699e6e44594b4f9b07f534770d7ac..63a2a64c4d82da306573f1dc01f374a649c9f566 100644 (file)
@@ -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);