summaryrefslogtreecommitdiff
path: root/fs/btrfs/free-space-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/free-space-tree.c')
-rw-r--r--fs/btrfs/free-space-tree.c92
1 files changed, 72 insertions, 20 deletions
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index ecddfca92b2b..b7a4a6ade30f 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -109,7 +109,7 @@ struct btrfs_free_space_info *btrfs_search_free_space_info(
ret = btrfs_search_slot(trans, root, &key, path, 0, cow);
if (ret < 0)
return ERR_PTR(ret);
- if (ret != 0) {
+ if (unlikely(ret != 0)) {
btrfs_warn(fs_info, "missing free space info for %llu",
block_group->start);
DEBUG_WARN();
@@ -209,7 +209,8 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
u64 bitmap_range, i;
u32 bitmap_size, flags, expected_extent_count;
u32 extent_count = 0;
- int done = 0, nr;
+ bool done = false;
+ int nr;
int ret;
bitmap_size = free_space_bitmap_size(fs_info, block_group->length);
@@ -240,7 +241,7 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
ASSERT(found_key.objectid == block_group->start);
ASSERT(found_key.offset == block_group->length);
- done = 1;
+ done = true;
break;
} else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY) {
u64 first, last;
@@ -259,7 +260,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
- ASSERT(0);
+ btrfs_err(fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ goto out;
}
}
@@ -349,7 +354,8 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
u32 bitmap_size, flags, expected_extent_count;
unsigned long nrbits, start_bit, end_bit;
u32 extent_count = 0;
- int done = 0, nr;
+ bool done = false;
+ int nr;
int ret;
bitmap_size = free_space_bitmap_size(fs_info, block_group->length);
@@ -380,7 +386,7 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
ASSERT(found_key.objectid == block_group->start);
ASSERT(found_key.offset == block_group->length);
- done = 1;
+ done = true;
break;
} else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
unsigned long ptr;
@@ -405,7 +411,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
nr++;
} else {
- ASSERT(0);
+ btrfs_err(fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ goto out;
}
}
@@ -1073,6 +1083,14 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
if (ret)
return ret;
+ extent_root = btrfs_extent_root(trans->fs_info, block_group->start);
+ if (unlikely(!extent_root)) {
+ btrfs_err(trans->fs_info,
+ "missing extent root for block group at offset %llu",
+ block_group->start);
+ return -EUCLEAN;
+ }
+
mutex_lock(&block_group->free_space_lock);
/*
@@ -1086,7 +1104,6 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0;
- extent_root = btrfs_extent_root(trans->fs_info, key.objectid);
ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
if (ret < 0)
goto out_locked;
@@ -1336,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
node = rb_first_cached(&fs_info->block_group_cache_tree);
@@ -1354,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans);
- return ret;
+ goto out_clear;
}
next:
if (btrfs_should_end_transaction(trans)) {
btrfs_end_transaction(trans);
trans = btrfs_start_transaction(free_space_root, 1);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out_clear;
+ }
}
node = rb_next(node);
}
@@ -1373,6 +1392,10 @@ next:
ret = btrfs_commit_transaction(trans);
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
return ret;
+
+out_clear:
+ clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+ return ret;
}
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
@@ -1458,7 +1481,8 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_key key, found_key;
struct extent_buffer *leaf;
u64 start, end;
- int done = 0, nr;
+ bool done = false;
+ int nr;
int ret;
if (!btrfs_fs_compat_ro(trans->fs_info, FREE_SPACE_TREE))
@@ -1499,7 +1523,7 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) {
ASSERT(found_key.objectid == block_group->start);
ASSERT(found_key.offset == block_group->length);
- done = 1;
+ done = true;
nr++;
path->slots[0]--;
break;
@@ -1511,7 +1535,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
- ASSERT(0);
+ btrfs_err(trans->fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ return ret;
}
}
@@ -1526,6 +1554,29 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
return 0;
}
+static int validate_free_space_key(struct btrfs_block_group *block_group,
+ const struct btrfs_key *key, u8 expected_type)
+{
+ const u64 end = btrfs_block_group_end(block_group);
+
+ if (unlikely(key->type != expected_type)) {
+ btrfs_err(block_group->fs_info,
+ "block group %llu has unexpected free space key type %u, expected %u",
+ block_group->start, key->type, expected_type);
+ return -EUCLEAN;
+ }
+
+ if (unlikely(key->objectid + key->offset > end)) {
+ btrfs_err(block_group->fs_info,
+ "block group %llu has invalid free space key (%llu %u %llu)",
+ block_group->start, key->objectid, key->type,
+ key->offset);
+ return -EUCLEAN;
+ }
+
+ return 0;
+}
+
static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
struct btrfs_path *path,
u32 expected_extent_count)
@@ -1557,8 +1608,9 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
if (key.type == BTRFS_FREE_SPACE_INFO_KEY)
break;
- ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY);
- ASSERT(key.objectid < end && key.objectid + key.offset <= end);
+ ret = validate_free_space_key(block_group, &key, BTRFS_FREE_SPACE_BITMAP_KEY);
+ if (unlikely(ret))
+ return ret;
offset = key.objectid;
while (offset < key.objectid + key.offset) {
@@ -1614,7 +1666,6 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl,
struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_root *root;
struct btrfs_key key;
- const u64 end = btrfs_block_group_end(block_group);
u64 total_found = 0;
u32 extent_count = 0;
int ret;
@@ -1635,8 +1686,9 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl,
if (key.type == BTRFS_FREE_SPACE_INFO_KEY)
break;
- ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY);
- ASSERT(key.objectid < end && key.objectid + key.offset <= end);
+ ret = validate_free_space_key(block_group, &key, BTRFS_FREE_SPACE_EXTENT_KEY);
+ if (unlikely(ret))
+ return ret;
ret = btrfs_add_new_free_space(block_group, key.objectid,
key.objectid + key.offset,