Commit d4993774 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: stop copying args to fuse_req



No need to duplicate the argument arrays in fuse_req, so just dereference
req->args instead of copying to the fuse_req internal ones.

This allows further cleanup of the fuse_req structure.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 145b673b
Loading
Loading
Loading
Loading
+26 −54
Original line number Original line Diff line number Diff line
@@ -202,7 +202,8 @@ static unsigned int fuse_req_hash(u64 unique)
static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req)
static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req)
{
{
	req->in.h.len = sizeof(struct fuse_in_header) +
	req->in.h.len = sizeof(struct fuse_in_header) +
		len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
		len_args(req->args->in_numargs,
			 (struct fuse_arg *) req->args->in_args);
	list_add_tail(&req->list, &fiq->pending);
	list_add_tail(&req->list, &fiq->pending);
	wake_up(&fiq->waitq);
	wake_up(&fiq->waitq);
	kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
	kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
@@ -257,6 +258,7 @@ static void flush_bg_queue(struct fuse_conn *fc)
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
{
	struct fuse_iqueue *fiq = &fc->iq;
	struct fuse_iqueue *fiq = &fc->iq;
	bool async = req->args->end;


	if (test_and_set_bit(FR_FINISHED, &req->flags))
	if (test_and_set_bit(FR_FINISHED, &req->flags))
		goto put_request;
		goto put_request;
@@ -302,8 +304,8 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
		wake_up(&req->waitq);
		wake_up(&req->waitq);
	}
	}


	if (req->end)
	if (async)
		req->end(fc, req);
		req->args->end(fc, req->args, req->out.h.error);
put_request:
put_request:
	fuse_put_request(fc, req);
	fuse_put_request(fc, req);
}
}
@@ -450,25 +452,12 @@ void fuse_args_to_req(struct fuse_req *req, struct fuse_args *args)


	req->in.h.opcode = args->opcode;
	req->in.h.opcode = args->opcode;
	req->in.h.nodeid = args->nodeid;
	req->in.h.nodeid = args->nodeid;
	req->in.numargs = args->in_numargs;
	memcpy(req->in.args, args->in_args,
	       args->in_numargs * sizeof(struct fuse_in_arg));
	req->out.argvar = args->out_argvar;
	req->out.numargs = args->out_numargs;
	memcpy(req->out.args, args->out_args,
	       args->out_numargs * sizeof(struct fuse_arg));

	if (args->in_pages || args->out_pages) {
	if (args->in_pages || args->out_pages) {
		req->in.argpages = args->in_pages;
		req->out.argpages = args->out_pages;
		req->out.page_zeroing = args->page_zeroing;
		req->out.page_replace = args->page_replace;

		req->pages = ap->pages;
		req->pages = ap->pages;
		req->page_descs = ap->descs;
		req->page_descs = ap->descs;
		req->num_pages = ap->num_pages;
		req->num_pages = ap->num_pages;
	}
	}

	req->args = args;
}
}


ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
@@ -502,7 +491,7 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
	ret = req->out.h.error;
	ret = req->out.h.error;
	if (!ret && args->out_argvar) {
	if (!ret && args->out_argvar) {
		BUG_ON(args->out_numargs == 0);
		BUG_ON(args->out_numargs == 0);
		ret = req->out.args[args->out_numargs - 1].size;
		ret = args->out_args[args->out_numargs - 1].size;
	}
	}
	fuse_put_request(fc, req);
	fuse_put_request(fc, req);


@@ -538,19 +527,6 @@ static bool fuse_request_queue_background(struct fuse_conn *fc,
	return queued;
	return queued;
}
}


static void fuse_simple_end(struct fuse_conn *fc, struct fuse_req *req)
{
	struct fuse_args *args = req->args;
	int err = req->out.h.error;

	if (!err && args->out_argvar) {
		BUG_ON(args->out_numargs == 0);
		args->out_args[args->out_numargs - 1].size =
			req->out.args[args->out_numargs - 1].size;
	}
	req->args->end(fc, req->args, req->out.h.error);
}

int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args,
int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args,
			    gfp_t gfp_flags)
			    gfp_t gfp_flags)
{
{
@@ -571,9 +547,6 @@ int fuse_simple_background(struct fuse_conn *fc, struct fuse_args *args,


	fuse_args_to_req(req, args);
	fuse_args_to_req(req, args);


	req->args = args;
	req->end = fuse_simple_end;

	if (!fuse_request_queue_background(fc, req)) {
	if (!fuse_request_queue_background(fc, req)) {
		fuse_put_request(fc, req);
		fuse_put_request(fc, req);
		return -ENOTCONN;
		return -ENOTCONN;
@@ -598,8 +571,6 @@ static int fuse_simple_notify_reply(struct fuse_conn *fc,
	req->in.h.unique = unique;
	req->in.h.unique = unique;


	fuse_args_to_req(req, args);
	fuse_args_to_req(req, args);
	req->args = args;
	req->end = fuse_simple_end;


	spin_lock(&fiq->lock);
	spin_lock(&fiq->lock);
	if (fiq->connected) {
	if (fiq->connected) {
@@ -1197,7 +1168,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
	struct fuse_iqueue *fiq = &fc->iq;
	struct fuse_iqueue *fiq = &fc->iq;
	struct fuse_pqueue *fpq = &fud->pq;
	struct fuse_pqueue *fpq = &fud->pq;
	struct fuse_req *req;
	struct fuse_req *req;
	struct fuse_in *in;
	struct fuse_args *args;
	unsigned reqsize;
	unsigned reqsize;
	unsigned int hash;
	unsigned int hash;


@@ -1258,14 +1229,14 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
	list_del_init(&req->list);
	list_del_init(&req->list);
	spin_unlock(&fiq->lock);
	spin_unlock(&fiq->lock);


	in = &req->in;
	args = req->args;
	reqsize = in->h.len;
	reqsize = req->in.h.len;


	/* If request is too large, reply with an error and restart the read */
	/* If request is too large, reply with an error and restart the read */
	if (nbytes < reqsize) {
	if (nbytes < reqsize) {
		req->out.h.error = -EIO;
		req->out.h.error = -EIO;
		/* SETXATTR is special, since it may contain too large data */
		/* SETXATTR is special, since it may contain too large data */
		if (in->h.opcode == FUSE_SETXATTR)
		if (args->opcode == FUSE_SETXATTR)
			req->out.h.error = -E2BIG;
			req->out.h.error = -E2BIG;
		request_end(fc, req);
		request_end(fc, req);
		goto restart;
		goto restart;
@@ -1274,10 +1245,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
	list_add(&req->list, &fpq->io);
	list_add(&req->list, &fpq->io);
	spin_unlock(&fpq->lock);
	spin_unlock(&fpq->lock);
	cs->req = req;
	cs->req = req;
	err = fuse_copy_one(cs, &in->h, sizeof(in->h));
	err = fuse_copy_one(cs, &req->in.h, sizeof(req->in.h));
	if (!err)
	if (!err)
		err = fuse_copy_args(cs, in->numargs, in->argpages,
		err = fuse_copy_args(cs, args->in_numargs, args->in_pages,
				     (struct fuse_arg *) in->args, 0);
				     (struct fuse_arg *) args->in_args, 0);
	fuse_copy_finish(cs);
	fuse_copy_finish(cs);
	spin_lock(&fpq->lock);
	spin_lock(&fpq->lock);
	clear_bit(FR_LOCKED, &req->flags);
	clear_bit(FR_LOCKED, &req->flags);
@@ -1808,27 +1779,25 @@ static struct fuse_req *request_find(struct fuse_pqueue *fpq, u64 unique)
	return NULL;
	return NULL;
}
}


static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out,
static int copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,
			 unsigned nbytes)
			 unsigned nbytes)
{
{
	unsigned reqsize = sizeof(struct fuse_out_header);
	unsigned reqsize = sizeof(struct fuse_out_header);


	if (out->h.error)
	reqsize += len_args(args->out_numargs, args->out_args);
		return nbytes != reqsize ? -EINVAL : 0;

	reqsize += len_args(out->numargs, out->args);


	if (reqsize < nbytes || (reqsize > nbytes && !out->argvar))
	if (reqsize < nbytes || (reqsize > nbytes && !args->out_argvar))
		return -EINVAL;
		return -EINVAL;
	else if (reqsize > nbytes) {
	else if (reqsize > nbytes) {
		struct fuse_arg *lastarg = &out->args[out->numargs-1];
		struct fuse_arg *lastarg = &args->out_args[args->out_numargs-1];
		unsigned diffsize = reqsize - nbytes;
		unsigned diffsize = reqsize - nbytes;

		if (diffsize > lastarg->size)
		if (diffsize > lastarg->size)
			return -EINVAL;
			return -EINVAL;
		lastarg->size -= diffsize;
		lastarg->size -= diffsize;
	}
	}
	return fuse_copy_args(cs, out->numargs, out->argpages, out->args,
	return fuse_copy_args(cs, args->out_numargs, args->out_pages,
			      out->page_zeroing);
			      args->out_args, args->page_zeroing);
}
}


/*
/*
@@ -1907,10 +1876,13 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
	set_bit(FR_LOCKED, &req->flags);
	set_bit(FR_LOCKED, &req->flags);
	spin_unlock(&fpq->lock);
	spin_unlock(&fpq->lock);
	cs->req = req;
	cs->req = req;
	if (!req->out.page_replace)
	if (!req->args->page_replace)
		cs->move_pages = 0;
		cs->move_pages = 0;


	err = copy_out_args(cs, &req->out, nbytes);
	if (oh.error)
		err = nbytes != sizeof(oh) ? -EINVAL : 0;
	else
		err = copy_out_args(cs, req->args, nbytes);
	fuse_copy_finish(cs);
	fuse_copy_finish(cs);


	spin_lock(&fpq->lock);
	spin_lock(&fpq->lock);
+8 −52
Original line number Original line Diff line number Diff line
@@ -224,57 +224,12 @@ struct fuse_in_arg {
	const void *value;
	const void *value;
};
};


/** The request input */
struct fuse_in {
	/** The request header */
	struct fuse_in_header h;

	/** True if the data for the last argument is in req->pages */
	unsigned argpages:1;

	/** Number of arguments */
	unsigned numargs;

	/** Array of arguments */
	struct fuse_in_arg args[3];
};

/** One output argument of a request */
/** One output argument of a request */
struct fuse_arg {
struct fuse_arg {
	unsigned size;
	unsigned size;
	void *value;
	void *value;
};
};


/** The request output */
struct fuse_out {
	/** Header returned from userspace */
	struct fuse_out_header h;

	/*
	 * The following bitfields are not changed during the request
	 * processing
	 */

	/** Last argument is variable length (can be shorter than
	    arg->size) */
	unsigned argvar:1;

	/** Last argument is a list of pages to copy data to */
	unsigned argpages:1;

	/** Zero partially or not copied pages */
	unsigned page_zeroing:1;

	/** Pages may be replaced with new ones */
	unsigned page_replace:1;

	/** Number or arguments */
	unsigned numargs;

	/** Array of arguments */
	struct fuse_arg args[2];
};

/** FUSE page descriptor */
/** FUSE page descriptor */
struct fuse_page_desc {
struct fuse_page_desc {
	unsigned int length;
	unsigned int length;
@@ -385,11 +340,15 @@ struct fuse_req {
	/* Request flags, updated with test/set/clear_bit() */
	/* Request flags, updated with test/set/clear_bit() */
	unsigned long flags;
	unsigned long flags;


	/** The request input */
	/* The request input header */
	struct fuse_in in;
	struct {
		struct fuse_in_header h;
	} in;


	/** The request output */
	/* The request output header */
	struct fuse_out out;
	struct {
		struct fuse_out_header h;
	} out;


	/** Used to wake up the task waiting for completion of request*/
	/** Used to wake up the task waiting for completion of request*/
	wait_queue_head_t waitq;
	wait_queue_head_t waitq;
@@ -403,9 +362,6 @@ struct fuse_req {
	/** number of pages in vector */
	/** number of pages in vector */
	unsigned num_pages;
	unsigned num_pages;


	/** Request completion callback */
	void (*end)(struct fuse_conn *, struct fuse_req *);

};
};


struct fuse_iqueue {
struct fuse_iqueue {