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

Btrfs: Fold some btree readahead routines into something more generic.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 9f3a7427
...@@ -639,6 +639,73 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -639,6 +639,73 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
return 1; return 1;
} }
/*
* readahead one full node of leaves
*/
static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
int slot)
{
struct btrfs_node *node;
int i;
u32 nritems;
u64 item_objectid;
u64 blocknr;
u64 search;
u64 cluster_start;
int ret;
int nread = 0;
int direction = path->reada;
struct radix_tree_root found;
unsigned long gang[8];
struct buffer_head *bh;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
search = btrfs_node_blockptr(node, slot);
bh = btrfs_find_tree_block(root, search);
if (bh) {
brelse(bh);
return;
}
init_bit_radix(&found);
nritems = btrfs_header_nritems(&node->header);
for (i = slot; i < nritems; i++) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
blocknr = btrfs_node_blockptr(node, i);
set_radix_bit(&found, blocknr);
}
if (direction > 0) {
cluster_start = search - 4;
if (cluster_start > search)
cluster_start = 0;
} else
cluster_start = search + 4;
while(1) {
ret = find_first_radix_bit(&found, gang, 0, ARRAY_SIZE(gang));
if (!ret)
break;
for (i = 0; i < ret; i++) {
blocknr = gang[i];
clear_radix_bit(&found, blocknr);
if (nread > 64)
continue;
if (direction > 0 && cluster_start <= blocknr &&
cluster_start + 8 > blocknr) {
cluster_start = blocknr;
readahead_tree_block(root, blocknr);
nread++;
} else if (direction < 0 && cluster_start >= blocknr &&
blocknr + 8 > cluster_start) {
cluster_start = blocknr;
readahead_tree_block(root, blocknr);
nread++;
}
}
}
}
/* /*
* look for key in the tree. path is filled in with nodes along the way * look for key in the tree. path is filled in with nodes along the way
* if key is found, we return zero and you can find the item in the leaf * if key is found, we return zero and you can find the item in the leaf
...@@ -660,9 +727,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -660,9 +727,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
struct buffer_head *cow_buf; struct buffer_head *cow_buf;
struct btrfs_node *c; struct btrfs_node *c;
struct btrfs_root_item *root_item = &root->root_item; struct btrfs_root_item *root_item = &root->root_item;
u64 blocknr;
int slot; int slot;
int ret; int ret;
int level; int level;
int should_reada = p->reada;
u8 lowest_level = 0; u8 lowest_level = 0;
if (btrfs_root_refs(root_item) == 0 && root->ref_cows) { if (btrfs_root_refs(root_item) == 0 && root->ref_cows) {
...@@ -728,7 +797,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -728,7 +797,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
/* this is only true while dropping a snapshot */ /* this is only true while dropping a snapshot */
if (level == lowest_level) if (level == lowest_level)
break; break;
blocknr = btrfs_node_blockptr(c, slot);
if (level == 1 && should_reada)
reada_for_search(root, p, slot);
b = read_tree_block(root, btrfs_node_blockptr(c, slot)); b = read_tree_block(root, btrfs_node_blockptr(c, slot));
} else { } else {
struct btrfs_leaf *l = (struct btrfs_leaf *)c; struct btrfs_leaf *l = (struct btrfs_leaf *)c;
p->slots[level] = slot; p->slots[level] = slot;
...@@ -1915,6 +1988,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) ...@@ -1915,6 +1988,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
blocknr = btrfs_node_blockptr(c_node, slot); blocknr = btrfs_node_blockptr(c_node, slot);
if (next) if (next)
btrfs_block_release(root, next); btrfs_block_release(root, next);
if (level == 1 && path->reada)
reada_for_search(root, path, slot);
next = read_tree_block(root, blocknr); next = read_tree_block(root, blocknr);
break; break;
} }
...@@ -1927,6 +2002,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) ...@@ -1927,6 +2002,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
path->slots[level] = 0; path->slots[level] = 0;
if (!level) if (!level)
break; break;
if (level == 1 && path->reada)
reada_for_search(root, path, slot);
next = read_tree_block(root, next = read_tree_block(root,
btrfs_node_blockptr(btrfs_buffer_node(next), 0)); btrfs_node_blockptr(btrfs_buffer_node(next), 0));
} }
......
...@@ -177,6 +177,7 @@ struct btrfs_node { ...@@ -177,6 +177,7 @@ struct btrfs_node {
struct btrfs_path { struct btrfs_path {
struct buffer_head *nodes[BTRFS_MAX_LEVEL]; struct buffer_head *nodes[BTRFS_MAX_LEVEL];
int slots[BTRFS_MAX_LEVEL]; int slots[BTRFS_MAX_LEVEL];
int reada;
}; };
/* /*
......
...@@ -32,33 +32,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct ...@@ -32,33 +32,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
static int del_pending_extents(struct btrfs_trans_handle *trans, struct static int del_pending_extents(struct btrfs_trans_handle *trans, struct
btrfs_root *extent_root); btrfs_root *extent_root);
static void reada_extent_leaves(struct btrfs_root *root,
struct btrfs_path *path, u64 limit)
{
struct btrfs_node *node;
int i;
int nritems;
u64 item_objectid;
u64 blocknr;
int slot;
int ret;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1] + 1;
nritems = btrfs_header_nritems(&node->header);
for (i = slot; i < nritems && i < slot + 8; i++) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid > limit)
break;
blocknr = btrfs_node_blockptr(node, i);
ret = readahead_tree_block(root, blocknr);
if (ret)
break;
}
}
static int cache_block_group(struct btrfs_root *root, static int cache_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache *block_group) struct btrfs_block_group_cache *block_group)
{ {
...@@ -84,6 +57,7 @@ static int cache_block_group(struct btrfs_root *root, ...@@ -84,6 +57,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;
key.objectid = block_group->key.objectid; key.objectid = block_group->key.objectid;
key.flags = 0; key.flags = 0;
key.offset = 0; key.offset = 0;
...@@ -94,12 +68,10 @@ static int cache_block_group(struct btrfs_root *root, ...@@ -94,12 +68,10 @@ static int cache_block_group(struct btrfs_root *root,
if (ret && path->slots[0] > 0) if (ret && path->slots[0] > 0)
path->slots[0]--; path->slots[0]--;
limit = block_group->key.objectid + block_group->key.offset; limit = block_group->key.objectid + block_group->key.offset;
reada_extent_leaves(root, path, limit);
while(1) { while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0]; slot = path->slots[0];
if (slot >= btrfs_header_nritems(&leaf->header)) { if (slot >= btrfs_header_nritems(&leaf->header)) {
reada_extent_leaves(root, path, limit);
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret < 0) if (ret < 0)
goto err; goto err;
......
...@@ -374,40 +374,6 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, ...@@ -374,40 +374,6 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
/*
* truncates go from a high offset to a low offset. So, walk
* from hi to lo in the node and issue readas. Stop when you find
* keys from a different objectid
*/
static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path,
u64 objectid)
{
struct btrfs_node *node;
int i;
int nritems;
u64 item_objectid;
u64 blocknr;
int slot;
int ret;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1];
if (slot == 0)
return;
nritems = btrfs_header_nritems(&node->header);
for (i = slot - 1; i >= 0; i--) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid != objectid)
break;
blocknr = btrfs_node_blockptr(node, i);
ret = readahead_tree_block(root, blocknr);
if (ret)
break;
}
}
/* /*
* this can truncate away extent items, csum items and directory items. * this can truncate away extent items, csum items and directory items.
* It starts at a high offset and removes keys until it can't find * It starts at a high offset and removes keys until it can't find
...@@ -434,6 +400,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, ...@@ -434,6 +400,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
int del_item; int del_item;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
path->reada = -1;
BUG_ON(!path); BUG_ON(!path);
/* FIXME, add redo link to tree so we don't leak on crash */ /* FIXME, add redo link to tree so we don't leak on crash */
key.objectid = inode->i_ino; key.objectid = inode->i_ino;
...@@ -450,7 +417,6 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, ...@@ -450,7 +417,6 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
BUG_ON(path->slots[0] == 0); BUG_ON(path->slots[0] == 0);
path->slots[0]--; path->slots[0]--;
} }
reada_truncate(root, path, inode->i_ino);
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
found_key = &leaf->items[path->slots[0]].key; found_key = &leaf->items[path->slots[0]].key;
found_type = btrfs_disk_key_type(found_key); found_type = btrfs_disk_key_type(found_key);
...@@ -827,36 +793,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -827,36 +793,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return d_splice_alias(inode, dentry); return d_splice_alias(inode, dentry);
} }
/*
* readahead one full node of leaves as long as their keys include
* the objectid supplied
*/
static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path,
u64 objectid)
{
struct btrfs_node *node;
int i;
u32 nritems;
u64 item_objectid;
u64 blocknr;
int slot;
int ret;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1];
nritems = btrfs_header_nritems(&node->header);
for (i = slot + 1; i < nritems; i++) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid != objectid)
break;
blocknr = btrfs_node_blockptr(node, i);
ret = readahead_tree_block(root, blocknr);
if (ret)
break;
}
}
static unsigned char btrfs_filetype_table[] = { static unsigned char btrfs_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
}; };
...@@ -890,18 +826,17 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -890,18 +826,17 @@ 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;
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;
advance = 0; advance = 0;
reada_leaves(root, path, inode->i_ino);
while(1) { while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
nritems = btrfs_header_nritems(&leaf->header); nritems = btrfs_header_nritems(&leaf->header);
slot = path->slots[0]; slot = path->slots[0];
if (advance || slot >= nritems) { if (advance || slot >= nritems) {
if (slot >= nritems -1) { if (slot >= nritems -1) {
reada_leaves(root, path, inode->i_ino);
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret) if (ret)
break; break;
......
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