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:
parent
451418fc92
commit
7678ac5061
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue