Commit 79787eaa authored by Jeff Mahoney's avatar Jeff Mahoney Committed by David Sterba

btrfs: replace many BUG_ONs with proper error handling

 btrfs currently handles most errors with BUG_ON. This patch is a work-in-
 progress but aims to handle most errors other than internal logic
 errors and ENOMEM more gracefully.

 This iteration prevents most crashes but can run into lockups with
 the page lock on occasion when the timing "works out."
Signed-off-by: default avatarJeff Mahoney <jeffm@suse.com>
parent 49b25e05
......@@ -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;
......
......@@ -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,6 +2713,7 @@ 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 */
if (ret == -ENOSPC)
ret = 1;
goto out;
}
......@@ -4017,7 +4018,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_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);
......
......@@ -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,
......
......@@ -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,
......
......@@ -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,
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 @@ int open_ctree(struct super_block *sb,
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);
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,7 +3407,7 @@ 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,
int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
struct btrfs_root *root)
{
struct rb_node *node;
......@@ -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,
};
......@@ -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;
......
This diff is collapsed.
......@@ -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 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
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 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
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)
......
......@@ -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 {
......
......@@ -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 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
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 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
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 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
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 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
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 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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;
......
......@@ -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 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
*/
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 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
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;
......
......@@ -135,6 +135,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
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,
......
......@@ -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,13 +460,18 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
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);
if (root->cached != BTRFS_CACHE_FINISHED) {
......@@ -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];
......
This diff is collapsed.
......@@ -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);
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);
......
......@@ -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;
}
......
......@@ -4102,10 +4102,11 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
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;
}
......
......@@ -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);
......
......@@ -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++) {
......
......@@ -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. */
......
......@@ -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 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
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;
......
......@@ -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 @@ int btrfs_del_dir_entries_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)
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 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
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 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
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 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
kfree(log_root_tree);
return 0;
error:
btrfs_free_path(path);
return ret;
}
/*
......
......@@ -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 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
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 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
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 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans,
(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 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment