aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.com>2011-08-05 18:46:16 -0400
committerDavid Sterba <dsterba@suse.cz>2012-03-21 20:45:37 -0400
commit0678b61851b510ba68341dff59cd9b47e1712e91 (patch)
treee8e8199ee3929e508c42bea39a3eeb122246626c /fs/btrfs
parentbe1a5564fd39fa2ca6adbb41c75fb08f96a1ffcb (diff)
btrfs: Don't BUG_ON kzalloc error in btrfs_lookup_csums_range()
Unfortunately it isn't enough to just exit here - the kzalloc() happens in a loop and the allocated items are added to a linked list whose head is passed in from the caller. To fix the BUG_ON() and also provide the semantic that the list passed in is only modified on success, I create function-local temporary list that we add items too. If no error is met, that list is spliced to the callers at the end of the function. Otherwise the list will be walked and all items freed before the error value is returned. I did a simple test on this patch by forcing an error at the kzalloc() point and verifying that when this hits (git clone seemed to exercise this), the function throws the proper error. Unfortunately but predictably, we later hit a BUG_ON(ret) type line that still hasn't been fixed up ;) Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/file-item.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index edb69b4d5335..89af104c7569 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -284,6 +284,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
284 struct btrfs_ordered_sum *sums; 284 struct btrfs_ordered_sum *sums;
285 struct btrfs_sector_sum *sector_sum; 285 struct btrfs_sector_sum *sector_sum;
286 struct btrfs_csum_item *item; 286 struct btrfs_csum_item *item;
287 LIST_HEAD(tmplist);
287 unsigned long offset; 288 unsigned long offset;
288 int ret; 289 int ret;
289 size_t size; 290 size_t size;
@@ -358,7 +359,10 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
358 MAX_ORDERED_SUM_BYTES(root)); 359 MAX_ORDERED_SUM_BYTES(root));
359 sums = kzalloc(btrfs_ordered_sum_size(root, size), 360 sums = kzalloc(btrfs_ordered_sum_size(root, size),
360 GFP_NOFS); 361 GFP_NOFS);
361 BUG_ON(!sums); 362 if (!sums) {
363 ret = -ENOMEM;
364 goto fail;
365 }
362 366
363 sector_sum = sums->sums; 367 sector_sum = sums->sums;
364 sums->bytenr = start; 368 sums->bytenr = start;
@@ -380,12 +384,19 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
380 offset += csum_size; 384 offset += csum_size;
381 sector_sum++; 385 sector_sum++;
382 } 386 }
383 list_add_tail(&sums->list, list); 387 list_add_tail(&sums->list, &tmplist);
384 } 388 }
385 path->slots[0]++; 389 path->slots[0]++;
386 } 390 }
387 ret = 0; 391 ret = 0;
388fail: 392fail:
393 while (ret < 0 && !list_empty(&tmplist)) {
394 sums = list_entry(&tmplist, struct btrfs_ordered_sum, list);
395 list_del(&sums->list);
396 kfree(sums);
397 }
398 list_splice_tail(&tmplist, list);
399
389 btrfs_free_path(path); 400 btrfs_free_path(path);
390 return ret; 401 return ret;
391} 402}