aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2012-03-12 11:03:00 -0400
committerDavid Sterba <dsterba@suse.cz>2012-03-22 06:52:54 -0400
commit79787eaab46121d4713ed03c8fc63b9ec3eaec76 (patch)
treeee6b17d0811ee54ab74a03aa4e0bb92769d2f12a /fs/btrfs/extent_io.c
parent49b25e0540904be0bf558b84475c69d72e4de66e (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.c40
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 */
2408static int __must_check submit_one_bio(int rw, struct bio *bio, 2410static 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 */
2529static int __extent_read_full_page(struct extent_io_tree *tree, 2531static 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)