Commit 3e1ad54f authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: allocator and tuning

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent be744175
...@@ -255,6 +255,7 @@ struct btrfs_block_group_item { ...@@ -255,6 +255,7 @@ struct btrfs_block_group_item {
struct btrfs_block_group_cache { struct btrfs_block_group_cache {
struct btrfs_key key; struct btrfs_key key;
struct btrfs_block_group_item item; struct btrfs_block_group_item item;
struct radix_tree_root *radix;
u64 first_free; u64 first_free;
u64 last_alloc; u64 last_alloc;
u64 pinned; u64 pinned;
......
...@@ -23,7 +23,7 @@ static struct btrfs_block_group_cache *lookup_block_group(struct ...@@ -23,7 +23,7 @@ static struct btrfs_block_group_cache *lookup_block_group(struct
(void **)&block_group, (void **)&block_group,
blocknr, 1); blocknr, 1);
if (ret) { if (ret) {
if (block_group->key.objectid <= blocknr && blocknr < if (block_group->key.objectid <= blocknr && blocknr <=
block_group->key.objectid + block_group->key.offset) block_group->key.objectid + block_group->key.offset)
return block_group; return block_group;
} }
...@@ -31,11 +31,16 @@ static struct btrfs_block_group_cache *lookup_block_group(struct ...@@ -31,11 +31,16 @@ static struct btrfs_block_group_cache *lookup_block_group(struct
(void **)&block_group, (void **)&block_group,
blocknr, 1); blocknr, 1);
if (ret) { if (ret) {
if (block_group->key.objectid <= blocknr && blocknr < if (block_group->key.objectid <= blocknr && blocknr <=
block_group->key.objectid + block_group->key.offset) block_group->key.objectid + block_group->key.offset)
return block_group; return block_group;
} }
printk("lookup_block_group fails for blocknr %Lu\n", blocknr); WARN_ON(1);
printk("lookup_block_group fails for blocknr %Lu\n", blocknr);
printk("last ret was %d\n", ret);
if (ret) {
printk("last block group was %Lu %Lu\n", block_group->key.objectid, block_group->key.offset);
}
return NULL; return NULL;
} }
...@@ -356,45 +361,20 @@ static int update_block_group(struct btrfs_trans_handle *trans, ...@@ -356,45 +361,20 @@ static int update_block_group(struct btrfs_trans_handle *trans,
{ {
struct btrfs_block_group_cache *cache; struct btrfs_block_group_cache *cache;
struct btrfs_fs_info *info = root->fs_info; struct btrfs_fs_info *info = root->fs_info;
struct radix_tree_root *radix;
u64 total = num; u64 total = num;
u64 old_val; u64 old_val;
u64 block_in_group; u64 block_in_group;
int ret;
if (num != 1)
radix = &info->block_group_data_radix;
else
radix = &info->block_group_radix;
while(total) { while(total) {
ret = radix_tree_gang_lookup(radix, (void **)&cache, cache = lookup_block_group(info, blocknr);
blocknr, 1); if (!cache) {
if (!ret) {
printk(KERN_CRIT "blocknr %Lu lookup failed\n", printk(KERN_CRIT "blocknr %Lu lookup failed\n",
blocknr); blocknr);
return -1; return -1;
} }
block_in_group = blocknr - cache->key.objectid; block_in_group = blocknr - cache->key.objectid;
if (block_in_group > cache->key.offset || cache->key.objectid >
blocknr) {
if (radix == &info->block_group_data_radix)
radix = &info->block_group_radix;
else
radix = &info->block_group_data_radix;
ret = radix_tree_gang_lookup(radix, (void **)&cache,
blocknr, 1);
if (!ret) {
printk(KERN_CRIT "blocknr %Lu lookup failed\n",
blocknr);
return -1;
}
block_in_group = blocknr - cache->key.objectid;
if (block_in_group > cache->key.offset ||
cache->key.objectid > blocknr) {
BUG();
}
}
WARN_ON(block_in_group > cache->key.offset); WARN_ON(block_in_group > cache->key.offset);
radix_tree_tag_set(radix, cache->key.objectid + radix_tree_tag_set(cache->radix, cache->key.objectid +
cache->key.offset - 1, cache->key.offset - 1,
BTRFS_BLOCK_GROUP_DIRTY); BTRFS_BLOCK_GROUP_DIRTY);
...@@ -693,6 +673,8 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -693,6 +673,8 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
num_blocks = 1; num_blocks = 1;
total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3; total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3;
} }
if (search_end == (u64)-1)
search_end = btrfs_super_total_blocks(info->disk_super);
if (search_start) { if (search_start) {
block_group = lookup_block_group(info, search_start); block_group = lookup_block_group(info, search_start);
block_group = btrfs_find_block_group(root, block_group, block_group = btrfs_find_block_group(root, block_group,
...@@ -704,7 +686,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -704,7 +686,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
} }
check_failed: check_failed:
if (block_group->data != data) if (!full_scan && block_group->data != data)
WARN_ON(1); WARN_ON(1);
if (block_group->last_alloc > search_start) if (block_group->last_alloc > search_start)
search_start = block_group->last_alloc; search_start = block_group->last_alloc;
...@@ -734,13 +716,13 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -734,13 +716,13 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
goto error; goto error;
if (!start_found) { if (!start_found) {
ins->objectid = search_start; ins->objectid = search_start;
ins->offset = (u64)-1 - search_start; ins->offset = search_end - search_start;
start_found = 1; start_found = 1;
goto check_pending; goto check_pending;
} }
ins->objectid = last_block > search_start ? ins->objectid = last_block > search_start ?
last_block : search_start; last_block : search_start;
ins->offset = (u64)-1 - ins->objectid; ins->offset = search_end - ins->objectid;
goto check_pending; goto check_pending;
} }
btrfs_disk_key_to_cpu(&key, &l->items[slot].key); btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
...@@ -777,7 +759,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -777,7 +759,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*/ */
btrfs_release_path(root, path); btrfs_release_path(root, path);
BUG_ON(ins->objectid < search_start); BUG_ON(ins->objectid < search_start);
if (ins->objectid >= btrfs_super_total_blocks(info->disk_super)) { if (ins->objectid + num_blocks >= search_end) {
if (full_scan) if (full_scan)
return -ENOSPC; return -ENOSPC;
search_start = orig_search_start; search_start = orig_search_start;
...@@ -840,7 +822,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -840,7 +822,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
return 0; return 0;
new_group: new_group:
if (search_start >= btrfs_super_total_blocks(info->disk_super)) { if (search_start + num_blocks >= search_end) {
search_start = orig_search_start; search_start = orig_search_start;
full_scan = 1; full_scan = 1;
} }
...@@ -900,7 +882,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ...@@ -900,7 +882,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
return ret; return ret;
/* then do prealloc for the extent tree */ /* then do prealloc for the extent tree */
ret = find_free_extent(trans, root, 0, ins->objectid + ins->offset, if (ins->objectid + ins->offset >= search_end)
search_end = ins->objectid - 1;
else
search_start = ins->objectid + ins->offset;
ret = find_free_extent(trans, root, 0, search_start,
search_end, &prealloc_key, 0); search_end, &prealloc_key, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -1198,6 +1185,12 @@ int btrfs_read_block_groups(struct btrfs_root *root) ...@@ -1198,6 +1185,12 @@ int btrfs_read_block_groups(struct btrfs_root *root)
err = -1; err = -1;
break; break;
} }
if (nr & 1)
radix = &info->block_group_data_radix;
else
radix = &info->block_group_radix;
bi = btrfs_item_ptr(leaf, path->slots[0], bi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_block_group_item); struct btrfs_block_group_item);
memcpy(&cache->item, bi, sizeof(*bi)); memcpy(&cache->item, bi, sizeof(*bi));
...@@ -1206,12 +1199,10 @@ int btrfs_read_block_groups(struct btrfs_root *root) ...@@ -1206,12 +1199,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
cache->first_free = cache->key.objectid; cache->first_free = cache->key.objectid;
cache->pinned = 0; cache->pinned = 0;
cache->data = (nr & 1); cache->data = (nr & 1);
cache->radix = radix;
key.objectid = found_key.objectid + found_key.offset; key.objectid = found_key.objectid + found_key.offset;
btrfs_release_path(root, path); btrfs_release_path(root, path);
if (nr & 1)
radix = &info->block_group_data_radix;
else
radix = &info->block_group_radix;
ret = radix_tree_insert(radix, found_key.objectid + ret = radix_tree_insert(radix, found_key.objectid +
found_key.offset - 1, found_key.offset - 1,
(void *)cache); (void *)cache);
......
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