diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-01 19:48:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-01 19:48:31 -0400 |
commit | 1b8e94993c4752d98c33903aa836acc15f7e6d5c (patch) | |
tree | b78cba208f0a193ce6ceebbc146021af4425b4e1 /fs/btrfs/inode.c | |
parent | 12ff47e7f5fb64c566f62e6cf6a3b291c51bd337 (diff) | |
parent | 206d440f64030b6425841bf7cb38e26a5ea0c382 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
xfs: Fix build breakage in xfs_iops.c when CONFIG_FS_POSIX_ACL is not set
VFS: Reorganise shrink_dcache_for_umount_subtree() after demise of dcache_lock
VFS: Remove dentry->d_lock locking from shrink_dcache_for_umount_subtree()
VFS: Remove detached-dentry counter from shrink_dcache_for_umount_subtree()
switch posix_acl_chmod() to umode_t
switch posix_acl_from_mode() to umode_t
switch posix_acl_equiv_mode() to umode_t *
switch posix_acl_create() to umode_t *
block: initialise bd_super in bdget()
vfs: avoid call to inode_lru_list_del() if possible
vfs: avoid taking inode_hash_lock on pipes and sockets
vfs: conditionally call inode_wb_list_del()
VFS: Fix automount for negative autofs dentries
Btrfs: load the key from the dir item in readdir into a fake dentry
devtmpfs: missing initialialization in never-hit case
hppfs: missing include
Diffstat (limited to 'fs/btrfs/inode.c')
-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 13e6255182e3..ae762dab37f8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3993,12 +3993,19 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
3993 | struct btrfs_root *sub_root = root; | 3993 | struct btrfs_root *sub_root = root; |
3994 | struct btrfs_key location; | 3994 | struct btrfs_key location; |
3995 | int index; | 3995 | int index; |
3996 | int ret; | 3996 | int ret = 0; |
3997 | 3997 | ||
3998 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 3998 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
3999 | return ERR_PTR(-ENAMETOOLONG); | 3999 | return ERR_PTR(-ENAMETOOLONG); |
4000 | 4000 | ||
4001 | ret = btrfs_inode_by_name(dir, dentry, &location); | 4001 | if (unlikely(d_need_lookup(dentry))) { |
4002 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); | ||
4003 | kfree(dentry->d_fsdata); | ||
4004 | dentry->d_fsdata = NULL; | ||
4005 | d_clear_need_lookup(dentry); | ||
4006 | } else { | ||
4007 | ret = btrfs_inode_by_name(dir, dentry, &location); | ||
4008 | } | ||
4002 | 4009 | ||
4003 | if (ret < 0) | 4010 | if (ret < 0) |
4004 | return ERR_PTR(ret); | 4011 | return ERR_PTR(ret); |
@@ -4053,6 +4060,12 @@ static int btrfs_dentry_delete(const struct dentry *dentry) | |||
4053 | return 0; | 4060 | return 0; |
4054 | } | 4061 | } |
4055 | 4062 | ||
4063 | static void btrfs_dentry_release(struct dentry *dentry) | ||
4064 | { | ||
4065 | if (dentry->d_fsdata) | ||
4066 | kfree(dentry->d_fsdata); | ||
4067 | } | ||
4068 | |||
4056 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 4069 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
4057 | struct nameidata *nd) | 4070 | struct nameidata *nd) |
4058 | { | 4071 | { |
@@ -4075,6 +4088,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4075 | struct btrfs_path *path; | 4088 | struct btrfs_path *path; |
4076 | struct list_head ins_list; | 4089 | struct list_head ins_list; |
4077 | struct list_head del_list; | 4090 | struct list_head del_list; |
4091 | struct qstr q; | ||
4078 | int ret; | 4092 | int ret; |
4079 | struct extent_buffer *leaf; | 4093 | struct extent_buffer *leaf; |
4080 | int slot; | 4094 | int slot; |
@@ -4164,6 +4178,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4164 | 4178 | ||
4165 | while (di_cur < di_total) { | 4179 | while (di_cur < di_total) { |
4166 | struct btrfs_key location; | 4180 | struct btrfs_key location; |
4181 | struct dentry *tmp; | ||
4167 | 4182 | ||
4168 | if (verify_dir_item(root, leaf, di)) | 4183 | if (verify_dir_item(root, leaf, di)) |
4169 | break; | 4184 | break; |
@@ -4184,6 +4199,33 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4184 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; | 4199 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; |
4185 | btrfs_dir_item_key_to_cpu(leaf, di, &location); | 4200 | btrfs_dir_item_key_to_cpu(leaf, di, &location); |
4186 | 4201 | ||
4202 | q.name = name_ptr; | ||
4203 | q.len = name_len; | ||
4204 | q.hash = full_name_hash(q.name, q.len); | ||
4205 | tmp = d_lookup(filp->f_dentry, &q); | ||
4206 | if (!tmp) { | ||
4207 | struct btrfs_key *newkey; | ||
4208 | |||
4209 | newkey = kzalloc(sizeof(struct btrfs_key), | ||
4210 | GFP_NOFS); | ||
4211 | if (!newkey) | ||
4212 | goto no_dentry; | ||
4213 | tmp = d_alloc(filp->f_dentry, &q); | ||
4214 | if (!tmp) { | ||
4215 | kfree(newkey); | ||
4216 | dput(tmp); | ||
4217 | goto no_dentry; | ||
4218 | } | ||
4219 | memcpy(newkey, &location, | ||
4220 | sizeof(struct btrfs_key)); | ||
4221 | tmp->d_fsdata = newkey; | ||
4222 | tmp->d_flags |= DCACHE_NEED_LOOKUP; | ||
4223 | d_rehash(tmp); | ||
4224 | dput(tmp); | ||
4225 | } else { | ||
4226 | dput(tmp); | ||
4227 | } | ||
4228 | no_dentry: | ||
4187 | /* is this a reference to our own snapshot? If so | 4229 | /* is this a reference to our own snapshot? If so |
4188 | * skip it | 4230 | * skip it |
4189 | */ | 4231 | */ |
@@ -7430,4 +7472,5 @@ static const struct inode_operations btrfs_symlink_inode_operations = { | |||
7430 | 7472 | ||
7431 | const struct dentry_operations btrfs_dentry_operations = { | 7473 | const struct dentry_operations btrfs_dentry_operations = { |
7432 | .d_delete = btrfs_dentry_delete, | 7474 | .d_delete = btrfs_dentry_delete, |
7475 | .d_release = btrfs_dentry_release, | ||
7433 | }; | 7476 | }; |