Commit 7678ac50 authored by Andrew Gallagher's avatar Andrew Gallagher Committed by Miklos Szeredi
Browse files

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: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 451418fc
...@@ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) ...@@ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
if (atomic_dec_and_test(&ff->count)) { if (atomic_dec_and_test(&ff->count)) {
struct fuse_req *req = ff->reserved_req; struct fuse_req *req = ff->reserved_req;
if (sync) { if (ff->fc->no_open) {
/*
* Drop the release request when client does not
* implement 'open'
*/
req->background = 0;
path_put(&req->misc.release.path);
fuse_put_request(ff->fc, req);
} else if (sync) {
req->background = 0; req->background = 0;
fuse_request_send(ff->fc, req); fuse_request_send(ff->fc, req);
path_put(&req->misc.release.path); path_put(&req->misc.release.path);
...@@ -144,27 +152,36 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) ...@@ -144,27 +152,36 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir) bool isdir)
{ {
struct fuse_open_out outarg;
struct fuse_file *ff; struct fuse_file *ff;
int err;
int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
ff = fuse_file_alloc(fc); ff = fuse_file_alloc(fc);
if (!ff) if (!ff)
return -ENOMEM; return -ENOMEM;
ff->fh = 0;
ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */
if (!fc->no_open || isdir) {
struct fuse_open_out outarg;
int err;
err = fuse_send_open(fc, nodeid, file, opcode, &outarg); err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
if (err) { if (!err) {
ff->fh = outarg.fh;
ff->open_flags = outarg.open_flags;
} else if (err != -ENOSYS || isdir) {
fuse_file_free(ff); fuse_file_free(ff);
return err; return err;
} else {
fc->no_open = 1;
}
} }
if (isdir) if (isdir)
outarg.open_flags &= ~FOPEN_DIRECT_IO; ff->open_flags &= ~FOPEN_DIRECT_IO;
ff->fh = outarg.fh;
ff->nodeid = nodeid; ff->nodeid = nodeid;
ff->open_flags = outarg.open_flags;
file->private_data = fuse_file_get(ff); file->private_data = fuse_file_get(ff);
return 0; return 0;
......
...@@ -485,6 +485,9 @@ struct fuse_conn { ...@@ -485,6 +485,9 @@ struct fuse_conn {
* and hence races in setting them will not cause malfunction * and hence races in setting them will not cause malfunction
*/ */
/** Is open/release not implemented by fs? */
unsigned no_open:1;
/** Is fsync not implemented by fs? */ /** Is fsync not implemented by fs? */
unsigned no_fsync:1; unsigned no_fsync:1;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment