From 42bcaf301e9e06836e0a504b211b7fa95260493f Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <miklos@szeredi.hu>
Date: Wed, 10 Nov 2010 11:41:21 +0100
Subject: [PATCH] store fuse_buf inside fuse_bufvec

Store the first fuse_buf inside fuse_bufvec.  This makes
initialization of fuse_bufvec simpler for the common case of a single
fuse_buf.  If multiple fuse_buf's are needed then fuse_bufvec needs to
be dynamically allocated.
---
 include/fuse_common.h |  27 ++++++++--
 lib/fuse_lowlevel.c   | 122 ++++++++++++++++++------------------------
 2 files changed, 73 insertions(+), 76 deletions(-)

diff --git a/include/fuse_common.h b/include/fuse_common.h
index ea8974d..233a0b4 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -368,13 +368,10 @@ struct fuse_buf {
  *
  * An array of data buffers, each containing a memory pointer or a
  * file descriptor.
+ *
+ * Allocate dynamically to add more than one buffer.
  */
 struct fuse_bufvec {
-	/**
-	 * Array of buffers
-	 */
-	const struct fuse_buf *buf;
-
 	/**
 	 * Number of buffers in the array
 	 */
@@ -389,8 +386,28 @@ struct fuse_bufvec {
 	 * Current offset within the current buffer
 	 */
 	size_t off;
+
+	/**
+	 * Array of buffers
+	 */
+	struct fuse_buf buf[1];
 };
 
+/* Initialize bufvec with a single buffer of given size */
+#define FUSE_BUFVEC_INIT(size__) 				\
+	((struct fuse_bufvec) {					\
+		/* .count= */ 1,				\
+		/* .idx =  */ 0,				\
+		/* .off =  */ 0,				\
+		/* .buf =  */ { /* [0] = */ {			\
+			/* .size =  */ (size__),		\
+			/* .flags = */ (enum fuse_buf_flags) 0,	\
+			/* .mem =   */ NULL,			\
+			/* .fd =    */ -1,			\
+			/* .pos =   */ 0,			\
+		} }						\
+	} )
+
 /**
  * Get total size of data in a fuse buffer vector
  *
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 02de394..a19d429 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -496,13 +496,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
 	size_t total_fd_size;
 	size_t idx;
 	size_t headerlen;
-	struct fuse_buf pbuf = {
-		.size = len,
-	};
-	struct fuse_bufvec pipe_buf = {
-		.buf = &pbuf,
-		.count = 1,
-	};
+	struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
 
 	if (f->broken_splice_nonblock)
 		goto fallback;
@@ -565,8 +559,8 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
 		goto clear_pipe;
 	}
 
-	pbuf.flags = FUSE_BUF_IS_FD;
-	pbuf.fd = llp->pipe[1];
+	pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
+	pipe_buf.buf[0].fd = llp->pipe[1];
 
 	res = fuse_buf_copy(&pipe_buf, buf,
 			    FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
@@ -594,13 +588,8 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
 	}
 
 	if (res != 0 && res < len) {
-		struct fuse_buf mbuf = {
-			.size = len,
-		};
-		struct fuse_bufvec mem_buf = {
-			.buf = &mbuf,
-			.count = 1,
-		};
+		struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
+		void *mbuf;
 		size_t now_len = res;
 		/*
 		 * For regular files a short count is either
@@ -611,10 +600,11 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
 		 * the pipe because of small buffer fragments.
 		 */
 
-		res = posix_memalign(&mbuf.mem, pagesize, len);
+		res = posix_memalign(&mbuf, pagesize, len);
 		if (res != 0)
 			goto clear_pipe;
 
+		mem_buf.buf[0].mem = mbuf;
 		mem_buf.off = now_len;
 		res = fuse_buf_copy(&mem_buf, buf, 0);
 		if (res > 0) {
@@ -627,30 +617,30 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
 			 */
 			tmpbuf = malloc(headerlen);
 			if (tmpbuf == NULL) {
-				free(mbuf.mem);
+				free(mbuf);
 				res = ENOMEM;
 				goto clear_pipe;
 			}
 			res = read_back(llp->pipe[0], tmpbuf, headerlen);
 			if (res != 0) {
-				free(mbuf.mem);
+				free(mbuf);
 				goto clear_pipe;
 			}
 			free(tmpbuf);
-			res = read_back(llp->pipe[0], mbuf.mem, now_len);
+			res = read_back(llp->pipe[0], mbuf, now_len);
 			if (res != 0) {
-				free(mbuf.mem);
+				free(mbuf);
 				goto clear_pipe;
 			}
 			len = now_len + extra_len;
-			iov[iov_count].iov_base = mbuf.mem;
+			iov[iov_count].iov_base = mbuf;
 			iov[iov_count].iov_len = len;
 			iov_count++;
 			res = fuse_send_msg(f, ch, iov, iov_count);
-			free(mbuf.mem);
+			free(mbuf);
 			return res;
 		}
-		free(mbuf.mem);
+		free(mbuf);
 		res = now_len;
 	}
 	len = res;
@@ -688,30 +678,26 @@ clear_pipe:
 
 fallback:
 	{
-		struct fuse_buf mbuf = {
-			.size = len,
-		};
-		struct fuse_bufvec mem_buf = {
-			.buf = &mbuf,
-			.count = 1,
-		};
+		struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
+		void *mbuf;
 
-		res = posix_memalign(&mbuf.mem, pagesize, len);
+		res = posix_memalign(&mbuf, pagesize, len);
 		if (res != 0)
 			return res;
 
+		mem_buf.buf[0].mem = mbuf;
 		res = fuse_buf_copy(&mem_buf, buf, 0);
 		if (res < 0) {
-			free(mbuf.mem);
+			free(mbuf);
 			return -res;
 		}
 		len = res;
 
-		iov[iov_count].iov_base = mbuf.mem;
+		iov[iov_count].iov_base = mbuf;
 		iov[iov_count].iov_len = len;
 		iov_count++;
 		res = fuse_send_msg(f, ch, iov, iov_count);
-		free(mbuf.mem);
+		free(mbuf);
 
 		return res;
 	}
@@ -1132,9 +1118,8 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
 			 const struct fuse_buf *ibuf)
 {
 	struct fuse_ll *f = req->f;
-	struct fuse_buf buf = *ibuf;
 	struct fuse_bufvec bufv = {
-		.buf = &buf,
+		.buf[0] = *ibuf,
 		.count = 1,
 	};
 	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
@@ -1146,25 +1131,25 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
 	fi.writepage = arg->write_flags & 1;
 
 	if (req->f->conn.proto_minor < 9) {
-		buf.mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
-		buf.size -= sizeof(struct fuse_in_header) +
+		bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
 			FUSE_COMPAT_WRITE_IN_SIZE;
-		assert(!(buf.flags & FUSE_BUF_IS_FD));
+		assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
 	} else {
 		fi.lock_owner = arg->lock_owner;
 		fi.flags = arg->flags;
-		if (!(buf.flags & FUSE_BUF_IS_FD))
-			buf.mem = PARAM(arg);
+		if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
+			bufv.buf[0].mem = PARAM(arg);
 
-		buf.size -= sizeof(struct fuse_in_header) +
+		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
 			sizeof(struct fuse_write_in);
 	}
-	if (buf.size < arg->size) {
+	if (bufv.buf[0].size < arg->size) {
 		fprintf(stderr, "fuse: do_write_buf: buffer size too small\n");
 		fuse_reply_err(req, EIO);
 		goto out;
 	}
-	buf.size = arg->size;
+	bufv.buf[0].size = arg->size;
 
 	req->f->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
 
@@ -1878,24 +1863,23 @@ static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
 	struct fuse_retrieve_req *rreq =
 		container_of(nreq, struct fuse_retrieve_req, nreq);
 	const struct fuse_notify_retrieve_in *arg = inarg;
-	struct fuse_buf buf = *ibuf;
 	struct fuse_bufvec bufv = {
-		.buf = &buf,
+		.buf[0] = *ibuf,
 		.count = 1,
 	};
 
-	if (!(buf.flags & FUSE_BUF_IS_FD))
-		buf.mem = PARAM(arg);
+	if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
+		bufv.buf[0].mem = PARAM(arg);
 
-	buf.size -= sizeof(struct fuse_in_header) +
+	bufv.buf[0].size -= sizeof(struct fuse_in_header) +
 		sizeof(struct fuse_notify_retrieve_in);
 
-	if (buf.size < arg->size) {
+	if (bufv.buf[0].size < arg->size) {
 		fprintf(stderr, "fuse: retrieve reply: buffer size too small\n");
 		fuse_reply_none(req);
 		goto out;
 	}
-	buf.size = arg->size;
+	bufv.buf[0].size = arg->size;
 
 	if (req->f->op.retrieve_reply)
 		req->f->op.retrieve_reply(rreq->cookie, ino, arg->offset, &bufv);
@@ -2058,18 +2042,15 @@ static const char *opname(enum fuse_opcode opcode)
 		return fuse_ll_ops[opcode].name;
 }
 
-static int fuse_ll_copy_from_pipe(struct fuse_buf *dst,
-				  struct fuse_bufvec *srcv)
+static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
+				  struct fuse_bufvec *src)
 {
-	int res;
-	struct fuse_bufvec dstv = { .buf = dst, .count = 1 };
-
-	res = fuse_buf_copy(&dstv, srcv, 0);
+	int res = fuse_buf_copy(dst, src, 0);
 	if (res < 0) {
 		fprintf(stderr, "fuse: copy from pipe: %s\n", strerror(-res));
 		return res;
 	}
-	if (res < dst->size) {
+	if (res < fuse_buf_size(dst)) {
 		fprintf(stderr, "fuse: copy from pipe: short read\n");
 		return -1;
 	}
@@ -2082,8 +2063,8 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf,
 	struct fuse_ll *f = (struct fuse_ll *) data;
 	const size_t write_header_size = sizeof(struct fuse_in_header) +
 		sizeof(struct fuse_write_in);
-	struct fuse_bufvec bufv = { .buf = buf, .count = 1 };
-	struct fuse_buf tmpbuf = { .size = write_header_size };
+	struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
+	struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
 	struct fuse_in_header *in;
 	const void *inarg;
 	struct fuse_req *req;
@@ -2092,15 +2073,15 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf,
 	int res;
 
 	if (buf->flags & FUSE_BUF_IS_FD) {
-		if (buf->size < tmpbuf.size)
-			tmpbuf.size = buf->size;
+		if (buf->size < tmpbuf.buf[0].size)
+			tmpbuf.buf[0].size = buf->size;
 
-		mbuf = malloc(tmpbuf.size);
+		mbuf = malloc(tmpbuf.buf[0].size);
 		if (mbuf == NULL) {
 			fprintf(stderr, "fuse: failed to allocate header\n");
 			goto clear_pipe;
 		}
-		tmpbuf.mem = mbuf;
+		tmpbuf.buf[0].mem = mbuf;
 
 		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
 		if (res < 0)
@@ -2178,10 +2159,9 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf,
 			goto reply_err;
 		mbuf = newmbuf;
 
-		tmpbuf = (struct fuse_buf) {
-			.size = buf->size - write_header_size,
-			.mem = mbuf + write_header_size,
-		};
+		tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
+		tmpbuf.buf[0].mem = mbuf + write_header_size;
+
 		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
 		err = -res;
 		if (res < 0)
@@ -2390,8 +2370,8 @@ static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
 	 */
 	if (res < sizeof(struct fuse_in_header) +
 	    sizeof(struct fuse_write_in) + pagesize) {
-		struct fuse_bufvec src = { .buf = &tmpbuf, .count = 1 };
-		struct fuse_bufvec dst = { .buf = buf, .count = 1 };
+		struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
+		struct fuse_bufvec dst = { .buf[0] = *buf, .count = 1 };
 
 		res = fuse_buf_copy(&dst, &src, 0);
 		if (res < 0) {
-- 
2.30.2