From 15d85ff1fb518ddd15e03daa297f59457376725f Mon Sep 17 00:00:00 2001 From: Csaba Henk Date: Sun, 16 Aug 2009 07:02:27 -0700 Subject: fuse: optimize request iov aligment for writes Idea by Avati. --- xlators/mount/fuse/src/fuse-bridge.c | 65 +++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) (limited to 'xlators') diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index d78de0dd2..559234c63 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -77,6 +77,7 @@ struct fuse_private { pthread_t fuse_thread; char fuse_thread_started; uint32_t direct_io_mode; + size_t *msg0_len_p; double entry_timeout; double attribute_timeout; pthread_cond_t first_call_cond; @@ -1748,8 +1749,11 @@ fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, static void fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_write_in *fwi = msg; - char *buf = (char *)(fwi + 1); + /* WRITE is special, metadata is attached to in_header, + * and msg is the payload as-is. + */ + struct fuse_write_in *fwi = (struct fuse_write_in *) + (finh + 1); fuse_private_t *priv = NULL; fuse_state_t *state = NULL; @@ -1759,15 +1763,13 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) struct iobuf *iobuf = NULL; priv = this->private; - if (priv->proto_minor < 9) - buf = (char *)msg + FUSE_COMPAT_WRITE_IN_SIZE; GET_STATE (this, finh, state); state->size = fwi->size; state->off = fwi->offset; fd = FH_TO_FD (fwi->fh); state->fd = fd; - vector.iov_base = (void *)buf; + vector.iov_base = msg; vector.iov_len = fwi->size; gf_log ("glusterfs-fuse", GF_LOG_TRACE, @@ -2642,6 +2644,8 @@ fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) priv->direct_io_mode = 0; fino.flags |= FUSE_BIG_WRITES; } + if (fini->minor < 9) + *priv->msg0_len_p = sizeof(*finh) + FUSE_COMPAT_WRITE_IN_SIZE; ret = send_fuse_obj (this, finh, &fino); if (ret == 0) @@ -2760,19 +2764,29 @@ fuse_thread_proc (void *data) struct iobuf *iobuf = NULL; fuse_in_header_t *finh; struct iovec iov_in[2]; + void *msg = NULL; + const size_t msg0_size = sizeof (*finh) + 128; this = data; priv = this->private; THIS = this; - iov_in[0].iov_len = sizeof (fuse_in_header_t); + iov_in[0].iov_len = sizeof (*finh) + sizeof (struct fuse_write_in); iov_in[1].iov_len = ((struct iobuf_pool *)this->ctx->iobuf_pool) ->page_size; + priv->msg0_len_p = &iov_in[0].iov_len; for (;;) { iobuf = iobuf_get (this->ctx->iobuf_pool); - iov_in[0].iov_base = CALLOC (1, sizeof (*finh)); + /* Add extra 128 byte to the first iov so that it can + * accomodate "ordinary" non-write requests. It's not + * guaranteed to be big enough, as SETXATTR and namespace + * operations with very long names may grow behind it, + * but it's good enough in most cases (and we can handle + * rest via realloc). + */ + iov_in[0].iov_base = CALLOC (1, msg0_size); if (!iobuf || !iov_in[0].iov_base) { gf_log (this->name, GF_LOG_ERROR, @@ -2811,10 +2825,7 @@ fuse_thread_proc (void *data) strerror (errno)); } - iobuf_unref (iobuf); - FREE (iov_in[0].iov_base); - - continue; + goto cont_err; } if (res < sizeof (finh)) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "short read on /dev/fuse"); @@ -2829,9 +2840,39 @@ fuse_thread_proc (void *data) priv->iobuf = iobuf; - fuse_ops[finh->opcode] (this, finh, iov_in[1].iov_base); + if (finh->opcode == FUSE_WRITE) + msg = iov_in[1].iov_base; + else { + if (res > msg0_size) { + iov_in[0].iov_base = + realloc (iov_in[0].iov_base, res); + if (iov_in[0].iov_base) + finh = (fuse_in_header_t *) + iov_in[0].iov_base; + else { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "Out of memory"); + send_fuse_err (this, finh, ENOMEM); + + goto cont_err; + } + } + + if (res > iov_in[0].iov_len) + memcpy (iov_in[0].iov_base + iov_in[0].iov_len, + iov_in[1].iov_base, + res - iov_in[0].iov_len); + + msg = finh + 1; + } + fuse_ops[finh->opcode] (this, finh, msg); + + iobuf_unref (iobuf); + continue; + cont_err: iobuf_unref (iobuf); + FREE (iov_in[0].iov_base); } iobuf_unref (iobuf); -- cgit