diff options
-rw-r--r-- | fs/fuse/dir.c | 37 | ||||
-rw-r--r-- | fs/fuse/inode.c | 2 | ||||
-rw-r--r-- | include/linux/fuse.h | 23 |
3 files changed, 47 insertions, 15 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index a058b664859c..8c5d156284a0 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -705,10 +705,12 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, | |||
705 | stat->blksize = (1 << inode->i_blkbits); | 705 | stat->blksize = (1 << inode->i_blkbits); |
706 | } | 706 | } |
707 | 707 | ||
708 | static int fuse_do_getattr(struct inode *inode, struct kstat *stat) | 708 | static int fuse_do_getattr(struct inode *inode, struct kstat *stat, |
709 | struct file *file) | ||
709 | { | 710 | { |
710 | int err; | 711 | int err; |
711 | struct fuse_attr_out arg; | 712 | struct fuse_getattr_in inarg; |
713 | struct fuse_attr_out outarg; | ||
712 | struct fuse_conn *fc = get_fuse_conn(inode); | 714 | struct fuse_conn *fc = get_fuse_conn(inode); |
713 | struct fuse_req *req; | 715 | struct fuse_req *req; |
714 | u64 attr_version; | 716 | u64 attr_version; |
@@ -721,24 +723,35 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat) | |||
721 | attr_version = fc->attr_version; | 723 | attr_version = fc->attr_version; |
722 | spin_unlock(&fc->lock); | 724 | spin_unlock(&fc->lock); |
723 | 725 | ||
726 | memset(&inarg, 0, sizeof(inarg)); | ||
727 | /* Directories have separate file-handle space */ | ||
728 | if (file && S_ISREG(inode->i_mode)) { | ||
729 | struct fuse_file *ff = file->private_data; | ||
730 | |||
731 | inarg.getattr_flags |= FUSE_GETATTR_FH; | ||
732 | inarg.fh = ff->fh; | ||
733 | } | ||
724 | req->in.h.opcode = FUSE_GETATTR; | 734 | req->in.h.opcode = FUSE_GETATTR; |
725 | req->in.h.nodeid = get_node_id(inode); | 735 | req->in.h.nodeid = get_node_id(inode); |
736 | req->in.numargs = 1; | ||
737 | req->in.args[0].size = sizeof(inarg); | ||
738 | req->in.args[0].value = &inarg; | ||
726 | req->out.numargs = 1; | 739 | req->out.numargs = 1; |
727 | req->out.args[0].size = sizeof(arg); | 740 | req->out.args[0].size = sizeof(outarg); |
728 | req->out.args[0].value = &arg; | 741 | req->out.args[0].value = &outarg; |
729 | request_send(fc, req); | 742 | request_send(fc, req); |
730 | err = req->out.h.error; | 743 | err = req->out.h.error; |
731 | fuse_put_request(fc, req); | 744 | fuse_put_request(fc, req); |
732 | if (!err) { | 745 | if (!err) { |
733 | if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { | 746 | if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { |
734 | make_bad_inode(inode); | 747 | make_bad_inode(inode); |
735 | err = -EIO; | 748 | err = -EIO; |
736 | } else { | 749 | } else { |
737 | fuse_change_attributes(inode, &arg.attr, | 750 | fuse_change_attributes(inode, &outarg.attr, |
738 | attr_timeout(&arg), | 751 | attr_timeout(&outarg), |
739 | attr_version); | 752 | attr_version); |
740 | if (stat) | 753 | if (stat) |
741 | fuse_fillattr(inode, &arg.attr, stat); | 754 | fuse_fillattr(inode, &outarg.attr, stat); |
742 | } | 755 | } |
743 | } | 756 | } |
744 | return err; | 757 | return err; |
@@ -833,7 +846,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
833 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { | 846 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { |
834 | struct fuse_inode *fi = get_fuse_inode(inode); | 847 | struct fuse_inode *fi = get_fuse_inode(inode); |
835 | if (fi->i_time < get_jiffies_64()) { | 848 | if (fi->i_time < get_jiffies_64()) { |
836 | err = fuse_do_getattr(inode, NULL); | 849 | err = fuse_do_getattr(inode, NULL, NULL); |
837 | if (err) | 850 | if (err) |
838 | return err; | 851 | return err; |
839 | 852 | ||
@@ -848,7 +861,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
848 | attributes. This is also needed, because the root | 861 | attributes. This is also needed, because the root |
849 | node will at first have no permissions */ | 862 | node will at first have no permissions */ |
850 | if (err == -EACCES && !refreshed) { | 863 | if (err == -EACCES && !refreshed) { |
851 | err = fuse_do_getattr(inode, NULL); | 864 | err = fuse_do_getattr(inode, NULL, NULL); |
852 | if (!err) | 865 | if (!err) |
853 | err = generic_permission(inode, mask, NULL); | 866 | err = generic_permission(inode, mask, NULL); |
854 | } | 867 | } |
@@ -864,7 +877,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
864 | if (refreshed) | 877 | if (refreshed) |
865 | return -EACCES; | 878 | return -EACCES; |
866 | 879 | ||
867 | err = fuse_do_getattr(inode, NULL); | 880 | err = fuse_do_getattr(inode, NULL, NULL); |
868 | if (!err && !(inode->i_mode & S_IXUGO)) | 881 | if (!err && !(inode->i_mode & S_IXUGO)) |
869 | return -EACCES; | 882 | return -EACCES; |
870 | } | 883 | } |
@@ -1107,7 +1120,7 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, | |||
1107 | return -EACCES; | 1120 | return -EACCES; |
1108 | 1121 | ||
1109 | if (fi->i_time < get_jiffies_64()) | 1122 | if (fi->i_time < get_jiffies_64()) |
1110 | err = fuse_do_getattr(inode, stat); | 1123 | err = fuse_do_getattr(inode, stat, NULL); |
1111 | else { | 1124 | else { |
1112 | err = 0; | 1125 | err = 0; |
1113 | generic_fillattr(inode, stat); | 1126 | generic_fillattr(inode, stat); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 2167fc4fcab8..6ef3973f4048 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -553,7 +553,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
553 | arg->major = FUSE_KERNEL_VERSION; | 553 | arg->major = FUSE_KERNEL_VERSION; |
554 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 554 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
555 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 555 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
556 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; | 556 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_FILE_OPS; |
557 | req->in.h.opcode = FUSE_INIT; | 557 | req->in.h.opcode = FUSE_INIT; |
558 | req->in.numargs = 1; | 558 | req->in.numargs = 1; |
559 | req->in.args[0].size = sizeof(*arg); | 559 | req->in.args[0].size = sizeof(*arg); |
diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 9fbe9d258e22..a50d0d9ac7ae 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h | |||
@@ -6,7 +6,14 @@ | |||
6 | See the file COPYING. | 6 | See the file COPYING. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* This file defines the kernel interface of FUSE */ | 9 | /* |
10 | * This file defines the kernel interface of FUSE | ||
11 | * | ||
12 | * Protocol changelog: | ||
13 | * | ||
14 | * 7.9: | ||
15 | * - new fuse_getattr_in input argument of GETATTR | ||
16 | */ | ||
10 | 17 | ||
11 | #include <asm/types.h> | 18 | #include <asm/types.h> |
12 | #include <linux/major.h> | 19 | #include <linux/major.h> |
@@ -15,7 +22,7 @@ | |||
15 | #define FUSE_KERNEL_VERSION 7 | 22 | #define FUSE_KERNEL_VERSION 7 |
16 | 23 | ||
17 | /** Minor version number of this interface */ | 24 | /** Minor version number of this interface */ |
18 | #define FUSE_KERNEL_MINOR_VERSION 8 | 25 | #define FUSE_KERNEL_MINOR_VERSION 9 |
19 | 26 | ||
20 | /** The node ID of the root inode */ | 27 | /** The node ID of the root inode */ |
21 | #define FUSE_ROOT_ID 1 | 28 | #define FUSE_ROOT_ID 1 |
@@ -91,12 +98,18 @@ struct fuse_file_lock { | |||
91 | */ | 98 | */ |
92 | #define FUSE_ASYNC_READ (1 << 0) | 99 | #define FUSE_ASYNC_READ (1 << 0) |
93 | #define FUSE_POSIX_LOCKS (1 << 1) | 100 | #define FUSE_POSIX_LOCKS (1 << 1) |
101 | #define FUSE_FILE_OPS (1 << 2) | ||
94 | 102 | ||
95 | /** | 103 | /** |
96 | * Release flags | 104 | * Release flags |
97 | */ | 105 | */ |
98 | #define FUSE_RELEASE_FLUSH (1 << 0) | 106 | #define FUSE_RELEASE_FLUSH (1 << 0) |
99 | 107 | ||
108 | /** | ||
109 | * Getattr flags | ||
110 | */ | ||
111 | #define FUSE_GETATTR_FH (1 << 0) | ||
112 | |||
100 | enum fuse_opcode { | 113 | enum fuse_opcode { |
101 | FUSE_LOOKUP = 1, | 114 | FUSE_LOOKUP = 1, |
102 | FUSE_FORGET = 2, /* no reply */ | 115 | FUSE_FORGET = 2, /* no reply */ |
@@ -154,6 +167,12 @@ struct fuse_forget_in { | |||
154 | __u64 nlookup; | 167 | __u64 nlookup; |
155 | }; | 168 | }; |
156 | 169 | ||
170 | struct fuse_getattr_in { | ||
171 | __u32 getattr_flags; | ||
172 | __u32 dummy; | ||
173 | __u64 fh; | ||
174 | }; | ||
175 | |||
157 | struct fuse_attr_out { | 176 | struct fuse_attr_out { |
158 | __u64 attr_valid; /* Cache timeout for the attributes */ | 177 | __u64 attr_valid; /* Cache timeout for the attributes */ |
159 | __u32 attr_valid_nsec; | 178 | __u32 attr_valid_nsec; |