diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 7 | ||||
-rw-r--r-- | fs/fuse/dir.c | 172 | ||||
-rw-r--r-- | fs/fuse/file.c | 132 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 17 |
4 files changed, 263 insertions, 65 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index a6f90a6c754a..8f873e621f41 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -184,6 +184,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
184 | fuse_putback_request() */ | 184 | fuse_putback_request() */ |
185 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) | 185 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) |
186 | up(&fc->outstanding_sem); | 186 | up(&fc->outstanding_sem); |
187 | } else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) { | ||
188 | /* Special case for failed iget in CREATE */ | ||
189 | u64 nodeid = req->in.h.nodeid; | ||
190 | __fuse_get_request(req); | ||
191 | fuse_reset_request(req); | ||
192 | fuse_send_forget(fc, req, nodeid, 1); | ||
193 | putback = 0; | ||
187 | } | 194 | } |
188 | if (putback) | 195 | if (putback) |
189 | fuse_putback_request(fc, req); | 196 | fuse_putback_request(fc, req); |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 70dba721acab..c045cc70c749 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/gfp.h> | 13 | #include <linux/gfp.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
16 | #include <linux/mount.h> | ||
16 | 17 | ||
17 | static inline unsigned long time_to_jiffies(unsigned long sec, | 18 | static inline unsigned long time_to_jiffies(unsigned long sec, |
18 | unsigned long nsec) | 19 | unsigned long nsec) |
@@ -134,6 +135,101 @@ static void fuse_invalidate_entry(struct dentry *entry) | |||
134 | entry->d_time = jiffies - 1; | 135 | entry->d_time = jiffies - 1; |
135 | } | 136 | } |
136 | 137 | ||
138 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | ||
139 | struct nameidata *nd) | ||
140 | { | ||
141 | int err; | ||
142 | struct inode *inode; | ||
143 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
144 | struct fuse_req *req; | ||
145 | struct fuse_open_in inarg; | ||
146 | struct fuse_open_out outopen; | ||
147 | struct fuse_entry_out outentry; | ||
148 | struct fuse_inode *fi; | ||
149 | struct fuse_file *ff; | ||
150 | struct file *file; | ||
151 | int flags = nd->intent.open.flags - 1; | ||
152 | |||
153 | err = -ENOSYS; | ||
154 | if (fc->no_create) | ||
155 | goto out; | ||
156 | |||
157 | err = -ENAMETOOLONG; | ||
158 | if (entry->d_name.len > FUSE_NAME_MAX) | ||
159 | goto out; | ||
160 | |||
161 | err = -EINTR; | ||
162 | req = fuse_get_request(fc); | ||
163 | if (!req) | ||
164 | goto out; | ||
165 | |||
166 | ff = fuse_file_alloc(); | ||
167 | if (!ff) | ||
168 | goto out_put_request; | ||
169 | |||
170 | flags &= ~O_NOCTTY; | ||
171 | memset(&inarg, 0, sizeof(inarg)); | ||
172 | inarg.flags = flags; | ||
173 | inarg.mode = mode; | ||
174 | req->in.h.opcode = FUSE_CREATE; | ||
175 | req->in.h.nodeid = get_node_id(dir); | ||
176 | req->inode = dir; | ||
177 | req->in.numargs = 2; | ||
178 | req->in.args[0].size = sizeof(inarg); | ||
179 | req->in.args[0].value = &inarg; | ||
180 | req->in.args[1].size = entry->d_name.len + 1; | ||
181 | req->in.args[1].value = entry->d_name.name; | ||
182 | req->out.numargs = 2; | ||
183 | req->out.args[0].size = sizeof(outentry); | ||
184 | req->out.args[0].value = &outentry; | ||
185 | req->out.args[1].size = sizeof(outopen); | ||
186 | req->out.args[1].value = &outopen; | ||
187 | request_send(fc, req); | ||
188 | err = req->out.h.error; | ||
189 | if (err) { | ||
190 | if (err == -ENOSYS) | ||
191 | fc->no_create = 1; | ||
192 | goto out_free_ff; | ||
193 | } | ||
194 | |||
195 | err = -EIO; | ||
196 | if (!S_ISREG(outentry.attr.mode)) | ||
197 | goto out_free_ff; | ||
198 | |||
199 | inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, | ||
200 | &outentry.attr); | ||
201 | err = -ENOMEM; | ||
202 | if (!inode) { | ||
203 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | ||
204 | ff->fh = outopen.fh; | ||
205 | fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); | ||
206 | goto out_put_request; | ||
207 | } | ||
208 | fuse_put_request(fc, req); | ||
209 | entry->d_time = time_to_jiffies(outentry.entry_valid, | ||
210 | outentry.entry_valid_nsec); | ||
211 | fi = get_fuse_inode(inode); | ||
212 | fi->i_time = time_to_jiffies(outentry.attr_valid, | ||
213 | outentry.attr_valid_nsec); | ||
214 | |||
215 | d_instantiate(entry, inode); | ||
216 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | ||
217 | if (IS_ERR(file)) { | ||
218 | ff->fh = outopen.fh; | ||
219 | fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0); | ||
220 | return PTR_ERR(file); | ||
221 | } | ||
222 | fuse_finish_open(inode, file, ff, &outopen); | ||
223 | return 0; | ||
224 | |||
225 | out_free_ff: | ||
226 | fuse_file_free(ff); | ||
227 | out_put_request: | ||
228 | fuse_put_request(fc, req); | ||
229 | out: | ||
230 | return err; | ||
231 | } | ||
232 | |||
137 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | 233 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, |
138 | struct inode *dir, struct dentry *entry, | 234 | struct inode *dir, struct dentry *entry, |
139 | int mode) | 235 | int mode) |
@@ -208,6 +304,12 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, | |||
208 | static int fuse_create(struct inode *dir, struct dentry *entry, int mode, | 304 | static int fuse_create(struct inode *dir, struct dentry *entry, int mode, |
209 | struct nameidata *nd) | 305 | struct nameidata *nd) |
210 | { | 306 | { |
307 | if (nd && (nd->flags & LOOKUP_CREATE)) { | ||
308 | int err = fuse_create_open(dir, entry, mode, nd); | ||
309 | if (err != -ENOSYS) | ||
310 | return err; | ||
311 | /* Fall back on mknod */ | ||
312 | } | ||
211 | return fuse_mknod(dir, entry, mode, 0); | 313 | return fuse_mknod(dir, entry, mode, 0); |
212 | } | 314 | } |
213 | 315 | ||
@@ -461,6 +563,38 @@ static int fuse_revalidate(struct dentry *entry) | |||
461 | return fuse_do_getattr(inode); | 563 | return fuse_do_getattr(inode); |
462 | } | 564 | } |
463 | 565 | ||
566 | static int fuse_access(struct inode *inode, int mask) | ||
567 | { | ||
568 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
569 | struct fuse_req *req; | ||
570 | struct fuse_access_in inarg; | ||
571 | int err; | ||
572 | |||
573 | if (fc->no_access) | ||
574 | return 0; | ||
575 | |||
576 | req = fuse_get_request(fc); | ||
577 | if (!req) | ||
578 | return -EINTR; | ||
579 | |||
580 | memset(&inarg, 0, sizeof(inarg)); | ||
581 | inarg.mask = mask; | ||
582 | req->in.h.opcode = FUSE_ACCESS; | ||
583 | req->in.h.nodeid = get_node_id(inode); | ||
584 | req->inode = inode; | ||
585 | req->in.numargs = 1; | ||
586 | req->in.args[0].size = sizeof(inarg); | ||
587 | req->in.args[0].value = &inarg; | ||
588 | request_send(fc, req); | ||
589 | err = req->out.h.error; | ||
590 | fuse_put_request(fc, req); | ||
591 | if (err == -ENOSYS) { | ||
592 | fc->no_access = 1; | ||
593 | err = 0; | ||
594 | } | ||
595 | return err; | ||
596 | } | ||
597 | |||
464 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 598 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) |
465 | { | 599 | { |
466 | struct fuse_conn *fc = get_fuse_conn(inode); | 600 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -491,11 +625,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
491 | return err; | 625 | return err; |
492 | } else { | 626 | } else { |
493 | int mode = inode->i_mode; | 627 | int mode = inode->i_mode; |
494 | if ((mask & MAY_WRITE) && IS_RDONLY(inode) && | ||
495 | (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) | ||
496 | return -EROFS; | ||
497 | if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) | 628 | if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) |
498 | return -EACCES; | 629 | return -EACCES; |
630 | |||
631 | if (nd && (nd->flags & LOOKUP_ACCESS)) | ||
632 | return fuse_access(inode, mask); | ||
499 | return 0; | 633 | return 0; |
500 | } | 634 | } |
501 | } | 635 | } |
@@ -629,29 +763,29 @@ static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) | |||
629 | return file ? fuse_fsync_common(file, de, datasync, 1) : 0; | 763 | return file ? fuse_fsync_common(file, de, datasync, 1) : 0; |
630 | } | 764 | } |
631 | 765 | ||
632 | static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) | 766 | static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) |
633 | { | 767 | { |
634 | unsigned ivalid = iattr->ia_valid; | 768 | unsigned ivalid = iattr->ia_valid; |
635 | unsigned fvalid = 0; | ||
636 | |||
637 | memset(fattr, 0, sizeof(*fattr)); | ||
638 | 769 | ||
639 | if (ivalid & ATTR_MODE) | 770 | if (ivalid & ATTR_MODE) |
640 | fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; | 771 | arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; |
641 | if (ivalid & ATTR_UID) | 772 | if (ivalid & ATTR_UID) |
642 | fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; | 773 | arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; |
643 | if (ivalid & ATTR_GID) | 774 | if (ivalid & ATTR_GID) |
644 | fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; | 775 | arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; |
645 | if (ivalid & ATTR_SIZE) | 776 | if (ivalid & ATTR_SIZE) |
646 | fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; | 777 | arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; |
647 | /* You can only _set_ these together (they may change by themselves) */ | 778 | /* You can only _set_ these together (they may change by themselves) */ |
648 | if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { | 779 | if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { |
649 | fvalid |= FATTR_ATIME | FATTR_MTIME; | 780 | arg->valid |= FATTR_ATIME | FATTR_MTIME; |
650 | fattr->atime = iattr->ia_atime.tv_sec; | 781 | arg->atime = iattr->ia_atime.tv_sec; |
651 | fattr->mtime = iattr->ia_mtime.tv_sec; | 782 | arg->mtime = iattr->ia_mtime.tv_sec; |
783 | } | ||
784 | if (ivalid & ATTR_FILE) { | ||
785 | struct fuse_file *ff = iattr->ia_file->private_data; | ||
786 | arg->valid |= FATTR_FH; | ||
787 | arg->fh = ff->fh; | ||
652 | } | 788 | } |
653 | |||
654 | return fvalid; | ||
655 | } | 789 | } |
656 | 790 | ||
657 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) | 791 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
@@ -686,7 +820,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
686 | return -EINTR; | 820 | return -EINTR; |
687 | 821 | ||
688 | memset(&inarg, 0, sizeof(inarg)); | 822 | memset(&inarg, 0, sizeof(inarg)); |
689 | inarg.valid = iattr_to_fattr(attr, &inarg.attr); | 823 | iattr_to_fattr(attr, &inarg); |
690 | req->in.h.opcode = FUSE_SETATTR; | 824 | req->in.h.opcode = FUSE_SETATTR; |
691 | req->in.h.nodeid = get_node_id(inode); | 825 | req->in.h.nodeid = get_node_id(inode); |
692 | req->inode = inode; | 826 | req->inode = inode; |
@@ -735,7 +869,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
735 | struct nameidata *nd) | 869 | struct nameidata *nd) |
736 | { | 870 | { |
737 | struct inode *inode; | 871 | struct inode *inode; |
738 | int err = fuse_lookup_iget(dir, entry, &inode); | 872 | int err; |
873 | |||
874 | err = fuse_lookup_iget(dir, entry, &inode); | ||
739 | if (err) | 875 | if (err) |
740 | return ERR_PTR(err); | 876 | return ERR_PTR(err); |
741 | if (inode && S_ISDIR(inode->i_mode)) { | 877 | if (inode && S_ISDIR(inode->i_mode)) { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 657ab11c173b..2ca86141d13a 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -14,11 +14,69 @@ | |||
14 | 14 | ||
15 | static struct file_operations fuse_direct_io_file_operations; | 15 | static struct file_operations fuse_direct_io_file_operations; |
16 | 16 | ||
17 | int fuse_open_common(struct inode *inode, struct file *file, int isdir) | 17 | static int fuse_send_open(struct inode *inode, struct file *file, int isdir, |
18 | struct fuse_open_out *outargp) | ||
18 | { | 19 | { |
19 | struct fuse_conn *fc = get_fuse_conn(inode); | 20 | struct fuse_conn *fc = get_fuse_conn(inode); |
20 | struct fuse_req *req; | ||
21 | struct fuse_open_in inarg; | 21 | struct fuse_open_in inarg; |
22 | struct fuse_req *req; | ||
23 | int err; | ||
24 | |||
25 | req = fuse_get_request(fc); | ||
26 | if (!req) | ||
27 | return -EINTR; | ||
28 | |||
29 | memset(&inarg, 0, sizeof(inarg)); | ||
30 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | ||
31 | req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; | ||
32 | req->in.h.nodeid = get_node_id(inode); | ||
33 | req->inode = inode; | ||
34 | req->in.numargs = 1; | ||
35 | req->in.args[0].size = sizeof(inarg); | ||
36 | req->in.args[0].value = &inarg; | ||
37 | req->out.numargs = 1; | ||
38 | req->out.args[0].size = sizeof(*outargp); | ||
39 | req->out.args[0].value = outargp; | ||
40 | request_send(fc, req); | ||
41 | err = req->out.h.error; | ||
42 | fuse_put_request(fc, req); | ||
43 | |||
44 | return err; | ||
45 | } | ||
46 | |||
47 | struct fuse_file *fuse_file_alloc(void) | ||
48 | { | ||
49 | struct fuse_file *ff; | ||
50 | ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); | ||
51 | if (ff) { | ||
52 | ff->release_req = fuse_request_alloc(); | ||
53 | if (!ff->release_req) { | ||
54 | kfree(ff); | ||
55 | ff = NULL; | ||
56 | } | ||
57 | } | ||
58 | return ff; | ||
59 | } | ||
60 | |||
61 | void fuse_file_free(struct fuse_file *ff) | ||
62 | { | ||
63 | fuse_request_free(ff->release_req); | ||
64 | kfree(ff); | ||
65 | } | ||
66 | |||
67 | void fuse_finish_open(struct inode *inode, struct file *file, | ||
68 | struct fuse_file *ff, struct fuse_open_out *outarg) | ||
69 | { | ||
70 | if (outarg->open_flags & FOPEN_DIRECT_IO) | ||
71 | file->f_op = &fuse_direct_io_file_operations; | ||
72 | if (!(outarg->open_flags & FOPEN_KEEP_CACHE)) | ||
73 | invalidate_inode_pages(inode->i_mapping); | ||
74 | ff->fh = outarg->fh; | ||
75 | file->private_data = ff; | ||
76 | } | ||
77 | |||
78 | int fuse_open_common(struct inode *inode, struct file *file, int isdir) | ||
79 | { | ||
22 | struct fuse_open_out outarg; | 80 | struct fuse_open_out outarg; |
23 | struct fuse_file *ff; | 81 | struct fuse_file *ff; |
24 | int err; | 82 | int err; |
@@ -34,73 +92,53 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) | |||
34 | /* If opening the root node, no lookup has been performed on | 92 | /* If opening the root node, no lookup has been performed on |
35 | it, so the attributes must be refreshed */ | 93 | it, so the attributes must be refreshed */ |
36 | if (get_node_id(inode) == FUSE_ROOT_ID) { | 94 | if (get_node_id(inode) == FUSE_ROOT_ID) { |
37 | int err = fuse_do_getattr(inode); | 95 | err = fuse_do_getattr(inode); |
38 | if (err) | 96 | if (err) |
39 | return err; | 97 | return err; |
40 | } | 98 | } |
41 | 99 | ||
42 | req = fuse_get_request(fc); | 100 | ff = fuse_file_alloc(); |
43 | if (!req) | ||
44 | return -EINTR; | ||
45 | |||
46 | err = -ENOMEM; | ||
47 | ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); | ||
48 | if (!ff) | 101 | if (!ff) |
49 | goto out_put_request; | 102 | return -ENOMEM; |
50 | 103 | ||
51 | ff->release_req = fuse_request_alloc(); | 104 | err = fuse_send_open(inode, file, isdir, &outarg); |
52 | if (!ff->release_req) { | 105 | if (err) |
53 | kfree(ff); | 106 | fuse_file_free(ff); |
54 | goto out_put_request; | 107 | else { |
55 | } | 108 | if (isdir) |
56 | 109 | outarg.open_flags &= ~FOPEN_DIRECT_IO; | |
57 | memset(&inarg, 0, sizeof(inarg)); | 110 | fuse_finish_open(inode, file, ff, &outarg); |
58 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | ||
59 | req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; | ||
60 | req->in.h.nodeid = get_node_id(inode); | ||
61 | req->inode = inode; | ||
62 | req->in.numargs = 1; | ||
63 | req->in.args[0].size = sizeof(inarg); | ||
64 | req->in.args[0].value = &inarg; | ||
65 | req->out.numargs = 1; | ||
66 | req->out.args[0].size = sizeof(outarg); | ||
67 | req->out.args[0].value = &outarg; | ||
68 | request_send(fc, req); | ||
69 | err = req->out.h.error; | ||
70 | if (err) { | ||
71 | fuse_request_free(ff->release_req); | ||
72 | kfree(ff); | ||
73 | } else { | ||
74 | if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO)) | ||
75 | file->f_op = &fuse_direct_io_file_operations; | ||
76 | if (!(outarg.open_flags & FOPEN_KEEP_CACHE)) | ||
77 | invalidate_inode_pages(inode->i_mapping); | ||
78 | ff->fh = outarg.fh; | ||
79 | file->private_data = ff; | ||
80 | } | 111 | } |
81 | 112 | ||
82 | out_put_request: | ||
83 | fuse_put_request(fc, req); | ||
84 | return err; | 113 | return err; |
85 | } | 114 | } |
86 | 115 | ||
87 | int fuse_release_common(struct inode *inode, struct file *file, int isdir) | 116 | void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, |
117 | u64 nodeid, struct inode *inode, int flags, int isdir) | ||
88 | { | 118 | { |
89 | struct fuse_conn *fc = get_fuse_conn(inode); | 119 | struct fuse_req * req = ff->release_req; |
90 | struct fuse_file *ff = file->private_data; | ||
91 | struct fuse_req *req = ff->release_req; | ||
92 | struct fuse_release_in *inarg = &req->misc.release_in; | 120 | struct fuse_release_in *inarg = &req->misc.release_in; |
93 | 121 | ||
94 | inarg->fh = ff->fh; | 122 | inarg->fh = ff->fh; |
95 | inarg->flags = file->f_flags & ~O_EXCL; | 123 | inarg->flags = flags; |
96 | req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; | 124 | req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; |
97 | req->in.h.nodeid = get_node_id(inode); | 125 | req->in.h.nodeid = nodeid; |
98 | req->inode = inode; | 126 | req->inode = inode; |
99 | req->in.numargs = 1; | 127 | req->in.numargs = 1; |
100 | req->in.args[0].size = sizeof(struct fuse_release_in); | 128 | req->in.args[0].size = sizeof(struct fuse_release_in); |
101 | req->in.args[0].value = inarg; | 129 | req->in.args[0].value = inarg; |
102 | request_send_background(fc, req); | 130 | request_send_background(fc, req); |
103 | kfree(ff); | 131 | kfree(ff); |
132 | } | ||
133 | |||
134 | int fuse_release_common(struct inode *inode, struct file *file, int isdir) | ||
135 | { | ||
136 | struct fuse_file *ff = file->private_data; | ||
137 | if (ff) { | ||
138 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
139 | u64 nodeid = get_node_id(inode); | ||
140 | fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir); | ||
141 | } | ||
104 | 142 | ||
105 | /* Return value is ignored by VFS */ | 143 | /* Return value is ignored by VFS */ |
106 | return 0; | 144 | return 0; |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5cb456f572c1..0ea5301f86be 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -266,6 +266,12 @@ struct fuse_conn { | |||
266 | /** Is removexattr not implemented by fs? */ | 266 | /** Is removexattr not implemented by fs? */ |
267 | unsigned no_removexattr : 1; | 267 | unsigned no_removexattr : 1; |
268 | 268 | ||
269 | /** Is access not implemented by fs? */ | ||
270 | unsigned no_access : 1; | ||
271 | |||
272 | /** Is create not implemented by fs? */ | ||
273 | unsigned no_create : 1; | ||
274 | |||
269 | /** Backing dev info */ | 275 | /** Backing dev info */ |
270 | struct backing_dev_info bdi; | 276 | struct backing_dev_info bdi; |
271 | }; | 277 | }; |
@@ -337,6 +343,17 @@ size_t fuse_send_read_common(struct fuse_req *req, struct file *file, | |||
337 | */ | 343 | */ |
338 | int fuse_open_common(struct inode *inode, struct file *file, int isdir); | 344 | int fuse_open_common(struct inode *inode, struct file *file, int isdir); |
339 | 345 | ||
346 | struct fuse_file *fuse_file_alloc(void); | ||
347 | void fuse_file_free(struct fuse_file *ff); | ||
348 | void fuse_finish_open(struct inode *inode, struct file *file, | ||
349 | struct fuse_file *ff, struct fuse_open_out *outarg); | ||
350 | |||
351 | /** | ||
352 | * Send a RELEASE request | ||
353 | */ | ||
354 | void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, | ||
355 | u64 nodeid, struct inode *inode, int flags, int isdir); | ||
356 | |||
340 | /** | 357 | /** |
341 | * Send RELEASE or RELEASEDIR request | 358 | * Send RELEASE or RELEASEDIR request |
342 | */ | 359 | */ |