提交 c286ac48 编写于 作者: C Chris Mason

Btrfs: alloc_mutex latency reduction

This releases the alloc_mutex in a few places that hold it for over long
operations.  btrfs_lookup_block_group is changed so that it doesn't need
the mutex at all.
Signed-off-by: NChris Mason <chris.mason@oracle.com>
上级 e34a5b4f
...@@ -483,6 +483,7 @@ struct btrfs_block_group_cache { ...@@ -483,6 +483,7 @@ 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 btrfs_space_info *space_info; struct btrfs_space_info *space_info;
spinlock_t lock;
u64 pinned; u64 pinned;
u64 flags; u64 flags;
int cached; int cached;
......
...@@ -319,7 +319,7 @@ static int noinline find_search_start(struct btrfs_root *root, ...@@ -319,7 +319,7 @@ static int noinline find_search_start(struct btrfs_root *root,
cache = btrfs_lookup_first_block_group(root->fs_info, last); cache = btrfs_lookup_first_block_group(root->fs_info, last);
} }
cache_miss = 0; cache_miss = 0;
cache = __btrfs_find_block_group(root, cache, last, data, 0); cache = btrfs_find_block_group(root, cache, last, data, 0);
if (!cache) if (!cache)
goto no_cache; goto no_cache;
*cache_ret = cache; *cache_ret = cache;
...@@ -379,19 +379,25 @@ __btrfs_find_block_group(struct btrfs_root *root, ...@@ -379,19 +379,25 @@ __btrfs_find_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache *shint; struct btrfs_block_group_cache *shint;
shint = btrfs_lookup_first_block_group(info, search_start); shint = btrfs_lookup_first_block_group(info, search_start);
if (shint && block_group_bits(shint, data) && !shint->ro) { if (shint && block_group_bits(shint, data) && !shint->ro) {
spin_lock(&shint->lock);
used = btrfs_block_group_used(&shint->item); used = btrfs_block_group_used(&shint->item);
if (used + shint->pinned < if (used + shint->pinned <
div_factor(shint->key.offset, factor)) { div_factor(shint->key.offset, factor)) {
spin_unlock(&shint->lock);
return shint; return shint;
} }
spin_unlock(&shint->lock);
} }
} }
if (hint && !hint->ro && block_group_bits(hint, data)) { if (hint && !hint->ro && block_group_bits(hint, data)) {
spin_lock(&hint->lock);
used = btrfs_block_group_used(&hint->item); used = btrfs_block_group_used(&hint->item);
if (used + hint->pinned < if (used + hint->pinned <
div_factor(hint->key.offset, factor)) { div_factor(hint->key.offset, factor)) {
spin_unlock(&hint->lock);
return hint; return hint;
} }
spin_unlock(&hint->lock);
last = hint->key.objectid + hint->key.offset; last = hint->key.objectid + hint->key.offset;
} else { } else {
if (hint) if (hint)
...@@ -413,6 +419,7 @@ __btrfs_find_block_group(struct btrfs_root *root, ...@@ -413,6 +419,7 @@ __btrfs_find_block_group(struct btrfs_root *root,
} }
cache = (struct btrfs_block_group_cache *)(unsigned long)ptr; cache = (struct btrfs_block_group_cache *)(unsigned long)ptr;
spin_lock(&cache->lock);
last = cache->key.objectid + cache->key.offset; last = cache->key.objectid + cache->key.offset;
used = btrfs_block_group_used(&cache->item); used = btrfs_block_group_used(&cache->item);
...@@ -420,9 +427,11 @@ __btrfs_find_block_group(struct btrfs_root *root, ...@@ -420,9 +427,11 @@ __btrfs_find_block_group(struct btrfs_root *root,
free_check = div_factor(cache->key.offset, factor); free_check = div_factor(cache->key.offset, factor);
if (used + cache->pinned < free_check) { if (used + cache->pinned < free_check) {
found_group = cache; found_group = cache;
spin_unlock(&cache->lock);
goto found; goto found;
} }
} }
spin_unlock(&cache->lock);
cond_resched(); cond_resched();
} }
if (!wrapped) { if (!wrapped) {
...@@ -447,9 +456,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -447,9 +456,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
{ {
struct btrfs_block_group_cache *ret; struct btrfs_block_group_cache *ret;
mutex_lock(&root->fs_info->alloc_mutex);
ret = __btrfs_find_block_group(root, hint, search_start, data, owner); ret = __btrfs_find_block_group(root, hint, search_start, data, owner);
mutex_unlock(&root->fs_info->alloc_mutex);
return ret; return ret;
} }
static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation, static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
...@@ -1262,21 +1269,25 @@ static int update_block_group(struct btrfs_trans_handle *trans, ...@@ -1262,21 +1269,25 @@ static int update_block_group(struct btrfs_trans_handle *trans,
set_extent_bits(&info->block_group_cache, start, end, set_extent_bits(&info->block_group_cache, start, end,
BLOCK_GROUP_DIRTY, GFP_NOFS); BLOCK_GROUP_DIRTY, GFP_NOFS);
spin_lock(&cache->lock);
old_val = btrfs_block_group_used(&cache->item); old_val = btrfs_block_group_used(&cache->item);
num_bytes = min(total, cache->key.offset - byte_in_group); num_bytes = min(total, cache->key.offset - byte_in_group);
if (alloc) { if (alloc) {
old_val += num_bytes; old_val += num_bytes;
cache->space_info->bytes_used += num_bytes; cache->space_info->bytes_used += num_bytes;
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
} else { } else {
old_val -= num_bytes; old_val -= num_bytes;
cache->space_info->bytes_used -= num_bytes; cache->space_info->bytes_used -= num_bytes;
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
if (mark_free) { if (mark_free) {
set_extent_dirty(&info->free_space_cache, set_extent_dirty(&info->free_space_cache,
bytenr, bytenr + num_bytes - 1, bytenr, bytenr + num_bytes - 1,
GFP_NOFS); GFP_NOFS);
} }
} }
btrfs_set_block_group_used(&cache->item, old_val);
total -= num_bytes; total -= num_bytes;
bytenr += num_bytes; bytenr += num_bytes;
} }
...@@ -1325,14 +1336,18 @@ static int update_pinned_extents(struct btrfs_root *root, ...@@ -1325,14 +1336,18 @@ static int update_pinned_extents(struct btrfs_root *root,
} }
if (pin) { if (pin) {
if (cache) { if (cache) {
spin_lock(&cache->lock);
cache->pinned += len; cache->pinned += len;
cache->space_info->bytes_pinned += len; cache->space_info->bytes_pinned += len;
spin_unlock(&cache->lock);
} }
fs_info->total_pinned += len; fs_info->total_pinned += len;
} else { } else {
if (cache) { if (cache) {
spin_lock(&cache->lock);
cache->pinned -= len; cache->pinned -= len;
cache->space_info->bytes_pinned -= len; cache->space_info->bytes_pinned -= len;
spin_unlock(&cache->lock);
} }
fs_info->total_pinned -= len; fs_info->total_pinned -= len;
} }
...@@ -1380,6 +1395,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, ...@@ -1380,6 +1395,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
update_pinned_extents(root, start, end + 1 - start, 0); update_pinned_extents(root, start, end + 1 - start, 0);
clear_extent_dirty(unpin, start, end, GFP_NOFS); clear_extent_dirty(unpin, start, end, GFP_NOFS);
set_extent_dirty(free_space_cache, start, end, GFP_NOFS); set_extent_dirty(free_space_cache, start, end, GFP_NOFS);
if (need_resched()) {
mutex_unlock(&root->fs_info->alloc_mutex);
cond_resched();
mutex_lock(&root->fs_info->alloc_mutex);
}
} }
mutex_unlock(&root->fs_info->alloc_mutex); mutex_unlock(&root->fs_info->alloc_mutex);
return 0; return 0;
...@@ -1417,8 +1437,16 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, ...@@ -1417,8 +1437,16 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
&extent_item, sizeof(extent_item)); &extent_item, sizeof(extent_item));
clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED, clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
GFP_NOFS); GFP_NOFS);
eb = read_tree_block(extent_root, ins.objectid, ins.offset,
trans->transid); eb = btrfs_find_tree_block(extent_root, ins.objectid,
ins.offset);
if (!btrfs_buffer_uptodate(eb, trans->transid)) {
mutex_unlock(&extent_root->fs_info->alloc_mutex);
btrfs_read_buffer(eb, trans->transid);
mutex_lock(&extent_root->fs_info->alloc_mutex);
}
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
level = btrfs_header_level(eb); level = btrfs_header_level(eb);
if (level == 0) { if (level == 0) {
...@@ -1437,6 +1465,11 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, ...@@ -1437,6 +1465,11 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
0, level, 0, level,
btrfs_disk_key_objectid(&first)); btrfs_disk_key_objectid(&first));
BUG_ON(err); BUG_ON(err);
if (need_resched()) {
mutex_unlock(&extent_root->fs_info->alloc_mutex);
cond_resched();
mutex_lock(&extent_root->fs_info->alloc_mutex);
}
} }
btrfs_free_path(path); btrfs_free_path(path);
return 0; return 0;
...@@ -1640,15 +1673,28 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct ...@@ -1640,15 +1673,28 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
EXTENT_LOCKED); EXTENT_LOCKED);
if (ret) if (ret)
break; break;
update_pinned_extents(extent_root, start, end + 1 - start, 1);
clear_extent_bits(pending_del, start, end, EXTENT_LOCKED, clear_extent_bits(pending_del, start, end, EXTENT_LOCKED,
GFP_NOFS); GFP_NOFS);
ret = __free_extent(trans, extent_root, if (!test_range_bit(&extent_root->fs_info->extent_ins,
start, end + 1 - start, start, end, EXTENT_LOCKED, 0)) {
extent_root->root_key.objectid, update_pinned_extents(extent_root, start,
0, 0, 0, 0, 0); end + 1 - start, 1);
ret = __free_extent(trans, extent_root,
start, end + 1 - start,
extent_root->root_key.objectid,
0, 0, 0, 0, 0);
} else {
clear_extent_bits(&extent_root->fs_info->extent_ins,
start, end, EXTENT_LOCKED, GFP_NOFS);
}
if (ret) if (ret)
err = ret; err = ret;
if (need_resched()) {
mutex_unlock(&extent_root->fs_info->alloc_mutex);
cond_resched();
mutex_lock(&extent_root->fs_info->alloc_mutex);
}
} }
return err; return err;
} }
...@@ -1768,12 +1814,12 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, ...@@ -1768,12 +1814,12 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
block_group = btrfs_lookup_first_block_group(info, hint_byte); block_group = btrfs_lookup_first_block_group(info, hint_byte);
if (!block_group) if (!block_group)
hint_byte = search_start; hint_byte = search_start;
block_group = __btrfs_find_block_group(root, block_group, block_group = btrfs_find_block_group(root, block_group,
hint_byte, data, 1); hint_byte, data, 1);
if (last_ptr && *last_ptr == 0 && block_group) if (last_ptr && *last_ptr == 0 && block_group)
hint_byte = block_group->key.objectid; hint_byte = block_group->key.objectid;
} else { } else {
block_group = __btrfs_find_block_group(root, block_group = btrfs_find_block_group(root,
trans->block_group, trans->block_group,
search_start, data, 1); search_start, data, 1);
} }
...@@ -1895,7 +1941,7 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, ...@@ -1895,7 +1941,7 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
} }
block_group = btrfs_lookup_first_block_group(info, search_start); block_group = btrfs_lookup_first_block_group(info, search_start);
cond_resched(); cond_resched();
block_group = __btrfs_find_block_group(root, block_group, block_group = btrfs_find_block_group(root, block_group,
search_start, data, 0); search_start, data, 0);
goto check_failed; goto check_failed;
...@@ -3032,11 +3078,14 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root, ...@@ -3032,11 +3078,14 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root,
u64 new_alloc_flags; u64 new_alloc_flags;
u64 calc; u64 calc;
spin_lock(&shrink_block_group->lock);
if (btrfs_block_group_used(&shrink_block_group->item) > 0) { if (btrfs_block_group_used(&shrink_block_group->item) > 0) {
spin_unlock(&shrink_block_group->lock);
mutex_unlock(&root->fs_info->alloc_mutex); mutex_unlock(&root->fs_info->alloc_mutex);
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
mutex_lock(&root->fs_info->alloc_mutex); mutex_lock(&root->fs_info->alloc_mutex);
spin_lock(&shrink_block_group->lock);
new_alloc_flags = update_block_group_flags(root, new_alloc_flags = update_block_group_flags(root,
shrink_block_group->flags); shrink_block_group->flags);
...@@ -3046,13 +3095,16 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root, ...@@ -3046,13 +3095,16 @@ int __alloc_chunk_for_shrink(struct btrfs_root *root,
} else { } else {
calc = shrink_block_group->key.offset; calc = shrink_block_group->key.offset;
} }
spin_unlock(&shrink_block_group->lock);
do_chunk_alloc(trans, root->fs_info->extent_root, do_chunk_alloc(trans, root->fs_info->extent_root,
calc + 2 * 1024 * 1024, new_alloc_flags, force); calc + 2 * 1024 * 1024, new_alloc_flags, force);
mutex_unlock(&root->fs_info->alloc_mutex); mutex_unlock(&root->fs_info->alloc_mutex);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
mutex_lock(&root->fs_info->alloc_mutex); mutex_lock(&root->fs_info->alloc_mutex);
} } else
spin_unlock(&shrink_block_group->lock);
return 0; return 0;
} }
...@@ -3199,6 +3251,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) ...@@ -3199,6 +3251,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
mutex_unlock(&root->fs_info->alloc_mutex); mutex_unlock(&root->fs_info->alloc_mutex);
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
mutex_lock(&root->fs_info->alloc_mutex); mutex_lock(&root->fs_info->alloc_mutex);
memcpy(&key, &shrink_block_group->key, sizeof(key)); memcpy(&key, &shrink_block_group->key, sizeof(key));
...@@ -3316,6 +3369,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) ...@@ -3316,6 +3369,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
break; break;
} }
spin_lock_init(&cache->lock);
read_extent_buffer(leaf, &cache->item, read_extent_buffer(leaf, &cache->item,
btrfs_item_ptr_offset(leaf, path->slots[0]), btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(cache->item)); sizeof(cache->item));
...@@ -3343,10 +3397,12 @@ int btrfs_read_block_groups(struct btrfs_root *root) ...@@ -3343,10 +3397,12 @@ int btrfs_read_block_groups(struct btrfs_root *root)
/* use EXTENT_LOCKED to prevent merging */ /* use EXTENT_LOCKED to prevent merging */
set_extent_bits(block_group_cache, found_key.objectid, set_extent_bits(block_group_cache, found_key.objectid,
found_key.objectid + found_key.offset - 1, found_key.objectid + found_key.offset - 1,
bit | EXTENT_LOCKED, GFP_NOFS); EXTENT_LOCKED, GFP_NOFS);
set_state_private(block_group_cache, found_key.objectid, set_state_private(block_group_cache, found_key.objectid,
(unsigned long)cache); (unsigned long)cache);
set_extent_bits(block_group_cache, found_key.objectid,
found_key.objectid + found_key.offset - 1,
bit | EXTENT_LOCKED, GFP_NOFS);
if (key.objectid >= if (key.objectid >=
btrfs_super_total_bytes(&info->super_copy)) btrfs_super_total_bytes(&info->super_copy))
break; break;
...@@ -3377,6 +3433,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ...@@ -3377,6 +3433,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
BUG_ON(!cache); BUG_ON(!cache);
cache->key.objectid = chunk_offset; cache->key.objectid = chunk_offset;
cache->key.offset = size; cache->key.offset = size;
spin_lock_init(&cache->lock);
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
btrfs_set_block_group_used(&cache->item, bytes_used); btrfs_set_block_group_used(&cache->item, bytes_used);
...@@ -3391,10 +3448,13 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ...@@ -3391,10 +3448,13 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
bit = block_group_state_bits(type); bit = block_group_state_bits(type);
set_extent_bits(block_group_cache, chunk_offset, set_extent_bits(block_group_cache, chunk_offset,
chunk_offset + size - 1, chunk_offset + size - 1,
bit | EXTENT_LOCKED, GFP_NOFS); EXTENT_LOCKED, GFP_NOFS);
set_state_private(block_group_cache, chunk_offset, set_state_private(block_group_cache, chunk_offset,
(unsigned long)cache); (unsigned long)cache);
set_extent_bits(block_group_cache, chunk_offset,
chunk_offset + size - 1,
bit | EXTENT_LOCKED, GFP_NOFS);
ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item, ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
sizeof(cache->item)); sizeof(cache->item));
BUG_ON(ret); BUG_ON(ret);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册