diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 81 |
1 files changed, 51 insertions, 30 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 3763757f9fe7..80d2f5292cf9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -132,6 +132,21 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | |||
132 | req->out.args[0].value = outarg; | 132 | req->out.args[0].value = outarg; |
133 | } | 133 | } |
134 | 134 | ||
135 | static u64 fuse_get_attr_version(struct fuse_conn *fc) | ||
136 | { | ||
137 | u64 curr_version; | ||
138 | |||
139 | /* | ||
140 | * The spin lock isn't actually needed on 64bit archs, but we | ||
141 | * don't yet care too much about such optimizations. | ||
142 | */ | ||
143 | spin_lock(&fc->lock); | ||
144 | curr_version = fc->attr_version; | ||
145 | spin_unlock(&fc->lock); | ||
146 | |||
147 | return curr_version; | ||
148 | } | ||
149 | |||
135 | /* | 150 | /* |
136 | * Check whether the dentry is still valid | 151 | * Check whether the dentry is still valid |
137 | * | 152 | * |
@@ -171,9 +186,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
171 | return 0; | 186 | return 0; |
172 | } | 187 | } |
173 | 188 | ||
174 | spin_lock(&fc->lock); | 189 | attr_version = fuse_get_attr_version(fc); |
175 | attr_version = fc->attr_version; | ||
176 | spin_unlock(&fc->lock); | ||
177 | 190 | ||
178 | parent = dget_parent(entry); | 191 | parent = dget_parent(entry); |
179 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | 192 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); |
@@ -264,9 +277,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
264 | return ERR_PTR(PTR_ERR(forget_req)); | 277 | return ERR_PTR(PTR_ERR(forget_req)); |
265 | } | 278 | } |
266 | 279 | ||
267 | spin_lock(&fc->lock); | 280 | attr_version = fuse_get_attr_version(fc); |
268 | attr_version = fc->attr_version; | ||
269 | spin_unlock(&fc->lock); | ||
270 | 281 | ||
271 | fuse_lookup_init(req, dir, entry, &outarg); | 282 | fuse_lookup_init(req, dir, entry, &outarg); |
272 | request_send(fc, req); | 283 | request_send(fc, req); |
@@ -646,6 +657,9 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
646 | err = req->out.h.error; | 657 | err = req->out.h.error; |
647 | fuse_put_request(fc, req); | 658 | fuse_put_request(fc, req); |
648 | if (!err) { | 659 | if (!err) { |
660 | /* ctime changes */ | ||
661 | fuse_invalidate_attr(oldent->d_inode); | ||
662 | |||
649 | fuse_invalidate_attr(olddir); | 663 | fuse_invalidate_attr(olddir); |
650 | if (olddir != newdir) | 664 | if (olddir != newdir) |
651 | fuse_invalidate_attr(newdir); | 665 | fuse_invalidate_attr(newdir); |
@@ -733,9 +747,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, | |||
733 | if (IS_ERR(req)) | 747 | if (IS_ERR(req)) |
734 | return PTR_ERR(req); | 748 | return PTR_ERR(req); |
735 | 749 | ||
736 | spin_lock(&fc->lock); | 750 | attr_version = fuse_get_attr_version(fc); |
737 | attr_version = fc->attr_version; | ||
738 | spin_unlock(&fc->lock); | ||
739 | 751 | ||
740 | memset(&inarg, 0, sizeof(inarg)); | 752 | memset(&inarg, 0, sizeof(inarg)); |
741 | memset(&outarg, 0, sizeof(outarg)); | 753 | memset(&outarg, 0, sizeof(outarg)); |
@@ -775,6 +787,31 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, | |||
775 | return err; | 787 | return err; |
776 | } | 788 | } |
777 | 789 | ||
790 | int fuse_update_attributes(struct inode *inode, struct kstat *stat, | ||
791 | struct file *file, bool *refreshed) | ||
792 | { | ||
793 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
794 | int err; | ||
795 | bool r; | ||
796 | |||
797 | if (fi->i_time < get_jiffies_64()) { | ||
798 | r = true; | ||
799 | err = fuse_do_getattr(inode, stat, file); | ||
800 | } else { | ||
801 | r = false; | ||
802 | err = 0; | ||
803 | if (stat) { | ||
804 | generic_fillattr(inode, stat); | ||
805 | stat->mode = fi->orig_i_mode; | ||
806 | } | ||
807 | } | ||
808 | |||
809 | if (refreshed != NULL) | ||
810 | *refreshed = r; | ||
811 | |||
812 | return err; | ||
813 | } | ||
814 | |||
778 | /* | 815 | /* |
779 | * Calling into a user-controlled filesystem gives the filesystem | 816 | * Calling into a user-controlled filesystem gives the filesystem |
780 | * daemon ptrace-like capabilities over the requester process. This | 817 | * daemon ptrace-like capabilities over the requester process. This |
@@ -862,14 +899,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
862 | */ | 899 | */ |
863 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || | 900 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || |
864 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { | 901 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { |
865 | struct fuse_inode *fi = get_fuse_inode(inode); | 902 | err = fuse_update_attributes(inode, NULL, NULL, &refreshed); |
866 | if (fi->i_time < get_jiffies_64()) { | 903 | if (err) |
867 | err = fuse_do_getattr(inode, NULL, NULL); | 904 | return err; |
868 | if (err) | ||
869 | return err; | ||
870 | |||
871 | refreshed = true; | ||
872 | } | ||
873 | } | 905 | } |
874 | 906 | ||
875 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { | 907 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { |
@@ -935,7 +967,6 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
935 | struct page *page; | 967 | struct page *page; |
936 | struct inode *inode = file->f_path.dentry->d_inode; | 968 | struct inode *inode = file->f_path.dentry->d_inode; |
937 | struct fuse_conn *fc = get_fuse_conn(inode); | 969 | struct fuse_conn *fc = get_fuse_conn(inode); |
938 | struct fuse_file *ff = file->private_data; | ||
939 | struct fuse_req *req; | 970 | struct fuse_req *req; |
940 | 971 | ||
941 | if (is_bad_inode(inode)) | 972 | if (is_bad_inode(inode)) |
@@ -952,7 +983,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
952 | } | 983 | } |
953 | req->num_pages = 1; | 984 | req->num_pages = 1; |
954 | req->pages[0] = page; | 985 | req->pages[0] = page; |
955 | fuse_read_fill(req, ff, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); | 986 | fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); |
956 | request_send(fc, req); | 987 | request_send(fc, req); |
957 | nbytes = req->out.args[0].size; | 988 | nbytes = req->out.args[0].size; |
958 | err = req->out.h.error; | 989 | err = req->out.h.error; |
@@ -1173,22 +1204,12 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, | |||
1173 | struct kstat *stat) | 1204 | struct kstat *stat) |
1174 | { | 1205 | { |
1175 | struct inode *inode = entry->d_inode; | 1206 | struct inode *inode = entry->d_inode; |
1176 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
1177 | struct fuse_conn *fc = get_fuse_conn(inode); | 1207 | struct fuse_conn *fc = get_fuse_conn(inode); |
1178 | int err; | ||
1179 | 1208 | ||
1180 | if (!fuse_allow_task(fc, current)) | 1209 | if (!fuse_allow_task(fc, current)) |
1181 | return -EACCES; | 1210 | return -EACCES; |
1182 | 1211 | ||
1183 | if (fi->i_time < get_jiffies_64()) | 1212 | return fuse_update_attributes(inode, stat, NULL, NULL); |
1184 | err = fuse_do_getattr(inode, stat, NULL); | ||
1185 | else { | ||
1186 | err = 0; | ||
1187 | generic_fillattr(inode, stat); | ||
1188 | stat->mode = fi->orig_i_mode; | ||
1189 | } | ||
1190 | |||
1191 | return err; | ||
1192 | } | 1213 | } |
1193 | 1214 | ||
1194 | static int fuse_setxattr(struct dentry *entry, const char *name, | 1215 | static int fuse_setxattr(struct dentry *entry, const char *name, |