aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorAndrew Gallagher <agallagher@fb.com>2013-11-05 10:05:52 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2014-01-22 13:36:59 -0500
commit7678ac50615d9c7a491d9861e020e4f5f71b594c (patch)
tree0625a52697800b032fd60b652833cf0ba04e43ae /fs/fuse
parent451418fc928b5ec1ee96a9afac807b6312811a2a (diff)
fuse: support clients that don't implement 'open'
open/release operations require userspace transitions to keep track of the open count and to perform any FS-specific setup. However, for some purely read-only FSs which don't need to perform any setup at open/release time, we can avoid the performance overhead of calling into userspace for open/release calls. This patch adds the necessary support to the fuse kernel modules to prevent open/release operations from hitting in userspace. When the client returns ENOSYS, we avoid sending the subsequent release to userspace, and also remember this so that future opens also don't trigger a userspace operation. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/file.c37
-rw-r--r--fs/fuse/fuse_i.h3
2 files changed, 30 insertions, 10 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d53af8f15236..74f6ca500504 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
127 if (atomic_dec_and_test(&ff->count)) { 127 if (atomic_dec_and_test(&ff->count)) {
128 struct fuse_req *req = ff->reserved_req; 128 struct fuse_req *req = ff->reserved_req;
129 129
130 if (sync) { 130 if (ff->fc->no_open) {
131 /*
132 * Drop the release request when client does not
133 * implement 'open'
134 */
135 req->background = 0;
136 path_put(&req->misc.release.path);
137 fuse_put_request(ff->fc, req);
138 } else if (sync) {
131 req->background = 0; 139 req->background = 0;
132 fuse_request_send(ff->fc, req); 140 fuse_request_send(ff->fc, req);
133 path_put(&req->misc.release.path); 141 path_put(&req->misc.release.path);
@@ -144,27 +152,36 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
144int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, 152int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
145 bool isdir) 153 bool isdir)
146{ 154{
147 struct fuse_open_out outarg;
148 struct fuse_file *ff; 155 struct fuse_file *ff;
149 int err;
150 int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; 156 int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
151 157
152 ff = fuse_file_alloc(fc); 158 ff = fuse_file_alloc(fc);
153 if (!ff) 159 if (!ff)
154 return -ENOMEM; 160 return -ENOMEM;
155 161
156 err = fuse_send_open(fc, nodeid, file, opcode, &outarg); 162 ff->fh = 0;
157 if (err) { 163 ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */
158 fuse_file_free(ff); 164 if (!fc->no_open || isdir) {
159 return err; 165 struct fuse_open_out outarg;
166 int err;
167
168 err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
169 if (!err) {
170 ff->fh = outarg.fh;
171 ff->open_flags = outarg.open_flags;
172
173 } else if (err != -ENOSYS || isdir) {
174 fuse_file_free(ff);
175 return err;
176 } else {
177 fc->no_open = 1;
178 }
160 } 179 }
161 180
162 if (isdir) 181 if (isdir)
163 outarg.open_flags &= ~FOPEN_DIRECT_IO; 182 ff->open_flags &= ~FOPEN_DIRECT_IO;
164 183
165 ff->fh = outarg.fh;
166 ff->nodeid = nodeid; 184 ff->nodeid = nodeid;
167 ff->open_flags = outarg.open_flags;
168 file->private_data = fuse_file_get(ff); 185 file->private_data = fuse_file_get(ff);
169 186
170 return 0; 187 return 0;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index dc44b9e3a0c9..2da5db2c8bdb 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -485,6 +485,9 @@ struct fuse_conn {
485 * and hence races in setting them will not cause malfunction 485 * and hence races in setting them will not cause malfunction
486 */ 486 */
487 487
488 /** Is open/release not implemented by fs? */
489 unsigned no_open:1;
490
488 /** Is fsync not implemented by fs? */ 491 /** Is fsync not implemented by fs? */
489 unsigned no_fsync:1; 492 unsigned no_fsync:1;
490 493