Merge branch 'error-handling' into for-linus
[deliverable/linux.git] / fs / btrfs / disk-io.c
index 6107b69584135e82485a676ebe7771558818235e..7b55eee15a51265e3d670cafa57c2772b8f0614a 100644 (file)
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
 static void free_fs_root(struct btrfs_root *root);
-static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
                                    int read_only);
-static int btrfs_destroy_ordered_operations(struct btrfs_root *root);
-static int btrfs_destroy_ordered_extents(struct btrfs_root *root);
+static void btrfs_destroy_ordered_operations(struct btrfs_root *root);
+static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                      struct btrfs_root *root);
-static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
-static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
+static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
+static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
 static int btrfs_destroy_marked_extents(struct btrfs_root *root,
                                        struct extent_io_tree *dirty_pages,
                                        int mark);
 static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
                                       struct extent_io_tree *pinned_extents);
-static int btrfs_cleanup_transaction(struct btrfs_root *root);
 
 /*
  * end_io_wq structs are used to do processing in task context when an IO is
@@ -99,6 +98,7 @@ struct async_submit_bio {
         */
        u64 bio_offset;
        struct btrfs_work work;
+       int error;
 };
 
 /*
@@ -332,7 +332,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                return 0;
 
        lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
-                        0, &cached_state, GFP_NOFS);
+                        0, &cached_state);
        if (extent_buffer_uptodate(eb) &&
            btrfs_header_generation(eb) == parent_transid) {
                ret = 0;
@@ -425,7 +425,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
        eb = (struct extent_buffer *)page->private;
        if (page != eb->pages[0])
                return 0;
-
        found_start = btrfs_header_bytenr(eb);
        if (found_start != start) {
                WARN_ON(1);
@@ -727,11 +726,14 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info)
 static void run_one_async_start(struct btrfs_work *work)
 {
        struct async_submit_bio *async;
+       int ret;
 
        async = container_of(work, struct  async_submit_bio, work);
-       async->submit_bio_start(async->inode, async->rw, async->bio,
-                              async->mirror_num, async->bio_flags,
-                              async->bio_offset);
+       ret = async->submit_bio_start(async->inode, async->rw, async->bio,
+                                     async->mirror_num, async->bio_flags,
+                                     async->bio_offset);
+       if (ret)
+               async->error = ret;
 }
 
 static void run_one_async_done(struct btrfs_work *work)
@@ -752,6 +754,12 @@ static void run_one_async_done(struct btrfs_work *work)
            waitqueue_active(&fs_info->async_submit_wait))
                wake_up(&fs_info->async_submit_wait);
 
+       /* If an error occured we just want to clean up the bio and move on */
+       if (async->error) {
+               bio_endio(async->bio, async->error);
+               return;
+       }
+
        async->submit_bio_done(async->inode, async->rw, async->bio,
                               async->mirror_num, async->bio_flags,
                               async->bio_offset);
@@ -793,6 +801,8 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
        async->bio_flags = bio_flags;
        async->bio_offset = bio_offset;
 
+       async->error = 0;
+
        atomic_inc(&fs_info->nr_async_submits);
 
        if (rw & REQ_SYNC)
@@ -814,15 +824,18 @@ static int btree_csum_one_bio(struct bio *bio)
        struct bio_vec *bvec = bio->bi_io_vec;
        int bio_index = 0;
        struct btrfs_root *root;
+       int ret = 0;
 
        WARN_ON(bio->bi_vcnt <= 0);
        while (bio_index < bio->bi_vcnt) {
                root = BTRFS_I(bvec->bv_page->mapping->host)->root;
-               csum_dirty_buffer(root, bvec->bv_page);
+               ret = csum_dirty_buffer(root, bvec->bv_page);
+               if (ret)
+                       break;
                bio_index++;
                bvec++;
        }
-       return 0;
+       return ret;
 }
 
 static int __btree_submit_bio_start(struct inode *inode, int rw,
@@ -834,8 +847,7 @@ static int __btree_submit_bio_start(struct inode *inode, int rw,
         * when we're called for a write, we're already in the async
         * submission context.  Just jump into btrfs_map_bio
         */
-       btree_csum_one_bio(bio);
-       return 0;
+       return btree_csum_one_bio(bio);
 }
 
 static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
@@ -863,7 +875,8 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                 */
                ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
                                          bio, 1);
-               BUG_ON(ret);
+               if (ret)
+                       return ret;
                return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
                                     mirror_num, 0);
        }
@@ -1080,8 +1093,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
 
 }
 
-int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                    struct extent_buffer *buf)
+void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                     struct extent_buffer *buf)
 {
        if (btrfs_header_generation(buf) ==
            root->fs_info->running_transaction->transid) {
@@ -1091,8 +1104,14 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        spin_lock(&root->fs_info->delalloc_lock);
                        if (root->fs_info->dirty_metadata_bytes >= buf->len)
                                root->fs_info->dirty_metadata_bytes -= buf->len;
-                       else
-                               WARN_ON(1);
+                       else {
+                               spin_unlock(&root->fs_info->delalloc_lock);
+                               btrfs_panic(root->fs_info, -EOVERFLOW,
+                                         "Can't clear %lu bytes from "
+                                         " dirty_mdatadata_bytes (%lu)",
+                                         buf->len,
+                                         root->fs_info->dirty_metadata_bytes);
+                       }
                        spin_unlock(&root->fs_info->delalloc_lock);
                }
 
@@ -1100,13 +1119,12 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                btrfs_set_lock_blocking(buf);
                clear_extent_buffer_dirty(buf);
        }
-       return 0;
 }
 
-static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
-                       u32 stripesize, struct btrfs_root *root,
-                       struct btrfs_fs_info *fs_info,
-                       u64 objectid)
+static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
+                        u32 stripesize, struct btrfs_root *root,
+                        struct btrfs_fs_info *fs_info,
+                        u64 objectid)
 {
        root->node = NULL;
        root->commit_root = NULL;
@@ -1158,13 +1176,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->defrag_running = 0;
        root->root_key.objectid = objectid;
        root->anon_dev = 0;
-       return 0;
 }
 
-static int find_and_setup_root(struct btrfs_root *tree_root,
-                              struct btrfs_fs_info *fs_info,
-                              u64 objectid,
-                              struct btrfs_root *root)
+static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
+                                           struct btrfs_fs_info *fs_info,
+                                           u64 objectid,
+                                           struct btrfs_root *root)
 {
        int ret;
        u32 blocksize;
@@ -1177,7 +1194,8 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
                                   &root->root_item, &root->root_key);
        if (ret > 0)
                return -ENOENT;
-       BUG_ON(ret);
+       else if (ret < 0)
+               return ret;
 
        generation = btrfs_root_generation(&root->root_item);
        blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
@@ -1346,7 +1364,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
                                     blocksize, generation);
        root->commit_root = btrfs_root_node(root);
-       BUG_ON(!root->node);
+       BUG_ON(!root->node); /* -ENOMEM */
 out:
        if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
                root->ref_cows = 1;
@@ -1537,9 +1555,10 @@ static int transaction_kthread(void *arg)
        u64 transid;
        unsigned long now;
        unsigned long delay;
-       int ret;
+       bool cannot_commit;
 
        do {
+               cannot_commit = false;
                delay = HZ * 30;
                vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
@@ -1561,11 +1580,14 @@ static int transaction_kthread(void *arg)
                transid = cur->transid;
                spin_unlock(&root->fs_info->trans_lock);
 
+               /* If the file system is aborted, this will always fail. */
                trans = btrfs_join_transaction(root);
-               BUG_ON(IS_ERR(trans));
+               if (IS_ERR(trans)) {
+                       cannot_commit = true;
+                       goto sleep;
+               }
                if (transid == trans->transid) {
-                       ret = btrfs_commit_transaction(trans, root);
-                       BUG_ON(ret);
+                       btrfs_commit_transaction(trans, root);
                } else {
                        btrfs_end_transaction(trans, root);
                }
@@ -1576,7 +1598,8 @@ sleep:
                if (!try_to_freeze()) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (!kthread_should_stop() &&
-                           !btrfs_transaction_blocked(root->fs_info))
+                           (!btrfs_transaction_blocked(root->fs_info) ||
+                            cannot_commit))
                                schedule_timeout(delay);
                        __set_current_state(TASK_RUNNING);
                }
@@ -2028,7 +2051,12 @@ int open_ctree(struct super_block *sb,
        /* check FS state, whether FS is broken. */
        fs_info->fs_state |= btrfs_super_flags(disk_super);
 
-       btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
+       ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
+       if (ret) {
+               printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
+               err = ret;
+               goto fail_alloc;
+       }
 
        /*
         * run through our array of backup supers and setup
@@ -2218,6 +2246,14 @@ int open_ctree(struct super_block *sb,
                goto fail_sb_buffer;
        }
 
+       if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
+                       (leafsize != nodesize || sectorsize != nodesize)) {
+               printk(KERN_WARNING "btrfs: unequal leaf/node/sector sizes "
+                               "are not allowed for mixed block groups on %s\n",
+                               sb->s_id);
+               goto fail_sb_buffer;
+       }
+
        mutex_lock(&fs_info->chunk_mutex);
        ret = btrfs_read_sys_array(tree_root);
        mutex_unlock(&fs_info->chunk_mutex);
@@ -2237,7 +2273,7 @@ int open_ctree(struct super_block *sb,
        chunk_root->node = read_tree_block(chunk_root,
                                           btrfs_super_chunk_root(disk_super),
                                           blocksize, generation);
-       BUG_ON(!chunk_root->node);
+       BUG_ON(!chunk_root->node); /* -ENOMEM */
        if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
                printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
                       sb->s_id);
@@ -2377,21 +2413,31 @@ retry_root_backup:
                log_tree_root->node = read_tree_block(tree_root, bytenr,
                                                      blocksize,
                                                      generation + 1);
+               /* returns with log_tree_root freed on success */
                ret = btrfs_recover_log_trees(log_tree_root);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_error(tree_root->fs_info, ret,
+                                   "Failed to recover log tree");
+                       free_extent_buffer(log_tree_root->node);
+                       kfree(log_tree_root);
+                       goto fail_trans_kthread;
+               }
 
                if (sb->s_flags & MS_RDONLY) {
-                       ret =  btrfs_commit_super(tree_root);
-                       BUG_ON(ret);
+                       ret = btrfs_commit_super(tree_root);
+                       if (ret)
+                               goto fail_trans_kthread;
                }
        }
 
        ret = btrfs_find_orphan_roots(tree_root);
-       BUG_ON(ret);
+       if (ret)
+               goto fail_trans_kthread;
 
        if (!(sb->s_flags & MS_RDONLY)) {
                ret = btrfs_cleanup_fs_roots(fs_info);
-               BUG_ON(ret);
+               if (ret) {
+                       }
 
                ret = btrfs_recover_relocation(tree_root);
                if (ret < 0) {
@@ -2811,6 +2857,8 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
        if (total_errors > max_errors) {
                printk(KERN_ERR "btrfs: %d errors while writing supers\n",
                       total_errors);
+
+               /* This shouldn't happen. FUA is masked off if unsupported */
                BUG();
        }
 
@@ -2827,9 +2875,9 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
        }
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
        if (total_errors > max_errors) {
-               printk(KERN_ERR "btrfs: %d errors while writing supers\n",
-                      total_errors);
-               BUG();
+               btrfs_error(root->fs_info, -EIO,
+                           "%d errors while writing supers", total_errors);
+               return -EIO;
        }
        return 0;
 }
@@ -2843,7 +2891,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
+/* Kill all outstanding I/O */
+void btrfs_abort_devices(struct btrfs_root *root)
+{
+       struct list_head *head;
+       struct btrfs_device *dev;
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       head = &root->fs_info->fs_devices->devices;
+       list_for_each_entry_rcu(dev, head, dev_list) {
+               blk_abort_queue(dev->bdev->bd_disk->queue);
+       }
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+}
+
+void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
 {
        spin_lock(&fs_info->fs_roots_radix_lock);
        radix_tree_delete(&fs_info->fs_roots_radix,
@@ -2856,7 +2917,6 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
        __btrfs_remove_free_space_cache(root->free_ino_pinned);
        __btrfs_remove_free_space_cache(root->free_ino_ctl);
        free_fs_root(root);
-       return 0;
 }
 
 static void free_fs_root(struct btrfs_root *root)
@@ -2873,7 +2933,7 @@ static void free_fs_root(struct btrfs_root *root)
        kfree(root);
 }
 
-static int del_fs_roots(struct btrfs_fs_info *fs_info)
+static void del_fs_roots(struct btrfs_fs_info *fs_info)
 {
        int ret;
        struct btrfs_root *gang[8];
@@ -2902,7 +2962,6 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info)
                for (i = 0; i < ret; i++)
                        btrfs_free_fs_root(fs_info, gang[i]);
        }
-       return 0;
 }
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
@@ -2951,14 +3010,21 @@ int btrfs_commit_super(struct btrfs_root *root)
        if (IS_ERR(trans))
                return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
        /* run commit again to drop the original snapshot */
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return PTR_ERR(trans);
-       btrfs_commit_transaction(trans, root);
+       ret = btrfs_commit_transaction(trans, root);
+       if (ret)
+               return ret;
        ret = btrfs_write_and_wait_transaction(NULL, root);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_error(root->fs_info, ret,
+                           "Failed to sync btree inode to disk.");
+               return ret;
+       }
 
        ret = write_ctree_super(NULL, root, 0);
        return ret;
@@ -3209,15 +3275,23 @@ out:
        return 0;
 }
 
-static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
                              int read_only)
 {
+       if (btrfs_super_csum_type(fs_info->super_copy) >= ARRAY_SIZE(btrfs_csum_sizes)) {
+               printk(KERN_ERR "btrfs: unsupported checksum algorithm\n");
+               return -EINVAL;
+       }
+
        if (read_only)
-               return;
+               return 0;
 
-       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
                printk(KERN_WARNING "warning: mount fs with errors, "
                       "running btrfsck is recommended\n");
+       }
+
+       return 0;
 }
 
 int btrfs_error_commit_super(struct btrfs_root *root)
@@ -3239,7 +3313,7 @@ int btrfs_error_commit_super(struct btrfs_root *root)
        return ret;
 }
 
-static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
+static void btrfs_destroy_ordered_operations(struct btrfs_root *root)
 {
        struct btrfs_inode *btrfs_inode;
        struct list_head splice;
@@ -3261,11 +3335,9 @@ static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
 
        spin_unlock(&root->fs_info->ordered_extent_lock);
        mutex_unlock(&root->fs_info->ordered_operations_mutex);
-
-       return 0;
 }
 
-static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
+static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
 {
        struct list_head splice;
        struct btrfs_ordered_extent *ordered;
@@ -3297,12 +3369,10 @@ static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
        }
 
        spin_unlock(&root->fs_info->ordered_extent_lock);
-
-       return 0;
 }
 
-static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
-                                     struct btrfs_root *root)
+int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+                              struct btrfs_root *root)
 {
        struct rb_node *node;
        struct btrfs_delayed_ref_root *delayed_refs;
@@ -3311,6 +3381,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
 
        delayed_refs = &trans->delayed_refs;
 
+again:
        spin_lock(&delayed_refs->lock);
        if (delayed_refs->num_entries == 0) {
                spin_unlock(&delayed_refs->lock);
@@ -3332,6 +3403,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                        struct btrfs_delayed_ref_head *head;
 
                        head = btrfs_delayed_node_to_head(ref);
+                       spin_unlock(&delayed_refs->lock);
                        mutex_lock(&head->mutex);
                        kfree(head->extent_op);
                        delayed_refs->num_heads--;
@@ -3339,8 +3411,9 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                delayed_refs->num_heads_ready--;
                        list_del_init(&head->cluster);
                        mutex_unlock(&head->mutex);
+                       btrfs_put_delayed_ref(ref);
+                       goto again;
                }
-
                spin_unlock(&delayed_refs->lock);
                btrfs_put_delayed_ref(ref);
 
@@ -3353,7 +3426,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
        return ret;
 }
 
-static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
+static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
 {
        struct btrfs_pending_snapshot *snapshot;
        struct list_head splice;
@@ -3371,11 +3444,9 @@ static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
 
                kfree(snapshot);
        }
-
-       return 0;
 }
 
-static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
+static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
 {
        struct btrfs_inode *btrfs_inode;
        struct list_head splice;
@@ -3395,8 +3466,6 @@ static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
        }
 
        spin_unlock(&root->fs_info->delalloc_lock);
-
-       return 0;
 }
 
 static int btrfs_destroy_marked_extents(struct btrfs_root *root,
@@ -3487,13 +3556,43 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
        return 0;
 }
 
-static int btrfs_cleanup_transaction(struct btrfs_root *root)
+void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
+                                  struct btrfs_root *root)
+{
+       btrfs_destroy_delayed_refs(cur_trans, root);
+       btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
+                               cur_trans->dirty_pages.dirty_bytes);
+
+       /* FIXME: cleanup wait for commit */
+       cur_trans->in_commit = 1;
+       cur_trans->blocked = 1;
+       if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
+               wake_up(&root->fs_info->transaction_blocked_wait);
+
+       cur_trans->blocked = 0;
+       if (waitqueue_active(&root->fs_info->transaction_wait))
+               wake_up(&root->fs_info->transaction_wait);
+
+       cur_trans->commit_done = 1;
+       if (waitqueue_active(&cur_trans->commit_wait))
+               wake_up(&cur_trans->commit_wait);
+
+       btrfs_destroy_pending_snapshots(cur_trans);
+
+       btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages,
+                                    EXTENT_DIRTY);
+
+       /*
+       memset(cur_trans, 0, sizeof(*cur_trans));
+       kmem_cache_free(btrfs_transaction_cachep, cur_trans);
+       */
+}
+
+int btrfs_cleanup_transaction(struct btrfs_root *root)
 {
        struct btrfs_transaction *t;
        LIST_HEAD(list);
 
-       WARN_ON(1);
-
        mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
        spin_lock(&root->fs_info->trans_lock);
@@ -3558,6 +3657,17 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
        return 0;
 }
 
+static int btree_writepage_io_failed_hook(struct bio *bio, struct page *page,
+                                         u64 start, u64 end,
+                                         struct extent_state *state)
+{
+       struct super_block *sb = page->mapping->host->i_sb;
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       btrfs_error(fs_info, -EIO,
+                   "Error occured while writing out btree at %llu", start);
+       return -EIO;
+}
+
 static struct extent_io_ops btree_extent_io_ops = {
        .write_cache_pages_lock_hook = btree_lock_page_hook,
        .readpage_end_io_hook = btree_readpage_end_io_hook,
@@ -3565,4 +3675,5 @@ static struct extent_io_ops btree_extent_io_ops = {
        .submit_bio_hook = btree_submit_bio_hook,
        /* note we're sharing with inode.c for the merge bio hook */
        .merge_bio_hook = btrfs_merge_bio_hook,
+       .writepage_io_failed_hook = btree_writepage_io_failed_hook,
 };
This page took 0.068117 seconds and 5 git commands to generate.