Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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
Loading
Loading
Loading
Loading
+27 −10
Original line number Diff line number Diff line
@@ -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;

	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) {
		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;
+3 −0
Original line number Diff line number Diff line
@@ -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;