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
* if key is found, we return zero and you can find the item in the leaf
struct buffer_head *cow_buf;
struct btrfs_node *c;
struct btrfs_root_item *root_item = &root->root_item;
+ u64 blocknr;
int slot;
int ret;
int level;
+ int should_reada = p->reada;
u8 lowest_level = 0;
if (btrfs_root_refs(root_item) == 0 && root->ref_cows) {
/* this is only true while dropping a snapshot */
if (level == lowest_level)
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));
+
} else {
struct btrfs_leaf *l = (struct btrfs_leaf *)c;
p->slots[level] = slot;
blocknr = btrfs_node_blockptr(c_node, slot);
if (next)
btrfs_block_release(root, next);
+ if (level == 1 && path->reada)
+ reada_for_search(root, path, slot);
next = read_tree_block(root, blocknr);
break;
}
path->slots[level] = 0;
if (!level)
break;
+ if (level == 1 && path->reada)
+ reada_for_search(root, path, slot);
next = read_tree_block(root,
btrfs_node_blockptr(btrfs_buffer_node(next), 0));
}
struct btrfs_path {
struct buffer_head *nodes[BTRFS_MAX_LEVEL];
int slots[BTRFS_MAX_LEVEL];
+ int reada;
};
/*
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
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,
struct btrfs_block_group_cache *block_group)
{
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
+ path->reada = 1;
key.objectid = block_group->key.objectid;
key.flags = 0;
key.offset = 0;
if (ret && path->slots[0] > 0)
path->slots[0]--;
limit = block_group->key.objectid + block_group->key.offset;
- reada_extent_leaves(root, path, limit);
while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0];
if (slot >= btrfs_header_nritems(&leaf->header)) {
- reada_extent_leaves(root, path, limit);
ret = btrfs_next_leaf(root, path);
if (ret < 0)
goto err;
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.
* It starts at a high offset and removes keys until it can't find
int del_item;
path = btrfs_alloc_path();
+ path->reada = -1;
BUG_ON(!path);
/* FIXME, add redo link to tree so we don't leak on crash */
key.objectid = inode->i_ino;
BUG_ON(path->slots[0] == 0);
path->slots[0]--;
}
- reada_truncate(root, path, inode->i_ino);
leaf = btrfs_buffer_leaf(path->nodes[0]);
found_key = &leaf->items[path->slots[0]].key;
found_type = btrfs_disk_key_type(found_key);
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[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
};
btrfs_set_key_type(&key, key_type);
key.offset = filp->f_pos;
path = btrfs_alloc_path();
+ path->reada = 1;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto err;
advance = 0;
- reada_leaves(root, path, inode->i_ino);
while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]);
nritems = btrfs_header_nritems(&leaf->header);
slot = path->slots[0];
if (advance || slot >= nritems) {
if (slot >= nritems -1) {
- reada_leaves(root, path, inode->i_ino);
ret = btrfs_next_leaf(root, path);
if (ret)
break;