diff options
-rw-r--r-- | fs/btrfs/inode.c | 47 |
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 | ||
4086 | static void btrfs_dentry_release(struct dentry *dentry) | ||
4087 | { | ||
4088 | if (dentry->d_fsdata) | ||
4089 | kfree(dentry->d_fsdata); | ||
4090 | } | ||
4091 | |||
4079 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 4092 | static 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 | } | ||
4251 | no_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 | ||
7453 | const struct dentry_operations btrfs_dentry_operations = { | 7495 | const 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 | }; |