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

Commit 9a57a331 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "fuse: Add support for shortcircuited read/write for files"

parents 8ac5c3ee 759832b6
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 xattr.o acl.o
fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o passthrough.o
+12 −3
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
*/

#include "fuse_i.h"
#include "fuse_passthrough.h"

#include <linux/init.h>
#include <linux/module.h>
@@ -550,10 +551,15 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
	       args->out.numargs * sizeof(struct fuse_arg));
	fuse_request_send(fc, req);
	ret = req->out.h.error;
	if (!ret && args->out.argvar) {
		BUG_ON(args->out.numargs != 1);
	if (!ret) {
		if (args->out.argvar) {
			WARN_ON(args->out.numargs != 1);
			ret = req->out.args[0].size;
		}

		if (req->passthrough_filp != NULL)
			args->out.passthrough_filp = req->passthrough_filp;
	}
	fuse_put_request(fc, req);

	return ret;
@@ -1890,6 +1896,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
	}
	fuse_copy_finish(cs);

	fuse_setup_passthrough(fc, req);


	spin_lock(&fpq->lock);
	clear_bit(FR_LOCKED, &req->flags);
	if (!fpq->connected)
+3 −0
Original line number Diff line number Diff line
@@ -491,6 +491,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	args.out.args[0].value = &outentry;
	args.out.args[1].size = sizeof(outopen);
	args.out.args[1].value = &outopen;
	args.out.passthrough_filp = NULL;
	err = fuse_simple_request(fc, &args);
	if (err)
		goto out_free_ff;
@@ -502,6 +503,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	ff->fh = outopen.fh;
	ff->nodeid = outentry.nodeid;
	ff->open_flags = outopen.open_flags;
	if (args.out.passthrough_filp != NULL)
		ff->passthrough_filp = args.out.passthrough_filp;
	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
			  &outentry.attr, entry_attr_timeout(&outentry), 0);
	if (!inode) {
+42 −5
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
*/

#include "fuse_i.h"
#include "fuse_passthrough.h"

#include <linux/pagemap.h>
#include <linux/slab.h>
@@ -21,8 +22,10 @@
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 **passthrough_filpp)
{
	int ret_val;
	struct fuse_open_in inarg;
	FUSE_ARGS(args);

@@ -38,8 +41,14 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
	args.out.numargs = 1;
	args.out.args[0].size = sizeof(*outargp);
	args.out.args[0].value = outargp;
	args.out.passthrough_filp = NULL;

	return fuse_simple_request(fc, &args);
	ret_val = fuse_simple_request(fc, &args);

	if (args.out.passthrough_filp != NULL)
		*passthrough_filpp = args.out.passthrough_filp;

	return ret_val;
}

struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
@@ -50,6 +59,11 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
	if (unlikely(!ff))
		return NULL;

	ff->passthrough_filp = NULL;
	ff->passthrough_enabled = 0;
	if (fc->passthrough)
		ff->passthrough_enabled = 1;

	ff->fc = fc;
	ff->reserved_req = fuse_request_alloc(0);
	if (unlikely(!ff->reserved_req)) {
@@ -118,6 +132,7 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
		 bool isdir)
{
	struct fuse_file *ff;
	struct file *passthrough_filp = NULL;
	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;

	ff = fuse_file_alloc(fc);
@@ -130,11 +145,12 @@ 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,
				     &(passthrough_filp));
		if (!err) {
			ff->fh = outarg.fh;
			ff->open_flags = outarg.open_flags;

			ff->passthrough_filp = passthrough_filp;
		} else if (err != -ENOSYS || isdir) {
			fuse_file_free(ff);
			return err;
@@ -253,6 +269,8 @@ void fuse_release_common(struct file *file, int opcode)
	if (unlikely(!ff))
		return;

	fuse_passthrough_release(ff);

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

@@ -917,8 +935,10 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,

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.
@@ -933,7 +953,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->passthrough_enabled && ff->passthrough_filp)
		ret_val = fuse_passthrough_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,
@@ -1165,6 +1190,7 @@ static ssize_t fuse_perform_write(struct file *file,
static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *file = iocb->ki_filp;
	struct fuse_file *ff = file->private_data;
	struct address_space *mapping = file->f_mapping;
	ssize_t written = 0;
	ssize_t written_buffered = 0;
@@ -1198,6 +1224,11 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
	if (err)
		goto out;

	if (ff && ff->passthrough_enabled && ff->passthrough_filp) {
		written = fuse_passthrough_write_iter(iocb, from);
		goto out;
	}

	if (iocb->ki_flags & IOCB_DIRECT) {
		loff_t pos = iocb->ki_pos;
		written = generic_file_direct_write(iocb, from);
@@ -2069,6 +2100,9 @@ static const struct vm_operations_struct fuse_file_vm_ops = {

static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct fuse_file *ff = file->private_data;

	ff->passthrough_enabled = 0;
	if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
		fuse_link_write_file(file);

@@ -2079,6 +2113,9 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)

static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct fuse_file *ff = file->private_data;

	ff->passthrough_enabled = 0;
	/* Can't provide the coherency needed for MAP_SHARED */
	if (vma->vm_flags & VM_MAYSHARE)
		return -ENODEV;
+11 −0
Original line number Diff line number Diff line
@@ -153,6 +153,10 @@ struct fuse_file {

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

	/* the read write file */
	struct file *passthrough_filp;
	bool passthrough_enabled;
};

/** One input argument of a request */
@@ -232,6 +236,7 @@ struct fuse_args {
		unsigned argvar:1;
		unsigned numargs;
		struct fuse_arg args[2];
		struct file *passthrough_filp;
	} out;
};

@@ -382,6 +387,9 @@ struct fuse_req {

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

	/** fuse passthrough file  */
	struct file *passthrough_filp;
};

struct fuse_iqueue {
@@ -542,6 +550,9 @@ struct fuse_conn {
	/** handle fs handles killing suid/sgid/cap on write/chown/trunc */
	unsigned handle_killpriv:1;

	/** passthrough IO. */
	unsigned passthrough:1;

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