btrfs: ->submit_bio_hook error push-up
[firefly-linux-kernel-4.4.55.git] / fs / btrfs / extent_io.c
index a55fbe6252ded4e41d9b76cb3bed1a9f98acd065..8368baa1f372b37771d6ba064e80e3f27c19b523 100644 (file)
@@ -53,6 +53,12 @@ struct extent_page_data {
        unsigned int sync_io:1;
 };
 
+static inline struct btrfs_fs_info *
+tree_fs_info(struct extent_io_tree *tree)
+{
+       return btrfs_sb(tree->mapping->host->i_sb);
+}
+
 int __init extent_io_init(void)
 {
        extent_state_cache = kmem_cache_create("extent_state",
@@ -439,6 +445,13 @@ alloc_extent_state_atomic(struct extent_state *prealloc)
        return prealloc;
 }
 
+void extent_io_tree_panic(struct extent_io_tree *tree, int err)
+{
+       btrfs_panic(tree_fs_info(tree), err, "Locking error: "
+                   "Extent tree was modified by another "
+                   "thread while locked.");
+}
+
 /*
  * clear some bits on a range in the tree.  This may require splitting
  * or inserting elements in the tree, so the gfp mask is used to
@@ -449,8 +462,7 @@ alloc_extent_state_atomic(struct extent_state *prealloc)
  *
  * the range [start, end] is inclusive.
  *
- * This takes the tree lock, and returns < 0 on error, > 0 if any of the
- * bits were already set, or zero if none of the bits were already set.
+ * This takes the tree lock, and returns 0 on success and < 0 on error.
  */
 int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
                     int bits, int wake, int delete,
@@ -464,7 +476,6 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        struct rb_node *node;
        u64 last_end;
        int err;
-       int set = 0;
        int clear = 0;
 
        if (delete)
@@ -542,12 +553,14 @@ hit_next:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, start);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
+
                prealloc = NULL;
                if (err)
                        goto out;
                if (state->end <= end) {
-                       set |= clear_state_bit(tree, state, &bits, wake);
+                       clear_state_bit(tree, state, &bits, wake);
                        if (last_end == (u64)-1)
                                goto out;
                        start = last_end + 1;
@@ -564,17 +577,19 @@ hit_next:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, end + 1);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
+
                if (wake)
                        wake_up(&state->wq);
 
-               set |= clear_state_bit(tree, prealloc, &bits, wake);
+               clear_state_bit(tree, prealloc, &bits, wake);
 
                prealloc = NULL;
                goto out;
        }
 
-       set |= clear_state_bit(tree, state, &bits, wake);
+       clear_state_bit(tree, state, &bits, wake);
 next:
        if (last_end == (u64)-1)
                goto out;
@@ -591,7 +606,7 @@ out:
        if (prealloc)
                free_extent_state(prealloc);
 
-       return set;
+       return 0;
 
 search_again:
        if (start > end)
@@ -742,8 +757,10 @@ again:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = insert_state(tree, prealloc, start, end, &bits);
+               if (err)
+                       extent_io_tree_panic(tree, err);
+
                prealloc = NULL;
-               BUG_ON(err == -EEXIST);
                goto out;
        }
        state = rb_entry(node, struct extent_state, rb_node);
@@ -809,7 +826,9 @@ hit_next:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, start);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
+
                prealloc = NULL;
                if (err)
                        goto out;
@@ -846,12 +865,9 @@ hit_next:
                 */
                err = insert_state(tree, prealloc, start, this_end,
                                   &bits);
-               BUG_ON(err == -EEXIST);
-               if (err) {
-                       free_extent_state(prealloc);
-                       prealloc = NULL;
-                       goto out;
-               }
+               if (err)
+                       extent_io_tree_panic(tree, err);
+
                cache_state(prealloc, cached_state);
                prealloc = NULL;
                start = this_end + 1;
@@ -873,7 +889,8 @@ hit_next:
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
                err = split_state(tree, state, prealloc, end + 1);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
 
                set_state_bits(tree, prealloc, &bits);
                cache_state(prealloc, cached_state);
@@ -946,7 +963,8 @@ again:
                }
                err = insert_state(tree, prealloc, start, end, &bits);
                prealloc = NULL;
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
                goto out;
        }
        state = rb_entry(node, struct extent_state, rb_node);
@@ -1002,7 +1020,8 @@ hit_next:
                        goto out;
                }
                err = split_state(tree, state, prealloc, start);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
                prealloc = NULL;
                if (err)
                        goto out;
@@ -1041,12 +1060,8 @@ hit_next:
                 */
                err = insert_state(tree, prealloc, start, this_end,
                                   &bits);
-               BUG_ON(err == -EEXIST);
-               if (err) {
-                       free_extent_state(prealloc);
-                       prealloc = NULL;
-                       goto out;
-               }
+               if (err)
+                       extent_io_tree_panic(tree, err);
                prealloc = NULL;
                start = this_end + 1;
                goto search_again;
@@ -1065,7 +1080,8 @@ hit_next:
                }
 
                err = split_state(tree, state, prealloc, end + 1);
-               BUG_ON(err == -EEXIST);
+               if (err)
+                       extent_io_tree_panic(tree, err);
 
                set_state_bits(tree, prealloc, &bits);
                clear_state_bit(tree, prealloc, &clear_bits, 0);
@@ -2183,6 +2199,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
                /* Writeback already completed */
                if (ret == 0)
                        return 1;
+               BUG_ON(ret < 0);
        }
 
        if (!uptodate) {
@@ -2335,6 +2352,7 @@ error_handled:
                                if (ret == 0)
                                        goto error_handled;
                        }
+                       BUG_ON(ret < 0);
                }
 
                if (uptodate) {
@@ -2386,8 +2404,8 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
        return bio;
 }
 
-static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
-                         unsigned long bio_flags)
+static int __must_check submit_one_bio(int rw, struct bio *bio,
+                                      int mirror_num, unsigned long bio_flags)
 {
        int ret = 0;
        struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
@@ -2413,6 +2431,19 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
        return ret;
 }
 
+static int merge_bio(struct extent_io_tree *tree, struct page *page,
+                    unsigned long offset, size_t size, struct bio *bio,
+                    unsigned long bio_flags)
+{
+       int ret = 0;
+       if (tree->ops && tree->ops->merge_bio_hook)
+               ret = tree->ops->merge_bio_hook(page, offset, size, bio,
+                                               bio_flags);
+       BUG_ON(ret < 0);
+       return ret;
+
+}
+
 static int submit_extent_page(int rw, struct extent_io_tree *tree,
                              struct page *page, sector_t sector,
                              size_t size, unsigned long offset,
@@ -2441,12 +2472,11 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
                                sector;
 
                if (prev_bio_flags != bio_flags || !contig ||
-                   (tree->ops && tree->ops->merge_bio_hook &&
-                    tree->ops->merge_bio_hook(page, offset, page_size, bio,
-                                              bio_flags)) ||
+                   merge_bio(tree, page, offset, page_size, bio, bio_flags) ||
                    bio_add_page(bio, page, page_size, offset) < page_size) {
                        ret = submit_one_bio(rw, bio, mirror_num,
                                             prev_bio_flags);
+                       BUG_ON(ret < 0);
                        bio = NULL;
                } else {
                        return 0;
@@ -2467,8 +2497,10 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
 
        if (bio_ret)
                *bio_ret = bio;
-       else
+       else {
                ret = submit_one_bio(rw, bio, mirror_num, bio_flags);
+               BUG_ON(ret < 0);
+       }
 
        return ret;
 }
@@ -2680,8 +2712,10 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
 
        ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num,
                                      &bio_flags);
-       if (bio)
+       if (bio) {
                ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
+               BUG_ON(ret < 0);
+       }
        return ret;
 }
 
@@ -3099,10 +3133,14 @@ retry:
 static void flush_epd_write_bio(struct extent_page_data *epd)
 {
        if (epd->bio) {
+               int rw = WRITE;
+               int ret;
+
                if (epd->sync_io)
-                       submit_one_bio(WRITE_SYNC, epd->bio, 0, 0);
-               else
-                       submit_one_bio(WRITE, epd->bio, 0, 0);
+                       rw = WRITE_SYNC;
+
+               ret = submit_one_bio(rw, epd->bio, 0, 0);
+               BUG_ON(ret < 0);
                epd->bio = NULL;
        }
 }
@@ -3218,8 +3256,10 @@ int extent_readpages(struct extent_io_tree *tree,
                page_cache_release(page);
        }
        BUG_ON(!list_empty(pages));
-       if (bio)
-               submit_one_bio(READ, bio, 0, bio_flags);
+       if (bio) {
+               int ret = submit_one_bio(READ, bio, 0, bio_flags);
+               BUG_ON(ret < 0);
+       }
        return 0;
 }
 
@@ -4048,8 +4088,10 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
                }
        }
 
-       if (bio)
-               submit_one_bio(READ, bio, mirror_num, bio_flags);
+       if (bio) {
+               err = submit_one_bio(READ, bio, mirror_num, bio_flags);
+               BUG_ON(err < 0);
+       }
 
        if (ret || wait != WAIT_COMPLETE)
                return ret;