]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
btrfs: replace many BUG_ONs with proper error handling
authorJeff Mahoney <jeffm@suse.com>
Mon, 12 Mar 2012 15:03:00 +0000 (16:03 +0100)
committerDavid Sterba <dsterba@suse.cz>
Thu, 22 Mar 2012 10:52:54 +0000 (11:52 +0100)
 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>
23 files changed:
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/delayed-inode.c
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode-item.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/orphan.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c

index cfd158dccdec5da2540550c9131d24b3b2cbf0b9..d11afa67c7d86711b87cdb0913da1b98f9027da8 100644 (file)
@@ -391,16 +391,16 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                         */
                        atomic_inc(&cb->pending_bios);
                        ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        if (!skip_sum) {
                                ret = btrfs_csum_one_bio(root, inode, bio,
                                                         start, 1);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                        }
 
                        ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        bio_put(bio);
 
@@ -420,15 +420,15 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        bio_get(bio);
 
        ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
 
        if (!skip_sum) {
                ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
 
        ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
 
        bio_put(bio);
        return 0;
@@ -661,7 +661,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                        bio_get(comp_bio);
 
                        ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        /*
                         * inc the count before we submit the bio so
@@ -674,14 +674,14 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
                                ret = btrfs_lookup_bio_sums(root, inode,
                                                        comp_bio, sums);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                        }
                        sums += (comp_bio->bi_size + root->sectorsize - 1) /
                                root->sectorsize;
 
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        bio_put(comp_bio);
 
@@ -697,15 +697,15 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        bio_get(comp_bio);
 
        ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
 
        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
                ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
 
        ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
 
        bio_put(comp_bio);
        return 0;
index 651a26a6c6511700af514f5f05da34677e0b7dbe..e697afd18159f5477d2089543c9adfd1ac3c9475 100644 (file)
@@ -356,14 +356,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                     root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
                    !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
                        ret = btrfs_inc_ref(trans, root, buf, 1, 1);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID) {
                                ret = btrfs_dec_ref(trans, root, buf, 0, 1);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                                ret = btrfs_inc_ref(trans, root, cow, 1, 1);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                        }
                        new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
                } else {
@@ -373,7 +373,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                                ret = btrfs_inc_ref(trans, root, cow, 1, 1);
                        else
                                ret = btrfs_inc_ref(trans, root, cow, 0, 1);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                }
                if (new_flags != 0) {
                        ret = btrfs_set_disk_extent_flags(trans, root,
@@ -390,9 +390,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                                ret = btrfs_inc_ref(trans, root, cow, 1, 1);
                        else
                                ret = btrfs_inc_ref(trans, root, cow, 0, 1);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                        ret = btrfs_dec_ref(trans, root, buf, 1, 1);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                }
                clean_tree_block(trans, root, buf);
                *last_ref = 1;
@@ -475,7 +475,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 
        ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
        if (ret) {
-               btrfs_std_error(root->fs_info, ret);
+               btrfs_abort_transaction(trans, root, ret);
                return ret;
        }
 
@@ -2713,7 +2713,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                              path->nodes[1], slot - 1, &left);
        if (ret) {
                /* we hit -ENOSPC, but it isn't fatal here */
-               ret = 1;
+               if (ret == -ENOSPC)
+                       ret = 1;
                goto out;
        }
 
@@ -4017,7 +4018,7 @@ find_next_key:
                }
                btrfs_set_path_blocking(path);
                cur = read_node_slot(root, cur, slot);
-               BUG_ON(!cur);
+               BUG_ON(!cur); /* -ENOMEM */
 
                btrfs_tree_read_lock(cur);
 
index 6829590d0fbb70ea422561bf1830bdadb060b429..03e3748d84d02407c19c6d46648667a56f13ba3e 100644 (file)
@@ -115,6 +115,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(struct inode *inode)
        return NULL;
 }
 
+/* Will return either the node or PTR_ERR(-ENOMEM) */
 static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
                                                        struct inode *inode)
 {
@@ -1106,16 +1107,25 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-/* Called when committing the transaction. */
+/*
+ * Called when committing the transaction.
+ * Returns 0 on success.
+ * Returns < 0 on error and returns with an aborted transaction with any
+ * outstanding delayed items cleaned up.
+ */
 int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
                            struct btrfs_root *root)
 {
+       struct btrfs_root *curr_root = root;
        struct btrfs_delayed_root *delayed_root;
        struct btrfs_delayed_node *curr_node, *prev_node;
        struct btrfs_path *path;
        struct btrfs_block_rsv *block_rsv;
        int ret = 0;
 
+       if (trans->aborted)
+               return -EIO;
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -1128,17 +1138,18 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
 
        curr_node = btrfs_first_delayed_node(delayed_root);
        while (curr_node) {
-               root = curr_node->root;
-               ret = btrfs_insert_delayed_items(trans, path, root,
+               curr_root = curr_node->root;
+               ret = btrfs_insert_delayed_items(trans, path, curr_root,
                                                 curr_node);
                if (!ret)
-                       ret = btrfs_delete_delayed_items(trans, path, root,
-                                                        curr_node);
+                       ret = btrfs_delete_delayed_items(trans, path,
+                                               curr_root, curr_node);
                if (!ret)
-                       ret = btrfs_update_delayed_inode(trans, root, path,
-                                                        curr_node);
+                       ret = btrfs_update_delayed_inode(trans, curr_root,
+                                               path, curr_node);
                if (ret) {
                        btrfs_release_delayed_node(curr_node);
+                       btrfs_abort_transaction(trans, root, ret);
                        break;
                }
 
@@ -1149,6 +1160,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
 
        btrfs_free_path(path);
        trans->block_rsv = block_rsv;
+
        return ret;
 }
 
@@ -1369,6 +1381,7 @@ void btrfs_balance_delayed_items(struct btrfs_root *root)
        btrfs_wq_run_delayed_node(delayed_root, root, 0);
 }
 
+/* Will return 0 or -ENOMEM */
 int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root, const char *name,
                                   int name_len, struct inode *dir,
index 76743308bd9f074baf530d95d1c637af1cf5fcba..c1a074d0696ff897258c576c127af7fd8d513846 100644 (file)
@@ -115,6 +115,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  * 'location' is the key to stuff into the directory item, 'type' is the
  * type of the inode we're pointing to, and 'index' is the sequence number
  * to use for the second index (if one is created).
+ * Will return 0 or -ENOMEM
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
                          *root, const char *name, int name_len,
index 6297a030ac50c0c5324180ca7d738152d4502538..16a0cada26c22195dcadd477f7ca634209a13ab3 100644 (file)
@@ -98,6 +98,7 @@ struct async_submit_bio {
         */
        u64 bio_offset;
        struct btrfs_work work;
+       int error;
 };
 
 /*
@@ -405,7 +406,7 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
        u64 found_start;
        unsigned long len;
        struct extent_buffer *eb;
-       int ret;
+       int ret = -EIO;
 
        tree = &BTRFS_I(page->mapping->host)->io_tree;
 
@@ -423,13 +424,20 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
        eb = alloc_extent_buffer(tree, start, len, page);
        if (eb == NULL) {
                WARN_ON(1);
+               ret = -ENOMEM;
                goto out;
        }
        ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
                                             btrfs_header_generation(eb));
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_printk(root->fs_info, KERN_WARNING
+                            "Failed to checksum dirty buffer @ %llu[%lu]\n",
+                             start, len);
+               goto err;
+       }
        WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
 
+       ret = -EIO;
        found_start = btrfs_header_bytenr(eb);
        if (found_start != start) {
                WARN_ON(1);
@@ -444,10 +452,11 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
                goto err;
        }
        csum_tree_block(root, eb, 0);
+       ret = 0;
 err:
        free_extent_buffer(eb);
 out:
-       return 0;
+       return ret;
 }
 
 static int check_tree_block_fsid(struct btrfs_root *root,
@@ -718,11 +727,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)
@@ -743,6 +755,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);
@@ -784,6 +802,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)
@@ -805,15 +825,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,
@@ -825,8 +848,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,
@@ -1381,7 +1403,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;
@@ -1618,7 +1640,6 @@ static int transaction_kthread(void *arg)
        u64 transid;
        unsigned long now;
        unsigned long delay;
-       int ret;
 
        do {
                delay = HZ * 30;
@@ -1642,11 +1663,12 @@ 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))
+                       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);
                }
@@ -2289,7 +2311,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);
@@ -2429,21 +2451,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) {
@@ -2863,6 +2895,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();
        }
 
@@ -2879,9 +2913,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;
 }
@@ -3014,14 +3048,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;
@@ -3366,8 +3407,8 @@ static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
        spin_unlock(&root->fs_info->ordered_extent_lock);
 }
 
-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;
@@ -3376,6 +3417,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);
@@ -3397,6 +3439,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--;
@@ -3404,8 +3447,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);
 
@@ -3649,6 +3693,17 @@ 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,
@@ -3656,4 +3711,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,
 };
index 5f77166fd01c7eb3d33cb78666e31822fc0a1083..e887ee62b6d4ba0a98f7e2437323eecfca88bf23 100644 (file)
@@ -193,7 +193,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
        if (ret < 0)
                goto fail;
 
-       BUG_ON(ret == 0);
+       BUG_ON(ret == 0); /* Key with offset of -1 found */
        if (path->slots[0] == 0) {
                ret = -ENOENT;
                goto fail;
index cd6f8ae0a78df27277d12734301d4a63c2855f7b..4b3f1eedced046ea04894b5ac113b3516e5ee9de 100644 (file)
@@ -245,7 +245,7 @@ static int exclude_super_stripes(struct btrfs_root *root,
                cache->bytes_super += stripe_len;
                ret = add_excluded_extent(root, cache->key.objectid,
                                          stripe_len);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
@@ -253,13 +253,13 @@ static int exclude_super_stripes(struct btrfs_root *root,
                ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
                                       cache->key.objectid, bytenr,
                                       0, &logical, &nr, &stripe_len);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
 
                while (nr--) {
                        cache->bytes_super += stripe_len;
                        ret = add_excluded_extent(root, logical[nr],
                                                  stripe_len);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                }
 
                kfree(logical);
@@ -321,7 +321,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
                        total_added += size;
                        ret = btrfs_add_free_space(block_group, start,
                                                   size);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM or logic error */
                        start = extent_end + 1;
                } else {
                        break;
@@ -332,7 +332,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
                size = end - start;
                total_added += size;
                ret = btrfs_add_free_space(block_group, start, size);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM or logic error */
        }
 
        return total_added;
@@ -474,7 +474,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
        int ret = 0;
 
        caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
-       BUG_ON(!caching_ctl);
+       if (!caching_ctl)
+               return -ENOMEM;
 
        INIT_LIST_HEAD(&caching_ctl->list);
        mutex_init(&caching_ctl->mutex);
@@ -982,7 +983,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
                                ret = btrfs_next_leaf(root, path);
                                if (ret < 0)
                                        return ret;
-                               BUG_ON(ret > 0);
+                               BUG_ON(ret > 0); /* Corruption */
                                leaf = path->nodes[0];
                        }
                        btrfs_item_key_to_cpu(leaf, &found_key,
@@ -1008,7 +1009,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
                                new_size + extra_size, 1);
        if (ret < 0)
                return ret;
-       BUG_ON(ret);
+       BUG_ON(ret); /* Corruption */
 
        btrfs_extend_item(trans, root, path, new_size);
 
@@ -1478,7 +1479,11 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
                err = ret;
                goto out;
        }
-       BUG_ON(ret);
+       if (ret && !insert) {
+               err = -ENOENT;
+               goto out;
+       }
+       BUG_ON(ret); /* Corruption */
 
        leaf = path->nodes[0];
        item_size = btrfs_item_size_nr(leaf, path->slots[0]);
@@ -1831,6 +1836,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
        /* Tell the block device(s) that the sectors can be discarded */
        ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
                              bytenr, &num_bytes, &bbio, 0);
+       /* Error condition is -ENOMEM */
        if (!ret) {
                struct btrfs_bio_stripe *stripe = bbio->stripes;
                int i;
@@ -1846,7 +1852,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
                        if (!ret)
                                discarded_bytes += stripe->length;
                        else if (ret != -EOPNOTSUPP)
-                               break;
+                               break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */
 
                        /*
                         * Just in case we get back EOPNOTSUPP for some reason,
@@ -1865,6 +1871,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
        return ret;
 }
 
+/* Can return -ENOMEM */
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
@@ -1940,7 +1947,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        ret = insert_extent_backref(trans, root->fs_info->extent_root,
                                    path, bytenr, parent, root_objectid,
                                    owner, offset, refs_to_add);
-       BUG_ON(ret);
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
 out:
        btrfs_free_path(path);
        return err;
@@ -2027,6 +2035,9 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
        int ret;
        int err = 0;
 
+       if (trans->aborted)
+               return 0;
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -2124,7 +2135,11 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                               struct btrfs_delayed_extent_op *extent_op,
                               int insert_reserved)
 {
-       int ret;
+       int ret = 0;
+
+       if (trans->aborted)
+               return 0;
+
        if (btrfs_delayed_ref_is_head(node)) {
                struct btrfs_delayed_ref_head *head;
                /*
@@ -2142,11 +2157,10 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                                ret = btrfs_del_csums(trans, root,
                                                      node->bytenr,
                                                      node->num_bytes);
-                               BUG_ON(ret);
                        }
                }
                mutex_unlock(&head->mutex);
-               return 0;
+               return ret;
        }
 
        if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
@@ -2193,6 +2207,10 @@ again:
        return NULL;
 }
 
+/*
+ * Returns 0 on success or if called with an already aborted transaction.
+ * Returns -ENOMEM or -EIO on failure and will abort the transaction.
+ */
 static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root,
                                       struct list_head *cluster)
@@ -2281,9 +2299,13 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
 
                                ret = run_delayed_extent_op(trans, root,
                                                            ref, extent_op);
-                               BUG_ON(ret);
                                kfree(extent_op);
 
+                               if (ret) {
+                                       printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
+                                       return ret;
+                               }
+
                                goto next;
                        }
 
@@ -2304,11 +2326,16 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
 
                ret = run_one_delayed_ref(trans, root, ref, extent_op,
                                          must_insert_reserved);
-               BUG_ON(ret);
 
                btrfs_put_delayed_ref(ref);
                kfree(extent_op);
                count++;
+
+               if (ret) {
+                       printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
+                       return ret;
+               }
+
 next:
                do_chunk_alloc(trans, root->fs_info->extent_root,
                               2 * 1024 * 1024,
@@ -2343,6 +2370,9 @@ static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
  * 0, which means to process everything in the tree at the start
  * of the run (but not newly added entries), or it can be some target
  * number you'd like to process.
+ *
+ * Returns 0 on success or if called with an aborted transaction
+ * Returns <0 on error and aborts the transaction
  */
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, unsigned long count)
@@ -2358,6 +2388,10 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        unsigned long num_refs = 0;
        int consider_waiting;
 
+       /* We'll clean this up in btrfs_cleanup_transaction */
+       if (trans->aborted)
+               return 0;
+
        if (root == root->fs_info->extent_root)
                root = root->fs_info->tree_root;
 
@@ -2415,7 +2449,11 @@ again:
                }
 
                ret = run_clustered_refs(trans, root, &cluster);
-               BUG_ON(ret < 0);
+               if (ret < 0) {
+                       spin_unlock(&delayed_refs->lock);
+                       btrfs_abort_transaction(trans, root, ret);
+                       return ret;
+               }
 
                count -= min_t(unsigned long, ret, count);
 
@@ -2580,7 +2618,7 @@ static noinline int check_committed_ref(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
        if (ret < 0)
                goto out;
-       BUG_ON(ret == 0);
+       BUG_ON(ret == 0); /* Corruption */
 
        ret = -ENOENT;
        if (path->slots[0] == 0)
@@ -2734,7 +2772,6 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
        }
        return 0;
 fail:
-       BUG();
        return ret;
 }
 
@@ -2763,7 +2800,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
        if (ret < 0)
                goto fail;
-       BUG_ON(ret);
+       BUG_ON(ret); /* Corruption */
 
        leaf = path->nodes[0];
        bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
@@ -2771,8 +2808,10 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(path);
 fail:
-       if (ret)
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
                return ret;
+       }
        return 0;
 
 }
@@ -2945,7 +2984,8 @@ again:
                if (last == 0) {
                        err = btrfs_run_delayed_refs(trans, root,
                                                     (unsigned long)-1);
-                       BUG_ON(err);
+                       if (err) /* File system offline */
+                               goto out;
                }
 
                cache = btrfs_lookup_first_block_group(root->fs_info, last);
@@ -2972,7 +3012,9 @@ again:
                last = cache->key.objectid + cache->key.offset;
 
                err = write_one_cache_group(trans, root, path, cache);
-               BUG_ON(err);
+               if (err) /* File system offline */
+                       goto out;
+
                btrfs_put_block_group(cache);
        }
 
@@ -2985,7 +3027,8 @@ again:
                if (last == 0) {
                        err = btrfs_run_delayed_refs(trans, root,
                                                     (unsigned long)-1);
-                       BUG_ON(err);
+                       if (err) /* File system offline */
+                               goto out;
                }
 
                cache = btrfs_lookup_first_block_group(root->fs_info, last);
@@ -3010,20 +3053,21 @@ again:
                        continue;
                }
 
-               btrfs_write_out_cache(root, trans, cache, path);
+               err = btrfs_write_out_cache(root, trans, cache, path);
 
                /*
                 * If we didn't have an error then the cache state is still
                 * NEED_WRITE, so we can set it to WRITTEN.
                 */
-               if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
+               if (!err && cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
                        cache->disk_cache_state = BTRFS_DC_WRITTEN;
                last = cache->key.objectid + cache->key.offset;
                btrfs_put_block_group(cache);
        }
+out:
 
        btrfs_free_path(path);
-       return 0;
+       return err;
 }
 
 int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
@@ -3407,9 +3451,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
        if (!space_info) {
                ret = update_space_info(extent_root->fs_info, flags,
                                        0, 0, &space_info);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
-       BUG_ON(!space_info);
+       BUG_ON(!space_info); /* Logic error */
 
 again:
        spin_lock(&space_info->lock);
@@ -3674,8 +3718,10 @@ again:
                ret = wait_event_interruptible(space_info->wait,
                                               !space_info->flush);
                /* Must have been interrupted, return */
-               if (ret)
+               if (ret) {
+                       printk(KERN_DEBUG "btrfs: %s returning -EINTR\n", __func__);
                        return -EINTR;
+               }
 
                spin_lock(&space_info->lock);
        }
@@ -3832,8 +3878,9 @@ out:
        return ret;
 }
 
-static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
-                                            struct btrfs_root *root)
+static struct btrfs_block_rsv *get_block_rsv(
+                                       const struct btrfs_trans_handle *trans,
+                                       const struct btrfs_root *root)
 {
        struct btrfs_block_rsv *block_rsv = NULL;
 
@@ -4200,6 +4247,7 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
        trans->bytes_reserved = 0;
 }
 
+/* Can only return 0 or -ENOSPC */
 int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
                                  struct inode *inode)
 {
@@ -4536,7 +4584,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
        while (total) {
                cache = btrfs_lookup_block_group(info, bytenr);
                if (!cache)
-                       return -1;
+                       return -ENOENT;
                if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
                                    BTRFS_BLOCK_GROUP_RAID1 |
                                    BTRFS_BLOCK_GROUP_RAID10))
@@ -4639,7 +4687,7 @@ int btrfs_pin_extent(struct btrfs_root *root,
        struct btrfs_block_group_cache *cache;
 
        cache = btrfs_lookup_block_group(root->fs_info, bytenr);
-       BUG_ON(!cache);
+       BUG_ON(!cache); /* Logic error */
 
        pin_down_extent(root, cache, bytenr, num_bytes, reserved);
 
@@ -4657,7 +4705,7 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
        struct btrfs_block_group_cache *cache;
 
        cache = btrfs_lookup_block_group(root->fs_info, bytenr);
-       BUG_ON(!cache);
+       BUG_ON(!cache); /* Logic error */
 
        /*
         * pull in the free space cache (if any) so that our pin
@@ -4702,6 +4750,7 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
 {
        struct btrfs_space_info *space_info = cache->space_info;
        int ret = 0;
+
        spin_lock(&space_info->lock);
        spin_lock(&cache->lock);
        if (reserve != RESERVE_FREE) {
@@ -4774,7 +4823,7 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
                        if (cache)
                                btrfs_put_block_group(cache);
                        cache = btrfs_lookup_block_group(fs_info, start);
-                       BUG_ON(!cache);
+                       BUG_ON(!cache); /* Logic error */
                }
 
                len = cache->key.objectid + cache->key.offset - start;
@@ -4811,6 +4860,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
        u64 end;
        int ret;
 
+       if (trans->aborted)
+               return 0;
+
        if (fs_info->pinned_extents == &fs_info->freed_extents[0])
                unpin = &fs_info->freed_extents[1];
        else
@@ -4896,7 +4948,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        ret = remove_extent_backref(trans, extent_root, path,
                                                    NULL, refs_to_drop,
                                                    is_data);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto abort;
                        btrfs_release_path(path);
                        path->leave_spinning = 1;
 
@@ -4914,10 +4967,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                        btrfs_print_leaf(extent_root,
                                                         path->nodes[0]);
                        }
-                       BUG_ON(ret);
+                       if (ret < 0)
+                               goto abort;
                        extent_slot = path->slots[0];
                }
-       } else {
+       } else if (ret == -ENOENT) {
                btrfs_print_leaf(extent_root, path->nodes[0]);
                WARN_ON(1);
                printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
@@ -4927,6 +4981,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                       (unsigned long long)root_objectid,
                       (unsigned long long)owner_objectid,
                       (unsigned long long)owner_offset);
+       } else {
+               goto abort;
        }
 
        leaf = path->nodes[0];
@@ -4936,7 +4992,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                BUG_ON(found_extent || extent_slot != path->slots[0]);
                ret = convert_extent_item_v0(trans, extent_root, path,
                                             owner_objectid, 0);
-               BUG_ON(ret < 0);
+               if (ret < 0)
+                       goto abort;
 
                btrfs_release_path(path);
                path->leave_spinning = 1;
@@ -4953,7 +5010,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                               (unsigned long long)bytenr);
                        btrfs_print_leaf(extent_root, path->nodes[0]);
                }
-               BUG_ON(ret);
+               if (ret < 0)
+                       goto abort;
                extent_slot = path->slots[0];
                leaf = path->nodes[0];
                item_size = btrfs_item_size_nr(leaf, extent_slot);
@@ -4990,7 +5048,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        ret = remove_extent_backref(trans, extent_root, path,
                                                    iref, refs_to_drop,
                                                    is_data);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto abort;
                }
        } else {
                if (found_extent) {
@@ -5007,12 +5066,14 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
-               BUG_ON(ret);
+               if (ret)
+                       goto abort;
                btrfs_release_path(path);
 
                if (is_data) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
-                       BUG_ON(ret);
+                       if (ret)
+                               goto abort;
                } else {
                        invalidate_mapping_pages(info->btree_inode->i_mapping,
                             bytenr >> PAGE_CACHE_SHIFT,
@@ -5020,10 +5081,16 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                }
 
                ret = update_block_group(trans, root, bytenr, num_bytes, 0);
-               BUG_ON(ret);
+               if (ret)
+                       goto abort;
        }
+out:
        btrfs_free_path(path);
        return ret;
+
+abort:
+       btrfs_abort_transaction(trans, extent_root, ret);
+       goto out;
 }
 
 /*
@@ -5119,7 +5186,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                                        parent, root->root_key.objectid,
                                        btrfs_header_level(buf),
                                        BTRFS_DROP_DELAYED_REF, NULL, for_cow);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
 
        if (!last_ref)
@@ -5153,6 +5220,7 @@ out:
        btrfs_put_block_group(cache);
 }
 
+/* Can return -ENOMEM */
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                      u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
                      u64 owner, u64 offset, int for_cow)
@@ -5174,14 +5242,12 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                                        num_bytes,
                                        parent, root_objectid, (int)owner,
                                        BTRFS_DROP_DELAYED_REF, NULL, for_cow);
-               BUG_ON(ret);
        } else {
                ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
                                                num_bytes,
                                                parent, root_objectid, owner,
                                                offset, BTRFS_DROP_DELAYED_REF,
                                                NULL, for_cow);
-               BUG_ON(ret);
        }
        return ret;
 }
@@ -5418,6 +5484,7 @@ have_block_group:
                        found_uncached_bg = true;
                        ret = cache_block_group(block_group, trans,
                                                orig_root, 1);
+                       BUG_ON(ret < 0); /* -ENOMEM */
                        if (block_group->cached == BTRFS_CACHE_FINISHED)
                                goto alloc;
 
@@ -5439,7 +5506,7 @@ have_block_group:
                        if (loop > LOOP_FIND_IDEAL) {
                                ret = cache_block_group(block_group, trans,
                                                        orig_root, 0);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                        }
 
                        /*
@@ -5712,6 +5779,11 @@ loop:
                                ret = do_chunk_alloc(trans, root, num_bytes +
                                                     2 * 1024 * 1024, data,
                                                     CHUNK_ALLOC_LIMITED);
+                               if (ret < 0) {
+                                       btrfs_abort_transaction(trans,
+                                                               root, ret);
+                                       goto out;
+                               }
                                allowed_chunk_alloc = 0;
                                if (ret == 1)
                                        done_chunk_alloc = 1;
@@ -5740,6 +5812,7 @@ loop:
        } else if (ins->objectid) {
                ret = 0;
        }
+out:
 
        return ret;
 }
@@ -5806,10 +5879,15 @@ again:
         * the only place that sets empty_size is btrfs_realloc_node, which
         * is not called recursively on allocations
         */
-       if (empty_size || root->ref_cows)
+       if (empty_size || root->ref_cows) {
                ret = do_chunk_alloc(trans, root->fs_info->extent_root,
                                     num_bytes + 2 * 1024 * 1024, data,
                                     CHUNK_ALLOC_NO_FORCE);
+               if (ret < 0 && ret != -ENOSPC) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       return ret;
+               }
+       }
 
        WARN_ON(num_bytes < root->sectorsize);
        ret = find_free_extent(trans, root, num_bytes, empty_size,
@@ -5821,8 +5899,12 @@ again:
                        num_bytes = num_bytes >> 1;
                        num_bytes = num_bytes & ~(root->sectorsize - 1);
                        num_bytes = max(num_bytes, min_alloc_size);
-                       do_chunk_alloc(trans, root->fs_info->extent_root,
+                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
                                       num_bytes, data, CHUNK_ALLOC_FORCE);
+                       if (ret < 0 && ret != -ENOSPC) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               return ret;
+                       }
                        if (num_bytes == min_alloc_size)
                                final_tried = true;
                        goto again;
@@ -5913,7 +5995,10 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
                                      ins, size);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_free_path(path);
+               return ret;
+       }
 
        leaf = path->nodes[0];
        extent_item = btrfs_item_ptr(leaf, path->slots[0],
@@ -5943,7 +6028,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        btrfs_free_path(path);
 
        ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
-       if (ret) {
+       if (ret) { /* -ENOENT, logic error */
                printk(KERN_ERR "btrfs update block group failed for %llu "
                       "%llu\n", (unsigned long long)ins->objectid,
                       (unsigned long long)ins->offset);
@@ -5974,7 +6059,10 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        path->leave_spinning = 1;
        ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
                                      ins, size);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_free_path(path);
+               return ret;
+       }
 
        leaf = path->nodes[0];
        extent_item = btrfs_item_ptr(leaf, path->slots[0],
@@ -6004,7 +6092,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        btrfs_free_path(path);
 
        ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
-       if (ret) {
+       if (ret) { /* -ENOENT, logic error */
                printk(KERN_ERR "btrfs update block group failed for %llu "
                       "%llu\n", (unsigned long long)ins->objectid,
                       (unsigned long long)ins->offset);
@@ -6052,28 +6140,28 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
        if (!caching_ctl) {
                BUG_ON(!block_group_cache_done(block_group));
                ret = btrfs_remove_free_space(block_group, start, num_bytes);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        } else {
                mutex_lock(&caching_ctl->mutex);
 
                if (start >= caching_ctl->progress) {
                        ret = add_excluded_extent(root, start, num_bytes);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                } else if (start + num_bytes <= caching_ctl->progress) {
                        ret = btrfs_remove_free_space(block_group,
                                                      start, num_bytes);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                } else {
                        num_bytes = caching_ctl->progress - start;
                        ret = btrfs_remove_free_space(block_group,
                                                      start, num_bytes);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
 
                        start = caching_ctl->progress;
                        num_bytes = ins->objectid + ins->offset -
                                    caching_ctl->progress;
                        ret = add_excluded_extent(root, start, num_bytes);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                }
 
                mutex_unlock(&caching_ctl->mutex);
@@ -6082,7 +6170,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
 
        ret = btrfs_update_reserved_bytes(block_group, ins->offset,
                                          RESERVE_ALLOC_NO_ACCOUNT);
-       BUG_ON(ret);
+       BUG_ON(ret); /* logic error */
        btrfs_put_block_group(block_group);
        ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
                                         0, owner, offset, ins, 1);
@@ -6218,7 +6306,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
 
        buf = btrfs_init_new_buffer(trans, root, ins.objectid,
                                    blocksize, level);
-       BUG_ON(IS_ERR(buf));
+       BUG_ON(IS_ERR(buf)); /* -ENOMEM */
 
        if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
                if (parent == 0)
@@ -6230,7 +6318,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
                struct btrfs_delayed_extent_op *extent_op;
                extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
-               BUG_ON(!extent_op);
+               BUG_ON(!extent_op); /* -ENOMEM */
                if (key)
                        memcpy(&extent_op->key, key, sizeof(extent_op->key));
                else
@@ -6245,7 +6333,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        ins.offset, parent, root_objectid,
                                        level, BTRFS_ADD_DELAYED_EXTENT,
                                        extent_op, for_cow);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
        return buf;
 }
@@ -6315,7 +6403,9 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
                /* We don't lock the tree block, it's OK to be racy here */
                ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
                                               &refs, &flags);
-               BUG_ON(ret);
+               /* We don't care about errors in readahead. */
+               if (ret < 0)
+                       continue;
                BUG_ON(refs == 0);
 
                if (wc->stage == DROP_REFERENCE) {
@@ -6382,7 +6472,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
                                               eb->start, eb->len,
                                               &wc->refs[level],
                                               &wc->flags[level]);
-               BUG_ON(ret);
+               BUG_ON(ret == -ENOMEM);
+               if (ret)
+                       return ret;
                BUG_ON(wc->refs[level] == 0);
        }
 
@@ -6401,12 +6493,12 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
        if (!(wc->flags[level] & flag)) {
                BUG_ON(!path->locks[level]);
                ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
                ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
                ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
                                                  eb->len, flag, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
                wc->flags[level] |= flag;
        }
 
@@ -6478,7 +6570,11 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
                                       &wc->refs[level - 1],
                                       &wc->flags[level - 1]);
-       BUG_ON(ret);
+       if (ret < 0) {
+               btrfs_tree_unlock(next);
+               return ret;
+       }
+
        BUG_ON(wc->refs[level - 1] == 0);
        *lookup_info = 0;
 
@@ -6547,7 +6643,7 @@ skip:
 
                ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
                                root->root_key.objectid, level - 1, 0, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
        btrfs_tree_unlock(next);
        free_extent_buffer(next);
@@ -6605,7 +6701,10 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                                                       eb->start, eb->len,
                                                       &wc->refs[level],
                                                       &wc->flags[level]);
-                       BUG_ON(ret);
+                       if (ret < 0) {
+                               btrfs_tree_unlock_rw(eb, path->locks[level]);
+                               return ret;
+                       }
                        BUG_ON(wc->refs[level] == 0);
                        if (wc->refs[level] == 1) {
                                btrfs_tree_unlock_rw(eb, path->locks[level]);
@@ -6625,7 +6724,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                        else
                                ret = btrfs_dec_ref(trans, root, eb, 0,
                                                    wc->for_reloc);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM */
                }
                /* make block locked assertion in clean_tree_block happy */
                if (!path->locks[level] &&
@@ -6762,7 +6861,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        }
 
        trans = btrfs_start_transaction(tree_root, 0);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans)) {
+               err = PTR_ERR(trans);
+               goto out_free;
+       }
 
        if (block_rsv)
                trans->block_rsv = block_rsv;
@@ -6787,7 +6889,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                path->lowest_level = 0;
                if (ret < 0) {
                        err = ret;
-                       goto out_free;
+                       goto out_end_trans;
                }
                WARN_ON(ret > 0);
 
@@ -6807,7 +6909,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                                path->nodes[level]->len,
                                                &wc->refs[level],
                                                &wc->flags[level]);
-                       BUG_ON(ret);
+                       if (ret < 0) {
+                               err = ret;
+                               goto out_end_trans;
+                       }
                        BUG_ON(wc->refs[level] == 0);
 
                        if (level == root_item->drop_level)
@@ -6858,26 +6963,40 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                        ret = btrfs_update_root(trans, tree_root,
                                                &root->root_key,
                                                root_item);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, tree_root, ret);
+                               err = ret;
+                               goto out_end_trans;
+                       }
 
                        btrfs_end_transaction_throttle(trans, tree_root);
                        trans = btrfs_start_transaction(tree_root, 0);
-                       BUG_ON(IS_ERR(trans));
+                       if (IS_ERR(trans)) {
+                               err = PTR_ERR(trans);
+                               goto out_free;
+                       }
                        if (block_rsv)
                                trans->block_rsv = block_rsv;
                }
        }
        btrfs_release_path(path);
-       BUG_ON(err);
+       if (err)
+               goto out_end_trans;
 
        ret = btrfs_del_root(trans, tree_root, &root->root_key);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, tree_root, ret);
+               goto out_end_trans;
+       }
 
        if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
                ret = btrfs_find_last_root(tree_root, root->root_key.objectid,
                                           NULL, NULL);
-               BUG_ON(ret < 0);
-               if (ret > 0) {
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, tree_root, ret);
+                       err = ret;
+                       goto out_end_trans;
+               } else if (ret > 0) {
                        /* if we fail to delete the orphan item this time
                         * around, it'll get picked up the next time.
                         *
@@ -6895,8 +7014,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                free_extent_buffer(root->commit_root);
                kfree(root);
        }
-out_free:
+out_end_trans:
        btrfs_end_transaction_throttle(trans, tree_root);
+out_free:
        kfree(wc);
        btrfs_free_path(path);
 out:
@@ -7099,12 +7219,16 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
        BUG_ON(cache->ro);
 
        trans = btrfs_join_transaction(root);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        alloc_flags = update_block_group_flags(root, cache->flags);
-       if (alloc_flags != cache->flags)
-               do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
-                              CHUNK_ALLOC_FORCE);
+       if (alloc_flags != cache->flags) {
+               ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
+                                    CHUNK_ALLOC_FORCE);
+               if (ret < 0)
+                       goto out;
+       }
 
        ret = set_block_group_ro(cache, 0);
        if (!ret)
@@ -7567,7 +7691,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                ret = update_space_info(info, cache->flags, found_key.offset,
                                        btrfs_block_group_used(&cache->item),
                                        &space_info);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
                cache->space_info = space_info;
                spin_lock(&cache->space_info->lock);
                cache->space_info->bytes_readonly += cache->bytes_super;
@@ -7576,7 +7700,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                __link_block_group(space_info, cache);
 
                ret = btrfs_add_block_group_cache(root->fs_info, cache);
-               BUG_ON(ret);
+               BUG_ON(ret); /* Logic error */
 
                set_avail_alloc_bits(root->fs_info, cache->flags);
                if (btrfs_chunk_readonly(root, cache->key.objectid))
@@ -7658,7 +7782,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
                                &cache->space_info);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
        update_global_block_rsv(root->fs_info);
 
        spin_lock(&cache->space_info->lock);
@@ -7668,11 +7792,14 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        __link_block_group(cache->space_info, cache);
 
        ret = btrfs_add_block_group_cache(root->fs_info, cache);
-       BUG_ON(ret);
+       BUG_ON(ret); /* Logic error */
 
        ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
                                sizeof(cache->item));
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, extent_root, ret);
+               return ret;
+       }
 
        set_avail_alloc_bits(extent_root->fs_info, type);
 
@@ -7753,7 +7880,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        inode = lookup_free_space_inode(tree_root, block_group, path);
        if (!IS_ERR(inode)) {
                ret = btrfs_orphan_add(trans, inode);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_add_delayed_iput(inode);
+                       goto out;
+               }
                clear_nlink(inode);
                /* One for the block groups ref */
                spin_lock(&block_group->lock);
index ffa7cc3370c7cb289ee63a2197b4e0c1db52d647..4c3ce7a0a7a4bb7a494cc498289b0bae025df76b 100644 (file)
@@ -1244,7 +1244,7 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
 
        while (index <= end_index) {
                page = find_get_page(tree->mapping, index);
-               BUG_ON(!page);
+               BUG_ON(!page); /* Pages should be in the extent_io_tree */
                set_page_writeback(page);
                page_cache_release(page);
                index++;
@@ -1523,7 +1523,7 @@ again:
                        goto out_failed;
                }
        }
-       BUG_ON(ret);
+       BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */
 
        /* step three, lock the state bits for the whole range */
        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)
                /* Writeback already completed */
                if (ret == 0)
                        return 1;
-               BUG_ON(ret < 0);
        }
 
        if (!uptodate) {
@@ -2353,7 +2352,6 @@ error_handled:
                                if (ret == 0)
                                        goto error_handled;
                        }
-                       BUG_ON(ret < 0);
                }
 
                if (uptodate) {
@@ -2405,6 +2403,10 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
        return bio;
 }
 
+/*
+ * Since writes are async, they will only return -ENOMEM.
+ * Reads can return the full range of I/O error conditions.
+ */
 static int __must_check submit_one_bio(int rw, struct bio *bio,
                                       int mirror_num, unsigned long bio_flags)
 {
@@ -2477,7 +2479,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
                    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);
+                       if (ret < 0)
+                               return ret;
                        bio = NULL;
                } else {
                        return 0;
@@ -2498,10 +2501,8 @@ 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;
 }
@@ -2525,6 +2526,7 @@ static void set_page_extent_head(struct page *page, unsigned long len)
  * basic readpage implementation.  Locked extent state structs are inserted
  * into the tree that are removed when the IO is done (by the end_io
  * handlers)
+ * XXX JDM: This needs looking at to ensure proper page locking
  */
 static int __extent_read_full_page(struct extent_io_tree *tree,
                                   struct page *page,
@@ -2687,6 +2689,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                                         end_bio_extent_readpage, mirror_num,
                                         *bio_flags,
                                         this_bio_flag);
+                       BUG_ON(ret == -ENOMEM);
                        nr++;
                        *bio_flags = this_bio_flag;
                }
@@ -2713,10 +2716,8 @@ 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;
 }
 
@@ -2830,7 +2831,11 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                                                       delalloc_end,
                                                       &page_started,
                                                       &nr_written);
-                       BUG_ON(ret);
+                       /* File system has been set read-only */
+                       if (ret) {
+                               SetPageError(page);
+                               goto done;
+                       }
                        /*
                         * delalloc_end is already one less than the total
                         * length, so we don't subtract one from
@@ -3141,7 +3146,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd)
                        rw = WRITE_SYNC;
 
                ret = submit_one_bio(rw, epd->bio, 0, 0);
-               BUG_ON(ret < 0);
+               BUG_ON(ret < 0); /* -ENOMEM */
                epd->bio = NULL;
        }
 }
@@ -3257,10 +3262,8 @@ int extent_readpages(struct extent_io_tree *tree,
                page_cache_release(page);
        }
        BUG_ON(!list_empty(pages));
-       if (bio) {
-               int ret = submit_one_bio(READ, bio, 0, bio_flags);
-               BUG_ON(ret < 0);
-       }
+       if (bio)
+               return submit_one_bio(READ, bio, 0, bio_flags);
        return 0;
 }
 
@@ -4090,7 +4093,8 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 
        if (bio) {
                err = submit_one_bio(READ, bio, mirror_num, bio_flags);
-               BUG_ON(err < 0);
+               if (err)
+                       return err;
        }
 
        if (ret || wait != WAIT_COMPLETE)
index 89af104c7569434b0ac73a4e826bafcd00cc8458..a14dbca5974ecd77c56c2b5f133d5dc8df72e7a6 100644 (file)
@@ -59,7 +59,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                                      sizeof(*item));
        if (ret < 0)
                goto out;
-       BUG_ON(ret);
+       BUG_ON(ret); /* Can't happen */
        leaf = path->nodes[0];
        item = btrfs_item_ptr(leaf, path->slots[0],
                              struct btrfs_file_extent_item);
@@ -431,7 +431,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 
        ordered = btrfs_lookup_ordered_extent(inode, offset);
-       BUG_ON(!ordered);
+       BUG_ON(!ordered); /* Logic error */
        sums->bytenr = ordered->start;
 
        while (bio_index < bio->bi_vcnt) {
@@ -450,11 +450,11 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
 
                        sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
                                       GFP_NOFS);
-                       BUG_ON(!sums);
+                       BUG_ON(!sums); /* -ENOMEM */
                        sector_sum = sums->sums;
                        sums->len = bytes_left;
                        ordered = btrfs_lookup_ordered_extent(inode, offset);
-                       BUG_ON(!ordered);
+                       BUG_ON(!ordered); /* Logic error */
                        sums->bytenr = ordered->start;
                }
 
@@ -643,7 +643,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                         * item changed size or key
                         */
                        ret = btrfs_split_item(trans, root, path, &key, offset);
-                       BUG_ON(ret && ret != -EAGAIN);
+                       if (ret && ret != -EAGAIN) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto out;
+                       }
 
                        key.offset = end_byte - 1;
                } else {
index 0eb80cc4ec816d58bc031d1d9cf0d4ad2a9958e5..d83260d7498fe2b535a59069ebba7c3ae78e255e 100644 (file)
@@ -452,7 +452,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split = alloc_extent_map();
                if (!split2)
                        split2 = alloc_extent_map();
-               BUG_ON(!split || !split2);
+               BUG_ON(!split || !split2); /* -ENOMEM */
 
                write_lock(&em_tree->lock);
                em = lookup_extent_mapping(em_tree, start, len);
@@ -494,7 +494,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split->flags = flags;
                        split->compress_type = em->compress_type;
                        ret = add_extent_mapping(em_tree, split);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* Logic error */
                        free_extent_map(split);
                        split = split2;
                        split2 = NULL;
@@ -520,7 +520,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        }
 
                        ret = add_extent_mapping(em_tree, split);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* Logic error */
                        free_extent_map(split);
                        split = NULL;
                }
@@ -679,7 +679,7 @@ next_slot:
                                                root->root_key.objectid,
                                                new_key.objectid,
                                                start - extent_offset, 0);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                                *hint_byte = disk_bytenr;
                        }
                        key.offset = start;
@@ -754,7 +754,7 @@ next_slot:
                                                root->root_key.objectid,
                                                key.objectid, key.offset -
                                                extent_offset, 0);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                                inode_sub_bytes(inode,
                                                extent_end - key.offset);
                                *hint_byte = disk_bytenr;
@@ -770,7 +770,10 @@ next_slot:
 
                        ret = btrfs_del_items(trans, root, path, del_slot,
                                              del_nr);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto out;
+                       }
 
                        del_nr = 0;
                        del_slot = 0;
@@ -782,11 +785,13 @@ next_slot:
                BUG_ON(1);
        }
 
-       if (del_nr > 0) {
+       if (!ret && del_nr > 0) {
                ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
-               BUG_ON(ret);
+               if (ret)
+                       btrfs_abort_transaction(trans, root, ret);
        }
 
+out:
        btrfs_free_path(path);
        return ret;
 }
@@ -944,7 +949,10 @@ again:
                        btrfs_release_path(path);
                        goto again;
                }
-               BUG_ON(ret < 0);
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
 
                leaf = path->nodes[0];
                fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
@@ -963,7 +971,7 @@ again:
                ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
                                           root->root_key.objectid,
                                           ino, orig_offset, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
 
                if (split == start) {
                        key.offset = start;
@@ -990,7 +998,7 @@ again:
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
                                        ino, orig_offset, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
        other_start = 0;
        other_end = start;
@@ -1007,7 +1015,7 @@ again:
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
                                        ino, orig_offset, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
        if (del_nr == 0) {
                fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -1025,7 +1033,10 @@ again:
                btrfs_mark_buffer_dirty(leaf);
 
                ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
-               BUG_ON(ret);
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
        }
 out:
        btrfs_free_path(path);
@@ -1666,7 +1677,13 @@ static long btrfs_fallocate(struct file *file, int mode,
 
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                      alloc_end - cur_offset, 0);
-               BUG_ON(IS_ERR_OR_NULL(em));
+               if (IS_ERR_OR_NULL(em)) {
+                       if (!em)
+                               ret = -ENOMEM;
+                       else
+                               ret = PTR_ERR(em);
+                       break;
+               }
                last_byte = min(extent_map_end(em), alloc_end);
                actual_end = min_t(u64, extent_map_end(em), offset + len);
                last_byte = (last_byte + mask) & ~mask;
index ecbcc8711a03facad230da95321fc6abe1c86205..054707ed57914ab97b2f8a5e2e1e9f9679884bba 100644 (file)
@@ -230,11 +230,13 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
 
        if (ret) {
                trans->block_rsv = rsv;
-               WARN_ON(1);
+               btrfs_abort_transaction(trans, root, ret);
                return ret;
        }
 
        ret = btrfs_update_inode(trans, root, inode);
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
        trans->block_rsv = rsv;
 
        return ret;
@@ -1948,14 +1950,14 @@ again:
                 */
                ret = btrfs_add_free_space(block_group, old_start,
                                           offset - old_start);
-               WARN_ON(ret);
+               WARN_ON(ret); /* -ENOMEM */
                goto out;
        }
 
        ret = remove_from_bitmap(ctl, info, &offset, &bytes);
        if (ret == -EAGAIN)
                goto again;
-       BUG_ON(ret);
+       BUG_ON(ret); /* logic error */
 out_lock:
        spin_unlock(&ctl->tree_lock);
 out:
@@ -2346,7 +2348,7 @@ again:
        rb_erase(&entry->offset_index, &ctl->free_space_offset);
        ret = tree_insert_offset(&cluster->root, entry->offset,
                                 &entry->offset_index, 1);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -EEXIST; Logic error */
 
        trace_btrfs_setup_cluster(block_group, cluster,
                                  total_found * block_group->sectorsize, 1);
@@ -2439,7 +2441,7 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                ret = tree_insert_offset(&cluster->root, entry->offset,
                                         &entry->offset_index, 0);
                total_size += entry->bytes;
-               BUG_ON(ret);
+               BUG_ON(ret); /* -EEXIST; Logic error */
        } while (node && entry != last);
 
        cluster->max_size = max_extent;
@@ -2830,6 +2832,7 @@ u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root)
                int ret;
 
                ret = search_bitmap(ctl, entry, &offset, &count);
+               /* Logic error; Should be empty if it can't find anything */
                BUG_ON(ret);
 
                ino = offset;
index c0792409bb6a0c3251c3bbbba9be4a3627d6021c..7ec58bd7c50d8b7cf5cadd2ef826bdcdac0b7d5d 100644 (file)
@@ -135,6 +135,7 @@ out:
        return ret;
 }
 
+/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
 int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           const char *name, int name_len,
index ee15d88b33d2a3dca65f41a4c5c3f6a36bbe5b48..7ca46e6e11aeda9d1c03ab1d58bcccc71f6fa289 100644 (file)
@@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root)
 
        tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
                          root->root_key.objectid);
-       BUG_ON(IS_ERR(tsk));
+       BUG_ON(IS_ERR(tsk)); /* -ENOMEM */
 }
 
 int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
@@ -271,7 +271,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
                        break;
 
                info = rb_entry(n, struct btrfs_free_space, offset_index);
-               BUG_ON(info->bitmap);
+               BUG_ON(info->bitmap); /* Logic error */
 
                if (info->offset > root->cache_progress)
                        goto free;
@@ -443,13 +443,13 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
                                      trans->bytes_reserved, 1);
 again:
        inode = lookup_free_ino_inode(root, path);
-       if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
+       if (IS_ERR(inode) && (PTR_ERR(inode) != -ENOENT || retry)) {
                ret = PTR_ERR(inode);
                goto out_release;
        }
 
        if (IS_ERR(inode)) {
-               BUG_ON(retry);
+               BUG_ON(retry); /* Logic error */
                retry = true;
 
                ret = create_free_ino_inode(root, trans, path);
@@ -460,12 +460,17 @@ again:
 
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
-       WARN_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_put;
+       }
 
        if (i_size_read(inode) > 0) {
                ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
-               if (ret)
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
                        goto out_put;
+               }
        }
 
        spin_lock(&root->cache_lock);
@@ -532,7 +537,7 @@ static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid)
        ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
        if (ret < 0)
                goto error;
-       BUG_ON(ret == 0);
+       BUG_ON(ret == 0); /* Corruption */
        if (path->slots[0] > 0) {
                slot = path->slots[0] - 1;
                l = path->nodes[0];
index 41132339e2ead2be931e4a1501532b4fc4f96468..d6420cca9c8d65b66b1c3acdc5be85e88b254c0f 100644 (file)
@@ -150,7 +150,6 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
        inode_add_bytes(inode, size);
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      datasize);
-       BUG_ON(ret);
        if (ret) {
                err = ret;
                goto fail;
@@ -206,9 +205,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
         * could end up racing with unlink.
         */
        BTRFS_I(inode)->disk_i_size = inode->i_size;
-       btrfs_update_inode(trans, root, inode);
+       ret = btrfs_update_inode(trans, root, inode);
 
-       return 0;
+       return ret;
 fail:
        btrfs_free_path(path);
        return err;
@@ -250,14 +249,18 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
 
        ret = btrfs_drop_extents(trans, inode, start, aligned_end,
                                 &hint_byte, 1);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        if (isize > actual_end)
                inline_len = min_t(u64, isize, actual_end);
        ret = insert_inline_extent(trans, root, inode, start,
                                   inline_len, compressed_size,
                                   compress_type, compressed_pages);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
+       }
        btrfs_delalloc_release_metadata(inode, end + 1 - start);
        btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
        return 0;
@@ -293,7 +296,7 @@ static noinline int add_async_extent(struct async_cow *cow,
        struct async_extent *async_extent;
 
        async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
-       BUG_ON(!async_extent);
+       BUG_ON(!async_extent); /* -ENOMEM */
        async_extent->start = start;
        async_extent->ram_size = ram_size;
        async_extent->compressed_size = compressed_size;
@@ -433,7 +436,11 @@ again:
 cont:
        if (start == 0) {
                trans = btrfs_join_transaction(root);
-               BUG_ON(IS_ERR(trans));
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       trans = NULL;
+                       goto cleanup_and_out;
+               }
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
                /* lets try to make an inline extent */
@@ -450,11 +457,11 @@ cont:
                                                    total_compressed,
                                                    compress_type, pages);
                }
-               if (ret == 0) {
+               if (ret <= 0) {
                        /*
-                        * inline extent creation worked, we don't need
-                        * to create any more async work items.  Unlock
-                        * and free up our temp pages.
+                        * inline extent creation worked or returned error,
+                        * we don't need to create any more async work items.
+                        * Unlock and free up our temp pages.
                         */
                        extent_clear_unlock_delalloc(inode,
                             &BTRFS_I(inode)->io_tree,
@@ -547,7 +554,7 @@ cleanup_and_bail_uncompressed:
        }
 
 out:
-       return 0;
+       return ret;
 
 free_pages_out:
        for (i = 0; i < nr_pages_ret; i++) {
@@ -557,6 +564,20 @@ free_pages_out:
        kfree(pages);
 
        goto out;
+
+cleanup_and_out:
+       extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
+                                    start, end, NULL,
+                                    EXTENT_CLEAR_UNLOCK_PAGE |
+                                    EXTENT_CLEAR_DIRTY |
+                                    EXTENT_CLEAR_DELALLOC |
+                                    EXTENT_SET_WRITEBACK |
+                                    EXTENT_END_WRITEBACK);
+       if (!trans || IS_ERR(trans))
+               btrfs_error(root->fs_info, ret, "Failed to join transaction");
+       else
+               btrfs_abort_transaction(trans, root, ret);
+       goto free_pages_out;
 }
 
 /*
@@ -606,6 +627,8 @@ retry:
                                             async_extent->ram_size - 1,
                                             &page_started, &nr_written, 0);
 
+                       /* JDM XXX */
+
                        /*
                         * if page_started, cow_file_range inserted an
                         * inline extent and took care of all the unlocking
@@ -628,14 +651,19 @@ retry:
                            async_extent->start + async_extent->ram_size - 1);
 
                trans = btrfs_join_transaction(root);
-               BUG_ON(IS_ERR(trans));
-               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-               ret = btrfs_reserve_extent(trans, root,
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+               } else {
+                       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+                       ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
                                           0, alloc_hint,
                                           (u64)-1, &ins, 1);
-               btrfs_end_transaction(trans, root);
+                       if (ret)
+                               btrfs_abort_transaction(trans, root, ret);
+                       btrfs_end_transaction(trans, root);
+               }
 
                if (ret) {
                        int i;
@@ -649,7 +677,9 @@ retry:
                        unlock_extent(io_tree, async_extent->start,
                                      async_extent->start +
                                      async_extent->ram_size - 1);
-                       goto retry;
+                       if (ret == -ENOSPC)
+                               goto retry;
+                       goto out_free; /* JDM: Requeue? */
                }
 
                /*
@@ -661,7 +691,7 @@ retry:
                                        async_extent->ram_size - 1, 0);
 
                em = alloc_extent_map();
-               BUG_ON(!em);
+               BUG_ON(!em); /* -ENOMEM */
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
                em->orig_start = em->start;
@@ -693,7 +723,7 @@ retry:
                                                ins.offset,
                                                BTRFS_ORDERED_COMPRESSED,
                                                async_extent->compress_type);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
 
                /*
                 * clear dirty, set writeback and unlock the pages.
@@ -715,13 +745,17 @@ retry:
                                    ins.offset, async_extent->pages,
                                    async_extent->nr_pages);
 
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
                alloc_hint = ins.objectid + ins.offset;
                kfree(async_extent);
                cond_resched();
        }
-
-       return 0;
+       ret = 0;
+out:
+       return ret;
+out_free:
+       kfree(async_extent);
+       goto out;
 }
 
 static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
@@ -790,7 +824,18 @@ static noinline int cow_file_range(struct inode *inode,
 
        BUG_ON(btrfs_is_free_space_inode(root, inode));
        trans = btrfs_join_transaction(root);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans)) {
+               extent_clear_unlock_delalloc(inode,
+                            &BTRFS_I(inode)->io_tree,
+                            start, end, NULL,
+                            EXTENT_CLEAR_UNLOCK_PAGE |
+                            EXTENT_CLEAR_UNLOCK |
+                            EXTENT_CLEAR_DELALLOC |
+                            EXTENT_CLEAR_DIRTY |
+                            EXTENT_SET_WRITEBACK |
+                            EXTENT_END_WRITEBACK);
+               return PTR_ERR(trans);
+       }
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        num_bytes = (end - start + blocksize) & ~(blocksize - 1);
@@ -820,8 +865,10 @@ static noinline int cow_file_range(struct inode *inode,
                        *nr_written = *nr_written +
                             (end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
                        *page_started = 1;
-                       ret = 0;
                        goto out;
+               } else if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out_unlock;
                }
        }
 
@@ -838,10 +885,13 @@ static noinline int cow_file_range(struct inode *inode,
                ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
                                           root->sectorsize, 0, alloc_hint,
                                           (u64)-1, &ins, 1);
-               BUG_ON(ret);
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out_unlock;
+               }
 
                em = alloc_extent_map();
-               BUG_ON(!em);
+               BUG_ON(!em); /* -ENOMEM */
                em->start = start;
                em->orig_start = em->start;
                ram_size = ins.offset;
@@ -867,13 +917,16 @@ static noinline int cow_file_range(struct inode *inode,
                cur_alloc_size = ins.offset;
                ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
                                               ram_size, cur_alloc_size, 0);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
 
                if (root->root_key.objectid ==
                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
                        ret = btrfs_reloc_clone_csums(inode, start,
                                                      cur_alloc_size);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto out_unlock;
+                       }
                }
 
                if (disk_num_bytes < cur_alloc_size)
@@ -898,11 +951,23 @@ static noinline int cow_file_range(struct inode *inode,
                alloc_hint = ins.objectid + ins.offset;
                start += cur_alloc_size;
        }
-out:
        ret = 0;
+out:
        btrfs_end_transaction(trans, root);
 
        return ret;
+out_unlock:
+       extent_clear_unlock_delalloc(inode,
+                    &BTRFS_I(inode)->io_tree,
+                    start, end, NULL,
+                    EXTENT_CLEAR_UNLOCK_PAGE |
+                    EXTENT_CLEAR_UNLOCK |
+                    EXTENT_CLEAR_DELALLOC |
+                    EXTENT_CLEAR_DIRTY |
+                    EXTENT_SET_WRITEBACK |
+                    EXTENT_END_WRITEBACK);
+
+       goto out;
 }
 
 /*
@@ -968,7 +1033,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
                         1, 0, NULL, GFP_NOFS);
        while (start < end) {
                async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
-               BUG_ON(!async_cow);
+               BUG_ON(!async_cow); /* -ENOMEM */
                async_cow->inode = inode;
                async_cow->root = root;
                async_cow->locked_page = locked_page;
@@ -1059,7 +1124,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        u64 disk_bytenr;
        u64 num_bytes;
        int extent_type;
-       int ret;
+       int ret, err;
        int type;
        int nocow;
        int check_prev = 1;
@@ -1077,7 +1142,11 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        else
                trans = btrfs_join_transaction(root);
 
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               return PTR_ERR(trans);
+       }
+
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        cow_start = (u64)-1;
@@ -1085,7 +1154,10 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        while (1) {
                ret = btrfs_lookup_file_extent(trans, root, path, ino,
                                               cur_offset, 0);
-               BUG_ON(ret < 0);
+               if (ret < 0) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto error;
+               }
                if (ret > 0 && path->slots[0] > 0 && check_prev) {
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &found_key,
@@ -1099,8 +1171,10 @@ next_slot:
                leaf = path->nodes[0];
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
                        ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
-                               BUG_ON(1);
+                       if (ret < 0) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto error;
+                       }
                        if (ret > 0)
                                break;
                        leaf = path->nodes[0];
@@ -1188,7 +1262,10 @@ out_check:
                        ret = cow_file_range(inode, locked_page, cow_start,
                                        found_key.offset - 1, page_started,
                                        nr_written, 1);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto error;
+                       }
                        cow_start = (u64)-1;
                }
 
@@ -1197,7 +1274,7 @@ out_check:
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
                        em = alloc_extent_map();
-                       BUG_ON(!em);
+                       BUG_ON(!em); /* -ENOMEM */
                        em->start = cur_offset;
                        em->orig_start = em->start;
                        em->len = num_bytes;
@@ -1223,13 +1300,16 @@ out_check:
 
                ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr,
                                               num_bytes, num_bytes, type);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
 
                if (root->root_key.objectid ==
                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
                        ret = btrfs_reloc_clone_csums(inode, cur_offset,
                                                      num_bytes);
-                       BUG_ON(ret);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               goto error;
+                       }
                }
 
                extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
@@ -1248,18 +1328,23 @@ out_check:
        if (cow_start != (u64)-1) {
                ret = cow_file_range(inode, locked_page, cow_start, end,
                                     page_started, nr_written, 1);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto error;
+               }
        }
 
+error:
        if (nolock) {
-               ret = btrfs_end_transaction_nolock(trans, root);
-               BUG_ON(ret);
+               err = btrfs_end_transaction_nolock(trans, root);
        } else {
-               ret = btrfs_end_transaction(trans, root);
-               BUG_ON(ret);
+               err = btrfs_end_transaction(trans, root);
        }
+       if (!ret)
+               ret = err;
+
        btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 /*
@@ -1448,7 +1533,7 @@ static int __btrfs_submit_bio_start(struct inode *inode, int rw,
        int ret = 0;
 
        ret = btrfs_csum_one_bio(root, inode, bio, 0, 0);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
        return 0;
 }
 
@@ -1677,13 +1762,15 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
         */
        ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
                                 &hint, 0);
-       BUG_ON(ret);
+       if (ret)
+               goto out;
 
        ins.objectid = btrfs_ino(inode);
        ins.offset = file_pos;
        ins.type = BTRFS_EXTENT_DATA_KEY;
        ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
-       BUG_ON(ret);
+       if (ret)
+               goto out;
        leaf = path->nodes[0];
        fi = btrfs_item_ptr(leaf, path->slots[0],
                            struct btrfs_file_extent_item);
@@ -1711,10 +1798,10 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        ret = btrfs_alloc_reserved_file_extent(trans, root,
                                        root->root_key.objectid,
                                        btrfs_ino(inode), file_pos, &ins);
-       BUG_ON(ret);
+out:
        btrfs_free_path(path);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -1742,22 +1829,24 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                             end - start + 1);
        if (!ret)
                return 0;
-       BUG_ON(!ordered_extent);
+       BUG_ON(!ordered_extent); /* Logic error */
 
        nolock = btrfs_is_free_space_inode(root, inode);
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
-               BUG_ON(!list_empty(&ordered_extent->list));
+               BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
                ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
                if (!ret) {
                        if (nolock)
                                trans = btrfs_join_transaction_nolock(root);
                        else
                                trans = btrfs_join_transaction(root);
-                       BUG_ON(IS_ERR(trans));
+                       if (IS_ERR(trans))
+                               return PTR_ERR(trans);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode_fallback(trans, root, inode);
-                       BUG_ON(ret);
+                       if (ret) /* -ENOMEM or corruption */
+                               btrfs_abort_transaction(trans, root, ret);
                }
                goto out;
        }
@@ -1770,7 +1859,11 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                trans = btrfs_join_transaction_nolock(root);
        else
                trans = btrfs_join_transaction(root);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               trans = NULL;
+               goto out_unlock;
+       }
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
@@ -1781,7 +1874,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                                ordered_extent->file_offset,
                                                ordered_extent->file_offset +
                                                ordered_extent->len);
-               BUG_ON(ret);
        } else {
                BUG_ON(root == root->fs_info->tree_root);
                ret = insert_reserved_file_extent(trans, inode,
@@ -1795,11 +1887,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
                                   ordered_extent->file_offset,
                                   ordered_extent->len);
-               BUG_ON(ret);
        }
        unlock_extent_cached(io_tree, ordered_extent->file_offset,
                             ordered_extent->file_offset +
                             ordered_extent->len - 1, &cached_state, GFP_NOFS);
+       if (ret < 0) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
+       }
 
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
@@ -1807,7 +1902,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
        ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
                ret = btrfs_update_inode_fallback(trans, root, inode);
-               BUG_ON(ret);
+               if (ret) { /* -ENOMEM or corruption */
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
        }
        ret = 0;
 out:
@@ -1826,6 +1924,11 @@ out:
        btrfs_put_ordered_extent(ordered_extent);
 
        return 0;
+out_unlock:
+       unlock_extent_cached(io_tree, ordered_extent->file_offset,
+                            ordered_extent->file_offset +
+                            ordered_extent->len - 1, &cached_state, GFP_NOFS);
+       goto out;
 }
 
 static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
@@ -1907,6 +2010,8 @@ struct delayed_iput {
        struct inode *inode;
 };
 
+/* JDM: If this is fs-wide, why can't we add a pointer to
+ * btrfs_inode instead and avoid the allocation? */
 void btrfs_add_delayed_iput(struct inode *inode)
 {
        struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
@@ -2053,20 +2158,27 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
        /* grab metadata reservation from transaction handle */
        if (reserve) {
                ret = btrfs_orphan_reserve_metadata(trans, inode);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOSPC in reservation; Logic error? JDM */
        }
 
        /* insert an orphan item to track this unlinked/truncated file */
        if (insert >= 1) {
                ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
-               BUG_ON(ret && ret != -EEXIST);
+               if (ret && ret != -EEXIST) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       return ret;
+               }
+               ret = 0;
        }
 
        /* insert an orphan item to track subvolume contains orphan files */
        if (insert >= 2) {
                ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
                                               root->root_key.objectid);
-               BUG_ON(ret);
+               if (ret && ret != -EEXIST) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       return ret;
+               }
        }
        return 0;
 }
@@ -2096,7 +2208,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
 
        if (trans && delete_item) {
                ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
        }
 
        if (release_rsv)
@@ -2230,7 +2342,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                        }
                        ret = btrfs_del_orphan_item(trans, root,
                                                    found_key.objectid);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
                        btrfs_end_transaction(trans, root);
                        continue;
                }
@@ -2612,16 +2724,22 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
                       "inode %llu parent %llu\n", name_len, name,
                       (unsigned long long)ino, (unsigned long long)dir_ino);
+               btrfs_abort_transaction(trans, root, ret);
                goto err;
        }
 
        ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
-       if (ret)
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
                goto err;
+       }
 
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
                                         inode, dir_ino);
-       BUG_ON(ret != 0 && ret != -ENOENT);
+       if (ret != 0 && ret != -ENOENT) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto err;
+       }
 
        ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
                                           dir, index);
@@ -2779,7 +2897,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
                        err = ret;
                        goto out;
                }
-               BUG_ON(ret == 0);
+               BUG_ON(ret == 0); /* Corruption */
                if (check_path_shared(root, path))
                        goto out;
                btrfs_release_path(path);
@@ -2812,7 +2930,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
                err = PTR_ERR(ref);
                goto out;
        }
-       BUG_ON(!ref);
+       BUG_ON(!ref); /* Logic error */
        if (check_path_shared(root, path))
                goto out;
        index = btrfs_inode_ref_index(path->nodes[0], ref);
@@ -2919,23 +3037,42 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
 
        di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
                                   name, name_len, -1);
-       BUG_ON(IS_ERR_OR_NULL(di));
+       if (IS_ERR_OR_NULL(di)) {
+               if (!di)
+                       ret = -ENOENT;
+               else
+                       ret = PTR_ERR(di);
+               goto out;
+       }
 
        leaf = path->nodes[0];
        btrfs_dir_item_key_to_cpu(leaf, di, &key);
        WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
+       }
        btrfs_release_path(path);
 
        ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
                                 dir_ino, &index, name, name_len);
        if (ret < 0) {
-               BUG_ON(ret != -ENOENT);
+               if (ret != -ENOENT) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
                di = btrfs_search_dir_index_item(root, path, dir_ino,
                                                 name, name_len);
-               BUG_ON(IS_ERR_OR_NULL(di));
+               if (IS_ERR_OR_NULL(di)) {
+                       if (!di)
+                               ret = -ENOENT;
+                       else
+                               ret = PTR_ERR(di);
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out;
+               }
 
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
@@ -2945,15 +3082,19 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
        btrfs_release_path(path);
 
        ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
+       }
 
        btrfs_i_size_write(dir, dir->i_size - name_len * 2);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
        ret = btrfs_update_inode(trans, root, dir);
-       BUG_ON(ret);
-
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
+out:
        btrfs_free_path(path);
-       return 0;
+       return ret;
 }
 
 static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
@@ -3212,7 +3353,11 @@ delete:
                                ret = btrfs_del_items(trans, root, path,
                                                pending_del_slot,
                                                pending_del_nr);
-                               BUG_ON(ret);
+                               if (ret) {
+                                       btrfs_abort_transaction(trans,
+                                                               root, ret);
+                                       goto error;
+                               }
                                pending_del_nr = 0;
                        }
                        btrfs_release_path(path);
@@ -3225,8 +3370,10 @@ out:
        if (pending_del_nr) {
                ret = btrfs_del_items(trans, root, path, pending_del_slot,
                                      pending_del_nr);
-               BUG_ON(ret);
+               if (ret)
+                       btrfs_abort_transaction(trans, root, ret);
        }
+error:
        btrfs_free_path(path);
        return err;
 }
@@ -3373,7 +3520,10 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
        while (1) {
                em = btrfs_get_extent(inode, NULL, 0, cur_offset,
                                block_end - cur_offset, 0);
-               BUG_ON(IS_ERR_OR_NULL(em));
+               if (IS_ERR(em)) {
+                       err = PTR_ERR(em);
+                       break;
+               }
                last_byte = min(extent_map_end(em), block_end);
                last_byte = (last_byte + mask) & ~mask;
                if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
@@ -3390,7 +3540,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                                 cur_offset + hole_size,
                                                 &hint_byte, 1);
                        if (err) {
-                               btrfs_update_inode(trans, root, inode);
+                               btrfs_abort_transaction(trans, root, err);
                                btrfs_end_transaction(trans, root);
                                break;
                        }
@@ -3400,7 +3550,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                        0, hole_size, 0, hole_size,
                                        0, 0, 0);
                        if (err) {
-                               btrfs_update_inode(trans, root, inode);
+                               btrfs_abort_transaction(trans, root, err);
                                btrfs_end_transaction(trans, root);
                                break;
                        }
@@ -4581,18 +4731,26 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
                                             parent_ino, index);
        }
 
-       if (ret == 0) {
-               ret = btrfs_insert_dir_item(trans, root, name, name_len,
-                                           parent_inode, &key,
-                                           btrfs_inode_type(inode), index);
-               if (ret)
-                       goto fail_dir_item;
+       /* Nothing to clean up yet */
+       if (ret)
+               return ret;
 
-               btrfs_i_size_write(parent_inode, parent_inode->i_size +
-                                  name_len * 2);
-               parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
-               ret = btrfs_update_inode(trans, root, parent_inode);
+       ret = btrfs_insert_dir_item(trans, root, name, name_len,
+                                   parent_inode, &key,
+                                   btrfs_inode_type(inode), index);
+       if (ret == -EEXIST)
+               goto fail_dir_item;
+       else if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
        }
+
+       btrfs_i_size_write(parent_inode, parent_inode->i_size +
+                          name_len * 2);
+       parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
+       ret = btrfs_update_inode(trans, root, parent_inode);
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
        return ret;
 
 fail_dir_item:
@@ -4806,7 +4964,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        } else {
                struct dentry *parent = dentry->d_parent;
                err = btrfs_update_inode(trans, root, inode);
-               BUG_ON(err);
+               if (err)
+                       goto fail;
                d_instantiate(dentry, inode);
                btrfs_log_new_name(trans, inode, NULL, parent);
        }
@@ -5137,7 +5296,7 @@ again:
                                ret = uncompress_inline(path, inode, page,
                                                        pg_offset,
                                                        extent_offset, item);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM */
                        } else {
                                map = kmap(page);
                                read_extent_buffer(leaf, map + pg_offset, ptr,
@@ -5252,6 +5411,7 @@ out:
                free_extent_map(em);
                return ERR_PTR(err);
        }
+       BUG_ON(!em); /* Error is always set */
        return em;
 }
 
@@ -5868,7 +6028,7 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
        int ret;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        ret = btrfs_csum_one_bio(root, inode, bio, offset, 1);
-       BUG_ON(ret);
+       BUG_ON(ret); /* -ENOMEM */
        return 0;
 }
 
@@ -7068,7 +7228,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!ret)
                        ret = btrfs_update_inode(trans, root, old_inode);
        }
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_fail;
+       }
 
        if (new_inode) {
                new_inode->i_ctime = CURRENT_TIME;
@@ -7086,11 +7249,14 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                                 new_dentry->d_name.name,
                                                 new_dentry->d_name.len);
                }
-               BUG_ON(ret);
-               if (new_inode->i_nlink == 0) {
+               if (!ret && new_inode->i_nlink == 0) {
                        ret = btrfs_orphan_add(trans, new_dentry->d_inode);
                        BUG_ON(ret);
                }
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto out_fail;
+               }
        }
 
        fixup_inode_flags(new_dir, old_inode);
@@ -7098,7 +7264,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        ret = btrfs_add_link(trans, new_dir, old_inode,
                             new_dentry->d_name.name,
                             new_dentry->d_name.len, 0, index);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_fail;
+       }
 
        if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
                struct dentry *parent = new_dentry->d_parent;
@@ -7323,7 +7492,12 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
                                                  ins.offset, ins.offset,
                                                  ins.offset, 0, 0, 0,
                                                  BTRFS_FILE_EXTENT_PREALLOC);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       if (own_trans)
+                               btrfs_end_transaction(trans, root);
+                       break;
+               }
                btrfs_drop_extent_cache(inode, cur_offset,
                                        cur_offset + ins.offset -1, 0);
 
@@ -7345,7 +7519,13 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
                }
 
                ret = btrfs_update_inode(trans, root, inode);
-               BUG_ON(ret);
+
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       if (own_trans)
+                               btrfs_end_transaction(trans, root);
+                       break;
+               }
 
                if (own_trans)
                        btrfs_end_transaction(trans, root);
index de25e4255aeb637287b56fa7fe737f3b78655851..20580920071470168a645db08fe60f84166ad5af 100644 (file)
@@ -425,13 +425,18 @@ static noinline int create_subvol(struct btrfs_root *root,
 
        key.offset = (u64)-1;
        new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
-       BUG_ON(IS_ERR(new_root));
+       if (IS_ERR(new_root)) {
+               btrfs_abort_transaction(trans, root, PTR_ERR(new_root));
+               ret = PTR_ERR(new_root);
+               goto fail;
+       }
 
        btrfs_record_root_in_trans(trans, new_root);
 
        ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
        if (ret) {
                /* We potentially lose an unused inode item here */
+               btrfs_abort_transaction(trans, root, ret);
                goto fail;
        }
 
@@ -439,13 +444,18 @@ static noinline int create_subvol(struct btrfs_root *root,
         * insert the directory item
         */
        ret = btrfs_set_inode_index(dir, &index);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto fail;
+       }
 
        ret = btrfs_insert_dir_item(trans, root,
                                    name, namelen, dir, &key,
                                    BTRFS_FT_DIR, index);
-       if (ret)
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
                goto fail;
+       }
 
        btrfs_i_size_write(dir, dir->i_size + namelen * 2);
        ret = btrfs_update_inode(trans, root, dir);
@@ -1970,7 +1980,11 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                dest->root_key.objectid,
                                dentry->d_name.name,
                                dentry->d_name.len);
-       BUG_ON(ret);
+       if (ret) {
+               err = ret;
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_end_trans;
+       }
 
        btrfs_record_root_in_trans(trans, dest);
 
@@ -1983,11 +1997,16 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                ret = btrfs_insert_orphan_item(trans,
                                        root->fs_info->tree_root,
                                        dest->root_key.objectid);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       err = ret;
+                       goto out_end_trans;
+               }
        }
-
+out_end_trans:
        ret = btrfs_end_transaction(trans, root);
-       BUG_ON(ret);
+       if (ret && !err)
+               err = ret;
        inode->i_flags |= S_DEAD;
 out_up_write:
        up_write(&root->fs_info->subvol_sem);
@@ -2451,11 +2470,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                         new_key.offset,
                                                         new_key.offset + datal,
                                                         &hint_byte, 1);
-                               BUG_ON(ret);
+                               if (ret) {
+                                       btrfs_abort_transaction(trans, root,
+                                                               ret);
+                                       btrfs_end_transaction(trans, root);
+                                       goto out;
+                               }
 
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
-                               BUG_ON(ret);
+                               if (ret) {
+                                       btrfs_abort_transaction(trans, root,
+                                                               ret);
+                                       btrfs_end_transaction(trans, root);
+                                       goto out;
+                               }
 
                                leaf = path->nodes[0];
                                slot = path->slots[0];
@@ -2482,7 +2511,15 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                        btrfs_ino(inode),
                                                        new_key.offset - datao,
                                                        0);
-                                       BUG_ON(ret);
+                                       if (ret) {
+                                               btrfs_abort_transaction(trans,
+                                                                       root,
+                                                                       ret);
+                                               btrfs_end_transaction(trans,
+                                                                     root);
+                                               goto out;
+
+                                       }
                                }
                        } else if (type == BTRFS_FILE_EXTENT_INLINE) {
                                u64 skip = 0;
@@ -2507,11 +2544,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                         new_key.offset,
                                                         new_key.offset + datal,
                                                         &hint_byte, 1);
-                               BUG_ON(ret);
+                               if (ret) {
+                                       btrfs_abort_transaction(trans, root,
+                                                               ret);
+                                       btrfs_end_transaction(trans, root);
+                                       goto out;
+                               }
 
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
-                               BUG_ON(ret);
+                               if (ret) {
+                                       btrfs_abort_transaction(trans, root,
+                                                               ret);
+                                       btrfs_end_transaction(trans, root);
+                                       goto out;
+                               }
 
                                if (skip) {
                                        u32 start =
@@ -2545,8 +2592,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                btrfs_i_size_write(inode, endoff);
 
                        ret = btrfs_update_inode(trans, root, inode);
-                       BUG_ON(ret);
-                       btrfs_end_transaction(trans, root);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_end_transaction(trans, root);
+                               goto out;
+                       }
+                       ret = btrfs_end_transaction(trans, root);
                }
 next:
                btrfs_release_path(path);
index f8be250963a09a283b8ec4ab04bcb1c3a962427e..24cad1695af74790ecc18182db35a0ed5c8cce7a 100644 (file)
@@ -58,7 +58,7 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
                goto out;
-       if (ret) {
+       if (ret) { /* JDM: Really? */
                ret = -ENOENT;
                goto out;
        }
index cba7a0bf3667260278671606cc4dbba8d8675301..017281dbb2a71f6a0c51f4f8cc52cf9e651f2fd0 100644 (file)
@@ -4102,10 +4102,11 @@ out:
 static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
 {
        struct btrfs_trans_handle *trans;
-       int ret;
+       int ret, err;
 
        trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        memset(&root->root_item.drop_progress, 0,
                sizeof(root->root_item.drop_progress));
@@ -4113,11 +4114,11 @@ static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
        btrfs_set_root_refs(&root->root_item, 0);
        ret = btrfs_update_root(trans, root->fs_info->tree_root,
                                &root->root_key, &root->root_item);
-       BUG_ON(ret);
 
-       ret = btrfs_end_transaction(trans, root->fs_info->tree_root);
-       BUG_ON(ret);
-       return 0;
+       err = btrfs_end_transaction(trans, root->fs_info->tree_root);
+       if (err)
+               return err;
+       return ret;
 }
 
 /*
@@ -4185,7 +4186,11 @@ int btrfs_recover_relocation(struct btrfs_root *root)
                                        err = ret;
                                        goto out;
                                }
-                               mark_garbage_root(reloc_root);
+                               ret = mark_garbage_root(reloc_root);
+                               if (ret < 0) {
+                                       err = ret;
+                                       goto out;
+                               }
                        }
                }
 
@@ -4231,14 +4236,19 @@ int btrfs_recover_relocation(struct btrfs_root *root)
 
                fs_root = read_fs_root(root->fs_info,
                                       reloc_root->root_key.offset);
-               BUG_ON(IS_ERR(fs_root));
+               if (IS_ERR(fs_root)) {
+                       err = PTR_ERR(fs_root);
+                       goto out_free;
+               }
 
                err = __add_reloc_root(reloc_root);
-               BUG_ON(err < 0);
+               BUG_ON(err < 0); /* -ENOMEM or logic error */
                fs_root->reloc_root = reloc_root;
        }
 
-       btrfs_commit_transaction(trans, rc->extent_root);
+       err = btrfs_commit_transaction(trans, rc->extent_root);
+       if (err)
+               goto out_free;
 
        merge_reloc_roots(rc);
 
@@ -4248,7 +4258,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        if (IS_ERR(trans))
                err = PTR_ERR(trans);
        else
-               btrfs_commit_transaction(trans, rc->extent_root);
+               err = btrfs_commit_transaction(trans, rc->extent_root);
 out_free:
        kfree(rc);
 out:
@@ -4297,6 +4307,8 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
        disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
        ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
                                       disk_bytenr + len - 1, &list, 0);
+       if (ret)
+               goto out;
 
        while (!list_empty(&list)) {
                sums = list_entry(list.next, struct btrfs_ordered_sum, list);
@@ -4314,6 +4326,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
 
                btrfs_add_ordered_sum(inode, ordered, sums);
        }
+out:
        btrfs_put_ordered_extent(ordered);
        return ret;
 }
index 1486cf9de1daae2be18cd3780f67600af09706d0..24fb8ce4e071091ace14af9db4f784eb6f0ea3d9 100644 (file)
@@ -97,8 +97,10 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
                return -ENOMEM;
 
        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-       if (ret < 0)
+       if (ret < 0) {
+               btrfs_abort_transaction(trans, root, ret);
                goto out;
+       }
 
        if (ret != 0) {
                btrfs_print_leaf(root, path->nodes[0]);
@@ -383,6 +385,8 @@ int btrfs_find_root_ref(struct btrfs_root *tree_root,
  *
  * For a back ref the root_id is the id of the subvol or snapshot and
  * ref_id is the id of the tree referencing it.
+ *
+ * Will return 0, -ENOMEM, or anything from the CoW path
  */
 int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
                       struct btrfs_root *tree_root,
@@ -406,7 +410,11 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
 again:
        ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
                                      sizeof(*ref) + name_len);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, tree_root, ret);
+               btrfs_free_path(path);
+               return ret;
+       }
 
        leaf = path->nodes[0];
        ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
index 794cbb52f3087d3c1cee9d844e919465e801a24a..0209d8a9ae39904cbbfb1e0c832214b9b48cde12 100644 (file)
@@ -1505,6 +1505,9 @@ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
        struct btrfs_device *device = sdev->dev;
        struct btrfs_root *root = device->dev_root;
 
+       if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+               return -EIO;
+
        gen = root->fs_info->last_trans_committed;
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
index 0517bd70b04c961951d5875c30766fa65c9f3b95..9db64165123a5ca3f11b1740fa462198fe724edb 100644 (file)
@@ -216,7 +216,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root, const char *function,
                               unsigned int line, int errno)
 {
-       WARN_ON_ONCE(1);
+       WARN_ONCE(1, KERN_DEBUG "btrfs: Transaction aborted");
        trans->aborted = errno;
        /* Nothing used. The other threads that have joined this
         * transaction may be able to continue. */
index 5a4999aa8fef00d50b5d1d1d23e3bfd89b6fc6d7..63f835aa9788168bb4ed8877dd858f64d01262d5 100644 (file)
@@ -949,18 +949,19 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                dentry->d_name.name, dentry->d_name.len,
                                parent_inode, &key,
                                BTRFS_FT_DIR, index);
-       if (ret) {
+       if (ret == -EEXIST) {
                pending->error = -EEXIST;
                dput(parent);
                goto fail;
-       } else if (ret)
-               goto abort_trans;
+       } else if (ret) {
+               goto abort_trans_dput;
+       }
 
        btrfs_i_size_write(parent_inode, parent_inode->i_size +
                                         dentry->d_name.len * 2);
        ret = btrfs_update_inode(trans, parent_root, parent_inode);
        if (ret)
-               goto abort_trans;
+               goto abort_trans_dput;
 
        /*
         * pull in the delayed directory update
@@ -969,8 +970,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
         * snapshot
         */
        ret = btrfs_run_delayed_items(trans, root);
-       if (ret) /* Transaction aborted */
+       if (ret) { /* Transaction aborted */
+               dput(parent);
                goto fail;
+       }
 
        record_root_in_trans(trans, root);
        btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
@@ -986,17 +989,20 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 
        old = btrfs_lock_root_node(root);
        ret = btrfs_cow_block(trans, root, old, NULL, 0, &old);
-       if (ret)
-               goto abort_trans;
+       if (ret) {
+               btrfs_tree_unlock(old);
+               free_extent_buffer(old);
+               goto abort_trans_dput;
+       }
 
        btrfs_set_lock_blocking(old);
 
        ret = btrfs_copy_root(trans, root, old, &tmp, objectid);
-       if (ret)
-               goto abort_trans;
-
+       /* clean up in any case */
        btrfs_tree_unlock(old);
        free_extent_buffer(old);
+       if (ret)
+               goto abort_trans_dput;
 
        /* see comments in should_cow_block() */
        root->force_cow = 1;
@@ -1009,7 +1015,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_tree_unlock(tmp);
        free_extent_buffer(tmp);
        if (ret)
-               goto abort_trans;
+               goto abort_trans_dput;
 
        /*
         * insert root back/forward references
@@ -1018,14 +1024,16 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                 parent_root->root_key.objectid,
                                 btrfs_ino(parent_inode), index,
                                 dentry->d_name.name, dentry->d_name.len);
+       dput(parent);
        if (ret)
                goto fail;
-       dput(parent);
 
        key.offset = (u64)-1;
        pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
-       if (IS_ERR(pending->snap))
+       if (IS_ERR(pending->snap)) {
+               ret = PTR_ERR(pending->snap);
                goto abort_trans;
+       }
 
        ret = btrfs_reloc_post_snapshot(trans, pending);
        if (ret)
@@ -1037,6 +1045,8 @@ fail:
        btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
        return ret;
 
+abort_trans_dput:
+       dput(parent);
 abort_trans:
        btrfs_abort_transaction(trans, root, ret);
        goto fail;
index 37b52b8c67278ee848866a8cf5e028500d7ed43b..d017283ae6f56fa8ea0ba1eeaa04077d443eb0fb 100644 (file)
@@ -1761,7 +1761,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                        BTRFS_TREE_LOG_OBJECTID);
                                ret = btrfs_free_and_pin_reserved_extent(root,
                                                         bytenr, blocksize);
-                               BUG_ON(ret);
+                               BUG_ON(ret); /* -ENOMEM or logic errors */
                        }
                        free_extent_buffer(next);
                        continue;
@@ -1869,20 +1869,26 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                wret = walk_down_log_tree(trans, log, path, &level, wc);
                if (wret > 0)
                        break;
-               if (wret < 0)
+               if (wret < 0) {
                        ret = wret;
+                       goto out;
+               }
 
                wret = walk_up_log_tree(trans, log, path, &level, wc);
                if (wret > 0)
                        break;
-               if (wret < 0)
+               if (wret < 0) {
                        ret = wret;
+                       goto out;
+               }
        }
 
        /* was the root node processed? if not, catch it here */
        if (path->nodes[orig_level]) {
-               wc->process_func(log, path->nodes[orig_level], wc,
+               ret = wc->process_func(log, path->nodes[orig_level], wc,
                         btrfs_header_generation(path->nodes[orig_level]));
+               if (ret)
+                       goto out;
                if (wc->free) {
                        struct extent_buffer *next;
 
@@ -1898,10 +1904,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                                BTRFS_TREE_LOG_OBJECTID);
                        ret = btrfs_free_and_pin_reserved_extent(log, next->start,
                                                         next->len);
-                       BUG_ON(ret);
+                       BUG_ON(ret); /* -ENOMEM or logic errors */
                }
        }
 
+out:
        for (i = 0; i <= orig_level; i++) {
                if (path->nodes[i]) {
                        free_extent_buffer(path->nodes[i]);
@@ -2043,7 +2050,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
         * wait for them until later.
         */
        ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               mutex_unlock(&root->log_mutex);
+               goto out;
+       }
 
        btrfs_set_root_node(&log->root_item, log->node);
 
@@ -2074,7 +2085,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        }
 
        if (ret) {
-               BUG_ON(ret != -ENOSPC);
+               if (ret != -ENOSPC) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       mutex_unlock(&log_root_tree->log_mutex);
+                       goto out;
+               }
                root->fs_info->last_trans_log_full_commit = trans->transid;
                btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
                mutex_unlock(&log_root_tree->log_mutex);
@@ -2114,7 +2129,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
                                &log_root_tree->dirty_log_pages,
                                EXTENT_DIRTY | EXTENT_NEW);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               mutex_unlock(&log_root_tree->log_mutex);
+               goto out_wake_log_root;
+       }
        btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
 
        btrfs_set_super_log_root(root->fs_info->super_for_commit,
@@ -2323,7 +2342,9 @@ out_unlock:
        if (ret == -ENOSPC) {
                root->fs_info->last_trans_log_full_commit = trans->transid;
                ret = 0;
-       }
+       } else if (ret < 0)
+               btrfs_abort_transaction(trans, root, ret);
+
        btrfs_end_log_trans(root);
 
        return err;
@@ -2354,7 +2375,8 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
        if (ret == -ENOSPC) {
                root->fs_info->last_trans_log_full_commit = trans->transid;
                ret = 0;
-       }
+       } else if (ret < 0 && ret != -ENOENT)
+               btrfs_abort_transaction(trans, root, ret);
        btrfs_end_log_trans(root);
 
        return ret;
@@ -3166,13 +3188,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
        fs_info->log_root_recovering = 1;
 
        trans = btrfs_start_transaction(fs_info->tree_root, 0);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto error;
+       }
 
        wc.trans = trans;
        wc.pin = 1;
 
        ret = walk_log_tree(trans, log_root_tree, &wc);
-       BUG_ON(ret);
+       if (ret) {
+               btrfs_error(fs_info, ret, "Failed to pin buffers while "
+                           "recovering log root tree.");
+               goto error;
+       }
 
 again:
        key.objectid = BTRFS_TREE_LOG_OBJECTID;
@@ -3181,8 +3210,12 @@ again:
 
        while (1) {
                ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
-               if (ret < 0)
-                       break;
+
+               if (ret < 0) {
+                       btrfs_error(fs_info, ret,
+                                   "Couldn't find tree log root.");
+                       goto error;
+               }
                if (ret > 0) {
                        if (path->slots[0] == 0)
                                break;
@@ -3196,14 +3229,24 @@ again:
 
                log = btrfs_read_fs_root_no_radix(log_root_tree,
                                                  &found_key);
-               BUG_ON(IS_ERR(log));
+               if (IS_ERR(log)) {
+                       ret = PTR_ERR(log);
+                       btrfs_error(fs_info, ret,
+                                   "Couldn't read tree log root.");
+                       goto error;
+               }
 
                tmp_key.objectid = found_key.offset;
                tmp_key.type = BTRFS_ROOT_ITEM_KEY;
                tmp_key.offset = (u64)-1;
 
                wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
-               BUG_ON(IS_ERR_OR_NULL(wc.replay_dest));
+               if (IS_ERR(wc.replay_dest)) {
+                       ret = PTR_ERR(wc.replay_dest);
+                       btrfs_error(fs_info, ret, "Couldn't read target root "
+                                   "for tree log recovery.");
+                       goto error;
+               }
 
                wc.replay_dest->log_root = log;
                btrfs_record_root_in_trans(trans, wc.replay_dest);
@@ -3251,6 +3294,10 @@ again:
 
        kfree(log_root_tree);
        return 0;
+
+error:
+       btrfs_free_path(path);
+       return ret;
 }
 
 /*
index 394bf15ea18c938f4840f53c4b5d0228bb1470c1..57305e88ea827b4bc65e47bc13787bfa70b40054 100644 (file)
@@ -549,10 +549,10 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                        fs_devices->num_can_discard--;
 
                new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
-               BUG_ON(!new_device);
+               BUG_ON(!new_device); /* -ENOMEM */
                memcpy(new_device, device, sizeof(*new_device));
                new_device->name = kstrdup(device->name, GFP_NOFS);
-               BUG_ON(device->name && !new_device->name);
+               BUG_ON(device->name && !new_device->name); /* -ENOMEM */
                new_device->bdev = NULL;
                new_device->writeable = 0;
                new_device->in_fs_metadata = 0;
@@ -1036,8 +1036,10 @@ again:
                leaf = path->nodes[0];
                extent = btrfs_item_ptr(leaf, path->slots[0],
                                        struct btrfs_dev_extent);
+       } else {
+               btrfs_error(root->fs_info, ret, "Slot search failed");
+               goto out;
        }
-       BUG_ON(ret);
 
        if (device->bytes_used > 0) {
                u64 len = btrfs_dev_extent_length(leaf, extent);
@@ -1047,7 +1049,10 @@ again:
                spin_unlock(&root->fs_info->free_chunk_lock);
        }
        ret = btrfs_del_item(trans, root, path);
-
+       if (ret) {
+               btrfs_error(root->fs_info, ret,
+                           "Failed to remove dev extent item");
+       }
 out:
        btrfs_free_path(path);
        return ret;
@@ -1117,7 +1122,7 @@ static noinline int find_next_chunk(struct btrfs_root *root,
        if (ret < 0)
                goto error;
 
-       BUG_ON(ret == 0);
+       BUG_ON(ret == 0); /* Corruption */
 
        ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY);
        if (ret) {
@@ -1161,7 +1166,7 @@ static noinline int find_next_devid(struct btrfs_root *root, u64 *objectid)
        if (ret < 0)
                goto error;
 
-       BUG_ON(ret == 0);
+       BUG_ON(ret == 0); /* Corruption */
 
        ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID,
                                  BTRFS_DEV_ITEM_KEY);
@@ -1595,7 +1600,7 @@ next_slot:
                                   (unsigned long)btrfs_device_fsid(dev_item),
                                   BTRFS_UUID_SIZE);
                device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
-               BUG_ON(!device);
+               BUG_ON(!device); /* Logic error */
 
                if (device->fs_devices->seeding) {
                        btrfs_set_device_generation(leaf, dev_item,
@@ -1705,7 +1710,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        if (seeding_dev) {
                sb->s_flags &= ~MS_RDONLY;
                ret = btrfs_prepare_sprout(root);
-               BUG_ON(ret);
+               BUG_ON(ret); /* -ENOMEM */
        }
 
        device->fs_devices = root->fs_info->fs_devices;
@@ -1743,11 +1748,15 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        if (seeding_dev) {
                ret = init_first_rw_device(trans, root, device);
-               BUG_ON(ret);
+               if (ret)
+                       goto error_trans;
                ret = btrfs_finish_sprout(trans, root);
-               BUG_ON(ret);
+               if (ret)
+                       goto error_trans;
        } else {
                ret = btrfs_add_device(trans, root, device);
+               if (ret)
+                       goto error_trans;
        }
 
        /*
@@ -1757,17 +1766,31 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        btrfs_clear_space_info_full(root->fs_info);
 
        unlock_chunks(root);
-       btrfs_commit_transaction(trans, root);
+       ret = btrfs_commit_transaction(trans, root);
 
        if (seeding_dev) {
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
 
+               if (ret) /* transaction commit */
+                       return ret;
+
                ret = btrfs_relocate_sys_chunks(root);
-               BUG_ON(ret);
+               if (ret < 0)
+                       btrfs_error(root->fs_info, ret,
+                                   "Failed to relocate sys chunks after "
+                                   "device initialization. This can be fixed "
+                                   "using the \"btrfs balance\" command.");
        }
 
        return ret;
+
+error_trans:
+       unlock_chunks(root);
+       btrfs_abort_transaction(trans, root, ret);
+       btrfs_end_transaction(trans, root);
+       kfree(device->name);
+       kfree(device);
 error:
        blkdev_put(bdev, FMODE_EXCL);
        if (seeding_dev) {
@@ -1875,10 +1898,20 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
        key.type = BTRFS_CHUNK_ITEM_KEY;
 
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-       BUG_ON(ret);
+       if (ret < 0)
+               goto out;
+       else if (ret > 0) { /* Logic error or corruption */
+               btrfs_error(root->fs_info, -ENOENT,
+                           "Failed lookup while freeing chunk.");
+               ret = -ENOENT;
+               goto out;
+       }
 
        ret = btrfs_del_item(trans, root, path);
-
+       if (ret < 0)
+               btrfs_error(root->fs_info, ret,
+                           "Failed to delete chunk item.");
+out:
        btrfs_free_path(path);
        return ret;
 }
@@ -2040,7 +2073,7 @@ again:
                ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
                if (ret < 0)
                        goto error;
-               BUG_ON(ret == 0);
+               BUG_ON(ret == 0); /* Corruption */
 
                ret = btrfs_previous_item(chunk_root, path, key.objectid,
                                          key.type);
@@ -3334,7 +3367,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        ret = btrfs_make_block_group(trans, extent_root, 0, type,
                                     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                     start, num_bytes);
-       BUG_ON(ret);
+       if (ret)
+               goto error;
 
        for (i = 0; i < map->num_stripes; ++i) {
                struct btrfs_device *device;
@@ -3347,7 +3381,10 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                                info->chunk_root->root_key.objectid,
                                BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                start, dev_offset, stripe_size);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_abort_transaction(trans, extent_root, ret);
+                       goto error;
+               }
        }
 
        kfree(devices_info);
@@ -3465,7 +3502,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
        ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
                                   chunk_size, stripe_size);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
        return 0;
 }
 
@@ -3497,7 +3535,8 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
 
        ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size,
                                  &stripe_size, chunk_offset, alloc_profile);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        sys_chunk_offset = chunk_offset + chunk_size;
 
@@ -3508,10 +3547,12 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
        ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
                                  &sys_chunk_size, &sys_stripe_size,
                                  sys_chunk_offset, alloc_profile);
-       BUG_ON(ret);
+       if (ret)
+               goto abort;
 
        ret = btrfs_add_device(trans, fs_info->chunk_root, device);
-       BUG_ON(ret);
+       if (ret)
+               goto abort;
 
        /*
         * Modifying chunk tree needs allocating new blocks from both
@@ -3521,13 +3562,20 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
         */
        ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
                                   chunk_size, stripe_size);
-       BUG_ON(ret);
+       if (ret)
+               goto abort;
 
        ret = __finish_chunk_alloc(trans, extent_root, sys_map,
                                   sys_chunk_offset, sys_chunk_size,
                                   sys_stripe_size);
-       BUG_ON(ret);
+       if (ret)
+               goto abort;
+
        return 0;
+
+abort:
+       btrfs_abort_transaction(trans, root, ret);
+       return ret;
 }
 
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
@@ -3878,7 +3926,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
                do_div(length, map->num_stripes);
 
        buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
-       BUG_ON(!buf);
+       BUG_ON(!buf); /* -ENOMEM */
 
        for (i = 0; i < map->num_stripes; i++) {
                if (devid && map->stripes[i].dev->devid != devid)
@@ -4039,7 +4087,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
 
        ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
                              mirror_num);
-       BUG_ON(ret);
+       if (ret) /* -ENOMEM */
+               return ret;
 
        total_devs = bbio->num_stripes;
        if (map_length < length) {
@@ -4058,7 +4107,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
        while (dev_nr < total_devs) {
                if (dev_nr < total_devs - 1) {
                        bio = bio_clone(first_bio, GFP_NOFS);
-                       BUG_ON(!bio);
+                       BUG_ON(!bio); /* -ENOMEM */
                } else {
                        bio = first_bio;
                }
@@ -4212,7 +4261,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
        write_lock(&map_tree->map_tree.lock);
        ret = add_extent_mapping(&map_tree->map_tree, em);
        write_unlock(&map_tree->map_tree.lock);
-       BUG_ON(ret);
+       BUG_ON(ret); /* Tree corruption */
        free_extent_map(em);
 
        return 0;