Skip to content

Commit

Permalink
fuse: support clients that don't implement 'open'
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
andrewjcg authored and Miklos Szeredi committed Jan 22, 2014
1 parent 451418f commit 7678ac5
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 10 deletions.
37 changes: 27 additions & 10 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 7678ac5

Please sign in to comment.