aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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};