Jeff Mahoney
2009-Feb-13 22:17 UTC
[PATCH 1/5] Btrfs: fix btrfs_read_block_groups return value
btrfs_read_block_groups returns an ambiguous value. Whether it finds a block group or not, it will return -ENOENT. find_first_block_group will eventually return -ENOENT when it reaches past the last block group, and that is what is returned to the caller. Also, if the kzalloc fails, it will return 0. None of this matters right now because open_ctree() isn''t checking the return value, but I have a patch to handle that as well. This patch returns 0 if find_first_block_group after it has already found at least one block group, and -ENOENT if it has found none. Other errors are reported as expected. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/extent-tree.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0a5d796..777af73 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6125,7 +6125,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) int btrfs_read_block_groups(struct btrfs_root *root) { struct btrfs_path *path; - int ret; + int ret, found = 0; struct btrfs_block_group_cache *cache; struct btrfs_fs_info *info = root->fs_info; struct btrfs_space_info *space_info; @@ -6143,12 +6143,13 @@ int btrfs_read_block_groups(struct btrfs_root *root) while (1) { ret = find_first_block_group(root, path, &key); - if (ret > 0) { + if (ret > 0 || (found && ret == -ENOENT)) { ret = 0; - goto error; + break; } + if (ret != 0) - goto error; + break; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); @@ -6187,9 +6188,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) set_avail_alloc_bits(root->fs_info, cache->flags); if (btrfs_chunk_readonly(root, cache->key.objectid)) set_block_group_readonly(cache); + found = 1; } - ret = 0; -error: btrfs_free_path(path); return ret; } -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
This patch changes start_transaction() to return an ERR_PTR instead of NULL. Things like I/O errors and allocation failures can be handled differently. It also checks every start_transaction call. Where the error can be handled simply, we clean up state and return an error. If the recovery is more involved, we BUG. This isn''t a change in functionality since we''d Oops anyway. The more complex recovery should be done in separate patches, so this is really just to annotate where that needs to happen. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/disk-io.c | 4 +++ fs/btrfs/extent-tree.c | 24 ++++++++++++++---- fs/btrfs/extent_io.c | 18 ++++++++----- fs/btrfs/file.c | 9 ++++--- fs/btrfs/inode.c | 62 ++++++++++++++++++++++++++++++++++++++--------- fs/btrfs/ioctl.c | 34 +++++++++++++++++++++---- fs/btrfs/super.c | 11 +++++++- fs/btrfs/transaction.c | 23 ++++++++++++++++- fs/btrfs/tree-log.c | 4 +++ fs/btrfs/volumes.c | 17 ++++++++++--- 10 files changed, 163 insertions(+), 43 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index adda739..c7d4136 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1492,6 +1492,8 @@ static int transaction_kthread(void *arg) } mutex_unlock(&root->fs_info->trans_mutex); trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + goto sleep; ret = btrfs_commit_transaction(trans, root); sleep: wake_up_process(root->fs_info->cleaner_kthread); @@ -2241,10 +2243,12 @@ int btrfs_commit_super(struct btrfs_root *root) btrfs_clean_old_snapshots(root); mutex_unlock(&root->fs_info->cleaner_mutex); trans = btrfs_start_transaction(root, 1); + BUG_ON(IS_ERR(trans)); ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); /* run commit again to drop the original snapshot */ trans = btrfs_start_transaction(root, 1); + BUG_ON(IS_ERR(trans)); btrfs_commit_transaction(trans, root); ret = btrfs_write_and_wait_transaction(NULL, root); BUG_ON(ret); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 777af73..ad699c2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5276,7 +5276,7 @@ int btrfs_drop_dead_reloc_roots(struct btrfs_root *root) BUG_ON(reloc_root->commit_root != NULL); while (1) { trans = btrfs_join_transaction(root, 1); - BUG_ON(!trans); + BUG_ON(IS_ERR(trans)); mutex_lock(&root->fs_info->drop_mutex); ret = btrfs_drop_snapshot(trans, reloc_root); @@ -5334,7 +5334,7 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root) if (found) { trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + BUG_ON(IS_ERR(trans)); ret = btrfs_commit_transaction(trans, root); BUG_ON(ret); } @@ -5581,7 +5581,8 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root, trans = btrfs_start_transaction(extent_root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) + return PTR_ERR(trans); if (extent_key->objectid == 0) { ret = del_extent_zero(trans, extent_root, path, extent_key); @@ -5761,6 +5762,8 @@ static int __alloc_chunk_for_shrink(struct btrfs_root *root, spin_unlock(&shrink_block_group->lock); trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); spin_lock(&shrink_block_group->lock); new_alloc_flags = update_block_group_flags(root, @@ -5831,7 +5834,8 @@ static noinline struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, return ERR_CAST(root); trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) + return ERR_CAST(trans); err = btrfs_find_free_objectid(trans, root, objectid, &objectid); if (err) @@ -5943,7 +5947,8 @@ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start) reloc_inode = create_reloc_inode(info, block_group); BUG_ON(IS_ERR(reloc_inode)); - __alloc_chunk_for_shrink(root, block_group, 1); + ret = __alloc_chunk_for_shrink(root, block_group, 1); + BUG_ON(ret); set_block_group_readonly(block_group); btrfs_start_delalloc_inodes(info->tree_root); @@ -5958,6 +5963,10 @@ again: cur_byte = key.objectid; trans = btrfs_start_transaction(info->tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } btrfs_commit_transaction(trans, info->tree_root); mutex_lock(&root->fs_info->cleaner_mutex); @@ -6008,7 +6017,8 @@ next: cur_byte = key.objectid + key.offset; btrfs_release_path(root, path); - __alloc_chunk_for_shrink(root, block_group, 0); + ret = __alloc_chunk_for_shrink(root, block_group, 0); + BUG_ON(ret); ret = relocate_one_extent(root, path, &key, block_group, reloc_inode, pass); BUG_ON(ret < 0); @@ -6034,6 +6044,7 @@ next: if (total_found == skipped && pass > 2) { iput(reloc_inode); reloc_inode = create_reloc_inode(info, block_group); + BUG_ON(IS_ERR(reloc_inode)); pass = 0; } goto again; @@ -6044,6 +6055,7 @@ next: /* unpin extents in this range */ trans = btrfs_start_transaction(info->tree_root, 1); + BUG_ON(IS_ERR(trans)); btrfs_commit_transaction(trans, info->tree_root); spin_lock(&block_group->lock); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ebe6b29..b192a15 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1848,10 +1848,11 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, bio_get(bio); - if (tree->ops && tree->ops->submit_bio_hook) - tree->ops->submit_bio_hook(page->mapping->host, rw, bio, - mirror_num, bio_flags); - else + if (tree->ops && tree->ops->submit_bio_hook) { + ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio, + mirror_num, bio_flags); + BUG_ON(ret); + } else submit_bio(rw, bio); if (bio_flagged(bio, BIO_EOPNOTSUPP)) ret = -EOPNOTSUPP; @@ -2174,9 +2175,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, delalloc_start = delalloc_end + 1; continue; } - tree->ops->fill_delalloc(inode, page, delalloc_start, - delalloc_end, &page_started, - &nr_written); + ret = tree->ops->fill_delalloc(inode, page, + delalloc_start, + delalloc_end, + &page_started, + &nr_written); + BUG_ON(ret); delalloc_start = delalloc_end + 1; } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3e8023e..c5419a4 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -129,8 +129,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); trans = btrfs_join_transaction(root, 1); - if (!trans) { - err = -ENOMEM; + if (IS_ERR(trans)) { + err = PTR_ERR(trans); goto out_unlock; } btrfs_set_trans_block_group(trans, inode); @@ -1154,6 +1154,7 @@ out_nolock: if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { trans = btrfs_start_transaction(root, 1); + BUG_ON(IS_ERR(trans)); ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); if (ret == 0) { @@ -1226,8 +1227,8 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) btrfs_ioctl_trans_end(file); trans = btrfs_start_transaction(root, 1); - if (!trans) { - ret = -ENOMEM; + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); goto out; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3cee77a..18a65f6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -429,7 +429,7 @@ again: } if (start == 0) { trans = btrfs_join_transaction(root, 1); - BUG_ON(!trans); + BUG_ON(IS_ERR(trans)); btrfs_set_trans_block_group(trans, inode); /* lets try to make an inline extent */ @@ -588,11 +588,12 @@ static noinline int submit_compressed_extents(struct inode *inode, async_extent->ram_size - 1, GFP_NOFS); /* allocate blocks */ - cow_file_range(inode, async_cow->locked_page, - async_extent->start, - async_extent->start + - async_extent->ram_size - 1, - &page_started, &nr_written, 0); + ret = cow_file_range(inode, async_cow->locked_page, + async_extent->start, + async_extent->start + + async_extent->ram_size - 1, + &page_started, &nr_written, 0); + BUG_ON(ret); /* * if page_started, cow_file_range inserted an @@ -725,7 +726,8 @@ static noinline int cow_file_range(struct inode *inode, int ret = 0; trans = btrfs_join_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) + return PTR_ERR(trans); btrfs_set_trans_block_group(trans, inode); actual_end = min_t(u64, isize, end + 1); @@ -987,7 +989,8 @@ static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, path = btrfs_alloc_path(); BUG_ON(!path); trans = btrfs_join_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) + return PTR_ERR(trans); cow_start = (u64)-1; cur_offset = start; @@ -1954,6 +1957,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) */ if (is_bad_inode(inode)) { trans = btrfs_start_transaction(root, 1); + BUG_ON(IS_ERR(trans)); btrfs_orphan_del(trans, inode); btrfs_end_transaction(trans, root); iput(inode); @@ -2250,6 +2254,10 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) goto fail; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto fail; + } btrfs_set_trans_block_group(trans, dir); ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode, @@ -2289,6 +2297,10 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) goto fail; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto fail; + } btrfs_set_trans_block_group(trans, dir); err = btrfs_orphan_add(trans, inode); @@ -2837,6 +2849,10 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) } trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + err = PTR_ERR(trans); + goto out; + } btrfs_set_trans_block_group(trans, inode); cur_offset = hole_start; @@ -2869,6 +2885,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) } btrfs_end_transaction(trans, root); +out: unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); return err; } @@ -3607,6 +3624,10 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, goto fail; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + err = PTR_ERR(trans); + goto fail; + } btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); @@ -3669,6 +3690,10 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, if (err) goto fail; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + err = PTR_ERR(trans); + goto fail; + } btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); @@ -3741,6 +3766,11 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, goto fail; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + BTRFS_I(dir)->index_cnt = index; + err = PTR_ERR(trans); + goto fail; + } btrfs_set_trans_block_group(trans, dir); atomic_inc(&inode->i_count); @@ -3784,13 +3814,13 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) goto out_unlock; trans = btrfs_start_transaction(root, 1); - btrfs_set_trans_block_group(trans, dir); - if (IS_ERR(trans)) { err = PTR_ERR(trans); goto out_unlock; } + btrfs_set_trans_block_group(trans, dir); + err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); if (err) { err = -ENOSPC; @@ -4400,7 +4430,7 @@ static void btrfs_truncate(struct inode *inode) struct btrfs_root *root = BTRFS_I(inode)->root; int ret; struct btrfs_trans_handle *trans; - unsigned long nr; + unsigned long nr = 0; u64 mask = root->sectorsize - 1; if (!S_ISREG(inode->i_mode)) @@ -4412,6 +4442,8 @@ static void btrfs_truncate(struct inode *inode) btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + return; btrfs_set_trans_block_group(trans, inode); btrfs_i_size_write(inode, inode->i_size); @@ -4636,6 +4668,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_unlock; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_unlock; + } btrfs_set_trans_block_group(trans, new_dir); @@ -4754,6 +4790,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, goto out_fail; trans = btrfs_start_transaction(root, 1); + BUG_ON(IS_ERR(trans)); btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); @@ -4855,7 +4892,8 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end, int ret = 0; trans = btrfs_join_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) + return PTR_ERR(trans); btrfs_set_trans_block_group(trans, inode); while (num_bytes > 0) { diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 988fdc8..4b62868 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -75,7 +75,10 @@ static noinline int create_subvol(struct btrfs_root *root, goto fail_commit; trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto fail_commit; + } ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, 0, &objectid); @@ -174,7 +177,11 @@ static noinline int create_subvol(struct btrfs_root *root, BUG_ON(!new_root); trans = btrfs_start_transaction(new_root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) { + /* JDM: When is all the stuff we just made cleaned up? */ + ret = PTR_ERR(trans); + goto fail_commit; + } ret = btrfs_create_subvol_root(trans, new_root, dentry, new_dirid, BTRFS_I(dir)->block_group); @@ -222,7 +229,12 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, pending_snapshot->name[namelen] = ''\0''; pending_snapshot->dentry = dentry; trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) { + kfree(pending_snapshot->name); + kfree(pending_snapshot); + ret = PTR_ERR(trans); + goto fail_unlock; + } pending_snapshot->root = root; list_add(&pending_snapshot->list, &trans->transaction->pending_snapshots); @@ -537,6 +549,10 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) if (new_size > old_size) { trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_unlock; + } ret = btrfs_grow_device(trans, device, new_size); btrfs_commit_transaction(trans, root); } else { @@ -651,8 +667,9 @@ static int btrfs_ioctl_defrag(struct file *file) ret = -EPERM; goto out; } - btrfs_defrag_root(root, 0); - btrfs_defrag_root(root->fs_info->extent_root, 0); + ret = btrfs_defrag_root(root, 0); + if (!ret) + ret = btrfs_defrag_root(root->fs_info->extent_root, 0); break; case S_IFREG: if (!(file->f_mode & FMODE_WRITE)) { @@ -827,7 +844,12 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, } trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + if (IS_ERR(trans)) { + btrfs_release_path(root, path); + unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); + ret = PTR_ERR(trans); + goto out_unlock; + } /* punch hole in destination first */ btrfs_drop_extents(trans, root, inode, off, off+len, 0, &hint_byte); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 19a4daf..19af4ca 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -380,7 +380,13 @@ int btrfs_sync_fs(struct super_block *sb, int wait) btrfs_wait_ordered_extents(root, 0); trans = btrfs_start_transaction(root, 1); - ret = btrfs_commit_transaction(trans, root); + if (!IS_ERR(trans)) + ret = btrfs_commit_transaction(trans, root); + else + ret = PTR_ERR(trans); + + /* Even if the transaction isn''t committed, sync_supers + * will loop if we don''t clear the dirty flag */ sb->s_dirt = 0; return ret; } @@ -530,7 +536,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) return -EINVAL; ret = btrfs_cleanup_reloc_trees(root); - WARN_ON(ret); + if (ret) + return ret; ret = btrfs_cleanup_fs_roots(root->fs_info); WARN_ON(ret); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4112d53..fa07264 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -51,7 +51,8 @@ static noinline int join_transaction(struct btrfs_root *root) if (!cur_trans) { cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); - BUG_ON(!cur_trans); + if (!cur_trans) + return -ENOMEM; root->fs_info->generation++; root->fs_info->last_alloc = 0; root->fs_info->last_data_alloc = 0; @@ -167,12 +168,18 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); int ret; + if (!h) + return ERR_PTR(-ENOMEM); + mutex_lock(&root->fs_info->trans_mutex); if (!root->fs_info->log_root_recovering && ((wait == 1 && !root->fs_info->open_ioctl_trans) || wait == 2)) wait_current_trans(root); ret = join_transaction(root); - BUG_ON(ret); + if (ret) { + h = ERR_PTR(ret); + goto out; + } btrfs_record_root_in_trans(root); h->transid = root->fs_info->running_transaction->transid; @@ -183,6 +190,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, h->alloc_exclude_nr = 0; h->alloc_exclude_start = 0; root->fs_info->running_transaction->use_count++; +out: mutex_unlock(&root->fs_info->trans_mutex); return h; } @@ -616,6 +624,8 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) if (root->defrag_running) return 0; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); while (1) { root->defrag_running = 1; ret = btrfs_defrag_leaves(trans, root, cacheonly); @@ -625,6 +635,11 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) cond_resched(); trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + root->defrag_running = 0; + smp_mb(); + return PTR_ERR(trans); + } if (root->fs_info->closing || ret != -EAGAIN) break; } @@ -662,6 +677,10 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, while (1) { trans = btrfs_start_transaction(tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + break; + } mutex_lock(&root->fs_info->drop_mutex); ret = btrfs_drop_snapshot(trans, dirty->root); if (ret != -EAGAIN) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9c462fb..b161e63 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2793,6 +2793,10 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) BUG_ON(!path); trans = btrfs_start_transaction(fs_info->tree_root, 1); + if (IS_ERR(trans)) { + btrfs_free_path(path); + return PTR_ERR(trans); + } wc.trans = trans; wc.pin = 1; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1316139..1b35ae0 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -951,6 +951,10 @@ static int btrfs_rm_dev_item(struct btrfs_root *root, return -ENOMEM; trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + btrfs_free_path(path); + return PTR_ERR(trans); + } key.objectid = BTRFS_DEV_ITEMS_OBJECTID; key.type = BTRFS_DEV_ITEM_KEY; key.offset = device->devid; @@ -1324,6 +1328,11 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) } trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + kfree(device); + ret = PTR_ERR(trans); + goto error; + } lock_chunks(root); device->barriers = 1; @@ -1569,7 +1578,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, BUG_ON(ret); trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + BUG_ON(IS_ERR(trans)); lock_chunks(root); @@ -1725,7 +1734,7 @@ int btrfs_balance(struct btrfs_root *dev_root) BUG_ON(ret); trans = btrfs_start_transaction(dev_root, 1); - BUG_ON(!trans); + BUG_ON(IS_ERR(trans)); ret = btrfs_grow_device(trans, device, old_size); BUG_ON(ret); @@ -1816,8 +1825,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) return -ENOMEM; trans = btrfs_start_transaction(root, 1); - if (!trans) { - ret = -ENOMEM; + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); goto done; } -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
This patch checks the returns from btrfs_path_alloc, and acts accordingly. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/acl.c | 3 ++ fs/btrfs/compression.c | 11 ++++-- fs/btrfs/ctree.c | 13 ++++++-- fs/btrfs/dir-item.c | 4 ++ fs/btrfs/disk-io.c | 9 ++++- fs/btrfs/export.c | 2 + fs/btrfs/extent-tree.c | 73 ++++++++++++++++++++++++++++++++++------------- fs/btrfs/file-item.c | 15 ++++++++-- fs/btrfs/file.c | 5 ++- fs/btrfs/inode-map.c | 8 ++++- fs/btrfs/inode.c | 63 +++++++++++++++++++++++----------------- fs/btrfs/ioctl.c | 11 ++++++- fs/btrfs/root-tree.c | 16 ++++++++-- fs/btrfs/transaction.c | 9 ++++- fs/btrfs/tree-log.c | 36 +++++++++++++++++++---- fs/btrfs/volumes.c | 4 ++- 16 files changed, 205 insertions(+), 77 deletions(-) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 1d53b62..fa99211 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -85,6 +85,9 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) btrfs_update_cached_acl(inode, p_acl, acl); } + if (!acl && size < 0 && size != -ENODATA) + acl = ERR_PTR(size); + return acl; } diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index ab07627..3ec7c0b 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -671,8 +671,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, atomic_inc(&cb->pending_bios); if (!btrfs_test_flag(inode, NODATASUM)) { - btrfs_lookup_bio_sums(root, inode, comp_bio, - sums); + ret = btrfs_lookup_bio_sums(root, inode, + comp_bio, sums); + BUG_ON(ret); } sums += (comp_bio->bi_size + root->sectorsize - 1) / root->sectorsize; @@ -697,8 +698,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0); BUG_ON(ret); - if (!btrfs_test_flag(inode, NODATASUM)) - btrfs_lookup_bio_sums(root, inode, comp_bio, sums); + if (!btrfs_test_flag(inode, NODATASUM)) { + ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums); + BUG_ON(ret); + } ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); BUG_ON(ret); diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 42491d7..2259b6d 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -99,8 +99,10 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p, /* this also releases the path */ void btrfs_free_path(struct btrfs_path *p) { - btrfs_release_path(NULL, p); - kmem_cache_free(btrfs_path_cachep, p); + if (p) { + btrfs_release_path(NULL, p); + kmem_cache_free(btrfs_path_cachep, p); + } } /* @@ -113,6 +115,9 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) { int i; + if (!p) + return; + for (i = 0; i < BTRFS_MAX_LEVEL; i++) { p->slots[i] = 0; if (!p->nodes[i]) @@ -3579,7 +3584,9 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root unsigned long ptr; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; + ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); if (!ret) { leaf = path->nodes[0]; diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 926a0b2..2b36b44 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -145,7 +145,11 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root key.objectid = dir; btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); key.offset = btrfs_name_hash(name, name_len); + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + data_size = sizeof(*dir_item) + name_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c7d4136..3e2688b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1111,7 +1111,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, root, fs_info, location->objectid); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) { + ret = -ENOMEM; + goto out; + } ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); if (ret != 0) { if (ret > 0) @@ -1834,7 +1837,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, csum_root->track_dirty = 1; - btrfs_read_block_groups(extent_root); + ret = btrfs_read_block_groups(extent_root); + if (ret) + goto fail_csum_root; fs_info->generation = generation; fs_info->last_trans_committed = generation; diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 85315d2..3d3984b 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -148,6 +148,8 @@ static struct dentry *btrfs_get_parent(struct dentry *child) int ret; path = btrfs_alloc_path(); + if (!path) + return ERR_PTR(-ENOMEM); key.objectid = dir->i_ino; btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ad699c2..ceef5be 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -399,7 +399,8 @@ int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len) struct btrfs_path *path; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; key.objectid = start; key.offset = len; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); @@ -1218,7 +1219,8 @@ static int __btrfs_update_extent_ref(struct btrfs_trans_handle *trans, parent, ref_root, ref_generation, owner_objectid); BUG_ON(ret); - finish_current_insert(trans, extent_root, 0); + ret = finish_current_insert(trans, extent_root, 0); + BUG_ON(ret); del_pending_extents(trans, extent_root, 0); out: btrfs_free_path(path); @@ -1297,7 +1299,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, ref_root, ref_generation, owner_objectid); BUG_ON(ret); - finish_current_insert(trans, root->fs_info->extent_root, 0); + ret = finish_current_insert(trans, root->fs_info->extent_root, 0); + BUG_ON(ret); del_pending_extents(trans, root->fs_info->extent_root, 0); btrfs_free_path(path); @@ -1325,10 +1328,11 @@ int btrfs_extent_post_op(struct btrfs_trans_handle *trans, { u64 start; u64 end; - int ret; while(1) { - finish_current_insert(trans, root->fs_info->extent_root, 1); + int ret = finish_current_insert(trans, + root->fs_info->extent_root, 1); + BUG_ON(ret); del_pending_extents(trans, root->fs_info->extent_root, 1); /* is there more work to do? */ @@ -1357,6 +1361,8 @@ int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans, WARN_ON(num_bytes < root->sectorsize); path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; path->reada = 1; key.objectid = bytenr; key.offset = num_bytes; @@ -1398,6 +1404,9 @@ int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, key.type = BTRFS_EXTENT_ITEM_KEY; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); if (ret < 0) goto out; @@ -1806,7 +1815,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); btrfs_release_path(extent_root, path); fail: - finish_current_insert(trans, extent_root, 0); + pending_ret = finish_current_insert(trans, extent_root, 0); + BUG_ON(pending_ret); pending_ret = del_pending_extents(trans, extent_root, 0); if (ret) return ret; @@ -2013,7 +2023,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, spin_unlock(&space_info->lock); ret = btrfs_alloc_chunk(trans, extent_root, flags); - if (ret) + if (ret == -ENOSPC) space_info->full = 1; out: mutex_unlock(&extent_root->fs_info->chunk_mutex); @@ -2236,6 +2246,8 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, int num_inserts = 0, max_inserts, restart = 0; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; INIT_LIST_HEAD(&insert_list); INIT_LIST_HEAD(&update_list); @@ -2597,7 +2609,8 @@ static int __free_extent(struct btrfs_trans_handle *trans, BUG_ON(ret); } btrfs_free_path(path); - finish_current_insert(trans, extent_root, 0); + ret = finish_current_insert(trans, extent_root, 0); + BUG_ON(ret); return ret; } @@ -2805,8 +2818,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ret = __free_extent(trans, root, bytenr, num_bytes, parent, root_objectid, ref_generation, owner_objectid, pin, pin == 0); + /* JDM: Can this actually handle a failure? */ - finish_current_insert(trans, root->fs_info->extent_root, 0); + pending_ret = finish_current_insert(trans, + root->fs_info->extent_root, 0); + BUG_ON(pending_ret); pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0); return ret ? ret : pending_ret; } @@ -3160,6 +3176,7 @@ again: BTRFS_BLOCK_GROUP_METADATA | (info->metadata_alloc_profile & info->avail_metadata_alloc_bits), 0); + /* JDM: Unhandled error */ } ret = do_chunk_alloc(trans, root->fs_info->extent_root, num_bytes + 2 * 1024 * 1024, data, 0); @@ -3175,8 +3192,9 @@ 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, - num_bytes, data, 1); + ret = do_chunk_alloc(trans, root->fs_info->extent_root, + num_bytes, data, 1); + /* JDM: Lost error */ goto again; } if (ret) { @@ -3317,7 +3335,8 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans, trans->alloc_exclude_start = 0; trans->alloc_exclude_nr = 0; btrfs_free_path(path); - finish_current_insert(trans, extent_root, 0); + pending_ret = finish_current_insert(trans, extent_root, 0); + BUG_ON(pending_ret); pending_ret = del_pending_extents(trans, extent_root, 0); if (ret) @@ -3370,8 +3389,9 @@ int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans, block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); mutex_lock(&block_group->cache_mutex); - cache_block_group(root, block_group); + ret = cache_block_group(root, block_group); mutex_unlock(&block_group->cache_mutex); + BUG_ON(ret); ret = btrfs_remove_free_space(block_group, ins->objectid, ins->offset); @@ -4115,7 +4135,8 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root WARN_ON(!mutex_is_locked(&root->fs_info->drop_mutex)); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; level = btrfs_header_level(root->node); orig_level = level; @@ -4194,7 +4215,8 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, int wret; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; BUG_ON(!btrfs_tree_locked(parent)); parent_level = btrfs_header_level(parent); @@ -4639,7 +4661,10 @@ static noinline int get_new_locations(struct inode *reloc_inode, } path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) { + kfree(exts); + return -ENOMEM; + } cur_pos = extent_key->objectid - offset; last_byte = extent_key->objectid + extent_key->offset; @@ -5262,7 +5287,7 @@ int btrfs_drop_dead_reloc_roots(struct btrfs_root *root) struct btrfs_root *reloc_root; struct btrfs_root *prev_root = NULL; struct list_head dead_roots; - int ret; + int ret = 0; unsigned long nr; INIT_LIST_HEAD(&dead_roots); @@ -5289,6 +5314,7 @@ int btrfs_drop_dead_reloc_roots(struct btrfs_root *root) BUG_ON(ret); btrfs_btree_balance_dirty(root, nr); } + BUG_ON(ret); free_extent_buffer(reloc_root->node); @@ -5778,6 +5804,7 @@ static int __alloc_chunk_for_shrink(struct btrfs_root *root, do_chunk_alloc(trans, root->fs_info->extent_root, calc + 2 * 1024 * 1024, new_alloc_flags, force); + /* JDM: Lost error */ btrfs_end_transaction(trans, root); } else @@ -5894,6 +5921,7 @@ 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); + BUG_ON(ret); while (!list_empty(&list)) { sums = list_entry(list.next, struct btrfs_ordered_sum, list); @@ -5942,7 +5970,8 @@ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start) (unsigned long long)block_group->flags); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; reloc_inode = create_reloc_inode(info, block_group); BUG_ON(IS_ERR(reloc_inode)); @@ -6251,7 +6280,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, sizeof(cache->item)); BUG_ON(ret); - finish_current_insert(trans, extent_root, 0); + ret = finish_current_insert(trans, extent_root, 0); + BUG_ON(ret); ret = del_pending_extents(trans, extent_root, 0); BUG_ON(ret); set_avail_alloc_bits(extent_root->fs_info, type); @@ -6276,7 +6306,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, memcpy(&key, &block_group->key, sizeof(key)); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) { + put_block_group(block_group); + return -ENOMEM; + } spin_lock(&root->fs_info->block_group_cache_lock); rb_erase(&block_group->cache_node, diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 9646524..f2f14f2 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -47,7 +47,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct extent_buffer *leaf; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; + file_key.objectid = objectid; file_key.offset = pos; btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); @@ -166,6 +168,9 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + if (bio->bi_size > PAGE_CACHE_SIZE * 8) path->reada = 2; @@ -259,7 +264,8 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.offset = start; @@ -517,6 +523,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, root = root->fs_info->csum_root; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; while (1) { key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; @@ -637,7 +645,8 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, btrfs_super_csum_size(&root->fs_info->super_copy); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; sector_sum = sums->sums; again: next_offset = (u64)-1; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c5419a4..2ecf07b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -289,6 +289,8 @@ int btrfs_check_file(struct btrfs_root *root, struct inode *inode) u64 extent_end = 0; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; ret = btrfs_lookup_file_extent(NULL, root, path, inode->i_ino, last_offset, 0); while (1) { @@ -748,7 +750,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, btrfs_drop_extent_cache(inode, start, end - 1, 0); path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; again: key.objectid = inode->i_ino; key.type = BTRFS_EXTENT_DATA_KEY; diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index cc7334d..fad09ae 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -30,7 +30,8 @@ int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid) int slot; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; search_key.objectid = BTRFS_LAST_FREE_OBJECTID; search_key.type = -1; @@ -78,7 +79,10 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, return 0; } path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) { + ret = -ENOMEM; + goto error; + } search_start = max(search_start, BTRFS_FIRST_FREE_OBJECTID); search_key.objectid = search_start; search_key.type = 0; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 18a65f6..67caee2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -987,7 +987,8 @@ static int run_delalloc_nocow(struct inode *inode, struct page *locked_page, int check_prev = 1; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; trans = btrfs_join_transaction(root, 1); if (IS_ERR(trans)) return PTR_ERR(trans); @@ -1325,8 +1326,10 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, if (bio_flags & EXTENT_BIO_COMPRESSED) { return btrfs_submit_compressed_read(inode, bio, mirror_num, bio_flags); - } else if (!skip_sum) - btrfs_lookup_bio_sums(root, inode, bio, NULL); + } else if (!skip_sum) { + ret = btrfs_lookup_bio_sums(root, inode, bio, NULL); + BUG_ON(ret); + } goto mapit; } else if (!skip_sum) { /* csum items have already been cloned */ @@ -1352,14 +1355,17 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, struct list_head *list) { struct btrfs_ordered_sum *sum; + int err = 0; btrfs_set_trans_block_group(trans, inode); list_for_each_entry(sum, list, list) { - btrfs_csum_file_blocks(trans, + err = btrfs_csum_file_blocks(trans, BTRFS_I(inode)->root->fs_info->csum_root, sum); + if (err) + break; } - return 0; + return err; } int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end) @@ -1478,7 +1484,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, int ret; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; ret = btrfs_drop_extents(trans, root, inode, file_pos, file_pos + num_bytes, file_pos, &hint); @@ -1571,8 +1578,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ordered_extent->file_offset + ordered_extent->len - 1, GFP_NOFS); nocow: - add_pending_csums(trans, inode, ordered_extent->file_offset, - &ordered_extent->list); + ret = add_pending_csums(trans, inode, ordered_extent->file_offset, + &ordered_extent->list); + BUG_ON(ret); mutex_lock(&BTRFS_I(inode)->extent_mutex); btrfs_ordered_update_i_size(inode, ordered_extent); @@ -2000,7 +2008,10 @@ void btrfs_read_locked_inode(struct inode *inode) int ret; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) { + ret = -ENOMEM; + goto make_bad; + } memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); ret = btrfs_lookup_inode(NULL, root, path, &location, 0); @@ -2128,7 +2139,9 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, int ret; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; + ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location, 1); if (ret) { @@ -2263,7 +2276,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode, dentry->d_name.name, dentry->d_name.len); - if (inode->i_nlink == 0) + if (!ret && inode->i_nlink == 0) /* JDM: Check this */ ret = btrfs_orphan_add(trans, inode); nr = trans->blocks_used; @@ -2535,8 +2548,9 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, if (root->ref_cows) btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; path->reada = -1; - BUG_ON(!path); /* FIXME, add redo link to tree so we don''t leak on crash */ key.objectid = inode->i_ino; @@ -2969,7 +2983,8 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, int ret = 0; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name, namelen, 0); @@ -3452,7 +3467,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, int owner; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return ERR_PTR(-ENOMEM); inode = new_inode(root->fs_info->sb); if (!inode) @@ -3631,10 +3647,8 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); - if (err) { - err = -ENOSPC; + if (err) goto out_unlock; - } inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, @@ -3697,10 +3711,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); - if (err) { - err = -ENOSPC; + if (err) goto out_unlock; - } inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, @@ -3822,10 +3834,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); - if (err) { - err = -ENOSPC; + if (err) goto out_unlock; - } inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, @@ -4453,6 +4463,7 @@ static void btrfs_truncate(struct inode *inode) /* FIXME, add redo link to tree so we don''t leak on crash */ ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, BTRFS_EXTENT_DATA_KEY); + /* JDM: Check error */ btrfs_update_inode(trans, root, inode); ret = btrfs_orphan_del(trans, inode); @@ -4794,10 +4805,8 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, btrfs_set_trans_block_group(trans, dir); err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); - if (err) { - err = -ENOSPC; + if (err) goto out_unlock; - } inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, @@ -4977,7 +4986,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, while (1) { em = btrfs_get_extent(inode, NULL, 0, cur_offset, alloc_end - cur_offset, 0); - BUG_ON(IS_ERR(em) || !em); + BUG_ON(IS_ERR(em)); last_byte = min(extent_map_end(em), alloc_end); last_byte = (last_byte + mask) & ~mask; if (em->block_start == EXTENT_MAP_HOLE) { diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4b62868..11afb1a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -302,11 +302,15 @@ static noinline int btrfs_mksubvol(struct path *parent, char *name, if (snap_src) { struct dentry *dir = dentry->d_parent; struct dentry *test = dir->d_parent; - struct btrfs_path *path = btrfs_alloc_path(); + struct btrfs_path *path; int ret; u64 test_oid; u64 parent_oid = BTRFS_I(dir->d_inode)->root->root_key.objectid; + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + test_oid = snap_src->root_key.objectid; ret = btrfs_find_root_ref(snap_src->fs_info->tree_root, @@ -852,7 +856,10 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, } /* punch hole in destination first */ - btrfs_drop_extents(trans, root, inode, off, off+len, 0, &hint_byte); + ret = btrfs_drop_extents(trans, root, inode, off, off+len, 0, + &hint_byte); + if (ret) + goto out; /* clone data */ key.objectid = src->i_ino; diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index b48650d..1d8669d 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -40,7 +40,8 @@ int btrfs_search_root(struct btrfs_root *root, u64 search_start, search_key.offset = (u64)-1; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; again: ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) @@ -88,7 +89,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, search_key.offset = (u64)-1; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) goto out; @@ -125,7 +127,8 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root unsigned long ptr; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; ret = btrfs_search_slot(trans, root, key, path, 0, 1); if (ret < 0) goto out; @@ -255,7 +258,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *leaf; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) goto out; @@ -283,6 +287,8 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, struct btrfs_path *path; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; key.objectid = root_id; key.type = type; @@ -343,6 +349,8 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; key.objectid = root_id; key.type = type; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index fa07264..508d764 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -433,7 +433,8 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root = root->fs_info->tree_root; btrfs_extent_post_op(trans, root); - btrfs_write_dirty_block_groups(trans, root); + ret = btrfs_write_dirty_block_groups(trans, root); + BUG_ON(ret); btrfs_extent_post_op(trans, root); while (1) { @@ -452,7 +453,8 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, &root->root_key, &root->root_item); BUG_ON(ret); - btrfs_write_dirty_block_groups(trans, root); + ret = btrfs_write_dirty_block_groups(trans, root); + BUG_ON(ret); btrfs_extent_post_op(trans, root); } return 0; @@ -567,6 +569,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, root->fs_info->tree_root, &root->root_key, &root->root_item); + /* JDM: Check error */ continue; } @@ -629,6 +632,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) while (1) { root->defrag_running = 1; ret = btrfs_defrag_leaves(trans, root, cacheonly); + /* JDM: unhandled error */ nr = trans->blocks_used; btrfs_end_transaction(trans, root); btrfs_btree_balance_dirty(info->tree_root, nr); @@ -693,6 +697,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, &dirty->root->root_item); if (err) ret = err; + /* JDM: Lost error */ nr = trans->blocks_used; ret = btrfs_end_transaction(trans, tree_root); BUG_ON(ret); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index b161e63..32704dd 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -512,7 +512,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, path->nodes[0]->start, root->root_key.objectid, trans->transid, key->objectid); + BUG_ON(ret < 0); } else { + BUG_ON(ret < 0); /* * insert the extent pointer in the extent * allocation tree @@ -673,6 +675,9 @@ static noinline int backref_in_log(struct btrfs_root *log, int match = 0; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + ret = btrfs_search_slot(NULL, log, key, path, 0, 0); if (ret != 0) goto out; @@ -800,8 +805,9 @@ conflict_again: (unsigned long)(victim_ref + 1), victim_name_len); - if (!backref_in_log(log, key, victim_name, - victim_name_len)) { + ret = backref_in_log(log, key, victim_name, + victim_name_len); + if (!ret) { btrfs_inc_nlink(inode); btrfs_release_path(root, path); ret = btrfs_unlink_inode(trans, root, dir, @@ -811,6 +817,7 @@ conflict_again: btrfs_release_path(root, path); goto conflict_again; } + BUG_ON(ret < 0); kfree(victim_name); ptr = (unsigned long)(victim_ref + 1) + victim_name_len; } @@ -889,6 +896,8 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, key.offset = (u64)-1; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; while (1) { ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); @@ -1495,7 +1504,8 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, return 0; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; nritems = btrfs_header_nritems(eb); for (i = 0; i < nritems; i++) { @@ -1760,7 +1770,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, int orig_level; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; level = btrfs_header_level(log->node); orig_level = level; @@ -2084,6 +2095,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, log = root->log_root; path = btrfs_alloc_path(); + if (!path) { + mutex_unlock(&BTRFS_I(dir)->log_mutex); + return -ENOMEM; + } + di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, name, name_len, -1); if (di && !IS_ERR(di)) { @@ -2578,7 +2594,13 @@ static int __btrfs_log_inode(struct btrfs_trans_handle *trans, log = root->log_root; path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; dst_path = btrfs_alloc_path(); + if (!dst_path) { + btrfs_free_path(path); + return -ENOMEM; + } min_key.objectid = inode->i_ino; min_key.type = BTRFS_INODE_ITEM_KEY; @@ -2790,7 +2812,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) fs_info->log_root_recovering = 1; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; trans = btrfs_start_transaction(fs_info->tree_root, 1); if (IS_ERR(trans)) { @@ -2801,7 +2824,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) wc.trans = trans; wc.pin = 1; - walk_log_tree(trans, log_root_tree, &wc); + ret = walk_log_tree(trans, log_root_tree, &wc); + BUG_ON(ret); again: key.objectid = BTRFS_TREE_LOG_OBJECTID; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1b35ae0..9bcf290 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -807,7 +807,8 @@ static noinline int find_next_chunk(struct btrfs_root *root, struct btrfs_key found_key; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; key.objectid = objectid; key.offset = (u64)-1; @@ -1381,6 +1382,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) BUG_ON(ret); } else { ret = btrfs_add_device(trans, root, device); + BUG_ON(ret); } unlock_chunks(root); -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Jeff Mahoney
2009-Feb-13 22:17 UTC
[PATCH 4/5] Btrfs: fix up btrfs_start_workers error handling
This patch fixes error handling for worker thread startup. The way btrfs_start_workers handles an error is to stop all existing threads in that pool and return an error. This works fine when we''re mounting, but when we''re looking to grow the thread pool, that''s not what we want to happen. This patch uses a temporary btrfs_workers struct to start up the requested threads and, once they''re all created successfully, splices the idle list into the real struct and updates its count. On failure, the temporary one is torn down so only the threads created during that run are cleaned up. Since they were never added to the worker or idle lists, this should be quick as well. It also handles startup failures during mount. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/async-thread.c | 17 ++++++++++++----- fs/btrfs/disk-io.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index c84ca1f..66def6f 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -259,9 +259,12 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) { struct btrfs_worker_thread *worker; + struct btrfs_workers tmp_workers; int ret = 0; int i; + btrfs_init_workers(&tmp_workers, NULL, num_workers); + for (i = 0; i < num_workers; i++) { worker = kzalloc(sizeof(*worker), GFP_NOFS); if (!worker) { @@ -283,15 +286,19 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) goto fail; } - spin_lock_irq(&workers->lock); - list_add_tail(&worker->worker_list, &workers->idle_list); + list_add_tail(&worker->worker_list, &tmp_workers.idle_list); worker->idle = 1; - workers->num_workers++; - spin_unlock_irq(&workers->lock); + tmp_workers.num_workers++; } + + spin_lock_irq(&workers->lock); + list_splice_init(&tmp_workers.idle_list, &workers->idle_list); + workers->num_workers += tmp_workers.num_workers; + spin_unlock_irq(&workers->lock); + return 0; fail: - btrfs_stop_workers(workers); + btrfs_stop_workers(&tmp_workers); return ret; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3e2688b..d066dc6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1737,17 +1737,41 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->endio_write_workers.idle_thresh = 64; fs_info->endio_meta_write_workers.idle_thresh = 64; - btrfs_start_workers(&fs_info->workers, 1); - btrfs_start_workers(&fs_info->submit_workers, 1); - btrfs_start_workers(&fs_info->delalloc_workers, 1); - btrfs_start_workers(&fs_info->fixup_workers, 1); - btrfs_start_workers(&fs_info->endio_workers, fs_info->thread_pool_size); - btrfs_start_workers(&fs_info->endio_meta_workers, + ret = btrfs_start_workers(&fs_info->workers, 1); + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->submit_workers, 1); + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->delalloc_workers, 1); + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->fixup_workers, 1); + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->endio_workers, + fs_info->thread_pool_size); + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->endio_meta_workers, fs_info->thread_pool_size); - btrfs_start_workers(&fs_info->endio_meta_write_workers, + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->endio_meta_write_workers, fs_info->thread_pool_size); - btrfs_start_workers(&fs_info->endio_write_workers, + if (ret) + goto fail_sb_buffer; + + ret = btrfs_start_workers(&fs_info->endio_write_workers, fs_info->thread_pool_size); + if (ret) + goto fail_sb_buffer; fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Jeff Mahoney
2009-Feb-13 22:17 UTC
[PATCH 5/5] Btrfs: fix potential busy loop in find_worker
When the system fails to allocate a new worker or create a new thread, find_worker can loop indefinitely. It goes into a busy loop trying to create a new thread and won''t return until it is successful. This patch takes an error from btrfs_start_workers to mean that there is a resource shortage and falls back to using the first worker thread in order to make progress. Signed-off-by: Jeff Mahoney <jeffm@suse.com> --- fs/btrfs/async-thread.c | 44 ++++++++++++++++++++++++-------------------- 1 files changed, 24 insertions(+), 20 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 66def6f..b1bfb28 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -344,6 +344,22 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) return worker; } +static struct btrfs_worker_thread *first_worker(struct btrfs_workers *workers) +{ + struct list_head *list = NULL; + + if (!list_empty(&workers->worker_list)) + list = &workers->worker_list; + + if (!list_empty(&workers->idle_list)) + list = &workers->idle_list; + + if (!list) + return NULL; + + return list_first_entry(list, struct btrfs_worker_thread, worker_list); +} + /* * selects a worker thread to take the next job. This will either find * an idle worker, start a new worker up to the max count, or just return @@ -351,37 +367,25 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) */ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) { - struct btrfs_worker_thread *worker; + struct btrfs_worker_thread *worker = NULL; unsigned long flags; + int ret = 0; again: spin_lock_irqsave(&workers->lock, flags); worker = next_worker(workers); - spin_unlock_irqrestore(&workers->lock, flags); - if (!worker) { - spin_lock_irqsave(&workers->lock, flags); - if (workers->num_workers >= workers->max_workers) { - struct list_head *fallback = NULL; - /* - * we have failed to find any workers, just - * return the force one - */ - if (!list_empty(&workers->worker_list)) - fallback = workers->worker_list.next; - if (!list_empty(&workers->idle_list)) - fallback = workers->idle_list.next; - BUG_ON(!fallback); - worker = list_entry(fallback, - struct btrfs_worker_thread, worker_list); - spin_unlock_irqrestore(&workers->lock, flags); - } else { + if (workers->num_workers >= workers->max_workers || ret) + worker = first_worker(workers); + else { spin_unlock_irqrestore(&workers->lock, flags); /* we''re below the limit, start another worker */ - btrfs_start_workers(workers, 1); + ret = btrfs_start_workers(workers, 1); goto again; } } + spin_unlock_irqrestore(&workers->lock, flags); + BUG_ON(!worker); return worker; } -- 1.6.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Jeff Mahoney
2009-Feb-13 22:29 UTC
Re: [PATCH 1/5] Btrfs: fix btrfs_read_block_groups return value
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 BTW Chris, these 5 patches are currently queued up on my git tree: git://jeffreymahoney.com/linux/btrfs-unstable for-mason - -Jeff Jeff Mahoney wrote:> btrfs_read_block_groups returns an ambiguous value. Whether it finds > a block group or not, it will return -ENOENT. find_first_block_group > will eventually return -ENOENT when it reaches past the last block > group, and that is what is returned to the caller. > > Also, if the kzalloc fails, it will return 0. > > None of this matters right now because open_ctree() isn''t checking > the return value, but I have a patch to handle that as well. > > This patch returns 0 if find_first_block_group after it has already > found at least one block group, and -ENOENT if it has found none. Other > errors are reported as expected. > > Signed-off-by: Jeff Mahoney <jeffm@suse.com> > --- > fs/btrfs/extent-tree.c | 12 ++++++------ > 1 files changed, 6 insertions(+), 6 deletions(-) > > diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c > index 0a5d796..777af73 100644 > --- a/fs/btrfs/extent-tree.c > +++ b/fs/btrfs/extent-tree.c > @@ -6125,7 +6125,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) > int btrfs_read_block_groups(struct btrfs_root *root) > { > struct btrfs_path *path; > - int ret; > + int ret, found = 0; > struct btrfs_block_group_cache *cache; > struct btrfs_fs_info *info = root->fs_info; > struct btrfs_space_info *space_info; > @@ -6143,12 +6143,13 @@ int btrfs_read_block_groups(struct btrfs_root *root) > > while (1) { > ret = find_first_block_group(root, path, &key); > - if (ret > 0) { > + if (ret > 0 || (found && ret == -ENOENT)) { > ret = 0; > - goto error; > + break; > } > + > if (ret != 0) > - goto error; > + break; > > leaf = path->nodes[0]; > btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); > @@ -6187,9 +6188,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) > set_avail_alloc_bits(root->fs_info, cache->flags); > if (btrfs_chunk_readonly(root, cache->key.objectid)) > set_block_group_readonly(cache); > + found = 1; > } > - ret = 0; > -error: > btrfs_free_path(path); > return ret; > }- -- Jeff Mahoney SUSE Labs -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkmV9GEACgkQLPWxlyuTD7JhXACfaFLqg8Y7/KUKhaBe157HKdMi UXcAniod+vqSzDqpk5AUu14ppyC5d7mN =TNos -----END PGP SIGNATURE----- -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html