summaryrefslogtreecommitdiff
path: root/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'extent-tree.c')
-rw-r--r--extent-tree.c120
1 files changed, 109 insertions, 11 deletions
diff --git a/extent-tree.c b/extent-tree.c
index a7f04f4a..a13b12ee 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -1624,20 +1624,27 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
u64 super_used, root_used;
u64 search_start = 0;
u64 alloc_profile;
- struct btrfs_fs_info *info = root->fs_info;
- struct btrfs_extent_ops *ops = info->extent_ops;
u32 sizes[2];
+ struct btrfs_fs_info *info = root->fs_info;
struct btrfs_root *extent_root = info->extent_root;
struct btrfs_path *path;
struct btrfs_extent_item *extent_item;
struct btrfs_extent_ref *ref;
struct btrfs_key keys[2];
+ if (info->extent_ops) {
+ struct btrfs_extent_ops *ops = info->extent_ops;
+ ret = ops->alloc_extent(root, num_bytes, hint_byte, ins);
+ BUG_ON(ret);
+ goto found;
+ }
+
if (data) {
alloc_profile = info->avail_data_alloc_bits &
info->data_alloc_profile;
data = BTRFS_BLOCK_GROUP_DATA | alloc_profile;
- } else if (root == info->chunk_root || info->force_system_allocs) {
+ } else if ((info->system_allocs > 0 || root == info->chunk_root) &&
+ info->system_allocs >= 0) {
alloc_profile = info->avail_system_alloc_bits &
info->system_alloc_profile;
data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile;
@@ -1660,15 +1667,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
}
WARN_ON(num_bytes < root->sectorsize);
- if (ops && ops->alloc_extent) {
- ret = ops->alloc_extent(root, num_bytes, hint_byte, ins);
- } else {
- ret = find_free_extent(trans, root, num_bytes, empty_size,
- search_start, search_end, hint_byte,
- ins, trans->alloc_exclude_start,
- trans->alloc_exclude_nr, data);
- }
+ ret = find_free_extent(trans, root, num_bytes, empty_size,
+ search_start, search_end, hint_byte, ins,
+ trans->alloc_exclude_start,
+ trans->alloc_exclude_nr, data);
BUG_ON(ret);
+found:
if (ret)
return ret;
@@ -2331,6 +2335,100 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
return 0;
}
+/*
+ * This is for converter use only.
+ *
+ * In that case, we don't know where are free blocks located.
+ * Therefore all block group cache entries must be setup properly
+ * before doing any block allocation.
+ */
+int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ u64 total_bytes;
+ u64 cur_start;
+ u64 group_type;
+ u64 group_size;
+ u64 group_nr = 0;
+ u64 chunk_objectid;
+ int ret;
+ int bit;
+ struct btrfs_root *extent_root;
+ struct btrfs_block_group_cache *cache;
+ struct extent_io_tree *block_group_cache;
+
+ extent_root = root->fs_info->extent_root;
+ block_group_cache = &root->fs_info->block_group_cache;
+ chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
+ total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
+
+ cur_start = 0;
+ while (cur_start < total_bytes) {
+ if (group_nr == 0) {
+ bit = BLOCK_GROUP_SYSTEM;
+ group_type = BTRFS_BLOCK_GROUP_SYSTEM;
+ } else if (group_nr % 3 == 1) {
+ bit = BLOCK_GROUP_DATA;
+ group_type = BTRFS_BLOCK_GROUP_METADATA;
+ } else {
+ bit = BLOCK_GROUP_METADATA;
+ group_type = BTRFS_BLOCK_GROUP_DATA;
+ }
+ group_nr++;
+
+ if (group_type == BTRFS_BLOCK_GROUP_SYSTEM) {
+ group_size = 32 * 1024 * 1024;
+ } else {
+ group_size = 256 * 1024 * 1024;
+ if (total_bytes - cur_start < group_size * 5 / 4)
+ group_size = total_bytes - cur_start;
+ }
+
+ cache = kzalloc(sizeof(*cache), GFP_NOFS);
+ BUG_ON(!cache);
+
+ cache->key.objectid = cur_start;
+ cache->key.offset = group_size;
+ btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
+
+ btrfs_set_block_group_used(&cache->item, 0);
+ btrfs_set_block_group_chunk_objectid(&cache->item,
+ chunk_objectid);
+ btrfs_set_block_group_flags(&cache->item, group_type);
+
+ cache->flags = group_type;
+
+ ret = update_space_info(root->fs_info, group_type, group_size,
+ 0, &cache->space_info);
+ BUG_ON(ret);
+ set_avail_alloc_bits(extent_root->fs_info, group_type);
+
+ set_extent_bits(block_group_cache, cur_start,
+ cur_start + group_size - 1,
+ bit | EXTENT_LOCKED, GFP_NOFS);
+ set_state_private(block_group_cache, cur_start,
+ (unsigned long)cache);
+ cur_start += group_size;
+ }
+ /* then insert all the items */
+ cur_start = 0;
+ while(cur_start < total_bytes) {
+ cache = btrfs_lookup_block_group(root->fs_info, cur_start);
+ BUG_ON(!cache);
+
+ ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
+ sizeof(cache->item));
+ BUG_ON(ret);
+
+ finish_current_insert(trans, extent_root);
+ ret = del_pending_extents(trans, extent_root);
+ BUG_ON(ret);
+
+ cur_start = cache->key.objectid + cache->key.offset;
+ }
+ return 0;
+}
+
u64 btrfs_hash_extent_ref(u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset)
{