diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 125 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 12 | ||||
-rw-r--r-- | fs/fuse/inode.c | 22 |
4 files changed, 111 insertions, 50 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 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c4b98c03a46e..4a28c3d37732 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -478,6 +478,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode, | |||
478 | int err; | 478 | int err; |
479 | size_t nres; | 479 | size_t nres; |
480 | struct fuse_conn *fc = get_fuse_conn(inode); | 480 | struct fuse_conn *fc = get_fuse_conn(inode); |
481 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
481 | unsigned offset = pos & (PAGE_CACHE_SIZE - 1); | 482 | unsigned offset = pos & (PAGE_CACHE_SIZE - 1); |
482 | struct fuse_req *req; | 483 | struct fuse_req *req; |
483 | 484 | ||
@@ -499,6 +500,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode, | |||
499 | if (!err) { | 500 | if (!err) { |
500 | pos += nres; | 501 | pos += nres; |
501 | spin_lock(&fc->lock); | 502 | spin_lock(&fc->lock); |
503 | fi->attr_version = ++fc->attr_version; | ||
502 | if (pos > inode->i_size) | 504 | if (pos > inode->i_size) |
503 | i_size_write(inode, pos); | 505 | i_size_write(inode, pos); |
504 | spin_unlock(&fc->lock); | 506 | spin_unlock(&fc->lock); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e7464b8ebbfb..ffbcadaa7d67 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -67,6 +67,9 @@ struct fuse_inode { | |||
67 | /** The sticky bit in inode->i_mode may have been removed, so | 67 | /** The sticky bit in inode->i_mode may have been removed, so |
68 | preserve the original mode */ | 68 | preserve the original mode */ |
69 | mode_t orig_i_mode; | 69 | mode_t orig_i_mode; |
70 | |||
71 | /** Version of last attribute change */ | ||
72 | u64 attr_version; | ||
70 | }; | 73 | }; |
71 | 74 | ||
72 | /** FUSE specific file data */ | 75 | /** FUSE specific file data */ |
@@ -387,6 +390,9 @@ struct fuse_conn { | |||
387 | 390 | ||
388 | /** Reserved request for the DESTROY message */ | 391 | /** Reserved request for the DESTROY message */ |
389 | struct fuse_req *destroy_req; | 392 | struct fuse_req *destroy_req; |
393 | |||
394 | /** Version counter for attribute changes */ | ||
395 | u64 attr_version; | ||
390 | }; | 396 | }; |
391 | 397 | ||
392 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 398 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) |
@@ -416,7 +422,8 @@ extern const struct file_operations fuse_dev_operations; | |||
416 | * Get a filled in inode | 422 | * Get a filled in inode |
417 | */ | 423 | */ |
418 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | 424 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, |
419 | int generation, struct fuse_attr *attr); | 425 | int generation, struct fuse_attr *attr, |
426 | u64 attr_valid, u64 attr_version); | ||
420 | 427 | ||
421 | /** | 428 | /** |
422 | * Send FORGET command | 429 | * Send FORGET command |
@@ -477,7 +484,8 @@ void fuse_init_symlink(struct inode *inode); | |||
477 | /** | 484 | /** |
478 | * Change attributes of an inode | 485 | * Change attributes of an inode |
479 | */ | 486 | */ |
480 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); | 487 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, |
488 | u64 attr_valid, u64 attr_version); | ||
481 | 489 | ||
482 | /** | 490 | /** |
483 | * Initialize the client device | 491 | * Initialize the client device |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 00bb5a255ded..2167fc4fcab8 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -117,12 +117,22 @@ static void fuse_truncate(struct address_space *mapping, loff_t offset) | |||
117 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | 117 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); |
118 | } | 118 | } |
119 | 119 | ||
120 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | 120 | |
121 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | ||
122 | u64 attr_valid, u64 attr_version) | ||
121 | { | 123 | { |
122 | struct fuse_conn *fc = get_fuse_conn(inode); | 124 | struct fuse_conn *fc = get_fuse_conn(inode); |
123 | struct fuse_inode *fi = get_fuse_inode(inode); | 125 | struct fuse_inode *fi = get_fuse_inode(inode); |
124 | loff_t oldsize; | 126 | loff_t oldsize; |
125 | 127 | ||
128 | spin_lock(&fc->lock); | ||
129 | if (attr_version != 0 && fi->attr_version > attr_version) { | ||
130 | spin_unlock(&fc->lock); | ||
131 | return; | ||
132 | } | ||
133 | fi->attr_version = ++fc->attr_version; | ||
134 | fi->i_time = attr_valid; | ||
135 | |||
126 | inode->i_ino = attr->ino; | 136 | inode->i_ino = attr->ino; |
127 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | 137 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); |
128 | inode->i_nlink = attr->nlink; | 138 | inode->i_nlink = attr->nlink; |
@@ -145,7 +155,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
145 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 155 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
146 | inode->i_mode &= ~S_ISVTX; | 156 | inode->i_mode &= ~S_ISVTX; |
147 | 157 | ||
148 | spin_lock(&fc->lock); | ||
149 | oldsize = inode->i_size; | 158 | oldsize = inode->i_size; |
150 | i_size_write(inode, attr->size); | 159 | i_size_write(inode, attr->size); |
151 | spin_unlock(&fc->lock); | 160 | spin_unlock(&fc->lock); |
@@ -194,7 +203,8 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp) | |||
194 | } | 203 | } |
195 | 204 | ||
196 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | 205 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, |
197 | int generation, struct fuse_attr *attr) | 206 | int generation, struct fuse_attr *attr, |
207 | u64 attr_valid, u64 attr_version) | ||
198 | { | 208 | { |
199 | struct inode *inode; | 209 | struct inode *inode; |
200 | struct fuse_inode *fi; | 210 | struct fuse_inode *fi; |
@@ -222,7 +232,8 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
222 | spin_lock(&fc->lock); | 232 | spin_lock(&fc->lock); |
223 | fi->nlookup ++; | 233 | fi->nlookup ++; |
224 | spin_unlock(&fc->lock); | 234 | spin_unlock(&fc->lock); |
225 | fuse_change_attributes(inode, attr); | 235 | fuse_change_attributes(inode, attr, attr_valid, attr_version); |
236 | |||
226 | return inode; | 237 | return inode; |
227 | } | 238 | } |
228 | 239 | ||
@@ -457,6 +468,7 @@ static struct fuse_conn *new_conn(void) | |||
457 | } | 468 | } |
458 | fc->reqctr = 0; | 469 | fc->reqctr = 0; |
459 | fc->blocked = 1; | 470 | fc->blocked = 1; |
471 | fc->attr_version = 1; | ||
460 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | 472 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); |
461 | } | 473 | } |
462 | out: | 474 | out: |
@@ -488,7 +500,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | |||
488 | attr.mode = mode; | 500 | attr.mode = mode; |
489 | attr.ino = FUSE_ROOT_ID; | 501 | attr.ino = FUSE_ROOT_ID; |
490 | attr.nlink = 1; | 502 | attr.nlink = 1; |
491 | return fuse_iget(sb, 1, 0, &attr); | 503 | return fuse_iget(sb, 1, 0, &attr, 0, 0); |
492 | } | 504 | } |
493 | 505 | ||
494 | static const struct super_operations fuse_super_operations = { | 506 | static const struct super_operations fuse_super_operations = { |