btrfs-progs: volumes: Remove BUG_ON in raid56 write routine

Remove various BUG_ON in raid56 write routine, including:
1) Memory allocation error
   Old codes allocates memory when code needs new memory in a loop, and
   catch the error using BUG_ON().
   New codes allocates memory in a allocation loop first, if any failure
   is caught, freeing already allocated memories then throw -ENOMEM.

2) Write error
   Change BUG_ON() to correct return value.

3) Validation check
   Same as write error.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2016-10-25 10:11:04 +08:00 committed by David Sterba
parent fd48a96b9a
commit 4d958295d2

View File

@ -2063,25 +2063,39 @@ static int rmw_eb(struct btrfs_fs_info *info,
return 0; return 0;
} }
static void split_eb_for_raid56(struct btrfs_fs_info *info, static int split_eb_for_raid56(struct btrfs_fs_info *info,
struct extent_buffer *orig_eb, struct extent_buffer *orig_eb,
struct extent_buffer **ebs, struct extent_buffer **ebs,
u64 stripe_len, u64 *raid_map, u64 stripe_len, u64 *raid_map,
int num_stripes) int num_stripes)
{ {
struct extent_buffer *eb; struct extent_buffer **tmp_ebs;
u64 start = orig_eb->start; u64 start = orig_eb->start;
u64 this_eb_start; u64 this_eb_start;
int i; int i;
int ret; int ret = 0;
tmp_ebs = calloc(num_stripes, sizeof(*tmp_ebs));
if (!tmp_ebs)
return -ENOMEM;
/* Alloc memory in a row for data stripes */
for (i = 0; i < num_stripes; i++) { for (i = 0; i < num_stripes; i++) {
if (raid_map[i] >= BTRFS_RAID5_P_STRIPE) if (raid_map[i] >= BTRFS_RAID5_P_STRIPE)
break; break;
eb = calloc(1, sizeof(struct extent_buffer) + stripe_len); tmp_ebs[i] = calloc(1, sizeof(**tmp_ebs) + stripe_len);
if (!eb) if (!tmp_ebs[i]) {
BUG(); ret = -ENOMEM;
goto clean_up;
}
}
for (i = 0; i < num_stripes; i++) {
struct extent_buffer *eb = tmp_ebs[i];
if (raid_map[i] >= BTRFS_RAID5_P_STRIPE)
break;
eb->start = raid_map[i]; eb->start = raid_map[i];
eb->len = stripe_len; eb->len = stripe_len;
@ -2095,12 +2109,21 @@ static void split_eb_for_raid56(struct btrfs_fs_info *info,
if (start > this_eb_start || if (start > this_eb_start ||
start + orig_eb->len < this_eb_start + stripe_len) { start + orig_eb->len < this_eb_start + stripe_len) {
ret = rmw_eb(info, eb, orig_eb); ret = rmw_eb(info, eb, orig_eb);
BUG_ON(ret); if (ret)
goto clean_up;
} else { } else {
memcpy(eb->data, orig_eb->data + eb->start - start, stripe_len); memcpy(eb->data, orig_eb->data + eb->start - start,
stripe_len);
} }
ebs[i] = eb; ebs[i] = eb;
} }
free(tmp_ebs);
return ret;
clean_up:
for (i = 0; i < num_stripes; i++)
free(tmp_ebs[i]);
free(tmp_ebs);
return ret;
} }
int write_raid56_with_parity(struct btrfs_fs_info *info, int write_raid56_with_parity(struct btrfs_fs_info *info,
@ -2113,15 +2136,20 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
int j; int j;
int ret; int ret;
int alloc_size = eb->len; int alloc_size = eb->len;
void **pointers;
ebs = kmalloc(sizeof(*ebs) * multi->num_stripes, GFP_NOFS); ebs = malloc(sizeof(*ebs) * multi->num_stripes);
BUG_ON(!ebs); pointers = malloc(sizeof(*pointers) * multi->num_stripes);
if (!ebs || !pointers)
return -ENOMEM;
if (stripe_len > alloc_size) if (stripe_len > alloc_size)
alloc_size = stripe_len; alloc_size = stripe_len;
split_eb_for_raid56(info, eb, ebs, stripe_len, raid_map, ret = split_eb_for_raid56(info, eb, ebs, stripe_len, raid_map,
multi->num_stripes); multi->num_stripes);
if (ret)
goto out;
for (i = 0; i < multi->num_stripes; i++) { for (i = 0; i < multi->num_stripes; i++) {
struct extent_buffer *new_eb; struct extent_buffer *new_eb;
@ -2129,11 +2157,17 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
ebs[i]->dev_bytenr = multi->stripes[i].physical; ebs[i]->dev_bytenr = multi->stripes[i].physical;
ebs[i]->fd = multi->stripes[i].dev->fd; ebs[i]->fd = multi->stripes[i].dev->fd;
multi->stripes[i].dev->total_ios++; multi->stripes[i].dev->total_ios++;
BUG_ON(ebs[i]->start != raid_map[i]); if (ebs[i]->start != raid_map[i]) {
ret = -EINVAL;
goto out_free_split;
}
continue; continue;
} }
new_eb = kmalloc(sizeof(*eb) + alloc_size, GFP_NOFS); new_eb = malloc(sizeof(*eb) + alloc_size);
BUG_ON(!new_eb); if (!new_eb) {
ret = -ENOMEM;
goto out_free_split;
}
new_eb->dev_bytenr = multi->stripes[i].physical; new_eb->dev_bytenr = multi->stripes[i].physical;
new_eb->fd = multi->stripes[i].dev->fd; new_eb->fd = multi->stripes[i].dev->fd;
multi->stripes[i].dev->total_ios++; multi->stripes[i].dev->total_ios++;
@ -2145,12 +2179,6 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
q_eb = new_eb; q_eb = new_eb;
} }
if (q_eb) { if (q_eb) {
void **pointers;
pointers = kmalloc(sizeof(*pointers) * multi->num_stripes,
GFP_NOFS);
BUG_ON(!pointers);
ebs[multi->num_stripes - 2] = p_eb; ebs[multi->num_stripes - 2] = p_eb;
ebs[multi->num_stripes - 1] = q_eb; ebs[multi->num_stripes - 1] = q_eb;
@ -2158,7 +2186,6 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
pointers[i] = ebs[i]->data; pointers[i] = ebs[i]->data;
raid6_gen_syndrome(multi->num_stripes, stripe_len, pointers); raid6_gen_syndrome(multi->num_stripes, stripe_len, pointers);
kfree(pointers);
} else { } else {
ebs[multi->num_stripes - 1] = p_eb; ebs[multi->num_stripes - 1] = p_eb;
memcpy(p_eb->data, ebs[0]->data, stripe_len); memcpy(p_eb->data, ebs[0]->data, stripe_len);
@ -2177,12 +2204,18 @@ int write_raid56_with_parity(struct btrfs_fs_info *info,
for (i = 0; i < multi->num_stripes; i++) { for (i = 0; i < multi->num_stripes; i++) {
ret = write_extent_to_disk(ebs[i]); ret = write_extent_to_disk(ebs[i]);
BUG_ON(ret); if (ret < 0)
goto out_free_split;
}
out_free_split:
for (i = 0; i < multi->num_stripes; i++) {
if (ebs[i] != eb) if (ebs[i] != eb)
kfree(ebs[i]); free(ebs[i]);
} }
out:
free(ebs);
free(pointers);
kfree(ebs); return ret;
return 0;
} }