diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 88 |
1 files changed, 66 insertions, 22 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b94c0da3b43f..4d14de6d121b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4009,12 +4009,19 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4009 | struct btrfs_root *sub_root = root; | 4009 | struct btrfs_root *sub_root = root; |
4010 | struct btrfs_key location; | 4010 | struct btrfs_key location; |
4011 | int index; | 4011 | int index; |
4012 | int ret; | 4012 | int ret = 0; |
4013 | 4013 | ||
4014 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 4014 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
4015 | return ERR_PTR(-ENAMETOOLONG); | 4015 | return ERR_PTR(-ENAMETOOLONG); |
4016 | 4016 | ||
4017 | ret = btrfs_inode_by_name(dir, dentry, &location); | 4017 | if (unlikely(d_need_lookup(dentry))) { |
4018 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); | ||
4019 | kfree(dentry->d_fsdata); | ||
4020 | dentry->d_fsdata = NULL; | ||
4021 | d_clear_need_lookup(dentry); | ||
4022 | } else { | ||
4023 | ret = btrfs_inode_by_name(dir, dentry, &location); | ||
4024 | } | ||
4018 | 4025 | ||
4019 | if (ret < 0) | 4026 | if (ret < 0) |
4020 | return ERR_PTR(ret); | 4027 | return ERR_PTR(ret); |
@@ -4069,16 +4076,16 @@ static int btrfs_dentry_delete(const struct dentry *dentry) | |||
4069 | return 0; | 4076 | return 0; |
4070 | } | 4077 | } |
4071 | 4078 | ||
4079 | static void btrfs_dentry_release(struct dentry *dentry) | ||
4080 | { | ||
4081 | if (dentry->d_fsdata) | ||
4082 | kfree(dentry->d_fsdata); | ||
4083 | } | ||
4084 | |||
4072 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 4085 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
4073 | struct nameidata *nd) | 4086 | struct nameidata *nd) |
4074 | { | 4087 | { |
4075 | struct inode *inode; | 4088 | return d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); |
4076 | |||
4077 | inode = btrfs_lookup_dentry(dir, dentry); | ||
4078 | if (IS_ERR(inode)) | ||
4079 | return ERR_CAST(inode); | ||
4080 | |||
4081 | return d_splice_alias(inode, dentry); | ||
4082 | } | 4089 | } |
4083 | 4090 | ||
4084 | unsigned char btrfs_filetype_table[] = { | 4091 | unsigned char btrfs_filetype_table[] = { |
@@ -4097,6 +4104,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4097 | struct btrfs_path *path; | 4104 | struct btrfs_path *path; |
4098 | struct list_head ins_list; | 4105 | struct list_head ins_list; |
4099 | struct list_head del_list; | 4106 | struct list_head del_list; |
4107 | struct qstr q; | ||
4100 | int ret; | 4108 | int ret; |
4101 | struct extent_buffer *leaf; | 4109 | struct extent_buffer *leaf; |
4102 | int slot; | 4110 | int slot; |
@@ -4186,6 +4194,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4186 | 4194 | ||
4187 | while (di_cur < di_total) { | 4195 | while (di_cur < di_total) { |
4188 | struct btrfs_key location; | 4196 | struct btrfs_key location; |
4197 | struct dentry *tmp; | ||
4189 | 4198 | ||
4190 | if (verify_dir_item(root, leaf, di)) | 4199 | if (verify_dir_item(root, leaf, di)) |
4191 | break; | 4200 | break; |
@@ -4206,6 +4215,33 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4206 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; | 4215 | d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; |
4207 | btrfs_dir_item_key_to_cpu(leaf, di, &location); | 4216 | btrfs_dir_item_key_to_cpu(leaf, di, &location); |
4208 | 4217 | ||
4218 | q.name = name_ptr; | ||
4219 | q.len = name_len; | ||
4220 | q.hash = full_name_hash(q.name, q.len); | ||
4221 | tmp = d_lookup(filp->f_dentry, &q); | ||
4222 | if (!tmp) { | ||
4223 | struct btrfs_key *newkey; | ||
4224 | |||
4225 | newkey = kzalloc(sizeof(struct btrfs_key), | ||
4226 | GFP_NOFS); | ||
4227 | if (!newkey) | ||
4228 | goto no_dentry; | ||
4229 | tmp = d_alloc(filp->f_dentry, &q); | ||
4230 | if (!tmp) { | ||
4231 | kfree(newkey); | ||
4232 | dput(tmp); | ||
4233 | goto no_dentry; | ||
4234 | } | ||
4235 | memcpy(newkey, &location, | ||
4236 | sizeof(struct btrfs_key)); | ||
4237 | tmp->d_fsdata = newkey; | ||
4238 | tmp->d_flags |= DCACHE_NEED_LOOKUP; | ||
4239 | d_rehash(tmp); | ||
4240 | dput(tmp); | ||
4241 | } else { | ||
4242 | dput(tmp); | ||
4243 | } | ||
4244 | no_dentry: | ||
4209 | /* is this a reference to our own snapshot? If so | 4245 | /* is this a reference to our own snapshot? If so |
4210 | * skip it | 4246 | * skip it |
4211 | */ | 4247 | */ |
@@ -4467,7 +4503,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
4467 | inode->i_generation = BTRFS_I(inode)->generation; | 4503 | inode->i_generation = BTRFS_I(inode)->generation; |
4468 | btrfs_set_inode_space_info(root, inode); | 4504 | btrfs_set_inode_space_info(root, inode); |
4469 | 4505 | ||
4470 | if (mode & S_IFDIR) | 4506 | if (S_ISDIR(mode)) |
4471 | owner = 0; | 4507 | owner = 0; |
4472 | else | 4508 | else |
4473 | owner = 1; | 4509 | owner = 1; |
@@ -4512,7 +4548,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
4512 | 4548 | ||
4513 | btrfs_inherit_iflags(inode, dir); | 4549 | btrfs_inherit_iflags(inode, dir); |
4514 | 4550 | ||
4515 | if ((mode & S_IFREG)) { | 4551 | if (S_ISREG(mode)) { |
4516 | if (btrfs_test_opt(root, NODATASUM)) | 4552 | if (btrfs_test_opt(root, NODATASUM)) |
4517 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | 4553 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; |
4518 | if (btrfs_test_opt(root, NODATACOW) || | 4554 | if (btrfs_test_opt(root, NODATACOW) || |
@@ -4766,11 +4802,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
4766 | if (err) { | 4802 | if (err) { |
4767 | drop_inode = 1; | 4803 | drop_inode = 1; |
4768 | } else { | 4804 | } else { |
4769 | struct dentry *parent = dget_parent(dentry); | 4805 | struct dentry *parent = dentry->d_parent; |
4770 | err = btrfs_update_inode(trans, root, inode); | 4806 | err = btrfs_update_inode(trans, root, inode); |
4771 | BUG_ON(err); | 4807 | BUG_ON(err); |
4772 | btrfs_log_new_name(trans, inode, NULL, parent); | 4808 | btrfs_log_new_name(trans, inode, NULL, parent); |
4773 | dput(parent); | ||
4774 | } | 4809 | } |
4775 | 4810 | ||
4776 | nr = trans->blocks_used; | 4811 | nr = trans->blocks_used; |
@@ -6882,7 +6917,7 @@ static int btrfs_getattr(struct vfsmount *mnt, | |||
6882 | { | 6917 | { |
6883 | struct inode *inode = dentry->d_inode; | 6918 | struct inode *inode = dentry->d_inode; |
6884 | generic_fillattr(inode, stat); | 6919 | generic_fillattr(inode, stat); |
6885 | stat->dev = BTRFS_I(inode)->root->anon_super.s_dev; | 6920 | stat->dev = BTRFS_I(inode)->root->anon_dev; |
6886 | stat->blksize = PAGE_CACHE_SIZE; | 6921 | stat->blksize = PAGE_CACHE_SIZE; |
6887 | stat->blocks = (inode_get_bytes(inode) + | 6922 | stat->blocks = (inode_get_bytes(inode) + |
6888 | BTRFS_I(inode)->delalloc_bytes) >> 9; | 6923 | BTRFS_I(inode)->delalloc_bytes) >> 9; |
@@ -7050,9 +7085,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
7050 | BUG_ON(ret); | 7085 | BUG_ON(ret); |
7051 | 7086 | ||
7052 | if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { | 7087 | if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { |
7053 | struct dentry *parent = dget_parent(new_dentry); | 7088 | struct dentry *parent = new_dentry->d_parent; |
7054 | btrfs_log_new_name(trans, old_inode, old_dir, parent); | 7089 | btrfs_log_new_name(trans, old_inode, old_dir, parent); |
7055 | dput(parent); | ||
7056 | btrfs_end_log_trans(root); | 7090 | btrfs_end_log_trans(root); |
7057 | } | 7091 | } |
7058 | out_fail: | 7092 | out_fail: |
@@ -7317,15 +7351,19 @@ static int btrfs_set_page_dirty(struct page *page) | |||
7317 | return __set_page_dirty_nobuffers(page); | 7351 | return __set_page_dirty_nobuffers(page); |
7318 | } | 7352 | } |
7319 | 7353 | ||
7320 | static int btrfs_permission(struct inode *inode, int mask, unsigned int flags) | 7354 | static int btrfs_permission(struct inode *inode, int mask) |
7321 | { | 7355 | { |
7322 | struct btrfs_root *root = BTRFS_I(inode)->root; | 7356 | struct btrfs_root *root = BTRFS_I(inode)->root; |
7357 | umode_t mode = inode->i_mode; | ||
7323 | 7358 | ||
7324 | if (btrfs_root_readonly(root) && (mask & MAY_WRITE)) | 7359 | if (mask & MAY_WRITE && |
7325 | return -EROFS; | 7360 | (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) { |
7326 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) | 7361 | if (btrfs_root_readonly(root)) |
7327 | return -EACCES; | 7362 | return -EROFS; |
7328 | return generic_permission(inode, mask, flags, btrfs_check_acl); | 7363 | if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) |
7364 | return -EACCES; | ||
7365 | } | ||
7366 | return generic_permission(inode, mask); | ||
7329 | } | 7367 | } |
7330 | 7368 | ||
7331 | static const struct inode_operations btrfs_dir_inode_operations = { | 7369 | static const struct inode_operations btrfs_dir_inode_operations = { |
@@ -7345,10 +7383,12 @@ static const struct inode_operations btrfs_dir_inode_operations = { | |||
7345 | .listxattr = btrfs_listxattr, | 7383 | .listxattr = btrfs_listxattr, |
7346 | .removexattr = btrfs_removexattr, | 7384 | .removexattr = btrfs_removexattr, |
7347 | .permission = btrfs_permission, | 7385 | .permission = btrfs_permission, |
7386 | .get_acl = btrfs_get_acl, | ||
7348 | }; | 7387 | }; |
7349 | static const struct inode_operations btrfs_dir_ro_inode_operations = { | 7388 | static const struct inode_operations btrfs_dir_ro_inode_operations = { |
7350 | .lookup = btrfs_lookup, | 7389 | .lookup = btrfs_lookup, |
7351 | .permission = btrfs_permission, | 7390 | .permission = btrfs_permission, |
7391 | .get_acl = btrfs_get_acl, | ||
7352 | }; | 7392 | }; |
7353 | 7393 | ||
7354 | static const struct file_operations btrfs_dir_file_operations = { | 7394 | static const struct file_operations btrfs_dir_file_operations = { |
@@ -7417,6 +7457,7 @@ static const struct inode_operations btrfs_file_inode_operations = { | |||
7417 | .removexattr = btrfs_removexattr, | 7457 | .removexattr = btrfs_removexattr, |
7418 | .permission = btrfs_permission, | 7458 | .permission = btrfs_permission, |
7419 | .fiemap = btrfs_fiemap, | 7459 | .fiemap = btrfs_fiemap, |
7460 | .get_acl = btrfs_get_acl, | ||
7420 | }; | 7461 | }; |
7421 | static const struct inode_operations btrfs_special_inode_operations = { | 7462 | static const struct inode_operations btrfs_special_inode_operations = { |
7422 | .getattr = btrfs_getattr, | 7463 | .getattr = btrfs_getattr, |
@@ -7426,6 +7467,7 @@ static const struct inode_operations btrfs_special_inode_operations = { | |||
7426 | .getxattr = btrfs_getxattr, | 7467 | .getxattr = btrfs_getxattr, |
7427 | .listxattr = btrfs_listxattr, | 7468 | .listxattr = btrfs_listxattr, |
7428 | .removexattr = btrfs_removexattr, | 7469 | .removexattr = btrfs_removexattr, |
7470 | .get_acl = btrfs_get_acl, | ||
7429 | }; | 7471 | }; |
7430 | static const struct inode_operations btrfs_symlink_inode_operations = { | 7472 | static const struct inode_operations btrfs_symlink_inode_operations = { |
7431 | .readlink = generic_readlink, | 7473 | .readlink = generic_readlink, |
@@ -7437,8 +7479,10 @@ static const struct inode_operations btrfs_symlink_inode_operations = { | |||
7437 | .getxattr = btrfs_getxattr, | 7479 | .getxattr = btrfs_getxattr, |
7438 | .listxattr = btrfs_listxattr, | 7480 | .listxattr = btrfs_listxattr, |
7439 | .removexattr = btrfs_removexattr, | 7481 | .removexattr = btrfs_removexattr, |
7482 | .get_acl = btrfs_get_acl, | ||
7440 | }; | 7483 | }; |
7441 | 7484 | ||
7442 | const struct dentry_operations btrfs_dentry_operations = { | 7485 | const struct dentry_operations btrfs_dentry_operations = { |
7443 | .d_delete = btrfs_dentry_delete, | 7486 | .d_delete = btrfs_dentry_delete, |
7487 | .d_release = btrfs_dentry_release, | ||
7444 | }; | 7488 | }; |