]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Fix serious memory leak
authorLukasz Dorau <lukasz.dorau@intel.com>
Mon, 19 Sep 2011 03:26:05 +0000 (13:26 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 19 Sep 2011 03:26:05 +0000 (13:26 +1000)
During reshape function restore_stripes is called periodically
and every time the buffer stripe_buf (of size raid_disks*chunk_size)
is allocated but is not freed. It happens also upon successful completion.
In case of huge arrays it can lead to the seizure of the entire
system memory (even of the order of gigabytes).

Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
restripe.c

index 9c83e2ebbedf0bc1774dd97ea2876873ca0b9258..00e7a822ffb9d2babf6e485991bd4491486a8246 100644 (file)
@@ -687,6 +687,7 @@ int restore_stripes(int *dest, unsigned long long *offsets,
        char **stripes = malloc(raid_disks * sizeof(char*));
        char **blocks = malloc(raid_disks * sizeof(char*));
        int i;
+       int rv;
 
        int data_disks = raid_disks - (level == 0 ? 0 : level <= 5 ? 1 : 2);
 
@@ -704,11 +705,8 @@ int restore_stripes(int *dest, unsigned long long *offsets,
 
        if (stripe_buf == NULL || stripes == NULL || blocks == NULL
            || zero == NULL) {
-               free(stripe_buf);
-               free(stripes);
-               free(blocks);
-               free(zero);
-               return -2;
+               rv = -2;
+               goto abort;
        }
        for (i = 0; i < raid_disks; i++)
                stripes[i] = stripe_buf + i * chunk_size;
@@ -717,20 +715,26 @@ int restore_stripes(int *dest, unsigned long long *offsets,
                unsigned long long offset;
                int disk, qdisk;
                int syndrome_disks;
-               if (length < len)
-                       return -3;
+               if (length < len) {
+                       rv = -3;
+                       goto abort;
+               }
                for (i = 0; i < data_disks; i++) {
                        int disk = geo_map(i, start/chunk_size/data_disks,
                                           raid_disks, level, layout);
                        if (src_buf == NULL) {
                                /* read from file */
-                               if (lseek64(source,
-                                       read_offset, 0) != (off64_t)read_offset)
-                                       return -1;
+                               if (lseek64(source, read_offset, 0) !=
+                                        (off64_t)read_offset) {
+                                       rv = -1;
+                                       goto abort;
+                               }
                                if (read(source,
                                         stripes[disk],
-                                        chunk_size) != chunk_size)
-                                       return -1;
+                                        chunk_size) != chunk_size) {
+                                       rv = -1;
+                                       goto abort;
+                               }
                        } else {
                                /* read from input buffer */
                                memcpy(stripes[disk],
@@ -782,15 +786,27 @@ int restore_stripes(int *dest, unsigned long long *offsets,
                }
                for (i=0; i < raid_disks ; i++)
                        if (dest[i] >= 0) {
-                               if (lseek64(dest[i], offsets[i]+offset, 0) < 0)
-                                       return -1;
-                               if (write(dest[i], stripes[i], chunk_size) != chunk_size)
-                                       return -1;
+                               if (lseek64(dest[i],
+                                        offsets[i]+offset, 0) < 0) {
+                                       rv = -1;
+                                       goto abort;
+                               }
+                               if (write(dest[i], stripes[i],
+                                        chunk_size) != chunk_size) {
+                                       rv = -1;
+                                       goto abort;
+                               }
                        }
                length -= len;
                start += len;
        }
-       return 0;
+       rv = 0;
+
+abort:
+       free(stripe_buf);
+       free(stripes);
+       free(blocks);
+       return rv;
 }
 
 #ifdef MAIN