@@ -1567,28 +1567,27 @@ int btrfs_inode_delayed_dir_index_count(struct inode *inode)
return 0;
}
-void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list,
- struct list_head *del_list)
+void btrfs_get_delayed_items(struct inode *inode, struct list_head *list,
+ struct btrfs_key *key, int action)
{
struct btrfs_delayed_node *delayed_node;
struct btrfs_delayed_item *item;
+ struct btrfs_delayed_item *next;
+ struct rb_root *root;
delayed_node = btrfs_get_delayed_node(inode);
if (!delayed_node)
return;
- mutex_lock(&delayed_node->mutex);
- item = __btrfs_first_delayed_insertion_item(delayed_node);
- while (item) {
- atomic_inc(&item->refs);
- list_add_tail(&item->readdir_list, ins_list);
- item = __btrfs_next_delayed_item(item);
- }
+ root = get_ins_del_root(delayed_node, action);
- item = __btrfs_first_delayed_deletion_item(delayed_node);
+ mutex_lock(&delayed_node->mutex);
+ item = __btrfs_lookup_delayed_item(root, key, NULL, &next);
+ if (item == NULL)
+ item = next;
while (item) {
atomic_inc(&item->refs);
- list_add_tail(&item->readdir_list, del_list);
+ list_add_tail(&item->readdir_list, list);
item = __btrfs_next_delayed_item(item);
}
mutex_unlock(&delayed_node->mutex);
@@ -133,8 +133,8 @@ void btrfs_kill_all_delayed_nodes(struct btrfs_root *root);
void btrfs_destroy_delayed_inodes(struct btrfs_root *root);
/* Used for readdir() */
-void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list,
- struct list_head *del_list);
+void btrfs_get_delayed_items(struct inode *inode, struct list_head *list,
+ struct btrfs_key *key, int action);
void btrfs_put_delayed_items(struct list_head *list);
int btrfs_should_delete_dir_index(struct list_head *del_list,
u64 index);
@@ -5048,13 +5048,14 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
path->reada = 1;
- if (key_type == BTRFS_DIR_INDEX_KEY)
- btrfs_get_delayed_items(inode, &ins_list, &del_list);
-
btrfs_set_key_type(&key, key_type);
key.offset = filp->f_pos;
key.objectid = btrfs_ino(inode);
+ if (key_type == BTRFS_DIR_INDEX_KEY)
+ btrfs_get_delayed_items(inode, &del_list, &key,
+ BTRFS_DELAYED_DELETION_ITEM);
+
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto err;
@@ -5146,7 +5147,14 @@ next:
path->slots[0]++;
}
+ /* don't acquire delayed item mutex while holding locked path */
+ btrfs_free_path(path);
+ path = NULL;
+
if (key_type == BTRFS_DIR_INDEX_KEY) {
+ key.offset = filp->f_pos;
+ btrfs_get_delayed_items(inode, &ins_list, &key,
+ BTRFS_DELAYED_INSERTION_ITEM);
ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
&ins_list);
if (ret)
On every readdir call all the delayed items for the dir are put on a private list with a held reference. If they're outside the f_pos values that this readdir call ends up using they're just dropped and removed from the list. We can make some tiny changes to cut down on this overhead. First, let's use the delayed item's key-sorted rbtree to skip items that are before f_pos and will never be used. Second, let's only acquire the new delayed items after we've exausted the existing in-tree items and still have room in the readdir buffer for more entries. Signed-off-by: Zach Brown <zab@redhat.com> --- fs/btrfs/delayed-inode.c | 21 ++++++++++----------- fs/btrfs/delayed-inode.h | 4 ++-- fs/btrfs/inode.c | 14 +++++++++++--- 3 files changed, 23 insertions(+), 16 deletions(-)