diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 125 |
1 files changed, 82 insertions, 43 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b18e06daeffb..a058b664859c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -63,13 +63,21 @@ static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) | |||
63 | * Set dentry and possibly attribute timeouts from the lookup/mk* | 63 | * Set dentry and possibly attribute timeouts from the lookup/mk* |
64 | * replies | 64 | * replies |
65 | */ | 65 | */ |
66 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | 66 | static void fuse_change_entry_timeout(struct dentry *entry, |
67 | struct fuse_entry_out *o) | ||
67 | { | 68 | { |
68 | fuse_dentry_settime(entry, | 69 | fuse_dentry_settime(entry, |
69 | time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); | 70 | time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); |
70 | if (entry->d_inode) | 71 | } |
71 | get_fuse_inode(entry->d_inode)->i_time = | 72 | |
72 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | 73 | static u64 attr_timeout(struct fuse_attr_out *o) |
74 | { | ||
75 | return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | ||
76 | } | ||
77 | |||
78 | static u64 entry_attr_timeout(struct fuse_entry_out *o) | ||
79 | { | ||
80 | return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | ||
73 | } | 81 | } |
74 | 82 | ||
75 | /* | 83 | /* |
@@ -140,6 +148,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
140 | struct fuse_req *req; | 148 | struct fuse_req *req; |
141 | struct fuse_req *forget_req; | 149 | struct fuse_req *forget_req; |
142 | struct dentry *parent; | 150 | struct dentry *parent; |
151 | u64 attr_version; | ||
143 | 152 | ||
144 | /* For negative dentries, always do a fresh lookup */ | 153 | /* For negative dentries, always do a fresh lookup */ |
145 | if (!inode) | 154 | if (!inode) |
@@ -156,6 +165,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
156 | return 0; | 165 | return 0; |
157 | } | 166 | } |
158 | 167 | ||
168 | spin_lock(&fc->lock); | ||
169 | attr_version = fc->attr_version; | ||
170 | spin_unlock(&fc->lock); | ||
171 | |||
159 | parent = dget_parent(entry); | 172 | parent = dget_parent(entry); |
160 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | 173 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); |
161 | request_send(fc, req); | 174 | request_send(fc, req); |
@@ -180,8 +193,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
180 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 193 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
181 | return 0; | 194 | return 0; |
182 | 195 | ||
183 | fuse_change_attributes(inode, &outarg.attr); | 196 | fuse_change_attributes(inode, &outarg.attr, |
184 | fuse_change_timeout(entry, &outarg); | 197 | entry_attr_timeout(&outarg), |
198 | attr_version); | ||
199 | fuse_change_entry_timeout(entry, &outarg); | ||
185 | } | 200 | } |
186 | return 1; | 201 | return 1; |
187 | } | 202 | } |
@@ -228,6 +243,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
228 | struct fuse_conn *fc = get_fuse_conn(dir); | 243 | struct fuse_conn *fc = get_fuse_conn(dir); |
229 | struct fuse_req *req; | 244 | struct fuse_req *req; |
230 | struct fuse_req *forget_req; | 245 | struct fuse_req *forget_req; |
246 | u64 attr_version; | ||
231 | 247 | ||
232 | if (entry->d_name.len > FUSE_NAME_MAX) | 248 | if (entry->d_name.len > FUSE_NAME_MAX) |
233 | return ERR_PTR(-ENAMETOOLONG); | 249 | return ERR_PTR(-ENAMETOOLONG); |
@@ -242,6 +258,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
242 | return ERR_PTR(PTR_ERR(forget_req)); | 258 | return ERR_PTR(PTR_ERR(forget_req)); |
243 | } | 259 | } |
244 | 260 | ||
261 | spin_lock(&fc->lock); | ||
262 | attr_version = fc->attr_version; | ||
263 | spin_unlock(&fc->lock); | ||
264 | |||
245 | fuse_lookup_init(req, dir, entry, &outarg); | 265 | fuse_lookup_init(req, dir, entry, &outarg); |
246 | request_send(fc, req); | 266 | request_send(fc, req); |
247 | err = req->out.h.error; | 267 | err = req->out.h.error; |
@@ -253,7 +273,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
253 | err = -EIO; | 273 | err = -EIO; |
254 | if (!err && outarg.nodeid) { | 274 | if (!err && outarg.nodeid) { |
255 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 275 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
256 | &outarg.attr); | 276 | &outarg.attr, entry_attr_timeout(&outarg), |
277 | attr_version); | ||
257 | if (!inode) { | 278 | if (!inode) { |
258 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 279 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
259 | return ERR_PTR(-ENOMEM); | 280 | return ERR_PTR(-ENOMEM); |
@@ -276,7 +297,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
276 | 297 | ||
277 | entry->d_op = &fuse_dentry_operations; | 298 | entry->d_op = &fuse_dentry_operations; |
278 | if (!err) | 299 | if (!err) |
279 | fuse_change_timeout(entry, &outarg); | 300 | fuse_change_entry_timeout(entry, &outarg); |
280 | else | 301 | else |
281 | fuse_invalidate_entry_cache(entry); | 302 | fuse_invalidate_entry_cache(entry); |
282 | return NULL; | 303 | return NULL; |
@@ -363,7 +384,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
363 | 384 | ||
364 | fuse_put_request(fc, req); | 385 | fuse_put_request(fc, req); |
365 | inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, | 386 | inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, |
366 | &outentry.attr); | 387 | &outentry.attr, entry_attr_timeout(&outentry), 0); |
367 | if (!inode) { | 388 | if (!inode) { |
368 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 389 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
369 | ff->fh = outopen.fh; | 390 | ff->fh = outopen.fh; |
@@ -373,7 +394,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
373 | } | 394 | } |
374 | fuse_put_request(fc, forget_req); | 395 | fuse_put_request(fc, forget_req); |
375 | d_instantiate(entry, inode); | 396 | d_instantiate(entry, inode); |
376 | fuse_change_timeout(entry, &outentry); | 397 | fuse_change_entry_timeout(entry, &outentry); |
377 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | 398 | file = lookup_instantiate_filp(nd, entry, generic_file_open); |
378 | if (IS_ERR(file)) { | 399 | if (IS_ERR(file)) { |
379 | ff->fh = outopen.fh; | 400 | ff->fh = outopen.fh; |
@@ -428,7 +449,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
428 | goto out_put_forget_req; | 449 | goto out_put_forget_req; |
429 | 450 | ||
430 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 451 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
431 | &outarg.attr); | 452 | &outarg.attr, entry_attr_timeout(&outarg), 0); |
432 | if (!inode) { | 453 | if (!inode) { |
433 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 454 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
434 | return -ENOMEM; | 455 | return -ENOMEM; |
@@ -451,7 +472,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
451 | } else | 472 | } else |
452 | d_instantiate(entry, inode); | 473 | d_instantiate(entry, inode); |
453 | 474 | ||
454 | fuse_change_timeout(entry, &outarg); | 475 | fuse_change_entry_timeout(entry, &outarg); |
455 | fuse_invalidate_attr(dir); | 476 | fuse_invalidate_attr(dir); |
456 | return 0; | 477 | return 0; |
457 | 478 | ||
@@ -663,15 +684,43 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, | |||
663 | return err; | 684 | return err; |
664 | } | 685 | } |
665 | 686 | ||
666 | static int fuse_do_getattr(struct inode *inode) | 687 | static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, |
688 | struct kstat *stat) | ||
689 | { | ||
690 | stat->dev = inode->i_sb->s_dev; | ||
691 | stat->ino = attr->ino; | ||
692 | stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | ||
693 | stat->nlink = attr->nlink; | ||
694 | stat->uid = attr->uid; | ||
695 | stat->gid = attr->gid; | ||
696 | stat->rdev = inode->i_rdev; | ||
697 | stat->atime.tv_sec = attr->atime; | ||
698 | stat->atime.tv_nsec = attr->atimensec; | ||
699 | stat->mtime.tv_sec = attr->mtime; | ||
700 | stat->mtime.tv_nsec = attr->mtimensec; | ||
701 | stat->ctime.tv_sec = attr->ctime; | ||
702 | stat->ctime.tv_nsec = attr->ctimensec; | ||
703 | stat->size = attr->size; | ||
704 | stat->blocks = attr->blocks; | ||
705 | stat->blksize = (1 << inode->i_blkbits); | ||
706 | } | ||
707 | |||
708 | static int fuse_do_getattr(struct inode *inode, struct kstat *stat) | ||
667 | { | 709 | { |
668 | int err; | 710 | int err; |
669 | struct fuse_attr_out arg; | 711 | struct fuse_attr_out arg; |
670 | struct fuse_conn *fc = get_fuse_conn(inode); | 712 | struct fuse_conn *fc = get_fuse_conn(inode); |
671 | struct fuse_req *req = fuse_get_req(fc); | 713 | struct fuse_req *req; |
714 | u64 attr_version; | ||
715 | |||
716 | req = fuse_get_req(fc); | ||
672 | if (IS_ERR(req)) | 717 | if (IS_ERR(req)) |
673 | return PTR_ERR(req); | 718 | return PTR_ERR(req); |
674 | 719 | ||
720 | spin_lock(&fc->lock); | ||
721 | attr_version = fc->attr_version; | ||
722 | spin_unlock(&fc->lock); | ||
723 | |||
675 | req->in.h.opcode = FUSE_GETATTR; | 724 | req->in.h.opcode = FUSE_GETATTR; |
676 | req->in.h.nodeid = get_node_id(inode); | 725 | req->in.h.nodeid = get_node_id(inode); |
677 | req->out.numargs = 1; | 726 | req->out.numargs = 1; |
@@ -685,30 +734,17 @@ static int fuse_do_getattr(struct inode *inode) | |||
685 | make_bad_inode(inode); | 734 | make_bad_inode(inode); |
686 | err = -EIO; | 735 | err = -EIO; |
687 | } else { | 736 | } else { |
688 | struct fuse_inode *fi = get_fuse_inode(inode); | 737 | fuse_change_attributes(inode, &arg.attr, |
689 | fuse_change_attributes(inode, &arg.attr); | 738 | attr_timeout(&arg), |
690 | fi->i_time = time_to_jiffies(arg.attr_valid, | 739 | attr_version); |
691 | arg.attr_valid_nsec); | 740 | if (stat) |
741 | fuse_fillattr(inode, &arg.attr, stat); | ||
692 | } | 742 | } |
693 | } | 743 | } |
694 | return err; | 744 | return err; |
695 | } | 745 | } |
696 | 746 | ||
697 | /* | 747 | /* |
698 | * Check if attributes are still valid, and if not send a GETATTR | ||
699 | * request to refresh them. | ||
700 | */ | ||
701 | static int fuse_refresh_attributes(struct inode *inode) | ||
702 | { | ||
703 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
704 | |||
705 | if (fi->i_time < get_jiffies_64()) | ||
706 | return fuse_do_getattr(inode); | ||
707 | else | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * Calling into a user-controlled filesystem gives the filesystem | 748 | * Calling into a user-controlled filesystem gives the filesystem |
713 | * daemon ptrace-like capabilities over the requester process. This | 749 | * daemon ptrace-like capabilities over the requester process. This |
714 | * means, that the filesystem daemon is able to record the exact | 750 | * means, that the filesystem daemon is able to record the exact |
@@ -795,11 +831,14 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
795 | */ | 831 | */ |
796 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || | 832 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || |
797 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { | 833 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { |
798 | err = fuse_refresh_attributes(inode); | 834 | struct fuse_inode *fi = get_fuse_inode(inode); |
799 | if (err) | 835 | if (fi->i_time < get_jiffies_64()) { |
800 | return err; | 836 | err = fuse_do_getattr(inode, NULL); |
837 | if (err) | ||
838 | return err; | ||
801 | 839 | ||
802 | refreshed = true; | 840 | refreshed = true; |
841 | } | ||
803 | } | 842 | } |
804 | 843 | ||
805 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { | 844 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { |
@@ -809,7 +848,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
809 | attributes. This is also needed, because the root | 848 | attributes. This is also needed, because the root |
810 | node will at first have no permissions */ | 849 | node will at first have no permissions */ |
811 | if (err == -EACCES && !refreshed) { | 850 | if (err == -EACCES && !refreshed) { |
812 | err = fuse_do_getattr(inode); | 851 | err = fuse_do_getattr(inode, NULL); |
813 | if (!err) | 852 | if (!err) |
814 | err = generic_permission(inode, mask, NULL); | 853 | err = generic_permission(inode, mask, NULL); |
815 | } | 854 | } |
@@ -825,7 +864,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
825 | if (refreshed) | 864 | if (refreshed) |
826 | return -EACCES; | 865 | return -EACCES; |
827 | 866 | ||
828 | err = fuse_do_getattr(inode); | 867 | err = fuse_do_getattr(inode, NULL); |
829 | if (!err && !(inode->i_mode & S_IXUGO)) | 868 | if (!err && !(inode->i_mode & S_IXUGO)) |
830 | return -EACCES; | 869 | return -EACCES; |
831 | } | 870 | } |
@@ -999,7 +1038,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
999 | { | 1038 | { |
1000 | struct inode *inode = entry->d_inode; | 1039 | struct inode *inode = entry->d_inode; |
1001 | struct fuse_conn *fc = get_fuse_conn(inode); | 1040 | struct fuse_conn *fc = get_fuse_conn(inode); |
1002 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
1003 | struct fuse_req *req; | 1041 | struct fuse_req *req; |
1004 | struct fuse_setattr_in inarg; | 1042 | struct fuse_setattr_in inarg; |
1005 | struct fuse_attr_out outarg; | 1043 | struct fuse_attr_out outarg; |
@@ -1053,8 +1091,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
1053 | return -EIO; | 1091 | return -EIO; |
1054 | } | 1092 | } |
1055 | 1093 | ||
1056 | fuse_change_attributes(inode, &outarg.attr); | 1094 | fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0); |
1057 | fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec); | ||
1058 | return 0; | 1095 | return 0; |
1059 | } | 1096 | } |
1060 | 1097 | ||
@@ -1069,8 +1106,10 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, | |||
1069 | if (!fuse_allow_task(fc, current)) | 1106 | if (!fuse_allow_task(fc, current)) |
1070 | return -EACCES; | 1107 | return -EACCES; |
1071 | 1108 | ||
1072 | err = fuse_refresh_attributes(inode); | 1109 | if (fi->i_time < get_jiffies_64()) |
1073 | if (!err) { | 1110 | err = fuse_do_getattr(inode, stat); |
1111 | else { | ||
1112 | err = 0; | ||
1074 | generic_fillattr(inode, stat); | 1113 | generic_fillattr(inode, stat); |
1075 | stat->mode = fi->orig_i_mode; | 1114 | stat->mode = fi->orig_i_mode; |
1076 | } | 1115 | } |