aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-06-28 16:18:59 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-08-01 01:31:42 -0400
commitb4aff1f874f679320c03e3d97b60fc7babfd4623 (patch)
tree7d70626056dd81bbdb194171d89f35cd390a5a78 /fs/btrfs/inode.c
parent9d108d25487bf958f8093409a4c0bee6169edba6 (diff)
Btrfs: load the key from the dir item in readdir into a fake dentry
In btrfs we have 2 indexes for inodes. One is for readdir, it's in this nice sequential order and works out brilliantly for readdir. However if you use ls, it usually stat's each file it gets from readdir. This is where the second index comes in, which is based on a hash of the name of the file. So then the lookup has to lookup this index, and then lookup the inode. The index lookup is going to be in random order (since its based on the name hash), which gives us less than stellar performance. Since we know the inode location from the readdir index, I create a dummy dentry and copy the location key into dentry->d_fsdata. Then on lookup if we have d_fsdata we use that location to lookup the inode, avoiding looking up the other directory index. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index caa26ab5ed68..540e3b43c688 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4016,12 +4016,19 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
4016 struct btrfs_root *sub_root = root; 4016 struct btrfs_root *sub_root = root;
4017 struct btrfs_key location; 4017 struct btrfs_key location;
4018 int index; 4018 int index;
4019 int ret; 4019 int ret = 0;
4020 4020
4021 if (dentry->d_name.len > BTRFS_NAME_LEN) 4021 if (dentry->d_name.len > BTRFS_NAME_LEN)
4022 return ERR_PTR(-ENAMETOOLONG); 4022 return ERR_PTR(-ENAMETOOLONG);
4023 4023
4024 ret = btrfs_inode_by_name(dir, dentry, &location); 4024 if (unlikely(d_need_lookup(dentry))) {
4025 memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
4026 kfree(dentry->d_fsdata);
4027 dentry->d_fsdata = NULL;
4028 d_clear_need_lookup(dentry);
4029 } else {
4030 ret = btrfs_inode_by_name(dir, dentry, &location);
4031 }
4025 4032
4026 if (ret < 0) 4033 if (ret < 0)
4027 return ERR_PTR(ret); 4034 return ERR_PTR(ret);
@@ -4076,6 +4083,12 @@ static int btrfs_dentry_delete(const struct dentry *dentry)
4076 return 0; 4083 return 0;
4077} 4084}
4078 4085
4086static void btrfs_dentry_release(struct dentry *dentry)
4087{
4088 if (dentry->d_fsdata)
4089 kfree(dentry->d_fsdata);
4090}
4091
4079static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, 4092static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
4080 struct nameidata *nd) 4093 struct nameidata *nd)
4081{ 4094{
@@ -4098,6 +4111,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
4098 struct btrfs_path *path; 4111 struct btrfs_path *path;
4099 struct list_head ins_list; 4112 struct list_head ins_list;
4100 struct list_head del_list; 4113 struct list_head del_list;
4114 struct qstr q;
4101 int ret; 4115 int ret;
4102 struct extent_buffer *leaf; 4116 struct extent_buffer *leaf;
4103 int slot; 4117 int slot;
@@ -4187,6 +4201,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
4187 4201
4188 while (di_cur < di_total) { 4202 while (di_cur < di_total) {
4189 struct btrfs_key location; 4203 struct btrfs_key location;
4204 struct dentry *tmp;
4190 4205
4191 if (verify_dir_item(root, leaf, di)) 4206 if (verify_dir_item(root, leaf, di))
4192 break; 4207 break;
@@ -4207,6 +4222,33 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
4207 d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; 4222 d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
4208 btrfs_dir_item_key_to_cpu(leaf, di, &location); 4223 btrfs_dir_item_key_to_cpu(leaf, di, &location);
4209 4224
4225 q.name = name_ptr;
4226 q.len = name_len;
4227 q.hash = full_name_hash(q.name, q.len);
4228 tmp = d_lookup(filp->f_dentry, &q);
4229 if (!tmp) {
4230 struct btrfs_key *newkey;
4231
4232 newkey = kzalloc(sizeof(struct btrfs_key),
4233 GFP_NOFS);
4234 if (!newkey)
4235 goto no_dentry;
4236 tmp = d_alloc(filp->f_dentry, &q);
4237 if (!tmp) {
4238 kfree(newkey);
4239 dput(tmp);
4240 goto no_dentry;
4241 }
4242 memcpy(newkey, &location,
4243 sizeof(struct btrfs_key));
4244 tmp->d_fsdata = newkey;
4245 tmp->d_flags |= DCACHE_NEED_LOOKUP;
4246 d_rehash(tmp);
4247 dput(tmp);
4248 } else {
4249 dput(tmp);
4250 }
4251no_dentry:
4210 /* is this a reference to our own snapshot? If so 4252 /* is this a reference to our own snapshot? If so
4211 * skip it 4253 * skip it
4212 */ 4254 */
@@ -7452,4 +7494,5 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
7452 7494
7453const struct dentry_operations btrfs_dentry_operations = { 7495const struct dentry_operations btrfs_dentry_operations = {
7454 .d_delete = btrfs_dentry_delete, 7496 .d_delete = btrfs_dentry_delete,
7497 .d_release = btrfs_dentry_release,
7455}; 7498};