Hi! I''m currently going through the btrfs code in order to understand how it works. I found a lot of places where a function tries to allocate a path and uses BUG_ON() to check if the allocation was successful. I think that one should rather return something like -ENOMEM instead of using BUG_ON(). Here''s an example from btrfs_find_last_root() in root-tree.c: ... path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); ... Since btrfs_alloc_path() reserves its space by calling kmem_cache_zalloc(), the result might be NULL if there isn''t enough memory left. This isn''t really a bug. Even worse, as far as I know, BUG_ON() might be a no-op. In the example above, a NULL pointer would be passed to btrfs_search_slot(). The patch at the end of the mail replaces the call to BUG_ON() with appropriate return statements. As I''m new to kernel development and btrfs, please use the patch with care. I would be glad about any feedback. Note: The return type of btrfs_read_locked_inode() is currently void, so some additional work is required to handle the situation cleanly. Here''s the patch + its description: Btrfs: Return -ENOMEM instead of using BUG_ON() when allocating paths This patch replaces code using BUG_ON() to test if btrfs_alloc_path() was successful with a return statement that lets the function fail with -ENOMEM. Signed-off-by: Andi Drebes <lists-receive@programmierforen.de> --- diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index ec96f3a..d93650f 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -3634,7 +3634,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/disk-io.c b/fs/btrfs/disk-io.c index ac8927b..5e3463f 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1106,11 +1106,19 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, root = kzalloc(sizeof(*root), GFP_NOFS); if (!root) return ERR_PTR(-ENOMEM); + + path = btrfs_alloc_path(); + if(!path) { + kfree(root); + return ERR_PTR(-ENOMEM); + } + if (location->offset == (u64)-1) { ret = find_and_setup_root(tree_root, fs_info, location->objectid, root); if (ret) { kfree(root); + btrfs_free_path(path); return ERR_PTR(ret); } goto out; @@ -1120,8 +1128,6 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, tree_root->sectorsize, tree_root->stripesize, root, fs_info, location->objectid); - path = btrfs_alloc_path(); - BUG_ON(!path); ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); if (ret == 0) { l = path->nodes[0]; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4aedbff..8643f42 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -582,7 +582,9 @@ 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); @@ -4600,7 +4602,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type); path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; path->leave_spinning = 1; ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, @@ -4661,7 +4664,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref); path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; path->leave_spinning = 1; ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, @@ -5380,7 +5384,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref) int level; path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; wc = kzalloc(sizeof(*wc), GFP_NOFS); BUG_ON(!wc); @@ -5542,7 +5547,8 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; wc = kzalloc(sizeof(*wc), GFP_NOFS); BUG_ON(!wc); @@ -6001,7 +6007,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; @@ -7523,6 +7532,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_key key; int ret; + path = btrfs_alloc_path(); + if(!path) + return -ENOMEM; + root = root->fs_info->extent_root; block_group = btrfs_lookup_block_group(root->fs_info, group_start); @@ -7546,9 +7559,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, btrfs_return_cluster_to_free_space(block_group, cluster); spin_unlock(&cluster->refill_lock); - path = btrfs_alloc_path(); - BUG_ON(!path); - spin_lock(&root->fs_info->block_group_cache_lock); rb_erase(&block_group->cache_node, &root->fs_info->block_group_cache_tree); diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 9b99886..1aecfbd 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); @@ -260,7 +262,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; @@ -639,7 +642,9 @@ 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 53fb1c9..8a4b7cd 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -296,13 +296,14 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, int recow; int ret; + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + inline_limit = 0; if (drop_cache) btrfs_drop_extent_cache(inode, start, end - 1, 0); - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; while (1) { recow = 0; btrfs_release_path(root, path); @@ -639,10 +640,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, int split_end = 1; int ret; + path = btrfs_alloc_path(); + if(!path) + return -ENOMEM; + btrfs_drop_extent_cache(inode, start, end - 1, 0); - path = btrfs_alloc_path(); - BUG_ON(!path); 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 c56eb59..19ebfa6 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; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ef399a7..f260bb2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -981,7 +981,9 @@ static noinline int run_delalloc_nocow(struct inode *inode, int check_prev = 1; path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; + trans = btrfs_join_transaction(root, 1); BUG_ON(!trans); @@ -1580,7 +1582,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; path->leave_spinning = 1; @@ -2216,7 +2219,8 @@ static void btrfs_read_locked_inode(struct inode *inode) int ret; path = btrfs_alloc_path(); - BUG_ON(!path); + BUG_ON(!path); /* FIXME: handle path == NULL correctly */ + memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); ret = btrfs_lookup_inode(NULL, root, path, &location, 0); @@ -2354,7 +2358,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, int ret; path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; path->leave_spinning = 1; ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location, 1); @@ -2806,10 +2811,13 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, int encoding; u64 mask = root->sectorsize - 1; + path = btrfs_alloc_path(); + if(!path) + return -ENOMEM; + if (root->ref_cows) btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); - path = btrfs_alloc_path(); - BUG_ON(!path); + path->reada = -1; /* FIXME, add redo link to tree so we don''t leak on crash */ @@ -3263,7 +3271,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); @@ -3937,7 +3946,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) @@ -4477,6 +4487,10 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, struct btrfs_trans_handle *trans = NULL; int compressed; + path = btrfs_alloc_path(); + if(!path) + return ERR_PTR(-ENOMEM); + again: read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, start, len); @@ -4503,11 +4517,6 @@ again: em->len = (u64)-1; em->block_len = (u64)-1; - if (!path) { - path = btrfs_alloc_path(); - BUG_ON(!path); - } - ret = btrfs_lookup_file_extent(trans, root, path, objectid, start, trans != NULL); if (ret < 0) { @@ -5502,7 +5511,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, goto out_unlock; path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) { + err = -ENOMEM; + goto out_unlock; + } + key.objectid = inode->i_ino; key.offset = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index cfcc93c..3724c97 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2873,7 +2873,8 @@ static int block_use_full_backref(struct reloc_control *rc, return 1; path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) + return -ENOMEM; key.objectid = eb->start; key.type = BTRFS_EXTENT_ITEM_KEY; @@ -3274,8 +3275,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) return -ENOMEM; path = btrfs_alloc_path(); - if (!path) + if (!path) { + kfree(cluster); return -ENOMEM; + } rc->extents_found = 0; rc->extents_skipped = 0; diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 9351428..5cbcef1 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,9 @@ 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; @@ -140,7 +143,9 @@ 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; @@ -319,7 +324,9 @@ 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; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 78f6254..b8485fb 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1577,7 +1577,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++) { @@ -1840,7 +1841,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; @@ -2977,7 +2979,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); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 20cbd2e..154ba17 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -946,7 +946,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; @@ -1928,7 +1929,10 @@ int btrfs_balance(struct btrfs_root *dev_root) /* step two, relocate all the chunks */ path = btrfs_alloc_path(); - BUG_ON(!path); + if(!path) { + ret = -ENOMEM; + goto error_path; + } key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; key.offset = (u64)-1; @@ -1974,6 +1978,7 @@ int btrfs_balance(struct btrfs_root *dev_root) ret = 0; error: btrfs_free_path(path); +error_path: mutex_unlock(&dev_root->fs_info->volume_mutex); return ret; } -- 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