diff options
author | Jeff Mahoney <jeffm@suse.com> | 2012-03-12 11:03:00 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2012-03-22 06:52:54 -0400 |
commit | 79787eaab46121d4713ed03c8fc63b9ec3eaec76 (patch) | |
tree | ee6b17d0811ee54ab74a03aa4e0bb92769d2f12a /fs/btrfs/extent_io.c | |
parent | 49b25e0540904be0bf558b84475c69d72e4de66e (diff) |
btrfs: replace many BUG_ONs with proper error handling
btrfs currently handles most errors with BUG_ON. This patch is a work-in-
progress but aims to handle most errors other than internal logic
errors and ENOMEM more gracefully.
This iteration prevents most crashes but can run into lockups with
the page lock on occasion when the timing "works out."
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ffa7cc3370c7..4c3ce7a0a7a4 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1244,7 +1244,7 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) | |||
1244 | 1244 | ||
1245 | while (index <= end_index) { | 1245 | while (index <= end_index) { |
1246 | page = find_get_page(tree->mapping, index); | 1246 | page = find_get_page(tree->mapping, index); |
1247 | BUG_ON(!page); | 1247 | BUG_ON(!page); /* Pages should be in the extent_io_tree */ |
1248 | set_page_writeback(page); | 1248 | set_page_writeback(page); |
1249 | page_cache_release(page); | 1249 | page_cache_release(page); |
1250 | index++; | 1250 | index++; |
@@ -1523,7 +1523,7 @@ again: | |||
1523 | goto out_failed; | 1523 | goto out_failed; |
1524 | } | 1524 | } |
1525 | } | 1525 | } |
1526 | BUG_ON(ret); | 1526 | BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */ |
1527 | 1527 | ||
1528 | /* step three, lock the state bits for the whole range */ | 1528 | /* step three, lock the state bits for the whole range */ |
1529 | lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state); | 1529 | lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state); |
@@ -2200,7 +2200,6 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) | |||
2200 | /* Writeback already completed */ | 2200 | /* Writeback already completed */ |
2201 | if (ret == 0) | 2201 | if (ret == 0) |
2202 | return 1; | 2202 | return 1; |
2203 | BUG_ON(ret < 0); | ||
2204 | } | 2203 | } |
2205 | 2204 | ||
2206 | if (!uptodate) { | 2205 | if (!uptodate) { |
@@ -2353,7 +2352,6 @@ error_handled: | |||
2353 | if (ret == 0) | 2352 | if (ret == 0) |
2354 | goto error_handled; | 2353 | goto error_handled; |
2355 | } | 2354 | } |
2356 | BUG_ON(ret < 0); | ||
2357 | } | 2355 | } |
2358 | 2356 | ||
2359 | if (uptodate) { | 2357 | if (uptodate) { |
@@ -2405,6 +2403,10 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, | |||
2405 | return bio; | 2403 | return bio; |
2406 | } | 2404 | } |
2407 | 2405 | ||
2406 | /* | ||
2407 | * Since writes are async, they will only return -ENOMEM. | ||
2408 | * Reads can return the full range of I/O error conditions. | ||
2409 | */ | ||
2408 | static int __must_check submit_one_bio(int rw, struct bio *bio, | 2410 | static int __must_check submit_one_bio(int rw, struct bio *bio, |
2409 | int mirror_num, unsigned long bio_flags) | 2411 | int mirror_num, unsigned long bio_flags) |
2410 | { | 2412 | { |
@@ -2477,7 +2479,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
2477 | bio_add_page(bio, page, page_size, offset) < page_size) { | 2479 | bio_add_page(bio, page, page_size, offset) < page_size) { |
2478 | ret = submit_one_bio(rw, bio, mirror_num, | 2480 | ret = submit_one_bio(rw, bio, mirror_num, |
2479 | prev_bio_flags); | 2481 | prev_bio_flags); |
2480 | BUG_ON(ret < 0); | 2482 | if (ret < 0) |
2483 | return ret; | ||
2481 | bio = NULL; | 2484 | bio = NULL; |
2482 | } else { | 2485 | } else { |
2483 | return 0; | 2486 | return 0; |
@@ -2498,10 +2501,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
2498 | 2501 | ||
2499 | if (bio_ret) | 2502 | if (bio_ret) |
2500 | *bio_ret = bio; | 2503 | *bio_ret = bio; |
2501 | else { | 2504 | else |
2502 | ret = submit_one_bio(rw, bio, mirror_num, bio_flags); | 2505 | ret = submit_one_bio(rw, bio, mirror_num, bio_flags); |
2503 | BUG_ON(ret < 0); | ||
2504 | } | ||
2505 | 2506 | ||
2506 | return ret; | 2507 | return ret; |
2507 | } | 2508 | } |
@@ -2525,6 +2526,7 @@ static void set_page_extent_head(struct page *page, unsigned long len) | |||
2525 | * basic readpage implementation. Locked extent state structs are inserted | 2526 | * basic readpage implementation. Locked extent state structs are inserted |
2526 | * into the tree that are removed when the IO is done (by the end_io | 2527 | * into the tree that are removed when the IO is done (by the end_io |
2527 | * handlers) | 2528 | * handlers) |
2529 | * XXX JDM: This needs looking at to ensure proper page locking | ||
2528 | */ | 2530 | */ |
2529 | static int __extent_read_full_page(struct extent_io_tree *tree, | 2531 | static int __extent_read_full_page(struct extent_io_tree *tree, |
2530 | struct page *page, | 2532 | struct page *page, |
@@ -2687,6 +2689,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | |||
2687 | end_bio_extent_readpage, mirror_num, | 2689 | end_bio_extent_readpage, mirror_num, |
2688 | *bio_flags, | 2690 | *bio_flags, |
2689 | this_bio_flag); | 2691 | this_bio_flag); |
2692 | BUG_ON(ret == -ENOMEM); | ||
2690 | nr++; | 2693 | nr++; |
2691 | *bio_flags = this_bio_flag; | 2694 | *bio_flags = this_bio_flag; |
2692 | } | 2695 | } |
@@ -2713,10 +2716,8 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page, | |||
2713 | 2716 | ||
2714 | ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num, | 2717 | ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num, |
2715 | &bio_flags); | 2718 | &bio_flags); |
2716 | if (bio) { | 2719 | if (bio) |
2717 | ret = submit_one_bio(READ, bio, mirror_num, bio_flags); | 2720 | ret = submit_one_bio(READ, bio, mirror_num, bio_flags); |
2718 | BUG_ON(ret < 0); | ||
2719 | } | ||
2720 | return ret; | 2721 | return ret; |
2721 | } | 2722 | } |
2722 | 2723 | ||
@@ -2830,7 +2831,11 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
2830 | delalloc_end, | 2831 | delalloc_end, |
2831 | &page_started, | 2832 | &page_started, |
2832 | &nr_written); | 2833 | &nr_written); |
2833 | BUG_ON(ret); | 2834 | /* File system has been set read-only */ |
2835 | if (ret) { | ||
2836 | SetPageError(page); | ||
2837 | goto done; | ||
2838 | } | ||
2834 | /* | 2839 | /* |
2835 | * delalloc_end is already one less than the total | 2840 | * delalloc_end is already one less than the total |
2836 | * length, so we don't subtract one from | 2841 | * length, so we don't subtract one from |
@@ -3141,7 +3146,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd) | |||
3141 | rw = WRITE_SYNC; | 3146 | rw = WRITE_SYNC; |
3142 | 3147 | ||
3143 | ret = submit_one_bio(rw, epd->bio, 0, 0); | 3148 | ret = submit_one_bio(rw, epd->bio, 0, 0); |
3144 | BUG_ON(ret < 0); | 3149 | BUG_ON(ret < 0); /* -ENOMEM */ |
3145 | epd->bio = NULL; | 3150 | epd->bio = NULL; |
3146 | } | 3151 | } |
3147 | } | 3152 | } |
@@ -3257,10 +3262,8 @@ int extent_readpages(struct extent_io_tree *tree, | |||
3257 | page_cache_release(page); | 3262 | page_cache_release(page); |
3258 | } | 3263 | } |
3259 | BUG_ON(!list_empty(pages)); | 3264 | BUG_ON(!list_empty(pages)); |
3260 | if (bio) { | 3265 | if (bio) |
3261 | int ret = submit_one_bio(READ, bio, 0, bio_flags); | 3266 | return submit_one_bio(READ, bio, 0, bio_flags); |
3262 | BUG_ON(ret < 0); | ||
3263 | } | ||
3264 | return 0; | 3267 | return 0; |
3265 | } | 3268 | } |
3266 | 3269 | ||
@@ -4090,7 +4093,8 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
4090 | 4093 | ||
4091 | if (bio) { | 4094 | if (bio) { |
4092 | err = submit_one_bio(READ, bio, mirror_num, bio_flags); | 4095 | err = submit_one_bio(READ, bio, mirror_num, bio_flags); |
4093 | BUG_ON(err < 0); | 4096 | if (err) |
4097 | return err; | ||
4094 | } | 4098 | } |
4095 | 4099 | ||
4096 | if (ret || wait != WAIT_COMPLETE) | 4100 | if (ret || wait != WAIT_COMPLETE) |