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>
This commit is contained in:
Andrew Gallagher 2013-11-05 16:05:52 +01:00 committed by Miklos Szeredi
parent 451418fc92
commit 7678ac5061
2 changed files with 30 additions and 10 deletions

View File

@ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
if (atomic_dec_and_test(&ff->count)) {
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;
fuse_request_send(ff->fc, req);
path_put(&req->misc.release.path);
@ -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,
bool isdir)
{
struct fuse_open_out outarg;
struct fuse_file *ff;
int err;
int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
ff = fuse_file_alloc(fc);
if (!ff)
return -ENOMEM;
err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
if (err) {
fuse_file_free(ff);
return err;
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);
if (!err) {
ff->fh = outarg.fh;
ff->open_flags = outarg.open_flags;
} else if (err != -ENOSYS || isdir) {
fuse_file_free(ff);
return err;
} else {
fc->no_open = 1;
}
}
if (isdir)
outarg.open_flags &= ~FOPEN_DIRECT_IO;
ff->open_flags &= ~FOPEN_DIRECT_IO;
ff->fh = outarg.fh;
ff->nodeid = nodeid;
ff->open_flags = outarg.open_flags;
file->private_data = fuse_file_get(ff);
return 0;

View File

@ -485,6 +485,9 @@ struct fuse_conn {
* 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? */
unsigned no_fsync:1;