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

Commit ef1d3a21 authored by Nikhilesh Reddy's avatar Nikhilesh Reddy
Browse files

fuse: Add support for shortcircuited read/write for files



Add support for shortcircuited read/write for files
when enabled through a userspace init option of
FUSE_SHORTCIRCUIT.

When FUSE_SHORTCIRCUIT is enabled all the reads and writes
to the fuse mount point go directly to the native filesystem
rather than through the fuse daemon. All requsts that aren't
read/write still go thought the userspace code.

This allows for significantly better performance on read and writes
and the difference between fuse and the native lower filesystem is
negligible.

Change-Id: I8258f356963505a2f8499f38879e9e36aba43ad4
Signed-off-by: default avatarNikhilesh Reddy <reddyn@codeaurora.org>
parent 1e289d81
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,4 +5,4 @@
obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o

fuse-objs := dev.o dir.o file.o inode.o control.o
fuse-objs := dev.o dir.o file.o inode.o control.o shortcircuit.o
+3 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
*/

#include "fuse_i.h"
#include "fuse_shortcircuit.h"

#include <linux/init.h>
#include <linux/module.h>
@@ -1867,6 +1868,8 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
	err = copy_out_args(cs, &req->out, nbytes);
	fuse_copy_finish(cs);

	fuse_setup_shortcircuit(fc, req);

	spin_lock(&fc->lock);
	req->locked = 0;
	if (!err) {
+3 −0
Original line number Diff line number Diff line
@@ -460,6 +460,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	if (err)
		goto out_free_ff;

	if (req->private_lower_rw_file != NULL)
		ff->rw_lower_file = req->private_lower_rw_file;

	err = -EIO;
	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
		goto out_free_ff;
+30 −3
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
*/

#include "fuse_i.h"
#include "fuse_shortcircuit.h"

#include <linux/pagemap.h>
#include <linux/slab.h>
@@ -21,7 +22,8 @@
static const struct file_operations fuse_direct_io_file_operations;

static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
			  int opcode, struct fuse_open_out *outargp)
			  int opcode, struct fuse_open_out *outargp,
			  struct file **lower_file)
{
	struct fuse_open_in inarg;
	struct fuse_req *req;
@@ -45,6 +47,10 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
	req->out.args[0].value = outargp;
	fuse_request_send(fc, req);
	err = req->out.h.error;

	if (!err && req->private_lower_rw_file != NULL)
		*lower_file =  req->private_lower_rw_file;

	fuse_put_request(fc, req);

	return err;
@@ -58,6 +64,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
	if (unlikely(!ff))
		return NULL;

	ff->rw_lower_file = NULL;
	ff->fc = fc;
	ff->reserved_req = fuse_request_alloc(0);
	if (unlikely(!ff->reserved_req)) {
@@ -165,7 +172,8 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
		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,
				     &(ff->rw_lower_file));
		if (!err) {
			ff->fh = outarg.fh;
			ff->open_flags = outarg.open_flags;
@@ -288,6 +296,8 @@ void fuse_release_common(struct file *file, int opcode)
	if (unlikely(!ff))
		return;

	fuse_shortcircuit_release(ff);

	req = ff->reserved_req;
	fuse_prepare_release(ff, file->f_flags, opcode);

@@ -935,8 +945,10 @@ out:

static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	ssize_t ret_val;
	struct inode *inode = iocb->ki_filp->f_mapping->host;
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_file *ff = iocb->ki_filp->private_data;

	/*
	 * In auto invalidate mode, always update attributes on read.
@@ -951,7 +963,12 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
			return err;
	}

	return generic_file_read_iter(iocb, to);
	if (ff && ff->rw_lower_file)
		ret_val = fuse_shortcircuit_read_iter(iocb, to);
	else
		ret_val = generic_file_read_iter(iocb, to);

	return ret_val;
}

static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
@@ -1184,6 +1201,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *file = iocb->ki_filp;
	struct address_space *mapping = file->f_mapping;
	struct fuse_file *ff = file->private_data;
	size_t count = iov_iter_count(from);
	ssize_t written = 0;
	ssize_t written_buffered = 0;
@@ -1192,6 +1210,15 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
	loff_t endbyte = 0;
	loff_t pos = iocb->ki_pos;

	if (ff && ff->rw_lower_file) {
		/* Update size (EOF optimization) and mode (SUID clearing) */
		err = fuse_update_attributes(mapping->host, NULL, file, NULL);
		if (err)
			return err;

		return fuse_shortcircuit_write_iter(iocb, from);
	}

	if (get_fuse_conn(inode)->writeback_cache) {
		/* Update size (EOF optimization) and mode (SUID clearing) */
		err = fuse_update_attributes(mapping->host, NULL, file, NULL);
+9 −0
Original line number Diff line number Diff line
@@ -157,6 +157,9 @@ struct fuse_file {

	/** Has flock been performed on this file? */
	bool flock:1;

	/* the read write file */
	struct file *rw_lower_file;
};

/** One input argument of a request */
@@ -362,6 +365,9 @@ struct fuse_req {

	/** Request is stolen from fuse_file->reserved_req */
	struct file *stolen_file;

	/** fuse shortcircuit file  */
	struct file *private_lower_rw_file;
};

/**
@@ -483,6 +489,9 @@ struct fuse_conn {
	/** write-back cache policy (default is write-through) */
	unsigned writeback_cache:1;

	/** Shortcircuited IO. */
	unsigned shortcircuit_io:1;

	/*
	 * The following bitfields are only for optimization purposes
	 * and hence races in setting them will not cause malfunction
Loading