summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Dorau <lukasz.dorau@intel.com>2011-09-19 13:26:05 +1000
committerNeilBrown <neilb@suse.de>2011-09-19 13:26:05 +1000
commit758be4f1c9cda8eefb2fd241835521462196e16c (patch)
treecfd228315e416d32cee78217f2e89f92087a7a7e
parenta8619d23b863cdce388527e1da12fea56f56c891 (diff)
downloadmdadm-758be4f1c9cda8eefb2fd241835521462196e16c.tar.gz
Fix serious memory leak
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>
-rw-r--r--restripe.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/restripe.c b/restripe.c
index 9c83e2e..00e7a82 100644
--- a/restripe.c
+++ b/restripe.c
@@ -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