Btrfs: Fold some btree readahead routines into something more generic.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
committed by
David Woodhouse
parent
9f3a742736
commit
3c69faecb8
@@ -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
|
|||||||
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 @@ again:
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user