Btrfs: Do more extensive readahead during tree searches
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
committed by
David Woodhouse
parent
3202061128
commit
2cc58cf24f
@@ -43,8 +43,10 @@ struct btrfs_path *btrfs_alloc_path(void)
|
|||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS);
|
path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS);
|
||||||
if (path)
|
if (path) {
|
||||||
btrfs_init_path(path);
|
btrfs_init_path(path);
|
||||||
|
path->reada = 1;
|
||||||
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +161,34 @@ static int close_blocks(u64 blocknr, u64 other)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int should_defrag_leaf(struct buffer_head *bh)
|
||||||
|
{
|
||||||
|
struct btrfs_leaf *leaf = btrfs_buffer_leaf(bh);
|
||||||
|
struct btrfs_disk_key *key;
|
||||||
|
u32 nritems;
|
||||||
|
|
||||||
|
if (buffer_defrag(bh))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nritems = btrfs_header_nritems(&leaf->header);
|
||||||
|
if (nritems == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
key = &leaf->items[0].key;
|
||||||
|
if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
key = &leaf->items[nritems-1].key;
|
||||||
|
if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
|
||||||
|
return 1;
|
||||||
|
if (nritems > 4) {
|
||||||
|
key = &leaf->items[nritems/2].key;
|
||||||
|
if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct buffer_head *parent,
|
struct btrfs_root *root, struct buffer_head *parent,
|
||||||
int cache_only, u64 *last_ret)
|
int cache_only, u64 *last_ret)
|
||||||
@@ -217,7 +247,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
cur_bh = btrfs_find_tree_block(root, blocknr);
|
cur_bh = btrfs_find_tree_block(root, blocknr);
|
||||||
if (!cur_bh || !buffer_uptodate(cur_bh) ||
|
if (!cur_bh || !buffer_uptodate(cur_bh) ||
|
||||||
buffer_locked(cur_bh) || !buffer_defrag(cur_bh)) {
|
buffer_locked(cur_bh) ||
|
||||||
|
(parent_level != 1 && !buffer_defrag(cur_bh)) ||
|
||||||
|
(parent_level == 1 && !should_defrag_leaf(cur_bh))) {
|
||||||
if (cache_only) {
|
if (cache_only) {
|
||||||
brelse(cur_bh);
|
brelse(cur_bh);
|
||||||
continue;
|
continue;
|
||||||
@@ -297,6 +329,7 @@ static int check_node(struct btrfs_root *root, struct btrfs_path *path,
|
|||||||
parent = btrfs_buffer_node(path->nodes[level + 1]);
|
parent = btrfs_buffer_node(path->nodes[level + 1]);
|
||||||
|
|
||||||
slot = path->slots[level];
|
slot = path->slots[level];
|
||||||
|
BUG_ON(!buffer_uptodate(path->nodes[level]));
|
||||||
BUG_ON(nritems == 0);
|
BUG_ON(nritems == 0);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
struct btrfs_disk_key *parent_key;
|
struct btrfs_disk_key *parent_key;
|
||||||
@@ -511,9 +544,6 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
err_on_enospc = 1;
|
err_on_enospc = 1;
|
||||||
|
|
||||||
left_buf = read_node_slot(root, parent_buf, pslot - 1);
|
left_buf = read_node_slot(root, parent_buf, pslot - 1);
|
||||||
right_buf = read_node_slot(root, parent_buf, pslot + 1);
|
|
||||||
|
|
||||||
/* first, try to make some room in the middle buffer */
|
|
||||||
if (left_buf) {
|
if (left_buf) {
|
||||||
wret = btrfs_cow_block(trans, root, left_buf,
|
wret = btrfs_cow_block(trans, root, left_buf,
|
||||||
parent_buf, pslot - 1, &left_buf);
|
parent_buf, pslot - 1, &left_buf);
|
||||||
@@ -521,6 +551,19 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
ret = wret;
|
ret = wret;
|
||||||
goto enospc;
|
goto enospc;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
right_buf = read_node_slot(root, parent_buf, pslot + 1);
|
||||||
|
if (right_buf) {
|
||||||
|
wret = btrfs_cow_block(trans, root, right_buf,
|
||||||
|
parent_buf, pslot + 1, &right_buf);
|
||||||
|
if (wret) {
|
||||||
|
ret = wret;
|
||||||
|
goto enospc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first, try to make some room in the middle buffer */
|
||||||
|
if (left_buf) {
|
||||||
left = btrfs_buffer_node(left_buf);
|
left = btrfs_buffer_node(left_buf);
|
||||||
orig_slot += btrfs_header_nritems(&left->header);
|
orig_slot += btrfs_header_nritems(&left->header);
|
||||||
wret = push_node_left(trans, root, left_buf, mid_buf);
|
wret = push_node_left(trans, root, left_buf, mid_buf);
|
||||||
@@ -534,13 +577,6 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
* then try to empty the right most buffer into the middle
|
* then try to empty the right most buffer into the middle
|
||||||
*/
|
*/
|
||||||
if (right_buf) {
|
if (right_buf) {
|
||||||
wret = btrfs_cow_block(trans, root, right_buf,
|
|
||||||
parent_buf, pslot + 1, &right_buf);
|
|
||||||
if (wret) {
|
|
||||||
ret = wret;
|
|
||||||
goto enospc;
|
|
||||||
}
|
|
||||||
|
|
||||||
right = btrfs_buffer_node(right_buf);
|
right = btrfs_buffer_node(right_buf);
|
||||||
wret = push_node_left(trans, root, mid_buf, right_buf);
|
wret = push_node_left(trans, root, mid_buf, right_buf);
|
||||||
if (wret < 0 && wret != -ENOSPC)
|
if (wret < 0 && wret != -ENOSPC)
|
||||||
@@ -817,7 +853,7 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
|
|||||||
for (i = 0; i < ret; i++) {
|
for (i = 0; i < ret; i++) {
|
||||||
blocknr = gang[i];
|
blocknr = gang[i];
|
||||||
clear_radix_bit(&found, blocknr);
|
clear_radix_bit(&found, blocknr);
|
||||||
if (nread > 32)
|
if (path->reada == 1 && nread > 16)
|
||||||
continue;
|
continue;
|
||||||
if (close_blocks(cluster_start, blocknr)) {
|
if (close_blocks(cluster_start, blocknr)) {
|
||||||
readahead_tree_block(root, blocknr);
|
readahead_tree_block(root, blocknr);
|
||||||
|
@@ -52,7 +52,7 @@ static int cache_block_group(struct btrfs_root *root,
|
|||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
path->reada = 1;
|
path->reada = 2;
|
||||||
key.objectid = block_group->key.objectid;
|
key.objectid = block_group->key.objectid;
|
||||||
key.flags = 0;
|
key.flags = 0;
|
||||||
key.offset = 0;
|
key.offset = 0;
|
||||||
@@ -1015,7 +1015,7 @@ check_failed:
|
|||||||
ins->objectid = search_start;
|
ins->objectid = search_start;
|
||||||
ins->offset = 0;
|
ins->offset = 0;
|
||||||
start_found = 0;
|
start_found = 0;
|
||||||
path->reada = 1;
|
path->reada = 2;
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
|
ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@@ -827,7 +827,7 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||||||
btrfs_set_key_type(&key, key_type);
|
btrfs_set_key_type(&key, key_type);
|
||||||
key.offset = filp->f_pos;
|
key.offset = filp->f_pos;
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
path->reada = 1;
|
path->reada = 2;
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
Reference in New Issue
Block a user