diff options
Diffstat (limited to 'xlators/protocol')
-rw-r--r-- | xlators/protocol/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/protocol/client/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/protocol/client/src/Makefile.am | 16 | ||||
-rw-r--r-- | xlators/protocol/client/src/client-protocol.c | 6671 | ||||
-rw-r--r-- | xlators/protocol/client/src/client-protocol.h | 173 | ||||
-rw-r--r-- | xlators/protocol/client/src/saved-frames.c | 178 | ||||
-rw-r--r-- | xlators/protocol/client/src/saved-frames.h | 74 | ||||
-rw-r--r-- | xlators/protocol/server/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/protocol/server/src/Makefile.am | 18 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-dentry.c | 413 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-helpers.c | 586 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-helpers.h | 77 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-protocol.c | 7984 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-protocol.h | 143 |
14 files changed, 16342 insertions, 0 deletions
diff --git a/xlators/protocol/Makefile.am b/xlators/protocol/Makefile.am new file mode 100644 index 00000000000..745e277c2a6 --- /dev/null +++ b/xlators/protocol/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = client server + +CLEANFILES = diff --git a/xlators/protocol/client/Makefile.am b/xlators/protocol/client/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/protocol/client/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/protocol/client/src/Makefile.am b/xlators/protocol/client/src/Makefile.am new file mode 100644 index 00000000000..fb720942cc6 --- /dev/null +++ b/xlators/protocol/client/src/Makefile.am @@ -0,0 +1,16 @@ + +xlator_LTLIBRARIES = client.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/protocol + +client_la_LDFLAGS = -module -avoidversion + +client_la_SOURCES = client-protocol.c saved-frames.c +client_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = client-protocol.h saved-frames.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) + +CLEANFILES = + diff --git a/xlators/protocol/client/src/client-protocol.c b/xlators/protocol/client/src/client-protocol.c new file mode 100644 index 00000000000..5c93bd6f135 --- /dev/null +++ b/xlators/protocol/client/src/client-protocol.c @@ -0,0 +1,6671 @@ +/* + Copyright (c) 2006, 2007, 2008, 2009 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include <inttypes.h> + + +#include "glusterfs.h" +#include "client-protocol.h" +#include "compat.h" +#include "dict.h" +#include "protocol.h" +#include "transport.h" +#include "xlator.h" +#include "logging.h" +#include "timer.h" +#include "defaults.h" +#include "compat.h" +#include "compat-errno.h" + +#include <sys/resource.h> +#include <inttypes.h> + +/* for default_*_cbk functions */ +#include "defaults.c" +#include "saved-frames.h" + + +int protocol_client_cleanup (transport_t *trans); +int protocol_client_interpret (xlator_t *this, transport_t *trans, + char *hdr_p, size_t hdrlen, + char *buf_p, size_t buflen); +int +protocol_client_xfer (call_frame_t *frame, xlator_t *this, transport_t *trans, + int type, int op, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iovec *vector, int count, + dict_t *refs); + +static gf_op_t gf_fops[]; +static gf_op_t gf_mops[]; +static gf_op_t gf_cbks[]; + + +static ino_t +this_ino_get_from_inode (inode_t *inode, xlator_t *this) +{ + ino_t ino = 0; + int32_t ret = 0; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + if (inode->ino == 1) { + ino = 1; + goto out; + } + + ret = inode_ctx_get (inode, this, &ino); + + if (inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "(%"PRId64"): failed to get remote inode number", + inode->ino); + } + +out: + return ino; +} + + +static ino_t +this_ino_get (loc_t *loc, xlator_t *this, int32_t which) +{ + ino_t ino = 0; + int32_t ret = 0; + inode_t *inode = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, out); + + if (which == GF_CLIENT_INODE_SELF) { + inode = loc->inode; + } else if (which == GF_CLIENT_INODE_PARENT) { + inode = loc->parent; + } + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + if (inode->ino == 1) { + ino = 1; + goto out; + } + + ret = inode_ctx_get (inode, this, &ino); + + if (inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s(%s - %"PRId64") failed to get remote inode number", + loc->path, + (which == GF_CLIENT_INODE_SELF? "self" : "parent"), + inode->ino); + } + +out: + return ino; +} + + +static void +this_ino_set (loc_t *loc, xlator_t *this, ino_t ino) +{ + ino_t old_ino = 0; + int32_t ret = -1; + inode_t *inode = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, out); + + inode = loc->inode; + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + ret = inode_ctx_get (inode, this, &old_ino); + + if (old_ino != ino) { + if (old_ino) + gf_log (this->name, GF_LOG_DEBUG, + "%s: inode number changed from %"PRId64" " + "to %"PRId64, + loc->path, old_ino, ino); + + ret = inode_ctx_put (inode, this, ino); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to set remote " + "inode number to inode ctx", + loc->path, ino); + } + } +out: + return; +} + + +static int +this_fd_get (fd_t *file, xlator_t *this, int64_t *remote_fd) +{ + int ret = 0; + int dict_ret = -1; + uint64_t tmp_fd = 0; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, file, out); + GF_VALIDATE_OR_GOTO (this->name, remote_fd, out); + + dict_ret = fd_ctx_get (file, this, &tmp_fd); + + if (dict_ret < 0) { + ret = -1; + } + *remote_fd = (int64_t)tmp_fd; +out: + return ret; +} + + +static void +this_fd_set (fd_t *file, xlator_t *this, loc_t *loc, int64_t fd) +{ + uint64_t old_fd = 0; + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, file, out); + + ret = fd_ctx_get (file, this, &old_fd); + if (ret >= 0) { + gf_log (this->name, GF_LOG_WARNING, + "%s (%"PRId64"): trying duplicate remote fd set. " + "%"PRId64" over-rides %"PRId64, + loc->path, loc->inode->ino, fd, old_fd); + } + + ret = fd_ctx_set (file, this, (uint64_t)fd); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to set remote fd", + loc->path, loc->inode->ino); + } +out: + return; +} + + +static int +client_local_wipe (client_local_t *local) +{ + if (local) { + loc_wipe (&local->loc); + + if (local->fd) + fd_unref (local->fd); + + free (local); + } + + return 0; +} + +/* + * lookup_frame - lookup call frame corresponding to a given callid + * @trans: transport object + * @callid: call id of the frame + * + * not for external reference + */ + +static call_frame_t * +lookup_frame (transport_t *trans, int32_t op, int8_t type, int64_t callid) +{ + client_connection_t *conn = NULL; + call_frame_t *frame = NULL; + + conn = trans->xl_private; + + pthread_mutex_lock (&conn->lock); + { + frame = saved_frames_get (conn->saved_frames, + op, type, callid); + } + pthread_mutex_unlock (&conn->lock); + + return frame; +} + + +static void +call_bail (void *data) +{ + client_connection_t *conn = NULL; + struct timeval current; + int32_t bail_out = 0; + transport_t *trans = NULL; + + GF_VALIDATE_OR_GOTO("client", data, out); + trans = data; + + conn = trans->xl_private; + + gettimeofday (¤t, NULL); + pthread_mutex_lock (&conn->lock); + { + /* Chaining to get call-always functionality from + call-once timer */ + if (conn->timer) { + struct timeval timeout = {0,}; + gf_timer_cbk_t timer_cbk = conn->timer->cbk; + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + gf_timer_call_cancel (trans->xl->ctx, conn->timer); + conn->timer = gf_timer_call_after (trans->xl->ctx, + timeout, + timer_cbk, + trans); + if (conn->timer == NULL) { + gf_log (trans->xl->name, GF_LOG_DEBUG, + "Cannot create bailout timer"); + } + } + + if (((conn->saved_frames->count > 0) && + (RECEIVE_TIMEOUT(conn, current)) && + (SEND_TIMEOUT(conn, current)))) { + + struct tm last_sent_tm, last_received_tm; + char last_sent[32] = {0,}, last_received[32] = {0,}; + + bail_out = 1; + + localtime_r (&conn->last_sent.tv_sec, + &last_sent_tm); + localtime_r (&conn->last_received.tv_sec, + &last_received_tm); + + strftime (last_sent, 32, + "%Y-%m-%d %H:%M:%S", &last_sent_tm); + strftime (last_received, 32, + "%Y-%m-%d %H:%M:%S", &last_received_tm); + + gf_log (trans->xl->name, GF_LOG_ERROR, + "activating bail-out. pending frames = %d. " + "last sent = %s. last received = %s. " + "transport-timeout = %d", + (int32_t) conn->saved_frames->count, + last_sent, last_received, + conn->transport_timeout); + } + } + + if (bail_out) { + conn->ping_started = 0; + } + + pthread_mutex_unlock (&conn->lock); + + if (bail_out) { + gf_log (trans->xl->name, GF_LOG_CRITICAL, + "bailing transport"); + transport_disconnect (trans); + } +out: + return; +} + + +void +save_frame (transport_t *trans, call_frame_t *frame, + int32_t op, int8_t type, uint64_t callid) +{ + client_connection_t *conn = NULL; + struct timeval timeout = {0, }; + + + conn = trans->xl_private; + + saved_frames_put (conn->saved_frames, frame, op, type, callid); + + if (conn->timer == NULL) { + timeout.tv_sec = 10; + timeout.tv_usec = 0; + conn->timer = gf_timer_call_after (trans->xl->ctx, timeout, + call_bail, (void *) trans); + } +} + + +int +client_get_forgets (xlator_t *this, client_forget_t *forget) +{ + call_frame_t *fr = NULL; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_cbk_forget_req_t *req = NULL; + int ret = -1; + client_conf_t *conf = NULL; + int count = 0; + int index = 0; + + conf = this->private; + + if (conf->forget.count > 0) { + count = conf->forget.count; + + hdrlen = gf_hdr_len (req, (count * sizeof (int64_t))); + hdr = gf_hdr_new (req, (count * sizeof (int64_t))); + GF_VALIDATE_OR_GOTO (this->name, hdr, out); + + req = gf_param (hdr); + + req->count = hton32 (count); + for (index = 0; index < count; index++) { + req->ino_array[index] = + hton64 (conf->forget.ino_array[index]); + } + + fr = create_frame (this, this->ctx->pool); + GF_VALIDATE_OR_GOTO (this->name, fr, out); + + conf->forget.frames_in_transit++; + + forget->frame = fr; + forget->hdr = hdr; + forget->hdrlen = hdrlen; + + ret = count; + + conf->forget.count = 0; + } + out: + return ret; +} + + +void +client_ping_timer_expired (void *data) +{ + xlator_t *this = NULL; + transport_t *trans = NULL; + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + + trans = data; + this = trans->xl; + conf = this->private; + conn = trans->xl_private; + + gf_log (this->name, GF_LOG_ERROR, + "ping timer expired! bailing transport"); + + pthread_mutex_lock (&conn->lock); + { + if (conn->ping_timer) + gf_timer_call_cancel (trans->xl->ctx, + conn->ping_timer); + + conn->ping_started = 0; + conn->ping_timer = NULL; + } + pthread_mutex_unlock (&conn->lock); + transport_disconnect (trans); +} + + +void +client_start_ping (void *data) +{ + xlator_t *this = NULL; + transport_t *trans = NULL; + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + int32_t ret = -1; + gf_hdr_common_t *hdr = NULL; + struct timeval timeout = {0, }; + call_frame_t *dummy_frame = NULL; + size_t hdrlen = -1; + gf_mop_ping_req_t *req = NULL; + + + trans = data; + this = trans->xl; + conf = this->private; + conn = trans->xl_private; + + pthread_mutex_lock (&conn->lock); + { + if ((conn->saved_frames->count == 0) || + !conn->connected) { + /* using goto looked ugly here, + * hence getting out this way */ + if (conn->ping_timer) + gf_timer_call_cancel (trans->xl->ctx, + conn->ping_timer); + conn->ping_timer = NULL; + conn->ping_started = 0; + /* unlock */ + pthread_mutex_unlock (&conn->lock); + return; + } + + if (conn->saved_frames->count < 0) { + gf_log (this->name, GF_LOG_ERROR, + "saved_frames->count is %"PRId64, + conn->saved_frames->count); + conn->saved_frames->count = 0; + } + timeout.tv_sec = conn->ping_timeout; + timeout.tv_usec = 0; + + conn->ping_timer = + gf_timer_call_after (trans->xl->ctx, timeout, + client_ping_timer_expired, + (void *) trans); + + if (conn->ping_timer == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "unable to setup timer"); + } else + conn->ping_started = 1; + } + pthread_mutex_unlock (&conn->lock); + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + + dummy_frame = create_frame (this, this->ctx->pool); + dummy_frame->local = trans; + + ret = protocol_client_xfer (dummy_frame, this, trans, + GF_OP_TYPE_MOP_REQUEST, GF_MOP_PING, + hdr, hdrlen, NULL, 0, NULL); +} + + +int +client_ping_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + xlator_t *this = NULL; + transport_t *trans = NULL; + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + struct timeval timeout = {0, }; + int op_ret = 0; + + trans = frame->local; frame->local = NULL; + this = trans->xl; + conf = this->private; + conn = trans->xl_private; + + op_ret = ntoh32 (hdr->rsp.op_ret); + + if (op_ret == -1) { + /* timer expired and transport bailed out */ + gf_log (this->name, GF_LOG_ERROR, "timer must have expired"); + goto out; + } + + pthread_mutex_lock (&conn->lock); + { + timeout.tv_sec = conn->ping_timeout; + timeout.tv_usec = 0; + + gf_timer_call_cancel (trans->xl->ctx, + conn->ping_timer); + + conn->ping_timer = + gf_timer_call_after (trans->xl->ctx, timeout, + client_start_ping, (void *)trans); + if (conn->ping_timer == NULL) + gf_log (this->name, GF_LOG_ERROR, + "gf_timer_call_after() returned NULL"); + } + pthread_mutex_unlock (&conn->lock); +out: + STACK_DESTROY (frame->root); + return 0; +} + + +int +protocol_client_xfer (call_frame_t *frame, xlator_t *this, transport_t *trans, + int type, int op, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iovec *vector, int count, + dict_t *refs) +{ + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + uint64_t callid = 0; + int32_t ret = -1; + int start_ping = 0; + gf_hdr_common_t rsphdr = {0, }; + client_forget_t forget = {0, }; + uint8_t send_forget = 0; + + + conf = this->private; + + if (!trans) { + /* default to bulk op since it is 'safer' */ + trans = conf->transport[CHANNEL_BULK]; + } + conn = trans->xl_private; + + if (!((type == GF_OP_TYPE_CBK_REQUEST) && + (op == GF_CBK_FORGET))) + { + LOCK (&conf->forget.lock); + { + ret = client_get_forgets (this, &forget); + if (ret <= 0) + send_forget = 0; + else + send_forget = 1; + } + UNLOCK (&conf->forget.lock); + + if (send_forget) { + ret = protocol_client_xfer (forget.frame, this, NULL, + GF_OP_TYPE_CBK_REQUEST, + GF_CBK_FORGET, + forget.hdr, forget.hdrlen, + NULL, 0, NULL); + } + } + + pthread_mutex_lock (&conn->lock); + { + callid = ++conn->callid; + + hdr->callid = hton64 (callid); + hdr->op = hton32 (op); + hdr->type = hton32 (type); + + if (frame) { + hdr->req.uid = hton32 (frame->root->uid); + hdr->req.gid = hton32 (frame->root->gid); + hdr->req.pid = hton32 (frame->root->pid); + } + + if (conn->connected == 0) + transport_connect (trans); + + ret = -1; + + if (conn->connected || + ((type == GF_OP_TYPE_MOP_REQUEST) && + (op == GF_MOP_SETVOLUME))) { + ret = transport_submit (trans, (char *)hdr, hdrlen, + vector, count, refs); + } + + if ((ret >= 0) && frame) { + /* TODO: check this logic */ + gettimeofday (&conn->last_sent, NULL); + save_frame (trans, frame, op, type, callid); + } + + if (!conn->ping_started && (ret >= 0)) { + start_ping = 1; + } + } + pthread_mutex_unlock (&conn->lock); + + if (start_ping) + client_start_ping ((void *) trans); + + if (frame && (ret < 0)) { + rsphdr.op = op; + rsphdr.rsp.op_ret = hton32 (-1); + rsphdr.rsp.op_errno = hton32 (ENOTCONN); + + if (type == GF_OP_TYPE_FOP_REQUEST) { + rsphdr.type = GF_OP_TYPE_FOP_REPLY; + gf_fops[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); + } else if (type == GF_OP_TYPE_MOP_REQUEST) { + rsphdr.type = GF_OP_TYPE_MOP_REPLY; + gf_mops[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); + } else { + rsphdr.type = GF_OP_TYPE_CBK_REPLY; + gf_cbks[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); + } + } + + return ret; +} + + + +/** + * client_create - create function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: complete path to file + * @flags: create flags + * @mode: create mode + * + * external reference through client_protocol_xlator->fops->create + */ + +int +client_create (call_frame_t *frame, xlator_t *this, + loc_t *loc, int32_t flags, + mode_t mode, fd_t *fd) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_create_req_t *req = NULL; + size_t hdrlen = 0; + size_t pathlen = 0; + size_t baselen = 0; + int32_t ret = -1; + ino_t par = 0; + client_conf_t *conf = NULL; + client_local_t *local = NULL; + + + conf = this->private; + + if (conf->child) { + STACK_WIND (frame, default_create_cbk, + conf->child, + conf->child->fops->create, + loc, flags, mode, fd); + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + local->fd = fd_ref (fd); + loc_copy (&local->loc, loc); + + frame->local = local; + + pathlen = STRLEN_0(loc->path); + baselen = STRLEN_0(loc->name); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen); + hdr = gf_hdr_new (req, pathlen + baselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->flags = hton32 (flags); + req->mode = hton32 (mode); + req->par = hton64 (par); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_CREATE, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, fd, NULL, NULL); + return 0; + +} + +/** + * client_open - open function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location of file + * @flags: open flags + * @mode: open modes + * + * external reference through client_protocol_xlator->fops->open + */ +int +client_open (call_frame_t *frame, xlator_t *this, + loc_t *loc, int32_t flags, fd_t *fd) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_fop_open_req_t *req = NULL; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = NULL; + client_local_t *local = NULL; + + conf = this->private; + if (conf->child) { + /* */ + STACK_WIND (frame, default_open_cbk, + conf->child, + conf->child->fops->open, + loc, flags, fd); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + local->fd = fd_ref (fd); + loc_copy (&local->loc, loc); + + frame->local = local; + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->flags = hton32 (flags); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_OPEN, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, fd); + return 0; + +} + + +/** + * client_stat - stat function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->stat + */ +int32_t +client_stat (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_stat_req_t *req = NULL; + size_t hdrlen = -1; + int32_t ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_stat_cbk, + conf->child, + conf->child->fops->stat, + loc); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_STAT, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_readlink - readlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @size: + * + * external reference through client_protocol_xlator->fops->readlink + */ +int32_t +client_readlink (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + size_t size) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readlink_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_readlink_cbk, + conf->child, + conf->child->fops->readlink, + loc, + size); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->size = hton32 (size); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_READLINK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_mknod - mknod function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: pathname of node + * @mode: + * @dev: + * + * external reference through client_protocol_xlator->fops->mknod + */ +int32_t +client_mknod (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode, + dev_t dev) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mknod_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + ino_t par = 0; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_mknod_cbk, + conf->child, + conf->child->fops->mknod, + loc, mode, dev); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, loc); + + frame->local = local; + + pathlen = STRLEN_0(loc->path); + baselen = STRLEN_0(loc->name); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen); + hdr = gf_hdr_new (req, pathlen + baselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->par = hton64 (par); + req->mode = hton32 (mode); + req->dev = hton64 (dev); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_MKNOD, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); + return 0; + +} + + +/** + * client_mkdir - mkdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: pathname of directory + * @mode: + * + * external reference through client_protocol_xlator->fops->mkdir + */ +int32_t +client_mkdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mkdir_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + ino_t par = 0; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_mkdir_cbk, + conf->child, + conf->child->fops->mkdir, + loc, mode); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, loc); + + frame->local = local; + + pathlen = STRLEN_0(loc->path); + baselen = STRLEN_0(loc->name); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen); + hdr = gf_hdr_new (req, pathlen + baselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->par = hton64 (par); + req->mode = hton32 (mode); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_MKDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); + return 0; + +} + + + +/** + * client_unlink - unlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location of file + * + * external reference through client_protocol_xlator->fops->unlink + */ +int32_t +client_unlink (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_unlink_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + ino_t par = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_unlink_cbk, + conf->child, + conf->child->fops->unlink, + loc); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + baselen = STRLEN_0(loc->name); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen); + hdr = gf_hdr_new (req, pathlen + baselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->par = hton64 (par); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_UNLINK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + +/** + * client_rmdir - rmdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->rmdir + */ +int32_t +client_rmdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rmdir_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + ino_t par = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_rmdir_cbk, + conf->child, + conf->child->fops->rmdir, + loc); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + baselen = STRLEN_0(loc->name); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen); + hdr = gf_hdr_new (req, pathlen + baselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->par = hton64 (par); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_RMDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + + + +/** + * client_symlink - symlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldpath: pathname of target + * @newpath: pathname of symlink + * + * external reference through client_protocol_xlator->fops->symlink + */ +int32_t +client_symlink (call_frame_t *frame, + xlator_t *this, + const char *linkname, + loc_t *loc) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_symlink_req_t *req = NULL; + size_t hdrlen = 0; + size_t pathlen = 0; + size_t newlen = 0; + size_t baselen = 0; + ino_t par = 0; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_symlink_cbk, + conf->child, + conf->child->fops->symlink, + linkname, loc); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, loc); + + frame->local = local; + + pathlen = STRLEN_0 (loc->path); + baselen = STRLEN_0 (loc->name); + newlen = STRLEN_0 (linkname); + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, pathlen + baselen + newlen); + hdr = gf_hdr_new (req, pathlen + baselen + newlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->par = hton64 (par); + strcpy (req->path, loc->path); + strcpy (req->bname + pathlen, loc->name); + strcpy (req->linkname + pathlen + baselen, linkname); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_SYMLINK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); + return 0; + +} + + +/** + * client_rename - rename function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldloc: location of old pathname + * @newloc: location of new pathname + * + * external reference through client_protocol_xlator->fops->rename + */ +int32_t +client_rename (call_frame_t *frame, + xlator_t *this, + loc_t *oldloc, + loc_t *newloc) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_rename_req_t *req = NULL; + size_t hdrlen = 0; + size_t oldpathlen = 0; + size_t oldbaselen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + ino_t oldpar = 0; + ino_t newpar = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_rename_cbk, + conf->child, + conf->child->fops->rename, + oldloc, newloc); + + return 0; + } + + oldpathlen = STRLEN_0(oldloc->path); + oldbaselen = STRLEN_0(oldloc->name); + newpathlen = STRLEN_0(newloc->path); + newbaselen = STRLEN_0(newloc->name); + oldpar = this_ino_get (oldloc, this, GF_CLIENT_INODE_PARENT); + newpar = this_ino_get (newloc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, (oldpathlen + oldbaselen + + newpathlen + newbaselen)); + hdr = gf_hdr_new (req, (oldpathlen + oldbaselen + + newpathlen + newbaselen)); + + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->oldpar = hton64 (oldpar); + req->newpar = hton64 (newpar); + + strcpy (req->oldpath, oldloc->path); + strcpy (req->oldbname + oldpathlen, oldloc->name); + strcpy (req->newpath + oldpathlen + oldbaselen, newloc->path); + strcpy (req->newbname + oldpathlen + oldbaselen + newpathlen, + newloc->name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_RENAME, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + + +/** + * client_link - link function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldloc: location of old pathname + * @newpath: new pathname + * + * external reference through client_protocol_xlator->fops->link + */ + +int32_t +client_link (call_frame_t *frame, + xlator_t *this, + loc_t *oldloc, + loc_t *newloc) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_link_req_t *req = NULL; + size_t hdrlen = 0; + size_t oldpathlen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + ino_t oldino = 0; + ino_t newpar = 0; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_link_cbk, + conf->child, + conf->child->fops->link, + oldloc, newloc); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, oldloc); + + frame->local = local; + + oldpathlen = STRLEN_0(oldloc->path); + newpathlen = STRLEN_0(newloc->path); + newbaselen = STRLEN_0(newloc->name); + oldino = this_ino_get (oldloc, this, GF_CLIENT_INODE_SELF); + newpar = this_ino_get (newloc, this, GF_CLIENT_INODE_PARENT); + + hdrlen = gf_hdr_len (req, oldpathlen + newpathlen + newbaselen); + hdr = gf_hdr_new (req, oldpathlen + newpathlen + newbaselen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + strcpy (req->oldpath, oldloc->path); + strcpy (req->newpath + oldpathlen, newloc->path); + strcpy (req->newbname + oldpathlen + newpathlen, newloc->name); + + req->oldino = hton64 (oldino); + req->newpar = hton64 (newpar); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_LINK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, oldloc->inode, NULL); + return 0; +} + + + +/** + * client_chmod - chmod function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @mode: + * + * external reference through client_protocol_xlator->fops->chmod + */ +int32_t +client_chmod (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_chmod_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_chmod_cbk, + conf->child, + conf->child->fops->chmod, + loc, + mode); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->mode = hton32 (mode); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHMOD, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_chown - chown function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @uid: uid of new owner + * @gid: gid of new owner group + * + * external reference through client_protocol_xlator->fops->chown + */ +int32_t +client_chown (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + uid_t uid, + gid_t gid) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_chown_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_chown_cbk, + conf->child, + conf->child->fops->chown, + loc, + uid, + gid); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->uid = hton32 (uid); + req->gid = hton32 (gid); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHOWN, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + +/** + * client_truncate - truncate function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @offset: + * + * external reference through client_protocol_xlator->fops->truncate + */ +int32_t +client_truncate (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_truncate_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_truncate_cbk, + conf->child, + conf->child->fops->truncate, + loc, + offset); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->offset = hton64 (offset); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_TRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + + +/** + * client_utimes - utimes function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @tvp: + * + * external reference through client_protocol_xlator->fops->utimes + */ +int32_t +client_utimens (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + struct timespec *tvp) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_utimens_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_utimens_cbk, + conf->child, + conf->child->fops->utimens, + loc, + tvp); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + gf_timespec_from_timespec (req->tv, tvp); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_UTIMENS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + + +/** + * client_readv - readv function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @size: + * @offset: + * + * external reference through client_protocol_xlator->fops->readv + */ +int32_t +client_readv (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + size_t size, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_read_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_readv_cbk, + conf->child, + conf->child->fops->readv, + fd, + size, + offset); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd, returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL, 0, NULL); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->size = hton32 (size); + req->offset = hton64 (offset); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_READ, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL, 0, NULL); + return 0; + +} + + +/** + * client_writev - writev function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @vector: + * @count: + * @offset: + * + * external reference through client_protocol_xlator->fops->writev + */ +int32_t +client_writev (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + struct iovec *vector, + int32_t count, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_write_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_writev_cbk, + conf->child, + conf->child->fops->writev, + fd, + vector, + count, + offset); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->size = hton32 (iov_length (vector, count)); + req->offset = hton64 (offset); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_WRITE, + hdr, hdrlen, vector, count, + frame->root->req_refs); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_statfs - statfs function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->statfs + */ +int32_t +client_statfs (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_statfs_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_statfs_cbk, + conf->child, + conf->child->fops->statfs, + loc); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_STATFS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_flush - flush function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->fops->flush + */ + +int32_t +client_flush (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_flush_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_flush_cbk, + conf->child, + conf->child->fops->flush, + fd); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FLUSH, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + + + + +/** + * client_fsync - fsync function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @flags: + * + * external reference through client_protocol_xlator->fops->fsync + */ + +int32_t +client_fsync (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t flags) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsync_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int32_t ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fsync_cbk, + conf->child, + conf->child->fops->fsync, + fd, + flags); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND(frame, -1, EBADFD); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->data = hton32 (flags); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSYNC, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + +int32_t +client_xattrop (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + gf_xattrop_flags_t flags, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_xattrop_req_t *req = NULL; + size_t hdrlen = 0; + size_t dict_len = 0; + int32_t ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = NULL; + + GF_VALIDATE_OR_GOTO("client", this, unwind); + + conf = this->private; + if (conf->child) { + /* */ + STACK_WIND (frame, + default_xattrop_cbk, + conf->child, + conf->child->fops->xattrop, + loc, + flags, + dict); + + return 0; + } + + GF_VALIDATE_OR_GOTO(this->name, loc, unwind); + + if (dict) { + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, dict_len + pathlen); + hdr = gf_hdr_new (req, dict_len + pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->flags = hton32 (flags); + req->dict_len = hton32 (dict_len); + if (dict) { + ret = dict_serialize (dict, req->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + dict); + goto unwind; + } + } + req->ino = hton64 (ino); + strcpy (req->path + dict_len, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_XATTROP, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; +} + + +int32_t +client_fxattrop (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + gf_xattrop_flags_t flags, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fxattrop_req_t *req = NULL; + size_t hdrlen = 0; + size_t dict_len = 0; + int64_t remote_fd = -1; + int32_t ret = -1; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fxattrop_cbk, + conf->child, + conf->child->fops->fxattrop, + fd, + flags, + dict); + + return 0; + } + + if (dict) { + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + } + + if (fd) { + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + goto unwind; + } + ino = fd->inode->ino; + } + + hdrlen = gf_hdr_len (req, dict_len); + hdr = gf_hdr_new (req, dict_len); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->flags = hton32 (flags); + req->dict_len = hton32 (dict_len); + if (dict) { + ret = dict_serialize (dict, req->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + dict); + goto unwind; + } + } + req->fd = hton64 (remote_fd); + req->ino = hton64 (ino); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FXATTROP, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + +} + + +/** + * client_setxattr - setxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @dict: dictionary which contains key:value to be set. + * @flags: + * + * external reference through client_protocol_xlator->fops->setxattr + */ +int32_t +client_setxattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + dict_t *dict, + int32_t flags) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setxattr_req_t *req = NULL; + size_t hdrlen = 0; + size_t dict_len = 0; + int ret = -1; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_setxattr_cbk, + conf->child, + conf->child->fops->setxattr, + loc, + dict, + flags); + + return 0; + } + + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, dict_len + pathlen); + hdr = gf_hdr_new (req, dict_len + pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->flags = hton32 (flags); + req->dict_len = hton32 (dict_len); + + ret = dict_serialize (dict, req->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + dict); + goto unwind; + } + + strcpy (req->path + dict_len, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_SETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; +} + +/** + * client_getxattr - getxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * + * external reference through client_protocol_xlator->fops->getxattr + */ +int32_t +client_getxattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_getxattr_req_t *req = NULL; + size_t hdrlen = 0; + size_t pathlen = 0; + size_t namelen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_getxattr_cbk, + conf->child, + conf->child->fops->getxattr, + loc, + name); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + if (name) + namelen = STRLEN_0(name); + + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen + namelen); + hdr = gf_hdr_new (req, pathlen + namelen); + GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->namelen = hton32 (namelen); + strcpy (req->path, loc->path); + if (name) + strcpy (req->name + pathlen, name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_GETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; +} + +/** + * client_removexattr - removexattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * @name: + * + * external reference through client_protocol_xlator->fops->removexattr + */ +int32_t +client_removexattr (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_removexattr_req_t *req = NULL; + size_t hdrlen = 0; + size_t namelen = 0; + size_t pathlen = 0; + ino_t ino = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_removexattr_cbk, + conf->child, + conf->child->fops->removexattr, + loc, + name); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + namelen = STRLEN_0(name); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen + namelen); + hdr = gf_hdr_new (req, pathlen + namelen); + GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + strcpy (req->path, loc->path); + strcpy (req->name + pathlen, name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_REMOVEXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL); + return 0; +} + + +/** + * client_opendir - opendir function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * + * external reference through client_protocol_xlator->fops->opendir + */ +int32_t +client_opendir (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + fd_t *fd) +{ + gf_fop_opendir_req_t *req = NULL; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + int ret = -1; + ino_t ino = 0; + size_t pathlen = 0; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_opendir_cbk, + conf->child, + conf->child->fops->opendir, + loc, fd); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, loc); + local->fd = fd_ref (fd); + + frame->local = local; + + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + pathlen = STRLEN_0(loc->path); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_OPENDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, fd); + return 0; + +} + + +/** + * client_readdir - readdir function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdir + */ + +int32_t +client_getdents (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + size_t size, + off_t offset, + int32_t flag) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_getdents_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_getdents_cbk, + conf->child, + conf->child->fops->getdents, + fd, + size, + offset, + flag); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + + req = gf_param (hdr); + GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + + req->fd = hton64 (remote_fd); + req->size = hton32 (size); + req->offset = hton64 (offset); + req->flags = hton32 (flag); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_GETDENTS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + STACK_UNWIND(frame, -1, EINVAL, NULL, 0); + return 0; +} + +/** + * client_readdir - readdir function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdir + */ + +int32_t +client_readdir (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + size_t size, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readdir_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_readdir_cbk, + conf->child, + conf->child->fops->readdir, + fd, size, offset); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + goto unwind; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req->fd = hton64 (remote_fd); + req->size = hton32 (size); + req->offset = hton64 (offset); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_READDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + +} + + + +/** + * client_fsyncdir - fsyncdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @flags: + * + * external reference through client_protocol_xlator->fops->fsyncdir + */ + +int32_t +client_fsyncdir (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t flags) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsyncdir_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int32_t ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fsyncdir_cbk, + conf->child, + conf->child->fops->fsyncdir, + fd, + flags); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + goto unwind; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->data = hton32 (flags); + req->fd = hton64 (remote_fd); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSYNCDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + STACK_UNWIND (frame, -1, EBADFD); + return 0; +} + + +/** + * client_access - access function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * @mode: + * + * external reference through client_protocol_xlator->fops->access + */ +int32_t +client_access (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t mask) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_access_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + ino_t ino = 0; + size_t pathlen = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_access_cbk, + conf->child, + conf->child->fops->access, + loc, + mask); + + return 0; + } + + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + pathlen = STRLEN_0(loc->path); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->mask = hton32 (mask); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_ACCESS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + + +/** + * client_ftrucate - ftruncate function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @offset: offset to truncate to + * + * external reference through client_protocol_xlator->fops->ftruncate + */ + +int32_t +client_ftruncate (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_ftruncate_req_t *req = NULL; + int64_t remote_fd = -1; + size_t hdrlen = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_ftruncate_cbk, + conf->child, + conf->child->fops->ftruncate, + fd, + offset); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->offset = hton64 (offset); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FTRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_fstat - fstat function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->fops->fstat + */ + +int32_t +client_fstat (call_frame_t *frame, + xlator_t *this, + fd_t *fd) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fstat_req_t *req = NULL; + int64_t remote_fd = -1; + size_t hdrlen = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fstat_cbk, + conf->child, + conf->child->fops->fstat, + fd); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSTAT, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; + +} + + +/** + * client_lk - lk function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @cmd: lock command + * @lock: + * + * external reference through client_protocol_xlator->fops->lk + */ +int32_t +client_lk (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t cmd, + struct flock *flock) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_lk_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int32_t gf_cmd = 0; + int32_t gf_type = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_lk_cbk, + conf->child, + conf->child->fops->lk, + fd, + cmd, + flock); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND(frame, -1, EBADFD, NULL); + return 0; + } + + if (cmd == F_GETLK || cmd == F_GETLK64) + gf_cmd = GF_LK_GETLK; + else if (cmd == F_SETLK || cmd == F_SETLK64) + gf_cmd = GF_LK_SETLK; + else if (cmd == F_SETLKW || cmd == F_SETLKW64) + gf_cmd = GF_LK_SETLKW; + else { + gf_log (this->name, GF_LOG_ERROR, + "Unknown cmd (%d)!", gf_cmd); + goto unwind; + } + + switch (flock->l_type) { + case F_RDLCK: + gf_type = GF_LK_F_RDLCK; + break; + case F_WRLCK: + gf_type = GF_LK_F_WRLCK; + break; + case F_UNLCK: + gf_type = GF_LK_F_UNLCK; + break; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->cmd = hton32 (gf_cmd); + req->type = hton32 (gf_type); + gf_flock_from_flock (&req->flock, flock); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_LK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; +} + + +/** + * client_inodelk - inodelk function for client protocol + * @frame: call frame + * @this: this translator structure + * @inode: inode structure + * @cmd: lock command + * @lock: flock struct + * + * external reference through client_protocol_xlator->fops->inodelk + */ +int32_t +client_inodelk (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t cmd, + struct flock *flock) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_inodelk_req_t *req = NULL; + size_t hdrlen = 0; + int32_t gf_cmd = 0; + int32_t gf_type = 0; + ino_t ino = 0; + size_t pathlen = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_inodelk_cbk, + conf->child, + conf->child->fops->inodelk, + loc, cmd, flock); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + if (cmd == F_GETLK || cmd == F_GETLK64) + gf_cmd = GF_LK_GETLK; + else if (cmd == F_SETLK || cmd == F_SETLK64) + gf_cmd = GF_LK_SETLK; + else if (cmd == F_SETLKW || cmd == F_SETLKW64) + gf_cmd = GF_LK_SETLKW; + else { + gf_log (this->name, GF_LOG_ERROR, + "Unknown cmd (%d)!", gf_cmd); + goto unwind; + } + + switch (flock->l_type) { + case F_RDLCK: + gf_type = GF_LK_F_RDLCK; + break; + case F_WRLCK: + gf_type = GF_LK_F_WRLCK; + break; + case F_UNLCK: + gf_type = GF_LK_F_UNLCK; + break; + } + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + strcpy (req->path, loc->path); + + req->ino = hton64 (ino); + + req->cmd = hton32 (gf_cmd); + req->type = hton32 (gf_type); + gf_flock_from_flock (&req->flock, flock); + + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, + GF_FOP_INODELK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + + +/** + * client_finodelk - finodelk function for client protocol + * @frame: call frame + * @this: this translator structure + * @inode: inode structure + * @cmd: lock command + * @lock: flock struct + * + * external reference through client_protocol_xlator->fops->finodelk + */ +int32_t +client_finodelk (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t cmd, + struct flock *flock) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_finodelk_req_t *req = NULL; + size_t hdrlen = 0; + int32_t gf_cmd = 0; + int32_t gf_type = 0; + int64_t remote_fd = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_finodelk_cbk, + conf->child, + conf->child->fops->finodelk, + fd, cmd, flock); + + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND(frame, -1, EBADFD); + return 0; + } + + if (cmd == F_GETLK || cmd == F_GETLK64) + gf_cmd = GF_LK_GETLK; + else if (cmd == F_SETLK || cmd == F_SETLK64) + gf_cmd = GF_LK_SETLK; + else if (cmd == F_SETLKW || cmd == F_SETLKW64) + gf_cmd = GF_LK_SETLKW; + else { + gf_log (this->name, GF_LOG_ERROR, + "Unknown cmd (%d)!", gf_cmd); + goto unwind; + } + + switch (flock->l_type) { + case F_RDLCK: + gf_type = GF_LK_F_RDLCK; + break; + case F_WRLCK: + gf_type = GF_LK_F_WRLCK; + break; + case F_UNLCK: + gf_type = GF_LK_F_UNLCK; + break; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + + req->cmd = hton32 (gf_cmd); + req->type = hton32 (gf_type); + gf_flock_from_flock (&req->flock, flock); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, + GF_FOP_FINODELK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; +} + + +int32_t +client_entrylk (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name, + entrylk_cmd cmd, + entrylk_type type) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_entrylk_req_t *req = NULL; + size_t pathlen = 0; + size_t hdrlen = -1; + int ret = -1; + ino_t ino = 0; + size_t namelen = 0; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, default_entrylk_cbk, + conf->child, + conf->child->fops->entrylk, + loc, name, cmd, type); + + return 0; + } + + pathlen = STRLEN_0(loc->path); + if (name) + namelen = STRLEN_0(name); + + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + + hdrlen = gf_hdr_len (req, pathlen + namelen); + hdr = gf_hdr_new (req, pathlen + namelen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->namelen = hton64 (namelen); + + strcpy (req->path, loc->path); + if (name) + strcpy (req->name + pathlen, name); + + req->cmd = hton32 (cmd); + req->type = hton32 (type); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_ENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; + +} + + +int32_t +client_fentrylk (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + const char *name, + entrylk_cmd cmd, + entrylk_type type) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fentrylk_req_t *req = NULL; + int64_t remote_fd = -1; + size_t namelen = 0; + size_t hdrlen = -1; + int ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, default_fentrylk_cbk, + conf->child, + conf->child->fops->fentrylk, + fd, name, cmd, type); + + return 0; + } + + if (name) + namelen = STRLEN_0(name); + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + STACK_UNWIND(frame, -1, EBADFD); + return 0; + } + + hdrlen = gf_hdr_len (req, namelen); + hdr = gf_hdr_new (req, namelen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->namelen = hton64 (namelen); + + if (name) + strcpy (req->name, name); + + req->cmd = hton32 (cmd); + req->type = hton32 (type); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + + STACK_UNWIND(frame, -1, EINVAL); + return 0; +} + + +/* + * client_lookup - lookup function for client protocol + * @frame: call frame + * @this: + * @loc: location + * + * not for external reference + */ +int32_t +client_lookup (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + dict_t *xattr_req) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_lookup_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + ino_t ino = 0; + ino_t par = 0; + size_t dictlen = 0; + size_t pathlen = 0; + size_t baselen = 0; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + client_conf_t *conf = this->private; + client_local_t *local = NULL; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_lookup_cbk, + conf->child, + conf->child->fops->lookup, + loc, + xattr_req); + + return 0; + } + + local = calloc (1, sizeof (*local)); + GF_VALIDATE_OR_GOTO(this->name, local, unwind); + + loc_copy (&local->loc, loc); + + frame->local = local; + + GF_VALIDATE_OR_GOTO (this->name, loc, unwind); + GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind); + + if (loc->ino != 1) { + par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind); + baselen = STRLEN_0(loc->name); + } else { + ino = 1; + } + + pathlen = STRLEN_0(loc->path); + + if (xattr_req) { + dictlen = dict_serialized_length (xattr_req); + if (dictlen < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get serialized length of dict(%p)", + xattr_req); + ret = dictlen; + goto unwind; + } + } + + hdrlen = gf_hdr_len (req, pathlen + baselen + dictlen); + hdr = gf_hdr_new (req, pathlen + baselen + dictlen); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->par = hton64 (par); + strcpy (req->path, loc->path); + if (baselen) + strcpy (req->path + pathlen, loc->name); + + if (dictlen) { + ret = dict_serialize (xattr_req, req->dict + baselen + pathlen); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + xattr_req); + goto unwind; + } + } + + req->dictlen = hton32 (dictlen); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_LOOKUP, + hdr, hdrlen, NULL, 0, NULL); + return ret; + +unwind: + STACK_UNWIND (frame, op_ret, op_errno, loc->inode, NULL, NULL); + return ret; +} + + + +/* + * client_fchmod + * + */ +int32_t +client_fchmod (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + mode_t mode) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fchmod_req_t *req = NULL; + int64_t remote_fd = -1; + size_t hdrlen = -1; + int ret = -1; + int32_t op_errno = EINVAL; + int32_t op_ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fchmod_cbk, + conf->child, + conf->child->fops->fchmod, + fd, + mode); + + return 0; + } + + GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + op_errno = EBADFD; + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + goto unwind; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->mode = hton32 (mode); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FCHMOD, + hdr, hdrlen, NULL, 0, NULL); + + return 0; + +unwind: + STACK_UNWIND (frame, op_ret, op_errno, NULL); + return 0; +} + + +/* + * client_fchown - + * + * @frame: + * @this: + * @fd: + * @uid: + * @gid: + * + */ +int32_t +client_fchown (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + uid_t uid, + gid_t gid) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fchown_req_t *req = NULL; + int64_t remote_fd = 0; + size_t hdrlen = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t ret = -1; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_fchown_cbk, + conf->child, + conf->child->fops->fchown, + fd, + uid, + gid); + + return 0; + } + + GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + op_errno = EBADFD; + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + goto unwind; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->uid = hton32 (uid); + req->gid = hton32 (gid); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_FCHOWN, + hdr, hdrlen, NULL, 0, NULL); + + return 0; + +unwind: + STACK_UNWIND (frame, op_ret, op_errno, NULL); + return 0; + +} + +/** + * client_setdents - + */ +int32_t +client_setdents (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t flags, + dir_entry_t *entries, + int32_t count) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setdents_req_t *req = NULL; + int64_t remote_fd = 0; + char *buffer = NULL; + char *ptr = NULL; + data_t *buf_data = NULL; + dict_t *reply_dict = NULL; + dir_entry_t *trav = NULL; + uint32_t len = 0; + int32_t buf_len = 0; + int32_t ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t vec_count = 0; + size_t hdrlen = -1; + struct iovec vector[1]; + client_conf_t *conf = this->private; + + if (conf->child) { + /* */ + STACK_WIND (frame, + default_setdents_cbk, + conf->child, + conf->child->fops->setdents, + fd, + flags, + entries, + count); + + return 0; + } + + GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd. returning EBADFD", + fd->inode->ino); + op_errno = EBADFD; + goto unwind; + } + + GF_VALIDATE_OR_GOTO (this->name, entries, unwind); + GF_VALIDATE_OR_GOTO (this->name, count, unwind); + + trav = entries->next; + while (trav) { + len += strlen (trav->name); + len += 1; + len += strlen (trav->link); + len += 1; + len += 256; // max possible for statbuf; + trav = trav->next; + } + buffer = CALLOC (1, len); + GF_VALIDATE_OR_GOTO (this->name, buffer, unwind); + + ptr = buffer; + + trav = entries->next; + while (trav) { + int32_t this_len = 0; + char *tmp_buf = NULL; + struct stat *stbuf = &trav->buf; + { + /* Convert the stat buf to string */ + uint64_t dev = stbuf->st_dev; + uint64_t ino = stbuf->st_ino; + uint32_t mode = stbuf->st_mode; + uint32_t nlink = stbuf->st_nlink; + uint32_t uid = stbuf->st_uid; + uint32_t gid = stbuf->st_gid; + uint64_t rdev = stbuf->st_rdev; + uint64_t size = stbuf->st_size; + uint32_t blksize = stbuf->st_blksize; + uint64_t blocks = stbuf->st_blocks; + + uint32_t atime = stbuf->st_atime; + uint32_t mtime = stbuf->st_mtime; + uint32_t ctime = stbuf->st_ctime; + + uint32_t atime_nsec = ST_ATIM_NSEC(stbuf); + uint32_t mtime_nsec = ST_MTIM_NSEC(stbuf); + uint32_t ctime_nsec = ST_CTIM_NSEC(stbuf); + + asprintf (&tmp_buf, + GF_STAT_PRINT_FMT_STR, + dev, + ino, + mode, + nlink, + uid, + gid, + rdev, + size, + blksize, + blocks, + atime, + atime_nsec, + mtime, + mtime_nsec, + ctime, + ctime_nsec); + } + this_len = sprintf (ptr, "%s/%s%s\n", + trav->name, + tmp_buf, + trav->link); + + FREE (tmp_buf); + trav = trav->next; + ptr += this_len; + } + buf_len = strlen (buffer); + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + req->flags = hton32 (flags); + req->count = hton32 (count); + + { + buf_data = get_new_data (); + GF_VALIDATE_OR_GOTO (this->name, buf_data, unwind); + reply_dict = get_new_dict(); + GF_VALIDATE_OR_GOTO (this->name, reply_dict, unwind); + + buf_data->data = buffer; + buf_data->len = buf_len; + dict_set (reply_dict, NULL, buf_data); + frame->root->rsp_refs = dict_ref (reply_dict); + vector[0].iov_base = buffer; + vector[0].iov_len = buf_len; + vec_count = 1; + } + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_SETDENTS, + hdr, hdrlen, vector, vec_count, + frame->root->rsp_refs); + + return ret; +unwind: + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + + +/* + * CBKs + */ +/* + * client_forget - forget function for client protocol + * @this: + * @inode: + * + * not for external reference + */ +int32_t +client_forget (xlator_t *this, + inode_t *inode) +{ + ino_t ino = 0; + client_conf_t *conf = NULL; + client_forget_t forget = {0,}; + uint8_t send_forget = 0; + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO ("client", this, out); + conf = this->private; + + if (conf->child) { + /* */ + /* Yenu beda */ + return 0; + } + + GF_VALIDATE_OR_GOTO (this->name, inode, out); + ino = this_ino_get_from_inode (inode, this); + + LOCK (&conf->forget.lock); + { + conf->forget.ino_array[conf->forget.count++] = ino; + + if ((!conf->forget.frames_in_transit) || + (conf->forget.count >= CLIENT_PROTO_FORGET_LIMIT)) { + ret = client_get_forgets (this, &forget); + if (ret <= 0) + send_forget = 0; + else + send_forget = 1; + } + } + UNLOCK (&conf->forget.lock); + + if (send_forget) { + ret = protocol_client_xfer (forget.frame, this, + CLIENT_CHANNEL (this,CHANNEL_BULK), + GF_OP_TYPE_CBK_REQUEST, + GF_CBK_FORGET, + forget.hdr, forget.hdrlen, + NULL, 0, NULL); + } +out: + return 0; +} + +/** + * client_releasedir - releasedir function for client protocol + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->cbks->releasedir + */ + +int32_t +client_releasedir (xlator_t *this, fd_t *fd) +{ + call_frame_t *fr = NULL; + int32_t ret = -1; + int64_t remote_fd = 0; + char key[32] = {0,}; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_cbk_releasedir_req_t *req = NULL; + client_conf_t *conf = NULL; + + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + conf = this->private; + if (conf->child) { + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1){ + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd.", + fd->inode->ino); + goto out; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, out); + + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + + { + sprintf (key, "%p", fd); + + pthread_mutex_lock (&conf->mutex); + { + dict_del (conf->saved_fds, key); + } + pthread_mutex_unlock (&conf->mutex); + } + + fr = create_frame (this, this->ctx->pool); + GF_VALIDATE_OR_GOTO (this->name, fr, out); + + ret = protocol_client_xfer (fr, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_CBK_REQUEST, GF_CBK_RELEASEDIR, + hdr, hdrlen, NULL, 0, NULL); +out: + return ret; +} + + +/** + * client_release - release function for client protocol + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->cbks->release + * + */ +int +client_release (xlator_t *this, fd_t *fd) +{ + call_frame_t *fr = NULL; + int32_t ret = -1; + int64_t remote_fd = 0; + char key[32] = {0,}; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_cbk_release_req_t *req = NULL; + client_conf_t *conf = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + conf = this->private; + + if (conf->child) { + return 0; + } + + ret = this_fd_get (fd, this, &remote_fd); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get remote fd.", + fd->inode->ino); + goto out; + } + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, out); + req = gf_param (hdr); + + req->fd = hton64 (remote_fd); + + { + sprintf (key, "%p", fd); + + pthread_mutex_lock (&conf->mutex); + { + dict_del (conf->saved_fds, key); + } + pthread_mutex_unlock (&conf->mutex); + } + + fr = create_frame (this, this->ctx->pool); + GF_VALIDATE_OR_GOTO (this->name, fr, out); + + ret = protocol_client_xfer (fr, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_CBK_REQUEST, GF_CBK_RELEASE, + hdr, hdrlen, NULL, 0, NULL); +out: + return ret; +} + +/* + * MGMT_OPS + */ + +/** + * client_stats - stats function for client protocol + * @frame: call frame + * @this: this translator structure + * @flags: + * + * external reference through client_protocol_xlator->mops->stats + */ + +int32_t +client_stats (call_frame_t *frame, + xlator_t *this, + int32_t flags) +{ + gf_hdr_common_t *hdr = NULL; + gf_mop_stats_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + client_conf_t *conf = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, unwind); + + conf = this->private; + if (conf->child) { + /* */ + STACK_WIND (frame, + default_stats_cbk, + conf->child, + conf->child->mops->stats, + flags); + + return 0; + } + + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->flags = hton32 (flags); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_MOP_REQUEST, GF_MOP_STATS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + STACK_UNWIND (frame, -1, EINVAL, NULL); + return 0; +} + + +/* Callbacks */ + +int32_t +client_fxattrop_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_xattrop_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t gf_errno = 0; + int32_t op_errno = 0; + int32_t dict_len = 0; + dict_t *dict = NULL; + int32_t ret = -1; + char *dictbuf = NULL; + + rsp = gf_param (hdr); + GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + + op_ret = ntoh32 (hdr->rsp.op_ret); + + if (op_ret >= 0) { + op_ret = -1; + dict_len = ntoh32 (rsp->dict_len); + + if (dict_len > 0) { + dictbuf = memdup (rsp->dict, dict_len); + GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + + dict = dict_new(); + GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); + + ret = dict_unserialize (dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + dict); + op_errno = -ret; + goto fail; + } else { + dict->extra_free = dictbuf; + dictbuf = NULL; + } + } + op_ret = 0; + } + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + +fail: + STACK_UNWIND (frame, op_ret, op_errno, dict); + + if (dictbuf) + free (dictbuf); + + if (dict) + dict_unref (dict); + + return 0; +} + +int32_t +client_xattrop_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_xattrop_rsp_t *rsp = NULL; + int32_t op_ret = -1; + int32_t gf_errno = EINVAL; + int32_t op_errno = 0; + int32_t dict_len = 0; + dict_t *dict = NULL; + int32_t ret = -1; + char *dictbuf = NULL; + + rsp = gf_param (hdr); + GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + + op_ret = ntoh32 (hdr->rsp.op_ret); + if (op_ret >= 0) { + op_ret = -1; + dict_len = ntoh32 (rsp->dict_len); + + if (dict_len > 0) { + dictbuf = memdup (rsp->dict, dict_len); + GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + + dict = get_new_dict(); + GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); + dict_ref (dict); + + ret = dict_unserialize (dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + dict); + goto fail; + } else { + dict->extra_free = dictbuf; + dictbuf = NULL; + } + } + op_ret = 0; + } + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + + +fail: + STACK_UNWIND (frame, op_ret, op_errno, dict); + + if (dictbuf) + free (dictbuf); + if (dict) + dict_unref (dict); + + return 0; +} + +/* + * client_chown_cbk - + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_fchown_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_fchown_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + + +/* + * client_fchmod_cbk + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_fchmod_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_fchmod_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + + +/* + * client_create_cbk - create callback function for client protocol + * @frame: call frame + * @args: arguments in dictionary + * + * not for external reference + */ + +int +client_create_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_create_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + fd_t *fd = NULL; + inode_t *inode = NULL; + struct stat stbuf = {0, }; + int64_t remote_fd = 0; + char key[32] = {0, }; + int32_t ret = -1; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + + + local = frame->local; frame->local = NULL; + conf = frame->this->private; + fd = local->fd; + inode = local->loc.inode; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = ntoh32 (hdr->rsp.op_errno); + + if (op_ret >= 0) { + remote_fd = ntoh64 (rsp->fd); + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + if (op_ret >= 0) { + this_ino_set (&local->loc, frame->this, stbuf.st_ino); + this_fd_set (fd, frame->this, &local->loc, remote_fd); + + sprintf (key, "%p", fd); + + pthread_mutex_lock (&conf->mutex); + { + ret = dict_set_str (conf->saved_fds, key, ""); + } + pthread_mutex_unlock (&conf->mutex); + + if (ret < 0) { + free (key); + gf_log (frame->this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to save remote fd", + local->loc.path, stbuf.st_ino); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, fd, inode, &stbuf); + + client_local_wipe (local); + + return 0; +} + + +/* + * client_open_cbk - open callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_open_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = -1; + int32_t op_errno = ENOTCONN; + fd_t *fd = NULL; + int64_t remote_fd = 0; + gf_fop_open_rsp_t *rsp = NULL; + char key[32] = {0,}; + int32_t ret = -1; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + + + local = frame->local; frame->local = NULL; + conf = frame->this->private; + fd = local->fd; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = ntoh32 (hdr->rsp.op_errno); + + if (op_ret >= 0) { + remote_fd = ntoh64 (rsp->fd); + } + + if (op_ret >= 0) { + this_fd_set (fd, frame->this, &local->loc, remote_fd); + + sprintf (key, "%p", fd); + + pthread_mutex_lock (&conf->mutex); + { + ret = dict_set_str (conf->saved_fds, key, ""); + } + pthread_mutex_unlock (&conf->mutex); + + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to save remote fd", + local->loc.path, local->loc.inode->ino); + free (key); + } + + } + + STACK_UNWIND (frame, op_ret, op_errno, fd); + + client_local_wipe (local); + + return 0; +} + +/* + * client_stat_cbk - stat callback for client protocol + * @frame: call frame + * @args: arguments dictionary + * + * not for external reference + */ +int +client_stat_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_stat_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_utimens_cbk - utimens callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_utimens_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_utimens_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_chmod_cbk - chmod for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_chmod_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_chmod_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_chown_cbk - chown for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_chown_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_chown_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_mknod_cbk - mknod callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_mknod_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_mknod_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct stat stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + + local = frame->local; + frame->local = NULL; + inode = local->loc.inode; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + this_ino_set (&local->loc, frame->this, stbuf.st_ino); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); + + client_local_wipe (local); + + return 0; +} + +/* + * client_symlink_cbk - symlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_symlink_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_symlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct stat stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + + local = frame->local; + frame->local = NULL; + inode = local->loc.inode; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + this_ino_set (&local->loc, frame->this, stbuf.st_ino); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); + + client_local_wipe (local); + + return 0; +} + +/* + * client_link_cbk - link callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_link_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_link_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct stat stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + + local = frame->local; + frame->local = NULL; + inode = local->loc.inode; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); + + client_local_wipe (local); + + return 0; +} + +/* + * client_truncate_cbk - truncate callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_truncate_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_truncate_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* client_fstat_cbk - fstat callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_fstat_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_fstat_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_ftruncate_cbk - ftruncate callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_ftruncate_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_ftruncate_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* client_readv_cbk - readv callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external referece + */ + +int32_t +client_readv_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_read_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iovec vector = {0, }; + struct stat stbuf = {0, }; + dict_t *refs = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret != -1) { + gf_stat_to_stat (&rsp->stat, &stbuf); + vector.iov_base = buf; + vector.iov_len = buflen; + + refs = get_new_dict (); + dict_set (refs, NULL, data_from_dynptr (buf, 0)); + frame->root->rsp_refs = dict_ref (refs); + } + + STACK_UNWIND (frame, op_ret, op_errno, &vector, 1, &stbuf); + + if (refs) + dict_unref (refs); + + return 0; +} + +/* + * client_write_cbk - write callback for client protocol + * @frame: cal frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_write_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_write_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct stat stbuf = {0, }; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) + gf_stat_to_stat (&rsp->stat, &stbuf); + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + + +int32_t +client_readdir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_readdir_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + uint32_t buf_size = 0; + gf_dirent_t entries; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = ntoh32 (hdr->rsp.op_errno); + + INIT_LIST_HEAD (&entries.list); + if (op_ret > 0) { + buf_size = ntoh32 (rsp->size); + gf_dirent_unserialize (&entries, rsp->buf, buf_size); + } + + STACK_UNWIND (frame, op_ret, op_errno, &entries); + + gf_dirent_free (&entries); + + return 0; +} + +/* + * client_fsync_cbk - fsync callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_fsync_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_fsync_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + + +/* + * client_unlink_cbk - unlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_unlink_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_unlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_rename_cbk - rename callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_rename_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + gf_fop_rename_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + + +/* + * client_readlink_cbk - readlink callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_readlink_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_readlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + char *link = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret > 0) { + link = rsp->path; + } + + STACK_UNWIND (frame, op_ret, op_errno, link); + return 0; +} + +/* + * client_mkdir_cbk - mkdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_mkdir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_mkdir_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct stat stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + + local = frame->local; + inode = local->loc.inode; + frame->local = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) { + gf_stat_to_stat (&rsp->stat, &stbuf); + this_ino_set (&local->loc, frame->this, stbuf.st_ino); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); + + client_local_wipe (local); + + return 0; +} + +/* + * client_flush_cbk - flush callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_flush_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = 0; + int32_t op_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + + +/* + * client_opendir_cbk - opendir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_opendir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = -1; + int32_t op_errno = ENOTCONN; + fd_t *fd = NULL; + int64_t remote_fd = 0; + gf_fop_opendir_rsp_t *rsp = NULL; + char key[32] = {0,}; + int32_t ret = -1; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + + + local = frame->local; frame->local = NULL; + conf = frame->this->private; + fd = local->fd; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = ntoh32 (hdr->rsp.op_errno); + + if (op_ret >= 0) { + remote_fd = ntoh64 (rsp->fd); + } + + if (op_ret >= 0) { + this_fd_set (fd, frame->this, &local->loc, remote_fd); + + sprintf (key, "%p", fd); + + pthread_mutex_lock (&conf->mutex); + { + ret = dict_set_str (conf->saved_fds, key, ""); + } + pthread_mutex_unlock (&conf->mutex); + + if (ret < 0) { + free (key); + gf_log (frame->this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to save remote fd", + local->loc.path, local->loc.inode->ino); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, fd); + + client_local_wipe (local); + + return 0; +} + + +/* + * client_rmdir_cbk - rmdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_rmdir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_rmdir_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_access_cbk - access callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_access_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_access_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + + + +/* + * client_lookup_cbk - lookup callback for client protocol + * + * @frame: call frame + * @args: arguments dictionary + * + * not for external reference + */ +int32_t +client_lookup_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct stat stbuf = {0, }; + inode_t *inode = NULL; + dict_t *xattr = NULL; + gf_fop_lookup_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + size_t dict_len = 0; + char *dictbuf = NULL; + int32_t ret = -1; + int32_t gf_errno = 0; + client_local_t *local = NULL; + + local = frame->local; + inode = local->loc.inode; + frame->local = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + + if (op_ret == 0) { + op_ret = -1; + gf_stat_to_stat (&rsp->stat, &stbuf); + this_ino_set (&local->loc, frame->this, stbuf.st_ino); + + dict_len = ntoh32 (rsp->dict_len); + + if (dict_len > 0) { + dictbuf = memdup (rsp->dict, dict_len); + GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + + xattr = dict_new(); + GF_VALIDATE_OR_GOTO(frame->this->name, xattr, fail); + + ret = dict_unserialize (dictbuf, dict_len, &xattr); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to unserialize dictionary", + local->loc.path, inode->ino); + goto fail; + } else { + xattr->extra_free = dictbuf; + dictbuf = NULL; + } + } + op_ret = 0; + } + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + +fail: + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, xattr); + + client_local_wipe (local); + + if (dictbuf) + free (dictbuf); + + if (xattr) + dict_unref (xattr); + + return 0; +} + +static dir_entry_t * +gf_bin_to_direntry (char *buf, size_t count) +{ + int32_t idx = 0, bread = 0; + size_t rcount = 0; + char *ender = NULL, *buffer = NULL; + char tmp_buf[512] = {0,}; + dir_entry_t *trav = NULL, *prev = NULL; + dir_entry_t *thead = NULL, *head = NULL; + + thead = CALLOC (1, sizeof (dir_entry_t)); + GF_VALIDATE_OR_GOTO("client-protocol", thead, fail); + + buffer = buf; + prev = thead; + + for (idx = 0; idx < count ; idx++) { + bread = 0; + trav = CALLOC (1, sizeof (dir_entry_t)); + GF_VALIDATE_OR_GOTO("client-protocol", trav, fail); + + ender = strchr (buffer, '/'); + if (!ender) + break; + rcount = ender - buffer; + trav->name = CALLOC (1, rcount + 2); + GF_VALIDATE_OR_GOTO("client-protocol", trav->name, fail); + + strncpy (trav->name, buffer, rcount); + bread = rcount + 1; + buffer += bread; + + ender = strchr (buffer, '\n'); + if (!ender) + break; + rcount = ender - buffer; + strncpy (tmp_buf, buffer, rcount); + bread = rcount + 1; + buffer += bread; + + gf_string_to_stat (tmp_buf, &trav->buf); + + ender = strchr (buffer, '\n'); + if (!ender) + break; + rcount = ender - buffer; + *ender = '\0'; + if (S_ISLNK (trav->buf.st_mode)) + trav->link = strdup (buffer); + else + trav->link = ""; + + bread = rcount + 1; + buffer += bread; + + prev->next = trav; + prev = trav; + } + + head = thead; +fail: + return head; +} + +int32_t +gf_free_direntry(dir_entry_t *head) +{ + dir_entry_t *prev = NULL, *trav = NULL; + + prev = head; + GF_VALIDATE_OR_GOTO("client-protocol", prev, fail); + + trav = head->next; + while (trav) { + prev->next = trav->next; + FREE (trav->name); + if (S_ISLNK (trav->buf.st_mode)) + FREE (trav->link); + FREE (trav); + trav = prev->next; + } + FREE (head); +fail: + return 0; +} +/* + * client_getdents_cbk - readdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_getdents_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_getdents_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + int32_t gf_errno = 0; + int32_t nr_count = 0; + dir_entry_t *entry = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + + if (op_ret >= 0) { + nr_count = ntoh32 (rsp->count); + entry = gf_bin_to_direntry(buf, nr_count); + if (entry == NULL) { + op_ret = -1; + op_errno = EINVAL; + } + } + + STACK_UNWIND (frame, op_ret, op_errno, entry, nr_count); + + if (op_ret >= 0) { + /* Free the buffer */ + FREE (buf); + gf_free_direntry(entry); + } + + return 0; +} + +/* + * client_statfs_cbk - statfs callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_statfs_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct statvfs stbuf = {0, }; + gf_fop_statfs_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret == 0) + { + gf_statfs_to_statfs (&rsp->statfs, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + + return 0; +} + +/* + * client_fsyncdir_cbk - fsyncdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_fsyncdir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = 0; + int32_t op_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_setxattr_cbk - setxattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_setxattr_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_setxattr_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_getxattr_cbk - getxattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_getxattr_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_getxattr_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t gf_errno = 0; + int32_t op_errno = 0; + int32_t dict_len = 0; + dict_t *dict = NULL; + int32_t ret = -1; + char *dictbuf = NULL; + client_local_t *local = NULL; + + local = frame->local; + frame->local = NULL; + + rsp = gf_param (hdr); + GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + + op_ret = ntoh32 (hdr->rsp.op_ret); + + if (op_ret >= 0) { + op_ret = -1; + dict_len = ntoh32 (rsp->dict_len); + + if (dict_len > 0) { + dictbuf = memdup (rsp->dict, dict_len); + GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + + dict = dict_new(); + GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); + + ret = dict_unserialize (dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to " + "unserialize xattr dictionary", + local->loc.path, local->loc.inode->ino); + goto fail; + } else { + dict->extra_free = dictbuf; + dictbuf = NULL; + } + } + op_ret = 0; + } + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); +fail: + STACK_UNWIND (frame, op_ret, op_errno, dict); + + client_local_wipe (local); + + if (dictbuf) + free (dictbuf); + + if (dict) + dict_unref (dict); + + return 0; +} + +/* + * client_removexattr_cbk - removexattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_removexattr_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = 0; + int32_t op_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_lk_cbk - lk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_lk_common_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct flock lock = {0,}; + gf_fop_lk_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) { + gf_flock_to_flock (&rsp->flock, &lock); + } + + STACK_UNWIND (frame, op_ret, op_errno, &lock); + return 0; +} + + +/* + * client_gf_file_lk_cbk - gf_file_lk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_inodelk_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_inodelk_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + + +int32_t +client_finodelk_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_finodelk_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + + +/* + * client_entrylk_cbk - entrylk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_entrylk_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_entrylk_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +int32_t +client_fentrylk_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_fentrylk_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + + +/** + * client_writedir_cbk - + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_setdents_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = 0; + int32_t op_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + + + +/* + * client_stats_cbk - stats callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_stats_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct xlator_stats stats = {0,}; + gf_mop_stats_rsp_t *rsp = NULL; + char *buffer = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret >= 0) + { + buffer = rsp->buf; + + sscanf (buffer, "%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64 + ",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64"\n", + &stats.nr_files, + &stats.disk_usage, + &stats.free_disk, + &stats.total_disk_size, + &stats.read_usage, + &stats.write_usage, + &stats.disk_speed, + &stats.nr_clients); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stats); + return 0; +} + +/* + * client_getspec - getspec function for client protocol + * @frame: call frame + * @this: client protocol xlator structure + * @flag: + * + * external reference through client_protocol_xlator->fops->getspec + */ +int32_t +client_getspec (call_frame_t *frame, + xlator_t *this, + const char *key, + int32_t flag) +{ + gf_hdr_common_t *hdr = NULL; + gf_mop_getspec_req_t *req = NULL; + size_t hdrlen = -1; + int keylen = 0; + int ret = -1; + + if (key) + keylen = STRLEN_0(key); + + hdrlen = gf_hdr_len (req, keylen); + hdr = gf_hdr_new (req, keylen); + GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + + req = gf_param (hdr); + req->flags = hton32 (flag); + req->keylen = hton32 (keylen); + if (keylen) + strcpy (req->key, key); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_MOP_REQUEST, GF_MOP_GETSPEC, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + free (hdr); + STACK_UNWIND(frame, -1, EINVAL, NULL); + return 0; +} + + +/* + * client_getspec_cbk - getspec callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_getspec_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_mop_getspec_rsp_t *rsp = NULL; + char *spec_data = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + int32_t gf_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + rsp = gf_param (hdr); + + if (op_ret >= 0) { + spec_data = rsp->spec; + } + + STACK_UNWIND (frame, op_ret, op_errno, spec_data); + return 0; +} + +int32_t +client_checksum (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flag) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_checksum_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + client_conf_t *conf = this->private; + ino_t ino = 0; + + if (conf->child) { + STACK_WIND (frame, + default_checksum_cbk, + conf->child, + conf->child->fops->checksum, + loc, + flag); + + return 0; + } + + hdrlen = gf_hdr_len (req, strlen (loc->path) + 1); + hdr = gf_hdr_new (req, strlen (loc->path) + 1); + req = gf_param (hdr); + + ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + req->ino = hton64 (ino); + req->flag = hton32 (flag); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +} + +int32_t +client_checksum_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_checksum_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + int32_t gf_errno = 0; + unsigned char *fchecksum = NULL; + unsigned char *dchecksum = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + gf_errno = ntoh32 (hdr->rsp.op_errno); + op_errno = gf_error_to_errno (gf_errno); + + if (op_ret >= 0) { + fchecksum = rsp->fchecksum; + dchecksum = rsp->dchecksum + ZR_FILENAME_MAX; + } + + STACK_UNWIND (frame, op_ret, op_errno, fchecksum, dchecksum); + return 0; +} + + +/* + * client_setspec_cbk - setspec callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_setspec_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t op_ret = 0; + int32_t op_errno = 0; + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + STACK_UNWIND (frame, op_ret, op_errno); + + return 0; +} + +/* + * client_setvolume_cbk - setvolume callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_setvolume_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_mop_setvolume_rsp_t *rsp = NULL; + client_connection_t *conn = NULL; + client_conf_t *conf = NULL; + glusterfs_ctx_t *ctx = NULL; + xlator_t *this = NULL; + xlator_list_t *parent = NULL; + transport_t *trans = NULL; + dict_t *reply = NULL; + char *remote_subvol = NULL; + char *remote_error = NULL; + char *process_uuid = NULL; + int32_t ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t dict_len = 0; + + + trans = frame->local; frame->local = NULL; + this = frame->this; + conf = this->private; + conn = trans->xl_private; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + + if (op_ret < 0 && op_errno == ENOTCONN) { + gf_log (this->name, GF_LOG_ERROR, + "setvolume failed (%s)", + strerror (op_errno)); + goto out; + } + + reply = dict_new (); + GF_VALIDATE_OR_GOTO(this->name, reply, out); + + dict_len = ntoh32 (rsp->dict_len); + ret = dict_unserialize (rsp->buf, dict_len, &reply); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "failed to unserialize buffer(%p) to dictionary", + rsp->buf); + goto out; + } + + ret = dict_get_str (reply, "ERROR", &remote_error); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get ERROR string from reply dictionary"); + } + + ret = dict_get_str (reply, "process-uuid", &process_uuid); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get 'process-uuid' from reply dictionary"); + } + + if (op_ret < 0) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "SETVOLUME on remote-host failed: %s", + remote_error ? remote_error : strerror (op_errno)); + errno = op_errno; + if (op_errno == ENOTCONN) + goto out; + } else { + ctx = get_global_ctx_ptr (); + if (process_uuid && !strcmp (ctx->process_uuid,process_uuid)) { + ret = dict_get_str (this->options, "remote-subvolume", + &remote_subvol); + if (!remote_subvol) + goto out; + + gf_log (this->name, GF_LOG_WARNING, + "attaching to the local volume '%s'", + remote_subvol); + + /* TODO: */ + conf->child = xlator_search_by_name (this, + remote_subvol); + } + gf_log (trans->xl->name, GF_LOG_INFO, + "connection and handshake succeeded"); + + pthread_mutex_lock (&(conn->lock)); + { + conn->connected = 1; + } + pthread_mutex_unlock (&(conn->lock)); + + parent = trans->xl->parents; + while (parent) { + parent->xlator->notify (parent->xlator, + GF_EVENT_CHILD_UP, + trans->xl); + parent = parent->next; + } + } + +out: + STACK_DESTROY (frame->root); + + if (reply) + dict_unref (reply); + + return op_ret; +} + +/* + * client_enosys_cbk - + * @frame: call frame + * + * not for external reference + */ +int +client_enosys_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + STACK_DESTROY (frame->root); + return 0; +} + + +void +client_protocol_reconnect (void *trans_ptr) +{ + transport_t *trans = NULL; + client_connection_t *conn = NULL; + struct timeval tv = {0, 0}; + + trans = trans_ptr; + conn = trans->xl_private; + pthread_mutex_lock (&conn->lock); + { + if (conn->reconnect) + gf_timer_call_cancel (trans->xl->ctx, + conn->reconnect); + conn->reconnect = 0; + + if (conn->connected == 0) { + tv.tv_sec = 10; + + gf_log (trans->xl->name, GF_LOG_DEBUG, + "attempting reconnect"); + transport_connect (trans); + + conn->reconnect = + gf_timer_call_after (trans->xl->ctx, tv, + client_protocol_reconnect, + trans); + } else { + gf_log (trans->xl->name, GF_LOG_DEBUG, + "breaking reconnect chain"); + } + } + pthread_mutex_unlock (&conn->lock); +} + +/* + * client_protocol_cleanup - cleanup function + * @trans: transport object + * + */ +int +protocol_client_cleanup (transport_t *trans) +{ + client_connection_t *conn = NULL; + struct saved_frames *saved_frames = NULL; + + conn = trans->xl_private; + + gf_log (trans->xl->name, GF_LOG_DEBUG, + "cleaning up state in transport object %p", trans); + + pthread_mutex_lock (&conn->lock); + { + saved_frames = conn->saved_frames; + conn->saved_frames = saved_frames_new (); + +/* + trav = conn->saved_fds->members_list; + this = trans->xl; + + while (trav) { + fd_t *fd_tmp = (fd_t *)(long) strtoul (trav->key, + NULL, 0); + fd_ctx_del (fd_tmp, this, NULL); + trav = trav->next; + } + + dict_destroy (conn->saved_fds); + + conn->saved_fds = get_new_dict_full (64); +*/ + /* bailout logic cleanup */ + memset (&(conn->last_sent), 0, + sizeof (conn->last_sent)); + + memset (&(conn->last_received), 0, + sizeof (conn->last_received)); + + if (conn->timer) { + gf_timer_call_cancel (trans->xl->ctx, conn->timer); + conn->timer = NULL; + } + + if (conn->reconnect == NULL) { + /* :O This part is empty.. any thing missing? */ + } + } + pthread_mutex_unlock (&conn->lock); + + saved_frames_destroy (trans->xl, saved_frames, + gf_fops, gf_mops, gf_cbks); + + return 0; +} + + +/* cbk callbacks */ +int +client_releasedir_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + STACK_DESTROY (frame->root); + return 0; +} + + +int +client_release_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + STACK_DESTROY (frame->root); + return 0; +} + + +int +client_forget_cbk (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + client_conf_t *conf = NULL; + client_forget_t forget = {0, }; + uint8_t send_forget = 0; + int32_t ret = -1; + + + conf = frame->this->private; + LOCK (&conf->forget.lock); + { + conf->forget.frames_in_transit--; + + ret = client_get_forgets (frame->this, &forget); + if (ret <= 0) + send_forget = 0; + else + send_forget = 1; + } + UNLOCK (&conf->forget.lock); + + if (send_forget) { + ret = protocol_client_xfer (forget.frame, frame->this, + CLIENT_CHANNEL (frame->this, + CHANNEL_BULK), + GF_OP_TYPE_CBK_REQUEST, + GF_CBK_FORGET, + forget.hdr, forget.hdrlen, + NULL, 0, NULL); + } + + STACK_DESTROY (frame->root); + return 0; +} + + +static gf_op_t gf_fops[] = { + [GF_FOP_STAT] = client_stat_cbk, + [GF_FOP_READLINK] = client_readlink_cbk, + [GF_FOP_MKNOD] = client_mknod_cbk, + [GF_FOP_MKDIR] = client_mkdir_cbk, + [GF_FOP_UNLINK] = client_unlink_cbk, + [GF_FOP_RMDIR] = client_rmdir_cbk, + [GF_FOP_SYMLINK] = client_symlink_cbk, + [GF_FOP_RENAME] = client_rename_cbk, + [GF_FOP_LINK] = client_link_cbk, + [GF_FOP_CHMOD] = client_chmod_cbk, + [GF_FOP_CHOWN] = client_chown_cbk, + [GF_FOP_TRUNCATE] = client_truncate_cbk, + [GF_FOP_OPEN] = client_open_cbk, + [GF_FOP_READ] = client_readv_cbk, + [GF_FOP_WRITE] = client_write_cbk, + [GF_FOP_STATFS] = client_statfs_cbk, + [GF_FOP_FLUSH] = client_flush_cbk, + [GF_FOP_FSYNC] = client_fsync_cbk, + [GF_FOP_SETXATTR] = client_setxattr_cbk, + [GF_FOP_GETXATTR] = client_getxattr_cbk, + [GF_FOP_REMOVEXATTR] = client_removexattr_cbk, + [GF_FOP_OPENDIR] = client_opendir_cbk, + [GF_FOP_GETDENTS] = client_getdents_cbk, + [GF_FOP_FSYNCDIR] = client_fsyncdir_cbk, + [GF_FOP_ACCESS] = client_access_cbk, + [GF_FOP_CREATE] = client_create_cbk, + [GF_FOP_FTRUNCATE] = client_ftruncate_cbk, + [GF_FOP_FSTAT] = client_fstat_cbk, + [GF_FOP_LK] = client_lk_common_cbk, + [GF_FOP_UTIMENS] = client_utimens_cbk, + [GF_FOP_FCHMOD] = client_fchmod_cbk, + [GF_FOP_FCHOWN] = client_fchown_cbk, + [GF_FOP_LOOKUP] = client_lookup_cbk, + [GF_FOP_SETDENTS] = client_setdents_cbk, + [GF_FOP_READDIR] = client_readdir_cbk, + [GF_FOP_INODELK] = client_inodelk_cbk, + [GF_FOP_FINODELK] = client_finodelk_cbk, + [GF_FOP_ENTRYLK] = client_entrylk_cbk, + [GF_FOP_FENTRYLK] = client_fentrylk_cbk, + [GF_FOP_CHECKSUM] = client_checksum_cbk, + [GF_FOP_XATTROP] = client_xattrop_cbk, + [GF_FOP_FXATTROP] = client_fxattrop_cbk, +}; + +static gf_op_t gf_mops[] = { + [GF_MOP_SETVOLUME] = client_setvolume_cbk, + [GF_MOP_GETVOLUME] = client_enosys_cbk, + [GF_MOP_STATS] = client_stats_cbk, + [GF_MOP_SETSPEC] = client_setspec_cbk, + [GF_MOP_GETSPEC] = client_getspec_cbk, + [GF_MOP_PING] = client_ping_cbk, +}; + +static gf_op_t gf_cbks[] = { + [GF_CBK_FORGET] = client_forget_cbk, + [GF_CBK_RELEASE] = client_release_cbk, + [GF_CBK_RELEASEDIR] = client_releasedir_cbk +}; + +/* + * client_protocol_interpret - protocol interpreter + * @trans: transport object + * @blk: data block + * + */ +int +protocol_client_interpret (xlator_t *this, transport_t *trans, + char *hdr_p, size_t hdrlen, + char *buf_p, size_t buflen) +{ + int ret = -1; + call_frame_t *frame = NULL; + gf_hdr_common_t *hdr = NULL; + uint64_t callid = 0; + int type = -1; + int op = -1; + + + hdr = (gf_hdr_common_t *)hdr_p; + + type = ntoh32 (hdr->type); + op = ntoh32 (hdr->op); + callid = ntoh64 (hdr->callid); + + frame = lookup_frame (trans, op, type, callid); + if (frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "no frame for callid=%"PRId64" type=%d op=%d", + callid, type, op); + return 0; + } + + switch (type) { + case GF_OP_TYPE_FOP_REPLY: + if ((op > GF_FOP_MAXVALUE) || + (op < 0)) { + gf_log (trans->xl->name, GF_LOG_WARNING, + "invalid fop '%d'", op); + } else { + ret = gf_fops[op] (frame, hdr, hdrlen, buf_p, buflen); + } + break; + case GF_OP_TYPE_MOP_REPLY: + if ((op > GF_MOP_MAXVALUE) || + (op < 0)) { + gf_log (trans->xl->name, GF_LOG_WARNING, + "invalid fop '%d'", op); + } else { + ret = gf_mops[op] (frame, hdr, hdrlen, buf_p, buflen); + } + break; + case GF_OP_TYPE_CBK_REPLY: + if ((op > GF_CBK_MAXVALUE) || + (op < 0)) { + gf_log (trans->xl->name, GF_LOG_WARNING, + "invalid cbk '%d'", op); + } else { + ret = gf_cbks[op] (frame, hdr, hdrlen, buf_p, buflen); + } + break; + default: + gf_log (trans->xl->name, GF_LOG_ERROR, + "invalid packet type: %d", type); + break; + } + + return ret; +} + +/* + * init - initiliazation function. called during loading of client protocol + * @this: + * + */ +int32_t +init (xlator_t *this) +{ + transport_t *trans = NULL; + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + int32_t transport_timeout = 0; + int32_t ping_timeout = 0; + data_t *remote_subvolume = NULL; + int32_t ret = -1; + int i = 0; + + if (this->children) { + gf_log (this->name, GF_LOG_ERROR, + "FATAL: client protocol translator cannot have " + "subvolumes"); + goto out; + } + + if (!this->parents) { + gf_log (this->name, GF_LOG_WARNING, + "dangling volume. check volfile "); + } + + remote_subvolume = dict_get (this->options, "remote-subvolume"); + if (remote_subvolume == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "missing 'option remote-subvolume'."); + goto out; + } + + ret = dict_get_int32 (this->options, "transport-timeout", + &transport_timeout); + if (ret >= 0) { + gf_log (this->name, GF_LOG_DEBUG, + "setting transport-timeout to %d", transport_timeout); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "defaulting transport-timeout to 42"); + transport_timeout = 42; + } + + ret = dict_get_int32 (this->options, "ping-timeout", + &ping_timeout); + if (ret >= 0) { + gf_log (this->name, GF_LOG_DEBUG, + "setting ping-timeout to %d", ping_timeout); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "defaulting ping-timeout to 10"); + ping_timeout = 10; + } + + conf = CALLOC (1, sizeof (client_conf_t)); + + LOCK_INIT (&conf->forget.lock); + pthread_mutex_init (&conf->mutex, NULL); + conf->saved_fds = get_new_dict_full (64); + + this->private = conf; + + for (i = 0; i < CHANNEL_MAX; i++) { + trans = transport_load (this->options, this); + if (trans == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to load transport"); + ret = -1; + goto out; + } + + conn = CALLOC (1, sizeof (*conn)); + + conn->saved_frames = saved_frames_new (); + + conn->callid = 1; + + memset (&(conn->last_sent), 0, sizeof (conn->last_sent)); + memset (&(conn->last_received), 0, + sizeof (conn->last_received)); + + conn->transport_timeout = transport_timeout; + conn->ping_timeout = ping_timeout; + + pthread_mutex_init (&conn->lock, NULL); + + trans->xl_private = conn; + conf->transport[i] = transport_ref (trans); + } + +#ifndef GF_DARWIN_HOST_OS + { + struct rlimit lim; + + lim.rlim_cur = 1048576; + lim.rlim_max = 1048576; + + ret = setrlimit (RLIMIT_NOFILE, &lim); + if (ret == -1) { + gf_log (this->name, GF_LOG_WARNING, + "WARNING: Failed to set 'ulimit -n 1M': %s", + strerror(errno)); + lim.rlim_cur = 65536; + lim.rlim_max = 65536; + + ret = setrlimit (RLIMIT_NOFILE, &lim); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set max open fd to 64k: %s", + strerror(errno)); + } else { + gf_log (this->name, GF_LOG_ERROR, + "max open fd set to 64k"); + } + + } + } +#endif + ret = 0; +out: + return ret; +} + +/* + * fini - finish function called during unloading of client protocol + * @this: + * + */ +void +fini (xlator_t *this) +{ + /* TODO: Check if its enough.. how to call transport's fini () */ + client_conf_t *conf = NULL; + + conf = this->private; + this->private = NULL; + + if (conf) { + LOCK_DESTROY (&conf->forget.lock); + FREE (conf); + } + return; +} + + +int +protocol_client_handshake (xlator_t *this, transport_t *trans) +{ + gf_hdr_common_t *hdr = NULL; + gf_mop_setvolume_req_t *req = NULL; + dict_t *options = NULL; + int32_t ret = -1; + int hdrlen = 0; + int dict_len = 0; + call_frame_t *fr = NULL; + char *process_uuid_xl; + + options = this->options; + ret = dict_set_str (options, "version", PACKAGE_VERSION); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to set version(%s) in options dictionary", + PACKAGE_VERSION); + } + + asprintf (&process_uuid_xl, "%s-%s", this->ctx->process_uuid, + this->name); + ret = dict_set_dynstr (options, "process-uuid", + process_uuid_xl); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to set process-uuid(%s) in options dictionary", + PACKAGE_VERSION); + } + + dict_len = dict_serialized_length (options); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get serialized length of dict(%p)", + options); + ret = dict_len; + goto fail; + } + + hdrlen = gf_hdr_len (req, dict_len); + hdr = gf_hdr_new (req, dict_len); + GF_VALIDATE_OR_GOTO(this->name, hdr, fail); + + req = gf_param (hdr); + + ret = dict_serialize (options, req->buf); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize dictionary(%p)", + options); + goto fail; + } + + req->dict_len = hton32 (dict_len); + fr = create_frame (this, this->ctx->pool); + GF_VALIDATE_OR_GOTO(this->name, fr, fail); + + fr->local = trans; + ret = protocol_client_xfer (fr, this, trans, + GF_OP_TYPE_MOP_REQUEST, GF_MOP_SETVOLUME, + hdr, hdrlen, NULL, 0, NULL); + return ret; +fail: + if (hdr) + free (hdr); + return ret; +} + + +int +protocol_client_pollout (xlator_t *this, transport_t *trans) +{ + client_connection_t *conn = NULL; + + conn = trans->xl_private; + + pthread_mutex_lock (&conn->lock); + { + gettimeofday (&conn->last_sent, NULL); + } + pthread_mutex_unlock (&conn->lock); + + return 0; +} + + +int +protocol_client_pollin (xlator_t *this, transport_t *trans) +{ + client_connection_t *conn = NULL; + int ret = -1; + char *buf = NULL; + size_t buflen = 0; + char *hdr = NULL; + size_t hdrlen = 0; + int connected = 0; + + conn = trans->xl_private; + + pthread_mutex_lock (&conn->lock); + { + gettimeofday (&conn->last_received, NULL); + connected = conn->connected; + } + pthread_mutex_unlock (&conn->lock); + + ret = transport_receive (trans, &hdr, &hdrlen, &buf, &buflen); + + if (ret == 0) + { + ret = protocol_client_interpret (this, trans, hdr, hdrlen, + buf, buflen); + } + + /* TODO: use mem-pool */ + FREE (hdr); + + return ret; +} + + +/* + * client_protocol_notify - notify function for client protocol + * @this: + * @trans: transport object + * @event + * + */ + +int32_t +notify (xlator_t *this, + int32_t event, + void *data, + ...) +{ + int ret = -1; + transport_t *trans = NULL; + client_connection_t *conn = NULL; + + trans = data; + + switch (event) { + case GF_EVENT_POLLOUT: + { + ret = protocol_client_pollout (this, trans); + + break; + } + case GF_EVENT_POLLIN: + { + ret = protocol_client_pollin (this, trans); + + break; + } + /* no break for ret check to happen below */ + case GF_EVENT_POLLERR: + { + ret = -1; + protocol_client_cleanup (trans); + } + + conn = trans->xl_private; + if (conn->connected) { + xlator_list_t *parent = NULL; + + gf_log (this->name, GF_LOG_INFO, "disconnected"); + + parent = this->parents; + while (parent) { + parent->xlator->notify (parent->xlator, + GF_EVENT_CHILD_DOWN, + this); + parent = parent->next; + } + + conn->connected = 0; + if (conn->reconnect == 0) + client_protocol_reconnect (trans); + } + break; + + case GF_EVENT_PARENT_UP: + { + xlator_list_t *parent = NULL; + client_conf_t *conf = NULL; + int i = 0; + transport_t *trans = NULL; + + conf = this->private; + for (i = 0; i < CHANNEL_MAX; i++) { + trans = conf->transport[i]; + if (!trans) { + gf_log (this->name, GF_LOG_DEBUG, + "transport init failed"); + return -1; + } + + conn = trans->xl_private; + + gf_log (this->name, GF_LOG_DEBUG, + "got GF_EVENT_PARENT_UP, attempting connect " + "on transport"); + + client_protocol_reconnect (trans); + } + + /* Let the connection/re-connection happen in + * background, for now, don't hang here, + * tell the parents that i am all ok.. + */ + parent = trans->xl->parents; + while (parent) { + parent->xlator->notify (parent->xlator, + GF_EVENT_CHILD_CONNECTING, + trans->xl); + parent = parent->next; + } + } + break; + + case GF_EVENT_CHILD_UP: + { + char *handshake = NULL; + + ret = dict_get_str (this->options, "disable-handshake", + &handshake); + gf_log (this->name, GF_LOG_DEBUG, + "got GF_EVENT_CHILD_UP"); + if ((ret < 0) || + (strcasecmp (handshake, "on"))) { + ret = protocol_client_handshake (this, trans); + } else { + conn = trans->xl_private; + conn->connected = 1; + ret = default_notify (this, event, trans); + } + + if (ret) + transport_disconnect (trans); + + } + break; + + default: + gf_log (this->name, GF_LOG_DEBUG, + "got %d, calling default_notify ()", event); + + default_notify (this, event, data); + break; + } + + return ret; +} + + +struct xlator_fops fops = { + .stat = client_stat, + .readlink = client_readlink, + .mknod = client_mknod, + .mkdir = client_mkdir, + .unlink = client_unlink, + .rmdir = client_rmdir, + .symlink = client_symlink, + .rename = client_rename, + .link = client_link, + .chmod = client_chmod, + .chown = client_chown, + .truncate = client_truncate, + .utimens = client_utimens, + .open = client_open, + .readv = client_readv, + .writev = client_writev, + .statfs = client_statfs, + .flush = client_flush, + .fsync = client_fsync, + .setxattr = client_setxattr, + .getxattr = client_getxattr, + .removexattr = client_removexattr, + .opendir = client_opendir, + .readdir = client_readdir, + .fsyncdir = client_fsyncdir, + .access = client_access, + .ftruncate = client_ftruncate, + .fstat = client_fstat, + .create = client_create, + .lk = client_lk, + .inodelk = client_inodelk, + .finodelk = client_finodelk, + .entrylk = client_entrylk, + .fentrylk = client_fentrylk, + .lookup = client_lookup, + .fchmod = client_fchmod, + .fchown = client_fchown, + .setdents = client_setdents, + .getdents = client_getdents, + .checksum = client_checksum, + .xattrop = client_xattrop, + .fxattrop = client_fxattrop, +}; + +struct xlator_mops mops = { + .stats = client_stats, + .getspec = client_getspec, +}; + +struct xlator_cbks cbks = { + .forget = client_forget, + .release = client_release, + .releasedir = client_releasedir +}; + + +struct volume_options options[] = { + { .key = {"username"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {"password"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {"transport-type"}, + .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp", + "tcp/client", "ib-verbs/client"}, + .type = GF_OPTION_TYPE_STR + }, + { .key = {"remote-host"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {"remote-subvolume"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {"transport-timeout"}, + .type = GF_OPTION_TYPE_TIME, + .min = 5, + .max = 1013, + }, + { .key = {"ping-timeout"}, + .type = GF_OPTION_TYPE_TIME, + .min = 5, + .max = 1013, + }, + { .key = {NULL} }, +}; diff --git a/xlators/protocol/client/src/client-protocol.h b/xlators/protocol/client/src/client-protocol.h new file mode 100644 index 00000000000..c90cc980d83 --- /dev/null +++ b/xlators/protocol/client/src/client-protocol.h @@ -0,0 +1,173 @@ +/* + Copyright (c) 2006, 2007 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CLIENT_PROTOCOL_H +#define _CLIENT_PROTOCOL_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <arpa/inet.h> +#include "inode.h" +#include "timer.h" +#include "byte-order.h" + +#define CLIENT_PROTO_FORGET_LIMIT 128 +#define CLIENT_PORT_CIELING 1023 + +#define GF_CLIENT_INODE_SELF 0 +#define GF_CLIENT_INODE_PARENT 1 + +#define CLIENT_CONF(this) ((client_conf_t *)(this->private)) + +#define RECEIVE_TIMEOUT(_cprivate,_current) \ + ((_cprivate->last_received.tv_sec + \ + _cprivate->transport_timeout) < \ + _current.tv_sec) + +#define SEND_TIMEOUT(_cprivate,_current) \ + ((_cprivate->last_sent.tv_sec + \ + _cprivate->transport_timeout) < \ + _current.tv_sec) + +enum { + CHANNEL_BULK = 0, + CHANNEL_LOWLAT = 1, + CHANNEL_MAX +}; +#define CLIENT_CHANNEL(xl,id) \ + (((client_conf_t *)(xl->private))->transport[id]) + +struct client_connection; +typedef struct client_connection client_connection_t; + +#include "stack.h" +#include "xlator.h" +#include "transport.h" +#include "protocol.h" + +struct _client_conf { + transport_t *transport[CHANNEL_MAX]; + xlator_t *child; + + /* enhancement for 'forget', a must required where lot + of stats happening */ + struct { + uint64_t ino_array[CLIENT_PROTO_FORGET_LIMIT + 4]; + uint32_t count; + uint32_t frames_in_transit; + gf_lock_t lock; + } forget; + dict_t *saved_fds; + pthread_mutex_t mutex; +}; +typedef struct _client_conf client_conf_t; + +/* This will be stored in transport_t->xl_private */ +struct client_connection { + pthread_mutex_t lock; + uint64_t callid; + struct saved_frames *saved_frames; + int32_t transport_timeout; + int32_t ping_started; + int32_t ping_timeout; + gf_timer_t *reconnect; + char connected; + uint64_t max_block_size; + struct timeval last_sent; + struct timeval last_received; + gf_timer_t *timer; + gf_timer_t *ping_timer; +}; + +typedef struct { + loc_t loc; + loc_t loc2; + fd_t *fd; +} client_local_t; + +typedef struct { + gf_hdr_common_t *hdr; + size_t hdrlen; + call_frame_t *frame; +} client_forget_t; + +static inline void +gf_string_to_stat(char *string, struct stat *stbuf) +{ + uint64_t dev = 0; + uint64_t ino = 0; + uint32_t mode = 0; + uint32_t nlink = 0; + uint32_t uid = 0; + uint32_t gid = 0; + uint64_t rdev = 0; + uint64_t size = 0; + uint32_t blksize = 0; + uint64_t blocks = 0; + uint32_t atime = 0; + uint32_t atime_nsec = 0; + uint32_t mtime = 0; + uint32_t mtime_nsec = 0; + uint32_t ctime = 0; + uint32_t ctime_nsec = 0; + + sscanf (string, GF_STAT_PRINT_FMT_STR, + &dev, + &ino, + &mode, + &nlink, + &uid, + &gid, + &rdev, + &size, + &blksize, + &blocks, + &atime, + &atime_nsec, + &mtime, + &mtime_nsec, + &ctime, + &ctime_nsec); + + stbuf->st_dev = dev; + stbuf->st_ino = ino; + stbuf->st_mode = mode; + stbuf->st_nlink = nlink; + stbuf->st_uid = uid; + stbuf->st_gid = gid; + stbuf->st_rdev = rdev; + stbuf->st_size = size; + stbuf->st_blksize = blksize; + stbuf->st_blocks = blocks; + + stbuf->st_atime = atime; + stbuf->st_mtime = mtime; + stbuf->st_ctime = ctime; + + ST_ATIM_NSEC_SET(stbuf, atime_nsec); + ST_MTIM_NSEC_SET(stbuf, mtime_nsec); + ST_CTIM_NSEC_SET(stbuf, ctime_nsec); + +} + +#endif diff --git a/xlators/protocol/client/src/saved-frames.c b/xlators/protocol/client/src/saved-frames.c new file mode 100644 index 00000000000..0d1366d8222 --- /dev/null +++ b/xlators/protocol/client/src/saved-frames.c @@ -0,0 +1,178 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#include "saved-frames.h" +#include "common-utils.h" +#include "protocol.h" +#include "xlator.h" + + + +struct saved_frames * +saved_frames_new (void) +{ + struct saved_frames *saved_frames = NULL; + + saved_frames = CALLOC (sizeof (*saved_frames), 1); + if (!saved_frames) { + return NULL; + } + + INIT_LIST_HEAD (&saved_frames->fops.list); + INIT_LIST_HEAD (&saved_frames->mops.list); + INIT_LIST_HEAD (&saved_frames->cbks.list); + + return saved_frames; +} + + +struct saved_frame * +get_head_frame_for_type (struct saved_frames *frames, int8_t type) +{ + struct saved_frame *head_frame = NULL; + + switch (type) { + case GF_OP_TYPE_FOP_REQUEST: + case GF_OP_TYPE_FOP_REPLY: + head_frame = &frames->fops; + break; + case GF_OP_TYPE_MOP_REQUEST: + case GF_OP_TYPE_MOP_REPLY: + head_frame = &frames->mops; + break; + case GF_OP_TYPE_CBK_REQUEST: + case GF_OP_TYPE_CBK_REPLY: + head_frame = &frames->cbks; + break; + } + + return head_frame; +} + + +int +saved_frames_put (struct saved_frames *frames, call_frame_t *frame, + int32_t op, int8_t type, int64_t callid) +{ + struct saved_frame *saved_frame = NULL; + struct saved_frame *head_frame = NULL; + + head_frame = get_head_frame_for_type (frames, type); + + saved_frame = CALLOC (sizeof (*saved_frame), 1); + if (!saved_frame) { + return -ENOMEM; + } + + INIT_LIST_HEAD (&saved_frame->list); + saved_frame->frame = frame; + saved_frame->op = op; + saved_frame->type = type; + saved_frame->callid = callid; + +// gettimeofday (&saved_frame->saved_at, NULL); + + list_add (&saved_frame->list, &head_frame->list); + frames->count++; + + return 0; +} + + +call_frame_t * +saved_frames_get (struct saved_frames *frames, int32_t op, + int8_t type, int64_t callid) +{ + struct saved_frame *saved_frame = NULL; + struct saved_frame *tmp = NULL; + struct saved_frame *head_frame = NULL; + call_frame_t *frame = NULL; + + head_frame = get_head_frame_for_type (frames, type); + + list_for_each_entry (tmp, &head_frame->list, list) { + if (tmp->callid == callid) { + list_del_init (&tmp->list); + frames->count--; + saved_frame = tmp; + break; + } + } + + if (saved_frame) + frame = saved_frame->frame; + + FREE (saved_frame); + + return frame; +} + + +void +saved_frames_unwind (xlator_t *this, struct saved_frames *saved_frames, + struct saved_frame *head, + gf_op_t gf_ops[], char *gf_op_list[]) +{ + struct saved_frame *trav = NULL; + struct saved_frame *tmp = NULL; + + gf_hdr_common_t hdr = {0, }; + call_frame_t *frame = NULL; + dict_t *reply = NULL; + + reply = get_new_dict(); + dict_ref (reply); + + hdr.rsp.op_ret = hton32 (-1); + hdr.rsp.op_errno = hton32 (ENOTCONN); + + list_for_each_entry_safe (trav, tmp, &head->list, list) { + gf_log (this->name, GF_LOG_ERROR, + "forced unwinding frame type(%d) op(%s)", + trav->type, gf_op_list[trav->op]); + + hdr.type = hton32 (trav->type); + hdr.op = hton32 (trav->op); + + frame = trav->frame; + frame->root->rsp_refs = reply; + + saved_frames->count--; + + gf_ops[trav->op] (frame, &hdr, sizeof (hdr), NULL, 0); + + list_del_init (&trav->list); + FREE (trav); + } + + dict_unref (reply); +} + + +void +saved_frames_destroy (xlator_t *this, struct saved_frames *frames, + gf_op_t gf_fops[], gf_op_t gf_mops[], gf_op_t gf_cbks[]) +{ + saved_frames_unwind (this, frames, &frames->fops, gf_fops, gf_fop_list); + saved_frames_unwind (this, frames, &frames->mops, gf_mops, gf_mop_list); + saved_frames_unwind (this, frames, &frames->cbks, gf_cbks, gf_cbk_list); + + FREE (frames); +} diff --git a/xlators/protocol/client/src/saved-frames.h b/xlators/protocol/client/src/saved-frames.h new file mode 100644 index 00000000000..e402feba33b --- /dev/null +++ b/xlators/protocol/client/src/saved-frames.h @@ -0,0 +1,74 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SAVED_FRAMES_H +#define _SAVED_FRAMES_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <sys/time.h> +#include "stack.h" +#include "list.h" +#include "protocol.h" + +/* UGLY: have common typedef b/w saved-frames.c and protocol-client.c */ +typedef int32_t (*gf_op_t) (call_frame_t *frame, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen); + + +struct saved_frame { + union { + struct list_head list; + struct { + struct saved_frame *frame_next; + struct saved_frame *frame_prev; + }; + }; + + struct timeval saved_at; + call_frame_t *frame; + int32_t op; + int8_t type; + uint64_t callid; +}; + + +struct saved_frames { + int64_t count; + struct saved_frame fops; + struct saved_frame mops; + struct saved_frame cbks; +}; + + +struct saved_frames *saved_frames_new (); +int saved_frames_put (struct saved_frames *frames, call_frame_t *frame, + int32_t op, int8_t type, int64_t callid); +call_frame_t *saved_frames_get (struct saved_frames *frames, int32_t op, + int8_t type, int64_t callid); +void saved_frames_destroy (xlator_t *this, struct saved_frames *frames, + gf_op_t gf_fops[], gf_op_t gf_mops[], + gf_op_t gf_cbks[]); + +#endif /* _SAVED_FRAMES_H */ diff --git a/xlators/protocol/server/Makefile.am b/xlators/protocol/server/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/protocol/server/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/protocol/server/src/Makefile.am b/xlators/protocol/server/src/Makefile.am new file mode 100644 index 00000000000..dcd92aeedd9 --- /dev/null +++ b/xlators/protocol/server/src/Makefile.am @@ -0,0 +1,18 @@ + +xlator_LTLIBRARIES = server.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/protocol + +server_la_LDFLAGS = -module -avoidversion + +server_la_SOURCES = server-protocol.c server-dentry.c server-helpers.c +server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = server-protocol.h server-helpers.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles \ + -DDATADIR=\"$(localstatedir)\" -DCONFDIR=\"$(sysconfdir)/glusterfs\" \ + $(GF_CFLAGS) + +CLEANFILES = + diff --git a/xlators/protocol/server/src/server-dentry.c b/xlators/protocol/server/src/server-dentry.c new file mode 100644 index 00000000000..d3a69a393fc --- /dev/null +++ b/xlators/protocol/server/src/server-dentry.c @@ -0,0 +1,413 @@ +#include "glusterfs.h" +#include "xlator.h" +#include "server-protocol.h" +#include "server-helpers.h" +#include <libgen.h> + +/* SERVER_DENTRY_STATE_PREPARE - prepare a fresh state for use + * + * @state - an empty state + * @loc - loc_t which needs to resolved + * @parent - most immediate parent of @loc available in dentry cache + * @resolved - component of @loc->path which has been resolved + * through dentry cache + */ +#define SERVER_DENTRY_STATE_PREPARE(_state,_loc,_parent,_resolved) do { \ + size_t pathlen = 0; \ + size_t resolvedlen = 0; \ + char *path = NULL; \ + int pad = 0; \ + pathlen = strlen (_loc->path) + 1; \ + path = CALLOC (1, pathlen); \ + _state->loc.parent = inode_ref (_parent); \ + _state->loc.inode = inode_new (_state->itable); \ + if (_resolved) { \ + resolvedlen = strlen (_resolved); \ + strncpy (path, _resolved, resolvedlen); \ + _state->resolved = memdup (path, pathlen); \ + if (resolvedlen == 1) /* only root resolved */ \ + pad = 0; \ + else { \ + pad = 1; \ + path[resolvedlen] = '/'; \ + } \ + strcpy_till (path + resolvedlen + pad, loc->path + resolvedlen + pad, '/'); \ + } else { \ + strncpy (path, _loc->path, pathlen); \ + } \ + _state->loc.path = path; \ + _state->loc.name = strrchr (path, '/'); \ + if (_state->loc.name) \ + _state->loc.name++; \ + _state->path = strdup (_loc->path); \ + }while (0); + +/* SERVER_DENTRY_UPDATE_STATE - update a server_state_t, to prepare state + * for new lookup + * + * @state - state to be updated. + */ +#define SERVER_DENTRY_UPDATE_STATE(_state) do { \ + char *path = NULL; \ + size_t pathlen = 0; \ + strcpy (_state->resolved, _state->loc.path); \ + pathlen = strlen (_state->loc.path); \ + if (!strcmp (_state->resolved, _state->path)) { \ + free (_state->resolved); \ + _state->resolved = NULL; \ + goto resume; \ + } \ + \ + path = (char *)(_state->loc.path + pathlen); \ + path[0] = '/'; \ + strcpy_till (path + 1, \ + _state->path + pathlen + 1, '/'); \ + _state->loc.name = strrchr (_state->loc.path, '/'); \ + if (_state->loc.name) \ + _state->loc.name++; \ + inode_unref (_state->loc.parent); \ + _state->loc.parent = inode_ref (_state->loc.inode); \ + inode_unref (_state->loc.inode); \ + _state->loc.inode = inode_new (_state->itable); \ + }while (0); + +/* NOTE: should be used only for a state which was created by __do_path_resolve + * using any other state will result in double free corruption. + */ +#define SERVER_STATE_CLEANUP(_state) do { \ + if (_state->resolved) \ + free (_state->resolved); \ + if (_state->path) \ + free (_state->path); \ + server_loc_wipe (&_state->loc); \ + free_state (_state); \ + } while (0); + +/* strcpy_till - copy @dname to @dest, until 'delim' is encountered in @dest + * @dest - destination string + * @dname - source string + * @delim - delimiter character + * + * return - NULL is returned if '0' is encountered in @dname, otherwise returns + * a pointer to remaining string begining in @dest. + */ +static char * +strcpy_till (char *dest, const char *dname, char delim) +{ + char *src = NULL; + int idx = 0; + char *ret = NULL; + + src = (char *)dname; + while (src[idx] && (src[idx] != delim)) { + dest[idx] = src[idx]; + idx++; + } + + dest[idx] = 0; + + if (src[idx] == 0) + ret = NULL; + else + ret = &(src[idx]); + + return ret; +} + +/* __server_path_to_parenti - derive parent inode for @path. if immediate parent is + * not available in the dentry cache, return nearest + * available parent inode and set @reslv to the path of + * the returned directory. + * + * @itable - inode table + * @path - path whose parent has to be looked up. + * @reslv - if immediate parent is not available, reslv will be set to path of the + * resolved parent. + * + * return - should never return NULL. should at least return '/' inode. + */ +static inode_t * +__server_path_to_parenti (inode_table_t *itable, + const char *path, + char **reslv) +{ + char *resolved_till = NULL; + char *strtokptr = NULL; + char *component = NULL; + char *next_component = NULL; + char *pathdup = NULL; + inode_t *curr = NULL; + inode_t *parent = NULL; + size_t pathlen = 0; + + + pathlen = STRLEN_0 (path); + resolved_till = CALLOC (1, pathlen); + + GF_VALIDATE_OR_GOTO("server-dentry", resolved_till, out); + pathdup = strdup (path); + GF_VALIDATE_OR_GOTO("server-dentry", pathdup, out); + + parent = inode_ref (itable->root); + curr = NULL; + + component = strtok_r (pathdup, "/", &strtokptr); + + while (component) { + curr = inode_search (itable, parent->ino, component); + if (!curr) { + /* if current component was the last component + set it to NULL + */ + component = strtok_r (NULL, "/", &strtokptr); + break; + } + + /* It is OK to append the component even if it is the + last component in the path, because, if 'next_component' + returns NULL, @parent will remain the same and + @resolved_till will not be sent back + */ + + strcat (resolved_till, "/"); + strcat (resolved_till, component); + + next_component = strtok_r (NULL, "/", &strtokptr); + + if (next_component) { + inode_unref (parent); + parent = curr; + curr = NULL; + } else { + /* will break */ + inode_unref (curr); + } + + component = next_component; + } + + free (pathdup); + + if (component) { + *reslv = resolved_till; + } else { + free (resolved_till); + } +out: + return parent; +} + + +/* __do_path_resolve_cbk - + * + * @frame - + * @cookie - + * @this - + * @op_ret - + * @op_errno - + * @inode - + * @stbuf - + * @dict - + * + */ +static int32_t +__do_path_resolve_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf, + dict_t *dict) +{ + server_state_t *state = NULL; + call_stub_t *stub = NULL; + inode_t *parent = NULL; + + stub = frame->local; + state = CALL_STATE(frame); + + parent = state->loc.parent; + + if (op_ret == -1) { + if (strcmp (state->path, state->loc.path)) + parent = NULL; + + server_stub_resume (stub, op_ret, op_errno, NULL, parent); + goto cleanup; + } else { + if (inode->ino == 0) { + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "looked up for %s (%"PRId64"/%s)", + state->loc.path, state->loc.parent->ino, state->loc.name); + inode_link (inode, state->loc.parent, state->loc.name, stbuf); + inode_lookup (inode); + } + + if (state->resolved) { + SERVER_DENTRY_UPDATE_STATE(state); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "looking up for %s (%"PRId64"/%s)", + state->loc.path, state->loc.parent->ino, state->loc.name); + + STACK_WIND (frame, + __do_path_resolve_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->lookup, + &(state->loc), + 0); + + goto out; + } + resume: + /* we are done, call stub_resume() to do rest of the job */ + server_stub_resume (stub, op_ret, op_errno, inode, parent); + cleanup: + SERVER_STATE_CLEANUP(state); + /* stub will be freed by stub_resume, leave no traces */ + frame->local = NULL; + STACK_DESTROY (frame->root); + } +out: + return 0; +} + +/* __do_path_resolve - resolve @loc->path into @loc->inode and @loc->parent. also + * update the dentry cache + * + * @stub - call stub to resume after resolving @loc->path + * @loc - loc to resolve before resuming @stub. + * + * return - return value of __do_path_resolve doesn't matter to the caller, if @stub + * is not NULL. + */ +static int32_t +__do_path_resolve (call_stub_t *stub, + const loc_t *loc) +{ + int32_t ret = -1; + char *resolved = NULL; + call_frame_t *new_frame = NULL; + server_state_t *state = NULL, *new_state = NULL; + inode_t *parent = NULL; + + state = CALL_STATE(stub->frame); + parent = loc->parent; + if (parent) { + inode_ref (parent); + gf_log (BOUND_XL(stub->frame)->name, GF_LOG_DEBUG, + "loc->parent(%"PRId64") already present. sending lookup " + "for %"PRId64"/%s", parent->ino, parent->ino, loc->name); + resolved = strdup (loc->path); + resolved = dirname (resolved); + } else { + parent = __server_path_to_parenti (state->itable, loc->path, &resolved); + } + + if (parent == NULL) { + /* fire in the bush.. run! run!! run!!! */ + gf_log ("server", + GF_LOG_CRITICAL, + "failed to get parent inode number"); + goto panic; + } + + if (resolved) { + gf_log (BOUND_XL(stub->frame)->name, + GF_LOG_DEBUG, + "resolved path(%s) till %"PRId64"(%s). " + "sending lookup for remaining path", + loc->path, parent->ino, resolved); + } + + { + new_frame = server_copy_frame (stub->frame); + new_state = CALL_STATE(new_frame); + + SERVER_DENTRY_STATE_PREPARE(new_state, loc, parent, resolved); + + if (parent) + inode_unref (parent); /* __server_path_to_parenti()'s inode_ref */ + free (resolved); + /* now interpret state as: + * state->path - compelete pathname to resolve + * state->resolved - pathname resolved from dentry cache + */ + new_frame->local = stub; + STACK_WIND (new_frame, + __do_path_resolve_cbk, + BOUND_XL(new_frame), + BOUND_XL(new_frame)->fops->lookup, + &(new_state->loc), + 0); + goto out; + } +panic: + server_stub_resume (stub, -1, ENOENT, NULL, NULL); +out: + return ret; +} + + +/* + * do_path_lookup - transform a pathname into inode, with the compelete + * dentry tree upto inode built. + * + * @stub - call stub to resume after completing pathname to inode transform + * @loc - location. valid fields that do_path_lookup() uses in @loc are + * @loc->path - pathname + * @loc->ino - inode number + * + * return - do_path_lookup returns only after complete dentry tree is built + * upto @loc->path. + */ +int32_t +do_path_lookup (call_stub_t *stub, + const loc_t *loc) +{ + char *pathname = NULL; + char *directory = NULL; + inode_t *inode = NULL; + inode_t *parent = NULL; + server_state_t *state = NULL; + + state = CALL_STATE(stub->frame); + + inode = inode_from_path (state->itable, loc->path); + pathname = strdup (loc->path); + directory = dirname (pathname); + parent = inode_from_path (state->itable, directory); + + if (inode && parent) { + gf_log (BOUND_XL(stub->frame)->name, + GF_LOG_DEBUG, + "resolved path(%s) to %"PRId64"/%"PRId64"(%s)", + loc->path, parent->ino, inode->ino, loc->name); + server_stub_resume (stub, 0, 0, inode, parent); + inode_unref (inode); + inode_unref (parent); + } else { + gf_log (BOUND_XL(stub->frame)->name, + GF_LOG_DEBUG, + "resolved path(%s) to %p(%"PRId64")/%p(%"PRId64")", + loc->path, parent, (parent ? parent->ino : 0), + inode, (inode ? inode->ino : 0)); + if (parent) { + inode_unref (parent); + } else if (inode) { + inode_unref (inode); + gf_log (BOUND_XL(stub->frame)->name, + GF_LOG_ERROR, + "undesired behaviour. inode(%"PRId64") for %s " + "exists without parent (%s)", + inode->ino, loc->path, directory); + } + __do_path_resolve (stub, loc); + } + + if (pathname) + free (pathname); + + return 0; +} diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c new file mode 100644 index 00000000000..b51c11aa994 --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.c @@ -0,0 +1,586 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server-protocol.h" +#include "server-helpers.h" + + +/* server_loc_fill - derive a loc_t for a given inode number + * + * NOTE: make sure that @loc is empty, because any pointers it holds with reference will + * be leaked after returning from here. + */ +int +server_loc_fill (loc_t *loc, server_state_t *state, + ino_t ino, ino_t par, + const char *name, const char *path) +{ + inode_t *inode = NULL; + inode_t *parent = NULL; + int32_t ret = -1; + char *dentry_path = NULL; + + + GF_VALIDATE_OR_GOTO ("server", loc, out); + GF_VALIDATE_OR_GOTO ("server", state, out); + GF_VALIDATE_OR_GOTO ("server", path, out); + + /* anything beyond this point is success */ + ret = 0; + loc->ino = ino; + inode = loc->inode; + if (inode == NULL) { + if (ino) + inode = inode_search (state->itable, ino, NULL); + + if ((inode == NULL) && + (par && name)) + inode = inode_search (state->itable, par, name); + + loc->inode = inode; + if (inode) + loc->ino = inode->ino; + } + + parent = loc->parent; + if (parent == NULL) { + if (inode) + parent = inode_parent (inode, par, name); + else + parent = inode_search (state->itable, par, NULL); + loc->parent = parent; + } + + if (name && parent) { + ret = inode_path (parent, name, &dentry_path); + if (ret < 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "failed to build path for %"PRId64"/%s: %s", + parent->ino, name, strerror (-ret)); + } + } else if (inode) { + ret = inode_path (inode, NULL, &dentry_path); + if (ret < 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "failed to build path for %"PRId64": %s", + inode->ino, strerror (-ret)); + + inode_unref (loc->inode); + loc->inode = NULL; + } + } + + if (dentry_path) { + if (strcmp (dentry_path, path)) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "paths differ for inode(%"PRId64"): " + "client path = %s. dentry path = %s", + ino, path, dentry_path); + } + + loc->path = dentry_path; + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + } else { + loc->path = strdup (path); + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + } + +out: + return ret; +} + +/* + * stat_to_str - convert struct stat to a ASCII string + * @stbuf: struct stat pointer + * + * not for external reference + */ +char * +stat_to_str (struct stat *stbuf) +{ + char *tmp_buf = NULL; + + uint64_t dev = stbuf->st_dev; + uint64_t ino = stbuf->st_ino; + uint32_t mode = stbuf->st_mode; + uint32_t nlink = stbuf->st_nlink; + uint32_t uid = stbuf->st_uid; + uint32_t gid = stbuf->st_gid; + uint64_t rdev = stbuf->st_rdev; + uint64_t size = stbuf->st_size; + uint32_t blksize = stbuf->st_blksize; + uint64_t blocks = stbuf->st_blocks; + uint32_t atime = stbuf->st_atime; + uint32_t mtime = stbuf->st_mtime; + uint32_t ctime = stbuf->st_ctime; + + uint32_t atime_nsec = ST_ATIM_NSEC(stbuf); + uint32_t mtime_nsec = ST_MTIM_NSEC(stbuf); + uint32_t ctime_nsec = ST_CTIM_NSEC(stbuf); + + + asprintf (&tmp_buf, + GF_STAT_PRINT_FMT_STR, + dev, + ino, + mode, + nlink, + uid, + gid, + rdev, + size, + blksize, + blocks, + atime, + atime_nsec, + mtime, + mtime_nsec, + ctime, + ctime_nsec); + + return tmp_buf; +} + + +void +server_loc_wipe (loc_t *loc) +{ + if (loc->parent) + inode_unref (loc->parent); + if (loc->inode) + inode_unref (loc->inode); + if (loc->path) + free ((char *)loc->path); +} + +void +free_state (server_state_t *state) +{ + transport_t *trans = NULL; + + trans = state->trans; + + if (state->fd) + fd_unref (state->fd); + + transport_unref (trans); + + if (state->xattr_req) + dict_unref (state->xattr_req); + + FREE (state); +} + + +call_frame_t * +server_copy_frame (call_frame_t *frame) +{ + call_frame_t *new_frame = NULL; + server_state_t *state = NULL, *new_state = NULL; + + state = frame->root->state; + + new_frame = copy_frame (frame); + + new_state = CALLOC (1, sizeof (server_state_t)); + + new_frame->root->op = frame->root->op; + new_frame->root->type = frame->root->type; + new_frame->root->trans = state->trans; + new_frame->root->state = new_state; + + new_state->bound_xl = state->bound_xl; + new_state->trans = transport_ref (state->trans); + new_state->itable = state->itable; + + return new_frame; +} + +int32_t +gf_add_locker (struct _lock_table *table, + loc_t *loc, + fd_t *fd, + pid_t pid) +{ + int32_t ret = -1; + struct _locker *new = NULL; + uint8_t dir = 0; + + new = CALLOC (1, sizeof (struct _locker)); + if (new == NULL) { + gf_log ("server", GF_LOG_ERROR, + "failed to allocate memory for \'struct _locker\'"); + goto out; + } + INIT_LIST_HEAD (&new->lockers); + + if (fd == NULL) { + loc_copy (&new->loc, loc); + dir = S_ISDIR (new->loc.inode->st_mode); + } else { + new->fd = fd_ref (fd); + dir = S_ISDIR (fd->inode->st_mode); + } + + new->pid = pid; + + LOCK (&table->lock); + { + if (dir) + list_add_tail (&new->lockers, &table->dir_lockers); + else + list_add_tail (&new->lockers, &table->file_lockers); + } + UNLOCK (&table->lock); +out: + return ret; +} + +int32_t +gf_del_locker (struct _lock_table *table, + loc_t *loc, + fd_t *fd, + pid_t pid) +{ + struct _locker *locker = NULL, *tmp = NULL; + int32_t ret = 0; + uint8_t dir = 0; + struct list_head *head = NULL; + struct list_head del; + + INIT_LIST_HEAD (&del); + + if (fd) { + dir = S_ISDIR (fd->inode->st_mode); + } else { + dir = S_ISDIR (loc->inode->st_mode); + } + + LOCK (&table->lock); + { + if (dir) { + head = &table->dir_lockers; + } else { + head = &table->file_lockers; + } + + list_for_each_entry_safe (locker, tmp, head, lockers) { + if (locker->fd && + fd && + (locker->fd == fd) && (locker->pid == pid)) { + list_move_tail (&locker->lockers, &del); + } else if (locker->loc.inode && + loc && + (locker->loc.inode == loc->inode) && + (locker->pid == pid)) { + list_move_tail (&locker->lockers, &del); + } + } + } + UNLOCK (&table->lock); + + tmp = NULL; + locker = NULL; + + list_for_each_entry_safe (locker, tmp, &del, lockers) { + list_del_init (&locker->lockers); + if (locker->fd) + fd_unref (locker->fd); + else + loc_wipe (&locker->loc); + + free (locker); + } + + return ret; +} + +int32_t +gf_direntry_to_bin (dir_entry_t *head, + char **bufferp) +{ + dir_entry_t *trav = NULL; + uint32_t len = 0; + uint32_t this_len = 0; + char *buffer = NULL; + size_t buflen = -1; + char *ptr = NULL; + char *tmp_buf = NULL; + + trav = head->next; + while (trav) { + len += strlen (trav->name); + len += 1; + len += strlen (trav->link); + len += 1; /* for '\n' */ + len += 256; // max possible for statbuf; + trav = trav->next; + } + + buffer = CALLOC (1, len); + if (buffer == NULL) { + gf_log ("server", GF_LOG_ERROR, + "failed to allocate memory for buffer"); + goto out; + } + + ptr = buffer; + trav = head->next; + while (trav) { + tmp_buf = stat_to_str (&trav->buf); + /* tmp_buf will have \n before \0 */ + + this_len = sprintf (ptr, "%s/%s%s\n", + trav->name, tmp_buf, + trav->link); + + FREE (tmp_buf); + trav = trav->next; + ptr += this_len; + } + if (bufferp) + *bufferp = buffer; + buflen = strlen (buffer); + +out: + return buflen; +} + + +static struct _lock_table * +gf_lock_table_new (void) +{ + struct _lock_table *new = NULL; + + new = CALLOC (1, sizeof (struct _lock_table)); + if (new == NULL) { + gf_log ("server-protocol", GF_LOG_CRITICAL, + "failed to allocate memory for new lock table"); + goto out; + } + INIT_LIST_HEAD (&new->dir_lockers); + INIT_LIST_HEAD (&new->file_lockers); + LOCK_INIT (&new->lock); +out: + return new; +} + + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn) +{ + + call_frame_t *frame = NULL, *tmp_frame = NULL; + xlator_t *bound_xl = NULL; + int32_t ret = -1; + server_state_t *state = NULL; + struct list_head file_lockers; + struct list_head dir_lockers; + struct _lock_table *ltable = NULL; + struct _locker *locker = NULL, *tmp = NULL; + struct flock flock = {0,}; + + + bound_xl = (xlator_t *) (conn->bound_xl); + + if (bound_xl) { + /* trans will have ref_count = 1 after this call, but its + ok since this function is called in + GF_EVENT_TRANSPORT_CLEANUP */ + frame = create_frame (this, this->ctx->pool); + + pthread_mutex_lock (&(conn->lock)); + { + if (conn->ltable) { + ltable = conn->ltable; + conn->ltable = NULL; + } + } + pthread_mutex_unlock (&conn->lock); + + INIT_LIST_HEAD (&file_lockers); + INIT_LIST_HEAD (&dir_lockers); + + LOCK (<able->lock); + { + list_splice_init (<able->file_lockers, + &file_lockers); + + list_splice_init (<able->dir_lockers, &dir_lockers); + } + UNLOCK (<able->lock); + free (ltable); + + flock.l_type = F_UNLCK; + flock.l_start = 0; + flock.l_len = 0; + list_for_each_entry_safe (locker, + tmp, &file_lockers, lockers) { + tmp_frame = copy_frame (frame); + /* + pid = 0 is a special case that tells posix-locks + to release all locks from this transport + */ + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->finodelk, + locker->fd, F_SETLK, &flock); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->inodelk, + &(locker->loc), F_SETLK, &flock); + loc_wipe (&locker->loc); + } + + list_del_init (&locker->lockers); + free (locker); + } + + tmp = NULL; + locker = NULL; + list_for_each_entry_safe (locker, tmp, &dir_lockers, lockers) { + tmp_frame = copy_frame (frame); + + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + + if (locker->fd) { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->fentrylk, + locker->fd, NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, + bound_xl, + bound_xl->fops->entrylk, + &(locker->loc), NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + loc_wipe (&locker->loc); + } + + list_del_init (&locker->lockers); + free (locker); + } + + state = CALL_STATE (frame); + if (state) + free (state); + STACK_DESTROY (frame->root); + + pthread_mutex_lock (&(conn->lock)); + { + if (conn->fdtable) { + gf_fd_fdtable_destroy (conn->fdtable); + conn->fdtable = NULL; + } + } + pthread_mutex_unlock (&conn->lock); + + } + + gf_log (this->name, GF_LOG_INFO, "destroyed connection of %s", + conn->id); + + FREE (conn->id); + FREE (conn); + + return ret; +} + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id) +{ + server_connection_t *conn = NULL; + server_connection_t *trav = NULL; + server_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + list_for_each_entry (trav, &conf->conns, list) { + if (!strcmp (id, trav->id)) { + conn = trav; + break; + } + } + + if (!conn) { + conn = (void *) CALLOC (1, sizeof (*conn)); + + conn->id = strdup (id); + conn->fdtable = gf_fd_fdtable_alloc (); + conn->ltable = gf_lock_table_new (); + + pthread_mutex_init (&conn->lock, NULL); + + list_add (&conn->list, &conf->conns); + } + + conn->ref++; + } + pthread_mutex_unlock (&conf->mutex); + + return conn; +} + + +void +server_connection_put (xlator_t *this, server_connection_t *conn) +{ + server_conf_t *conf = NULL; + server_connection_t *todel = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + conn->ref--; + + if (!conn->ref) { + list_del_init (&conn->list); + todel = conn; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (todel) { + server_connection_destroy (this, todel); + } + + return; +} diff --git a/xlators/protocol/server/src/server-helpers.h b/xlators/protocol/server/src/server-helpers.h new file mode 100644 index 00000000000..36c0ce98e40 --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.h @@ -0,0 +1,77 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __SERVER_HELPERS_H__ +#define __SERVER_HELPERS_H__ + +#define CALL_STATE(frame) ((server_state_t *)frame->root->state) + +#define BOUND_XL(frame) ((xlator_t *) CALL_STATE(frame)->bound_xl) + +#define TRANSPORT_FROM_FRAME(frame) ((transport_t *) CALL_STATE(frame)->trans) + +#define SERVER_CONNECTION(frame) \ + ((server_connection_t *) TRANSPORT_FROM_FRAME(frame)->xl_private) + +#define SERVER_CONF(frame) \ + ((server_conf_t *)TRANSPORT_FROM_FRAME(frame)->xl->private) + +#define TRANSPORT_FROM_XLATOR(this) ((((server_conf_t *)this->private))->trans) + +#define INODE_LRU_LIMIT(this) \ + (((server_conf_t *)(this->private))->inode_lru_limit) + +#define IS_ROOT_INODE(inode) (inode == inode->table->root) + +#define IS_NOT_ROOT(pathlen) ((pathlen > 2)? 1 : 0) + +int32_t +server_loc_fill (loc_t *loc, + server_state_t *state, + ino_t ino, + ino_t par, + const char *name, + const char *path); + +char * +stat_to_str (struct stat *stbuf); + +call_frame_t * +server_copy_frame (call_frame_t *frame); + +void free_state (server_state_t *state); + +void server_loc_wipe (loc_t *loc); + +int32_t +gf_add_locker (struct _lock_table *table, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_del_locker (struct _lock_table *table, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_direntry_to_bin (dir_entry_t *head, + char **bufferp); +#endif /* __SERVER_HELPERS_H__ */ diff --git a/xlators/protocol/server/src/server-protocol.c b/xlators/protocol/server/src/server-protocol.c new file mode 100644 index 00000000000..a5198c1ed07 --- /dev/null +++ b/xlators/protocol/server/src/server-protocol.c @@ -0,0 +1,7984 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include <time.h> +#include <sys/uio.h> +#include <sys/resource.h> + +#include <libgen.h> + +#include "transport.h" +#include "fnmatch.h" +#include "xlator.h" +#include "protocol.h" +#include "server-protocol.h" +#include "server-helpers.h" +#include "call-stub.h" +#include "defaults.h" +#include "list.h" +#include "dict.h" +#include "compat.h" +#include "compat-errno.h" + + +static void +protocol_server_reply (call_frame_t *frame, + int type, int op, + gf_hdr_common_t *hdr, size_t hdrlen, + struct iovec *vector, int count, + dict_t *refs) +{ + server_state_t *state = NULL; + xlator_t *bound_xl = NULL; + transport_t *trans = NULL; + + bound_xl = BOUND_XL(frame); + state = CALL_STATE(frame); + trans = state->trans; + + hdr->callid = hton64 (frame->root->unique); + hdr->type = hton32 (type); + hdr->op = hton32 (op); + + transport_submit (trans, (char *)hdr, hdrlen, vector, count, refs); + /* TODO: If transport submit fails, there is no reply sent to client, + * its bailed out as of now.. loggically, only this frame should fail. + */ + + STACK_DESTROY (frame->root); + + if (state) + free_state (state); + +} + + +/* + * server_fchmod_cbk + */ +int32_t +server_fchmod_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fchmod_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FCHMOD %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FCHMOD, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fchmod + * + */ +int32_t +server_fchmod (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_connection_t *conn = NULL; + gf_fop_fchmod_req_t *req = NULL; + server_state_t *state = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->mode = ntoh32 (req->mode); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + STACK_WIND (frame, + server_fchmod_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->fchmod, + state->fd, + state->mode); + + return 0; +fail: + server_fchmod_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + return 0; +} + + +/* + * server_fchown_cbk + */ +int32_t +server_fchown_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fchown_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FCHOWN %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FCHOWN, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fchown + * + */ +int32_t +server_fchown (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_connection_t *conn = NULL; + gf_fop_fchown_req_t *req = NULL; + server_state_t *state = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->uid = ntoh32 (req->uid); + state->gid = ntoh32 (req->gid); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + STACK_WIND (frame, + server_fchown_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->fchown, + state->fd, + state->uid, + state->gid); + + return 0; +fail: + server_fchown_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + return 0; +} + +/* + * server_setdents_cbk - writedir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_setdents_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setdents_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SETDENTS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_lk_cbk - lk callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int32_t +server_lk_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct flock *lock) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_lk_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_flock_from_flock (&rsp->flock, lock); + } else if (op_errno != ENOSYS) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": LK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int32_t +server_inodelk_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_inodelk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_loc_wipe (&state->loc); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_INODELK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int32_t +server_finodelk_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_finodelk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, + NULL, state->fd, frame->root->pid); + else + gf_add_locker (conn->ltable, + NULL, state->fd, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FINODELK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FINODELK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_entrylk_cbk - + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int32_t +server_entrylk_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_entrylk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_loc_wipe (&state->loc); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_ENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +int32_t +server_fentrylk_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_fentrylk_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + state = CALL_STATE(frame); + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, + NULL, state->fd, frame->root->pid); + else + gf_add_locker (conn->ltable, + NULL, state->fd, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FENTRYLK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_access_cbk - access callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_access_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_access_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_ACCESS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_utimens_cbk - utimens callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_utimens_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_utimens_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) + gf_stat_from_stat (&rsp->stat, stbuf); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_UTIMENS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_chmod_cbk - chmod callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_chmod_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_chmod_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) + gf_stat_from_stat (&rsp->stat, stbuf); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHMOD, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_chown_cbk - chown callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_chown_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_chown_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) + gf_stat_from_stat (&rsp->stat, stbuf); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHOWN, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_rmdir_cbk - rmdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_rmdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rmdir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + + state = CALL_STATE(frame); + + if (op_ret == 0) { + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": RMDIR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_RMDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_mkdir_cbk - mkdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_mkdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mkdir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + inode_link (inode, state->loc.parent, state->loc.name, stbuf); + inode_lookup (inode); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": MKDIR %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_MKDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_mknod_cbk - mknod callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_mknod_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_mknod_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + inode_link (inode, state->loc.parent, state->loc.name, stbuf); + inode_lookup (inode); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": MKNOD %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_MKNOD, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fsyncdir_cbk - fsyncdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_fsyncdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsyncdir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSYNCDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSYNCDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_getdents_cbk - readdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @entries: + * @count: + * + * not for external reference + */ +int32_t +server_getdents_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dir_entry_t *entries, + int32_t count) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_getdents_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t vec_count = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + dict_t *reply_dict = NULL; + char *buffer = NULL; + size_t buflen = 0; + struct iovec vector[1]; + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + buflen = gf_direntry_to_bin (entries, &buffer); + if (buflen < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to convert " + "entries list to string buffer", + state->fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + reply_dict = dict_new (); + if (reply_dict == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to get new dict", + state->fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + ret = dict_set_dynptr (reply_dict, NULL, + buffer, buflen); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to set read buffer " + "to reply dictionary", + state->fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = -ret; + goto out; + } + frame->root->rsp_refs = reply_dict; + vector[0].iov_base = buffer; + vector[0].iov_len = buflen; + vec_count = 1; + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": GETDENTS %"PRId64" (%"PRId64"): %"PRId32" (%s)", + frame->root->unique, + state->fd_no, + state->fd ? state->fd->inode->ino : 0, + op_ret, strerror (op_errno)); + vector[0].iov_base = NULL; + vector[0].iov_len = 0; + } + +out: + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + rsp->count = hton32 (count); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_GETDENTS, + hdr, hdrlen, vector, vec_count, + frame->root->rsp_refs); + + if (reply_dict) + dict_unref (reply_dict); + + return 0; +} + + +/* + * server_readdir_cbk - getdents callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_readdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + gf_dirent_t *entries) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readdir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + size_t buf_size = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret > 0) + buf_size = gf_dirent_serialize (entries, NULL, 0); + + hdrlen = gf_hdr_len (rsp, buf_size); + hdr = gf_hdr_new (rsp, buf_size); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret > 0) { + rsp->size = hton32 (buf_size); + gf_dirent_serialize (entries, rsp->buf, buf_size); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_releasedir_cbk - releasedir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_releasedir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_cbk_releasedir_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASEDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_opendir_cbk - opendir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @fd: file descriptor structure of opened directory + * + * not for external reference + */ +int32_t +server_opendir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_opendir_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + fd_bind (fd); + + state->fd_no = gf_fd_unused_get (conn->fdtable, fd); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": OPENDIR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + + /* NOTE: corresponding to fd_create()'s ref */ + if (state->fd) + fd_unref (state->fd); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (state->fd_no); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_OPENDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_statfs_cbk - statfs callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @buf: + * + * not for external reference + */ +int32_t +server_statfs_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct statvfs *buf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_statfs_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_statfs_from_statfs (&rsp->statfs, buf); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_STATFS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_removexattr_cbk - removexattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_removexattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_removexattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_REMOVEXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_getxattr_cbk - getxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @value: + * + * not for external reference + */ +int32_t +server_getxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_getxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized length of " + "reply dict", + state->loc.path, state->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if (op_ret >= 0) { + ret = dict_serialize (dict, rsp->dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->ino); + op_ret = -1; + op_errno = -ret; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_GETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_setxattr_cbk - setxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_setxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setxattr_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SETXATTR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_rename_cbk - rename callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_rename_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rename_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + stbuf->st_ino = state->loc.inode->ino; + stbuf->st_mode = state->loc.inode->st_mode; + + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": RENAME_CBK (%"PRId64") %"PRId64"/%s " + "==> %"PRId64"/%s", + frame->root->unique, state->loc.inode->ino, + state->loc.parent->ino, state->loc.name, + state->loc2.parent->ino, state->loc2.name); + + inode_rename (state->itable, + state->loc.parent, state->loc.name, + state->loc2.parent, state->loc2.name, + state->loc.inode, stbuf); + gf_stat_from_stat (&rsp->stat, stbuf); + } + + server_loc_wipe (&(state->loc)); + server_loc_wipe (&(state->loc2)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_RENAME, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_unlink_cbk - unlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_unlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_unlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + if (op_ret == 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": UNLINK_CBK %"PRId64"/%s (%"PRId64")", + frame->root->unique, state->loc.parent->ino, + state->loc.name, state->loc.inode->ino); + + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": UNLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_UNLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_symlink_cbk - symlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_symlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_symlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + inode_link (inode, state->loc.parent, state->loc.name, stbuf); + inode_lookup (inode); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": SYMLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SYMLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_link_cbk - link callback for server protocol + * @frame: call frame + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_link_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_link_rsp_t *rsp = NULL; + server_state_t *state = NULL; + int32_t gf_errno = 0; + size_t hdrlen = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + stbuf->st_ino = state->loc.inode->ino; + gf_stat_from_stat (&rsp->stat, stbuf); + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s", + frame->root->unique, inode->ino, state->loc2.parent->ino, + state->loc2.name, state->loc.parent->ino, state->loc.name); + + inode_link (inode, state->loc2.parent, + state->loc2.name, stbuf); + } else { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s " + " ==> %"PRId32" (%s)", + frame->root->unique, inode->ino, state->loc2.parent->ino, + state->loc2.name, state->loc.parent->ino, state->loc.name, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + server_loc_wipe (&(state->loc2)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_truncate_cbk - truncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_truncate_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_truncate_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": TRUNCATE %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_TRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fstat_cbk - fstat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_fstat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fstat_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSTAT %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSTAT, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_ftruncate_cbk - ftruncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_ftruncate_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_ftruncate_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FTRUNCATE %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FTRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_flush_cbk - flush callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_flush_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_flush_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FLUSH %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FLUSH, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_fsync_cbk - fsync callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_fsync_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsync_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + if (op_ret < 0) { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSYNC %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSYNC, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_release_cbk - rleease callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_release_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_cbk_release_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_writev_cbk - writev callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ + +int32_t +server_writev_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_write_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": WRITEV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, + GF_OP_TYPE_FOP_REPLY, GF_FOP_WRITE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_readv_cbk - readv callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @vector: + * @count: + * + * not for external reference + */ +int32_t +server_readv_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iovec *vector, + int32_t count, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_read_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + server_state_t *state = NULL; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + state = CALL_STATE(frame); + + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READ, + hdr, hdrlen, vector, count, + frame->root->rsp_refs); + + return 0; +} + + +/* + * server_open_cbk - open callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @fd: + * + * not for external reference + */ +int32_t +server_open_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_open_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + fd_bind (fd); + + state->fd_no = gf_fd_unused_get (conn->fdtable, fd); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": OPEN %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + + /* NOTE: corresponding to fd_create()'s ref */ + if (state->fd) + fd_unref (state->fd); + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (state->fd_no); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_OPEN, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_create_cbk - create callback for server + * @frame: call frame + * @cookie: + * @this: translator structure + * @op_ret: + * @op_errno: + * @fd: file descriptor + * @inode: inode structure + * @stbuf: struct stat of created file + * + * not for external reference + */ +int32_t +server_create_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd, + inode_t *inode, + struct stat *stbuf) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + gf_fop_create_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + conn = SERVER_CONNECTION(frame); + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + gf_log (state->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": CREATE %"PRId64"/%s (%"PRId64")", + frame->root->unique, state->loc.parent->ino, + state->loc.name, stbuf->st_ino); + + inode_link (inode, state->loc.parent, state->loc.name, stbuf); + inode_lookup (inode); + + fd_bind (fd); + + state->fd_no = gf_fd_unused_get (conn->fdtable, fd); + + if ((state->fd_no < 0) || (fd == 0)) { + op_ret = state->fd_no; + op_errno = errno; + } + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": CREATE %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + + /* NOTE: corresponding to fd_create()'s ref */ + if (state->fd) + fd_unref (state->fd); + + } + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + rsp->fd = hton64 (state->fd_no); + + if (op_ret >= 0) + gf_stat_from_stat (&rsp->stat, stbuf); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CREATE, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_readlink_cbk - readlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @buf: + * + * not for external reference + */ +int32_t +server_readlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + const char *buf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readlink_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + size_t linklen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + linklen = strlen (buf) + 1; + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READLINK %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + hdrlen = gf_hdr_len (rsp, linklen); + hdr = gf_hdr_new (rsp, linklen); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret >= 0) + strcpy (rsp->path, buf); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READLINK, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_stat_cbk - stat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_stat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_stat_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + state = CALL_STATE(frame); + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + + if (op_ret == 0) { + gf_stat_from_stat (&rsp->stat, stbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": STAT %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_STAT, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_forget_cbk - forget callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_forget_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + gf_hdr_common_t *hdr = NULL; + gf_cbk_forget_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_FORGET, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * server_lookup_cbk - lookup callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @inode: + * @stbuf: + * + * not for external reference + */ +int32_t +server_lookup_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *stbuf, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_lookup_rsp_t *rsp = NULL; + server_state_t *state = NULL; + inode_t *root_inode = NULL; + int32_t dict_len = 0; + size_t hdrlen = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE(frame); + if ((op_errno == ESTALE) && (op_ret == -1)) { + /* Send lookup again with new ctx dictionary */ + loc_t loc = {0,}; + + root_inode = BOUND_XL(frame)->itable->root; + if (state->loc.inode != root_inode) { + if (state->loc.inode) + inode_unref (state->loc.inode); + state->loc.inode = inode_new (BOUND_XL(frame)->itable); + } + loc.inode = state->loc.inode; + loc.path = state->path; + state->is_revalidate = 2; + STACK_WIND (frame, server_lookup_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->lookup, + &loc, + state->xattr_req); + return 0; + } + + if (dict) { + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized " + "length of reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = EINVAL; + dict_len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, dict_len); + hdr = gf_hdr_new (rsp, dict_len); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = -ret; + dict_len = 0; + } + } + rsp->dict_len = hton32 (dict_len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret == 0) { + root_inode = BOUND_XL(frame)->itable->root; + if (inode == root_inode) { + /* we just looked up root ("/") */ + stbuf->st_ino = 1; + if (inode->st_mode == 0) + inode->st_mode = stbuf->st_mode; + } + + gf_stat_from_stat (&rsp->stat, stbuf); + + if (inode->ino == 0) { + inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (inode); + } + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": LOOKUP %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + server_loc_wipe (&state->loc); + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LOOKUP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int32_t +server_xattrop_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_xattrop_rsp_t *rsp = NULL; + server_state_t *state = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + + state = CALL_STATE(frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": XATTROP %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + if ((op_ret >= 0) && dict) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to get serialized length" + " for reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->loc.inode->ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + server_loc_wipe (&(state->loc)); + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_XATTROP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int32_t +server_fxattrop_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_xattrop_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t len = 0; + int32_t gf_errno = 0; + int32_t ret = -1; + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FXATTROP %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + if ((op_ret >= 0) && dict) { + len = dict_serialized_length (dict); + if (len < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to get " + "serialized length for reply dict", + state->fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } + + hdrlen = gf_hdr_len (rsp, len + 1); + hdr = gf_hdr_new (rsp, len + 1); + rsp = gf_param (hdr); + + if ((op_ret >= 0) && dict) { + ret = dict_serialize (dict, rsp->dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to " + "serialize reply dict", + state->fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } + rsp->dict_len = hton32 (len); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FXATTROP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * server_stub_resume - this is callback function used whenever an fop does + * STACK_WIND to fops->lookup in order to lookup the inode + * for a pathname. this case of doing fops->lookup arises + * when fop searches in inode table for pathname and search + * fails. + * + * @stub: call stub + * @op_ret: + * @op_errno: + * @inode: + * @parent: + * + * not for external reference + */ +int32_t +server_stub_resume (call_stub_t *stub, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + inode_t *parent) +{ + inode_t *server_inode = inode; + + if (!stub) { + return 0; + } + switch (stub->fop) + { + case GF_FOP_RENAME: + if (stub->args.rename.old.inode == NULL) { + loc_t *newloc = NULL; + /* now we are called by lookup of oldpath. */ + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": RENAME (%s -> %s) on %s " + "returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.rename.old.path, + stub->args.rename.new.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + /* lookup of oldpath failed, UNWIND to + * server_rename_cbk with ret=-1 and + * errno=ENOENT + */ + server_rename_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT, + NULL); + server_loc_wipe (&stub->args.rename.old); + server_loc_wipe (&stub->args.rename.new); + FREE (stub); + return 0; + } + + if (stub->args.rename.old.parent == NULL) + stub->args.rename.old.parent = + inode_ref (parent); + + /* store inode information of oldpath in our stub + * and search for newpath in inode table. + */ + if (server_inode) { + stub->args.rename.old.inode = + inode_ref (server_inode); + + stub->args.rename.old.ino = + server_inode->ino; + } + + /* now lookup for newpath */ + newloc = &stub->args.rename.new; + + if (newloc->parent == NULL) { + /* lookup for newpath */ + do_path_lookup (stub, newloc); + break; + } else { + /* found newpath in inode cache */ + call_resume (stub); + break; + } + } else { + /* we are called by the lookup of newpath */ + if (stub->args.rename.new.parent == NULL) + stub->args.rename.new.parent = + inode_ref (parent); + } + + /* after looking up for oldpath as well as newpath, + * we are ready to resume */ + { + call_resume (stub); + } + break; + + case GF_FOP_OPEN: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": OPEN (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.open.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_open_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT, + NULL); + FREE (stub->args.open.loc.path); + FREE (stub); + return 0; + } + if (stub->args.open.loc.parent == NULL) + stub->args.open.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.open.loc.inode == NULL)) { + stub->args.open.loc.inode = inode_ref (server_inode); + stub->args.open.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_LOOKUP: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, + GF_LOG_DEBUG, + "%"PRId64": LOOKUP (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.lookup.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_lookup_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL, + NULL); + server_loc_wipe (&stub->args.lookup.loc); + FREE (stub); + return 0; + } + + if (stub->args.lookup.loc.parent == NULL) + stub->args.lookup.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.lookup.loc.inode == NULL)) { + stub->args.lookup.loc.inode = inode_ref (server_inode); + stub->args.lookup.loc.ino = server_inode->ino; + } + + call_resume (stub); + + break; + } + + case GF_FOP_STAT: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": STAT (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.stat.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_stat_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.stat.loc); + FREE (stub); + return 0; + } + + /* TODO:reply from here only, we already have stat structure */ + if (stub->args.stat.loc.parent == NULL) + stub->args.stat.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.stat.loc.inode == NULL)) { + stub->args.stat.loc.inode = inode_ref (server_inode); + stub->args.stat.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_XATTROP: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": XATTROP (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.xattrop.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_xattrop_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.xattrop.loc); + FREE (stub); + return 0; + } + + if (stub->args.xattrop.loc.parent == NULL) + stub->args.xattrop.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.xattrop.loc.inode == NULL)) { + stub->args.xattrop.loc.inode = + inode_ref (server_inode); + + stub->args.xattrop.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_UNLINK: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": UNLINK (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.unlink.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_unlink_cbk (stub->frame, NULL, + stub->frame->this, + -1, ENOENT); + server_loc_wipe (&stub->args.unlink.loc); + FREE (stub); + return 0; + } + + if (stub->args.unlink.loc.parent == NULL) + stub->args.unlink.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.unlink.loc.inode == NULL)) { + stub->args.unlink.loc.inode = inode_ref (server_inode); + stub->args.unlink.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_SYMLINK: + { + if ((op_ret < 0) && (parent == NULL)) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": SYMLINK (%s -> %s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.symlink.loc.path, + stub->args.symlink.linkname, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_symlink_cbk (stub->frame, NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL); + server_loc_wipe (&stub->args.symlink.loc); + FREE (stub); + return 0; + } + + if (stub->args.symlink.loc.parent == NULL) + stub->args.symlink.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.symlink.loc.inode == NULL)) { + stub->args.symlink.loc.inode = + inode_ref (server_inode); + stub->args.symlink.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_RMDIR: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": RMDIR (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.rmdir.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_rmdir_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT); + server_loc_wipe (&stub->args.rmdir.loc); + FREE (stub); + return 0; + } + + if (stub->args.rmdir.loc.parent == NULL) + stub->args.rmdir.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.rmdir.loc.inode == NULL)) { + stub->args.rmdir.loc.inode = inode_ref (server_inode); + stub->args.rmdir.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_CHMOD: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": CHMOD (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.chmod.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_chmod_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT, + NULL); + server_loc_wipe (&stub->args.chmod.loc); + FREE (stub); + return 0; + } + + if (stub->args.chmod.loc.parent == NULL) + stub->args.chmod.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.chmod.loc.inode == NULL)) { + stub->args.chmod.loc.inode = inode_ref (server_inode); + stub->args.chmod.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_CHOWN: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": CHOWN (%s) on %s returning ENOENT: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.chown.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + server_chown_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT, + NULL); + server_loc_wipe (&stub->args.chown.loc); + FREE (stub); + return 0; + } + + if (stub->args.chown.loc.parent == NULL) + stub->args.chown.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.chown.loc.inode == NULL)) { + stub->args.chown.loc.inode = inode_ref (server_inode); + stub->args.chown.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_LINK: + { + if (stub->args.link.oldloc.inode == NULL) { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": LINK (%s -> %s) on %s returning " + "error for oldloc: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.link.oldloc.path, + stub->args.link.newloc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_link_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL); + server_loc_wipe (&stub->args.link.oldloc); + server_loc_wipe (&stub->args.link.newloc); + FREE (stub); + return 0; + } + + if (stub->args.link.oldloc.parent == NULL) + stub->args.link.oldloc.parent = + inode_ref (parent); + + if (server_inode && + (stub->args.link.oldloc.inode == NULL)) { + stub->args.link.oldloc.inode = + inode_ref (server_inode); + stub->args.link.oldloc.ino = server_inode->ino; + } + + if (stub->args.link.newloc.parent == NULL) { + do_path_lookup (stub, + &(stub->args.link.newloc)); + break; + } + } else { + /* we are called by the lookup of newpath */ + if ((op_ret < 0) && (parent == NULL)) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": LINK (%s -> %s) on %s returning " + "error for newloc: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.link.oldloc.path, + stub->args.link.newloc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_link_cbk (stub->frame, NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL); + + server_loc_wipe (&stub->args.link.oldloc); + server_loc_wipe (&stub->args.link.newloc); + FREE (stub); + break; + } + + if (stub->args.link.newloc.parent == NULL) { + stub->args.link.newloc.parent = + inode_ref (parent); + } + + if (server_inode && + (stub->args.link.newloc.inode == NULL)) { + /* as new.inode doesn't get forget, it + * needs to be unref'd here */ + stub->args.link.newloc.inode = + inode_ref (server_inode); + stub->args.link.newloc.ino = server_inode->ino; + } + } + call_resume (stub); + break; + } + + case GF_FOP_TRUNCATE: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": TRUNCATE (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.truncate.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_truncate_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.truncate.loc); + FREE (stub); + return 0; + } + + if (stub->args.truncate.loc.parent == NULL) + stub->args.truncate.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.truncate.loc.inode == NULL)) { + stub->args.truncate.loc.inode = + inode_ref (server_inode); + stub->args.truncate.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_STATFS: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": STATFS (%s) on %s returning ENOENT: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.statfs.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_statfs_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.statfs.loc); + FREE (stub); + return 0; + } + + if (stub->args.statfs.loc.parent == NULL) + stub->args.statfs.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.statfs.loc.inode == NULL)) { + stub->args.statfs.loc.inode = inode_ref (server_inode); + stub->args.statfs.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_SETXATTR: + { + dict_t *dict = stub->args.setxattr.dict; + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": SETXATTR (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.setxattr.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_setxattr_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT); + + server_loc_wipe (&stub->args.setxattr.loc); + dict_unref (dict); + FREE (stub); + return 0; + } + + if (stub->args.setxattr.loc.parent == NULL) + stub->args.setxattr.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.setxattr.loc.inode == NULL)) { + stub->args.setxattr.loc.inode = + inode_ref (server_inode); + stub->args.setxattr.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_GETXATTR: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": GETXATTR (%s) on %s for key %s " + "returning error: %"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.getxattr.loc.path, + BOUND_XL(stub->frame)->name, + stub->args.getxattr.name ? + stub->args.getxattr.name : "<nul>", + op_ret, op_errno); + + server_getxattr_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.getxattr.loc); + FREE (stub); + return 0; + } + + if (stub->args.getxattr.loc.parent == NULL) + stub->args.getxattr.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.getxattr.loc.inode == NULL)) { + stub->args.getxattr.loc.inode = + inode_ref (server_inode); + stub->args.getxattr.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_REMOVEXATTR: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": REMOVEXATTR (%s) on %s for key %s " + "returning error: %"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.removexattr.loc.path, + BOUND_XL(stub->frame)->name, + stub->args.removexattr.name, + op_ret, op_errno); + + server_removexattr_cbk (stub->frame, + NULL, + stub->frame->this, + -1, + ENOENT); + server_loc_wipe (&stub->args.removexattr.loc); + FREE (stub); + return 0; + } + + if (stub->args.removexattr.loc.parent == NULL) + stub->args.removexattr.loc.parent = inode_ref (parent); + + if (server_inode && + (stub->args.removexattr.loc.inode == NULL)) { + stub->args.removexattr.loc.inode = + inode_ref (server_inode); + stub->args.removexattr.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_OPENDIR: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": OPENDIR (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.opendir.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_opendir_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.opendir.loc); + FREE (stub); + return 0; + } + + if (stub->args.opendir.loc.parent == NULL) + stub->args.opendir.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.opendir.loc.inode == NULL)) { + stub->args.opendir.loc.inode = + inode_ref (server_inode); + stub->args.opendir.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_ACCESS: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": ACCESS (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.access.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_access_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT); + server_loc_wipe (&stub->args.access.loc); + FREE (stub); + return 0; + } + + if (stub->args.access.loc.parent == NULL) + stub->args.access.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.access.loc.inode == NULL)) { + stub->args.access.loc.inode = inode_ref (server_inode); + stub->args.access.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + + case GF_FOP_UTIMENS: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": UTIMENS (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.utimens.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_utimens_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.utimens.loc); + FREE (stub); + return 0; + } + + if (stub->args.utimens.loc.parent == NULL) + stub->args.utimens.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.utimens.loc.inode == NULL)) { + stub->args.utimens.loc.inode = + inode_ref (server_inode); + stub->args.utimens.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + + case GF_FOP_READLINK: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": READLINK (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.readlink.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_readlink_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL); + server_loc_wipe (&stub->args.readlink.loc); + FREE (stub); + return 0; + } + + if (stub->args.readlink.loc.parent == NULL) + stub->args.readlink.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.readlink.loc.inode == NULL)) { + stub->args.readlink.loc.inode = + inode_ref (server_inode); + stub->args.readlink.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + case GF_FOP_MKDIR: + { + if ((op_ret < 0) && (parent == NULL)) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": MKDIR (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.mkdir.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_mkdir_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL); + server_loc_wipe (&stub->args.mkdir.loc); + FREE (stub); + break; + } + + if (stub->args.mkdir.loc.parent == NULL) + stub->args.mkdir.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.mkdir.loc.inode == NULL)) { + stub->args.mkdir.loc.inode = inode_ref (server_inode); + stub->args.mkdir.loc.ino = server_inode->ino; + } + + call_resume (stub); + break; + } + + case GF_FOP_CREATE: + { + if ((op_ret < 0) && (parent == NULL)) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": CREATE (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.create.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_create_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL, + NULL); + if (stub->args.create.fd) + fd_unref (stub->args.create.fd); + server_loc_wipe (&stub->args.create.loc); + FREE (stub); + break; + } + + if (stub->args.create.loc.parent == NULL) + stub->args.create.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.create.loc.inode == NULL)) { + stub->args.create.loc.inode = inode_ref (server_inode); + stub->args.create.loc.ino = server_inode->ino; + } + + call_resume (stub); + break; + } + + case GF_FOP_MKNOD: + { + if ((op_ret < 0) && (parent == NULL)) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": MKNOD (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.mknod.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_mknod_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT, + NULL, NULL); + server_loc_wipe (&stub->args.mknod.loc); + FREE (stub); + break; + } + + if (stub->args.mknod.loc.parent == NULL) + stub->args.mknod.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.mknod.loc.inode == NULL)) { + stub->args.mknod.loc.inode = inode_ref (server_inode); + stub->args.mknod.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + case GF_FOP_ENTRYLK: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": ENTRYLK (%s) on %s for key %s returning " + "error: %"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.entrylk.loc.path, + BOUND_XL(stub->frame)->name, + stub->args.entrylk.name ? + stub->args.entrylk.name : "<nul>", + op_ret, op_errno); + + server_entrylk_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT); + server_loc_wipe (&stub->args.entrylk.loc); + FREE (stub); + break; + } + + if (stub->args.entrylk.loc.parent == NULL) + stub->args.entrylk.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.entrylk.loc.inode == NULL)) { + stub->args.entrylk.loc.inode = inode_ref (server_inode); + stub->args.entrylk.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + case GF_FOP_INODELK: + { + if (op_ret < 0) { + gf_log (stub->frame->this->name, GF_LOG_ERROR, + "%"PRId64": INODELK (%s) on %s returning error: " + "%"PRId32" (%"PRId32")", + stub->frame->root->unique, + stub->args.inodelk.loc.path, + BOUND_XL(stub->frame)->name, + op_ret, op_errno); + + server_inodelk_cbk (stub->frame, + NULL, + stub->frame->this, + -1, ENOENT); + server_loc_wipe (&stub->args.inodelk.loc); + FREE (stub); + break; + } + + if (stub->args.inodelk.loc.parent == NULL) + stub->args.inodelk.loc.parent = inode_ref (parent); + + if (server_inode && (stub->args.inodelk.loc.inode == NULL)) { + stub->args.inodelk.loc.inode = + inode_ref (server_inode); + stub->args.inodelk.loc.ino = server_inode->ino; + } + call_resume (stub); + break; + } + default: + call_resume (stub); + } + + return 0; +} + +static int +server_lookup_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + dict_t *xattr_req) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if ((state->loc.parent == NULL) && + (loc->parent)) + state->loc.parent = inode_ref (loc->parent); + + if (state->loc.inode == NULL) { + if (loc->inode == NULL) + state->loc.inode = inode_new (state->itable); + else + /* FIXME: why another lookup? */ + state->loc.inode = inode_ref (loc->inode); + } else { + if (loc->inode && (state->loc.inode != loc->inode)) { + if (state->loc.inode) + inode_unref (state->loc.inode); + state->loc.inode = inode_ref (loc->inode); + } + } + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": LOOKUP \'%"PRId64"/%s\'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_lookup_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->lookup, + &(state->loc), + xattr_req); + return 0; +} + +/* + * server_lookup - lookup function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int +server_lookup (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_lookup_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *lookup_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0, baselen = 0; + size_t dictlen = 0; + dict_t *xattr_req = NULL; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + + pathlen = STRLEN_0 (req->path); + dictlen = ntoh32 (req->dictlen); + + /* NOTE: lookup() uses req->ino only to identify if a lookup() + * is requested for 'root' or not + */ + state->ino = ntoh64 (req->ino); + if (state->ino != 1) + state->ino = 0; + + state->par = ntoh64 (req->par); + state->path = req->path; + if (IS_NOT_ROOT(pathlen)) { + state->bname = req->bname + pathlen; + baselen = STRLEN_0 (state->bname); + } + + if (dictlen) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict + pathlen + baselen, dictlen); + GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + + xattr_req = dict_new (); + GF_VALIDATE_OR_GOTO(bound_xl->name, xattr_req, fail); + + ret = dict_unserialize (req_dictbuf, dictlen, &xattr_req); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->ino); + free (req_dictbuf); + goto fail; + } else{ + xattr_req->extra_free = req_dictbuf; + state->xattr_req = xattr_req; + xattr_req = NULL; + } + } + } + + ret = server_loc_fill (&state->loc, state, + state->ino, state->par, state->bname, + state->path); + + if (state->loc.inode) { + /* revalidate */ + state->is_revalidate = 1; + } else { + /* fresh lookup or inode was previously pruned out */ + state->is_revalidate = -1; + } + + lookup_stub = fop_lookup_stub (frame, server_lookup_resume, + &(state->loc), state->xattr_req); + GF_VALIDATE_OR_GOTO(bound_xl->name, lookup_stub, fail); + + if ((state->loc.parent == NULL) && + IS_NOT_ROOT(pathlen)) + do_path_lookup (lookup_stub, &(state->loc)); + else + call_resume (lookup_stub); + + return 0; +fail: + server_lookup_cbk (frame, NULL, frame->this, + -1,EINVAL, + NULL, NULL, NULL); + if (xattr_req) + dict_unref (xattr_req); + + return 0; +} + + +/* + * server_forget - forget function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_forget (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int index = 0; + ino_t ino = 0; + int32_t count = 0; + inode_t *inode = NULL; + gf_cbk_forget_req_t *req = NULL; + + req = gf_param (hdr); + count = ntoh32 (req->count); + + for (index = 0; index < count; index++) { + + ino = ntoh64 (req->ino_array[index]); + + if (!ino) + continue; + + inode = inode_search (bound_xl->itable, ino, NULL); + + if (inode) { + inode_forget (inode, 0); + inode_unref (inode); + } else { + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FORGET %"PRId64" not found " + "in inode table", + frame->root->unique, ino); + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FORGET \'%"PRId64"\'", + frame->root->unique, ino); + } + + server_forget_cbk (frame, NULL, bound_xl, 0, 0); + + return 0; +} + + + +int32_t +server_stat_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": STAT \'%s (%"PRId64")\'", + frame->root->unique, state->loc.path, state->loc.ino); + + STACK_WIND (frame, + server_stat_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->stat, + loc); + return 0; +} + +/* + * server_stat - stat function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_stat (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *stat_stub = NULL; + gf_fop_stat_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + + ret = server_loc_fill (&(state->loc), state, + state->ino, state->par, state->bname, + state->path); + + stat_stub = fop_stat_stub (frame, + server_stat_resume, + &(state->loc)); + GF_VALIDATE_OR_GOTO(bound_xl->name, stat_stub, fail); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (stat_stub, &(state->loc)); + } else { + call_resume (stat_stub); + } + return 0; +fail: + server_stat_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL); + return 0; +} + + +int32_t +server_readlink_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + size_t size) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": READLINK \'%s (%"PRId64")\'", + frame->root->unique, state->loc.path, state->loc.ino); + + STACK_WIND (frame, + server_readlink_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->readlink, + loc, + size); + return 0; +} + +/* + * server_readlink - readlink function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_readlink (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *readlink_stub = NULL; + gf_fop_readlink_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->size = ntoh32 (req->size); + + state->ino = ntoh64 (req->ino); + state->path = req->path; + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + readlink_stub = fop_readlink_stub (frame, + server_readlink_resume, + &(state->loc), + state->size); + GF_VALIDATE_OR_GOTO(bound_xl->name, readlink_stub, fail); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (readlink_stub, &(state->loc)); + } else { + call_resume (readlink_stub); + } + return 0; +fail: + server_readlink_cbk (frame, NULL,frame->this, + -1, EINVAL, + NULL); + return 0; +} + +int32_t +server_create_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flags, + mode_t mode, + fd_t *fd) +{ + server_state_t *state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + state->loc.inode = inode_new (state->itable); + GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, state->loc.inode, fail); + + state->fd = fd_create (state->loc.inode, frame->root->pid); + GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, state->fd, fail); + + state->fd->flags = flags; + state->fd = fd_ref (state->fd); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": CREATE \'%"PRId64"/%s\'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_create_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->create, + &(state->loc), + flags, + mode, + state->fd); + + return 0; +fail: + server_create_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL, NULL, NULL); + return 0; +} + + +/* + * server_create - create function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_create (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_create_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *create_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + + state->par = ntoh64 (req->par); + state->path = req->path; + if (IS_NOT_ROOT(pathlen)) + state->bname = req->bname + pathlen; + + state->mode = ntoh32 (req->mode); + state->flags = ntoh32 (req->flags); + } + + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + + create_stub = fop_create_stub (frame, server_create_resume, + &(state->loc), state->flags, + state->mode, state->fd); + GF_VALIDATE_OR_GOTO(bound_xl->name, create_stub, fail); + + if (state->loc.parent == NULL) { + do_path_lookup (create_stub, &state->loc); + } else { + call_resume (create_stub); + } + return 0; +fail: + server_create_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL, NULL, NULL); + return 0; +} + + +int32_t +server_open_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flags, + fd_t *fd) +{ + server_state_t *state = CALL_STATE(frame); + fd_t *new_fd = NULL; + + new_fd = fd_create (loc->inode, frame->root->pid); + GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, new_fd, fail); + + new_fd->flags = flags; + + state->fd = fd_ref (new_fd); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": OPEN \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_open_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->open, + loc, + flags, + state->fd); + + return 0; +fail: + server_open_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL); + return 0; +} + +/* + * server_open - open function for server protocol + * @frame: call frame + * @bound_xl: translator this server protocol is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_open (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *open_stub = NULL; + gf_fop_open_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + state->flags = ntoh32 (req->flags); + } + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + open_stub = fop_open_stub (frame, + server_open_resume, + &(state->loc), state->flags, NULL); + GF_VALIDATE_OR_GOTO(bound_xl->name, open_stub, fail); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (open_stub, &state->loc); + } else { + call_resume (open_stub); + } + return 0; +fail: + server_open_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL); + return 0; +} + + +/* + * server_readv - readv function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_readv (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_read_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": READV \'fd=%"PRId64" (%"PRId64"); " + "offset=%"PRId64"; size=%"PRId64, + frame->root->unique, state->fd_no, state->fd->inode->ino, + state->offset, (int64_t)state->size); + + STACK_WIND (frame, + server_readv_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->readv, + state->fd, state->size, state->offset); + return 0; +fail: + server_readv_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL, 0, NULL); + return 0; +} + + +/* + * server_writev - writev function for server + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_writev (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_connection_t *conn = NULL; + gf_fop_write_req_t *req = NULL; + struct iovec iov = {0, }; + dict_t *refs = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->offset = ntoh64 (req->offset); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + iov.iov_base = buf; + iov.iov_len = buflen; + + refs = dict_new (); + GF_VALIDATE_OR_GOTO(bound_xl->name, refs, fail); + + ret = dict_set_dynptr (refs, NULL, buf, buflen); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to set buffer entry " + "to req_refs", + state->fd_no, state->fd->inode->ino); + goto fail; + } else { + buf = NULL; + } + + frame->root->req_refs = refs; + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": WRITEV \'fd=%"PRId64" (%"PRId64"); " + "offset=%"PRId64"; size=%"PRId64, + frame->root->unique, state->fd_no, state->fd->inode->ino, + state->offset, (int64_t)buflen); + + STACK_WIND (frame, + server_writev_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->writev, + state->fd, &iov, 1, state->offset); + + if (refs) + dict_unref (refs); + return 0; +fail: + server_writev_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + + if (buf) + free (buf); + + if (refs) + dict_unref (refs); + + return 0; +} + + + +/* + * server_release - release function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_release (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_cbk_release_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->fd_no = ntoh64 (req->fd); + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + gf_fd_put (conn->fdtable, + state->fd_no); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": RELEASE \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_release_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->flush, + state->fd); + return 0; +fail: + server_release_cbk (frame, NULL, frame->this, + -1, EINVAL); + return 0; +} + + +/* + * server_fsync - fsync function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_fsync (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_fsync_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->flags = ntoh32 (req->data); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FSYNC \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_fsync_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->fsync, + state->fd, state->flags); + return 0; +fail: + server_fsync_cbk (frame, NULL, frame->this, + -1, EINVAL); + + return 0; +} + + +/* + * server_flush - flush function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_flush (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_flush_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FLUSH \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_flush_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->flush, + state->fd); + return 0; + +fail: + server_flush_cbk (frame, NULL, frame->this, + -1, EINVAL); + + return 0; +} + + +/* + * server_ftruncate - ftruncate function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_ftruncate (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_ftruncate_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->offset = ntoh64 (req->offset); + } + + GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FTRUNCATE \'fd=%"PRId64" (%"PRId64"); " + "offset=%"PRId64"\'", + frame->root->unique, state->fd_no, state->fd->inode->ino, + state->offset); + + STACK_WIND (frame, + server_ftruncate_cbk, + bound_xl, + bound_xl->fops->ftruncate, + state->fd, + state->offset); + return 0; +fail: + server_ftruncate_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + + return 0; +} + + +/* + * server_fstat - fstat function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_fstat (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_fstat_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + } + + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_fstat_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + + goto out; + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FSTAT \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_fstat_cbk, + bound_xl, + bound_xl->fops->fstat, + state->fd); +out: + return 0; +} + + +int32_t +server_truncate_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + off_t offset) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": TRUNCATE \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_truncate_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->truncate, + loc, + offset); + return 0; +} + + +/* + * server_truncate - truncate function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_truncate (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *truncate_stub = NULL; + gf_fop_truncate_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + state->offset = ntoh64 (req->offset); + + state->path = req->path; + state->ino = ntoh64 (req->ino); + } + + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + truncate_stub = fop_truncate_stub (frame, + server_truncate_resume, + &(state->loc), + state->offset); + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (truncate_stub, &(state->loc)); + } else { + call_resume (truncate_stub); + } + + return 0; +} + + + + + +int32_t +server_unlink_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + if (state->loc.inode == NULL) + state->loc.inode = inode_ref (loc->inode); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": UNLINK \'%"PRId64"/%s (%"PRId64")\'", + frame->root->unique, state->par, state->path, + state->loc.inode->ino); + + STACK_WIND (frame, + server_unlink_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->unlink, + loc); + return 0; +} + +/* + * server_unlink - unlink function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_unlink (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *unlink_stub = NULL; + gf_fop_unlink_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + pathlen = STRLEN_0(req->path); + + state->par = ntoh64 (req->par); + state->path = req->path; + if (IS_NOT_ROOT(pathlen)) + state->bname = req->bname + pathlen; + + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + + unlink_stub = fop_unlink_stub (frame, + server_unlink_resume, + &(state->loc)); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (unlink_stub, &state->loc); + } else { + call_resume (unlink_stub); + } + + return 0; +} + + + + + +int32_t +server_setxattr_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + dict_t *dict, + int32_t flags) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": SETXATTR \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_setxattr_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->setxattr, + loc, + dict, + flags); + return 0; +} + +/* + * server_setxattr - setxattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_setxattr (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *setxattr_stub = NULL; + gf_fop_setxattr_req_t *req = NULL; + dict_t *dict = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + size_t dict_len = 0; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + dict_len = ntoh32 (req->dict_len); + + state->path = req->path + dict_len; + + pathlen = STRLEN_0(state->path); + state->ino = ntoh64 (req->ino); + + state->flags = ntoh32 (req->flags); + } + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict, dict_len); + GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + + dict = dict_new (); + GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->ino); + free (req_dictbuf); + goto fail; + } else{ + dict->extra_free = req_dictbuf; + } + } + + setxattr_stub = fop_setxattr_stub (frame, + server_setxattr_resume, + &(state->loc), + dict, + state->flags); + GF_VALIDATE_OR_GOTO(bound_xl->name, setxattr_stub, fail); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (setxattr_stub, &(state->loc)); + } else { + call_resume (setxattr_stub); + } + + if (dict) + dict_unref (dict); + + return 0; +fail: + if (dict) + dict_unref (dict); + + server_setxattr_cbk (frame, NULL, frame->this, + -1, ENOENT); + return 0; + +} + + + +int32_t +server_fxattrop (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_connection_t *conn = NULL; + gf_fop_fxattrop_req_t *req = NULL; + dict_t *dict = NULL; + server_state_t *state = NULL; + size_t dict_len = 0; + char *req_dictbuf = NULL; + int32_t ret = -1; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + dict_len = ntoh32 (req->dict_len); + state->ino = ntoh64 (req->ino); + state->flags = ntoh32 (req->flags); + } + + if (dict_len) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict, dict_len); + GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + + dict = dict_new (); + GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->fd_no, state->fd->inode->ino); + free (req_dictbuf); + goto fail; + } else { + dict->extra_free = req_dictbuf; + } + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FXATTROP \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_fxattrop_cbk, + bound_xl, + bound_xl->fops->fxattrop, + state->fd, + state->flags, + dict); + if (dict) + dict_unref (dict); + return 0; +fail: + if (dict) + dict_unref (dict); + + server_fxattrop_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + return 0; +} + +int32_t +server_xattrop_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + gf_xattrop_flags_t flags, + dict_t *dict) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": XATTROP \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_xattrop_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->xattrop, + loc, + flags, + dict); + return 0; +} + +int32_t +server_xattrop (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_xattrop_req_t *req = NULL; + dict_t *dict = NULL; + server_state_t *state = NULL; + call_stub_t *xattrop_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0; + size_t dict_len = 0; + char *req_dictbuf = NULL; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + dict_len = ntoh32 (req->dict_len); + state->ino = ntoh64 (req->ino); + state->path = req->path + dict_len; + pathlen = STRLEN_0(state->path); + state->flags = ntoh32 (req->flags); + } + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + if (dict_len) { + /* Unserialize the dictionary */ + req_dictbuf = memdup (req->dict, dict_len); + GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + + dict = dict_new (); + GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + + ret = dict_unserialize (req_dictbuf, dict_len, &dict); + if (ret < 0) { + gf_log (bound_xl->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->loc.path, state->ino); + goto fail; + } else { + dict->extra_free = req_dictbuf; + } + } + xattrop_stub = fop_xattrop_stub (frame, + server_xattrop_resume, + &(state->loc), + state->flags, + dict); + GF_VALIDATE_OR_GOTO(bound_xl->name, xattrop_stub, fail); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (xattrop_stub, &(state->loc)); + } else { + call_resume (xattrop_stub); + } + + if (dict) + dict_unref (dict); + return 0; +fail: + if (dict) + dict_unref (dict); + + server_xattrop_cbk (frame, NULL, frame->this, + -1, EINVAL, + NULL); + return 0; +} + + +int32_t +server_getxattr_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": GETXATTR \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_getxattr_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->getxattr, + loc, + name); + return 0; +} + +/* + * server_getxattr - getxattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_getxattr (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_getxattr_req_t *req = NULL; + call_stub_t *getxattr_stub = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t namelen = 0; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + + state->path = req->path; + state->ino = ntoh64 (req->ino); + + namelen = ntoh32 (req->namelen); + if (namelen) + state->name = (req->name + pathlen); + } + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + getxattr_stub = fop_getxattr_stub (frame, + server_getxattr_resume, + &(state->loc), + state->name); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (getxattr_stub, &(state->loc)); + } else { + call_resume (getxattr_stub); + } + + return 0; +} + + + +int32_t +server_removexattr_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + const char *name) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": REMOVEXATTR \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_removexattr_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->removexattr, + loc, + name); + return 0; +} + +/* + * server_removexattr - removexattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_removexattr (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_removexattr_req_t *req = NULL; + call_stub_t *removexattr_stub = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + + state->path = req->path; + state->ino = ntoh64 (req->ino); + + state->name = (req->name + pathlen); + } + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + removexattr_stub = fop_removexattr_stub (frame, + server_removexattr_resume, + &(state->loc), + state->name); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (removexattr_stub, &(state->loc)); + } else { + call_resume (removexattr_stub); + } + + return 0; +} + + +/* + * server_statfs - statfs function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_statfs (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_statfs_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + + req = gf_param (hdr); + + state = CALL_STATE(frame); + state->ino = ntoh64 (req->ino); + state->path = req->path; + + ret = server_loc_fill (&state->loc, state, + state->ino, 0, NULL, state->path); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": STATFS \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_statfs_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->statfs, + &(state->loc)); + + return 0; +} + + + +int32_t +server_opendir_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + fd_t *fd) +{ + server_state_t *state = CALL_STATE(frame); + fd_t *new_fd = NULL; + + new_fd = fd_create (loc->inode, frame->root->pid); + state->fd = fd_ref (new_fd); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": OPENDIR \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_opendir_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->opendir, + loc, + state->fd); + return 0; +} + + +/* + * server_opendir - opendir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_opendir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *opendir_stub = NULL; + gf_fop_opendir_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->path = req->path; + pathlen = STRLEN_0(state->path); + state->ino = ntoh64 (req->ino); + } + + ret = server_loc_fill (&state->loc, state, + state->ino, 0, NULL, state->path); + + opendir_stub = fop_opendir_stub (frame, + server_opendir_resume, + &(state->loc), + NULL); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (opendir_stub, &(state->loc)); + } else { + call_resume (opendir_stub); + } + + return 0; +} + + +/* + * server_releasedir - releasedir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_releasedir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_cbk_releasedir_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->fd_no = ntoh64 (req->fd); + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_releasedir_cbk (frame, NULL, frame->this, + -1, EINVAL); + goto out; + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": RELEASEDIR \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + gf_fd_put (conn->fdtable, state->fd_no); + + server_releasedir_cbk (frame, NULL, frame->this, + 0, 0); +out: + return 0; +} + + +/* + * server_readdir - readdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_getdents (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_getdents_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + state->flags = ntoh32 (req->flags); + } + + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_getdents_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL, 0); + + goto out; + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": GETDENTS \'fd=%"PRId64" (%"PRId64"); " + "offset=%"PRId64"; size=%"PRId64, + frame->root->unique, state->fd_no, state->fd->inode->ino, + state->offset, (int64_t)state->size); + + STACK_WIND (frame, + server_getdents_cbk, + bound_xl, + bound_xl->fops->getdents, + state->fd, + state->size, + state->offset, + state->flags); +out: + return 0; +} + + +/* + * server_readdir - readdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_readdir (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_readdir_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->size = ntoh32 (req->size); + state->offset = ntoh64 (req->offset); + } + + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_readdir_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + + goto out; + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": READDIR \'fd=%"PRId64" (%"PRId64"); " + "offset=%"PRId64"; size=%"PRId64, + frame->root->unique, state->fd_no, state->fd->inode->ino, + state->offset, (int64_t)state->size); + + STACK_WIND (frame, + server_readdir_cbk, + bound_xl, + bound_xl->fops->readdir, + state->fd, state->size, state->offset); +out: + return 0; +} + + + +/* + * server_fsyncdir - fsyncdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_fsyncdir (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_fsyncdir_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->flags = ntoh32 (req->data); + } + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_fsyncdir_cbk (frame, NULL, frame->this, + -1, EINVAL); + goto out; + } + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": FSYNCDIR \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, + server_fsyncdir_cbk, + bound_xl, + bound_xl->fops->fsyncdir, + state->fd, state->flags); +out: + return 0; +} + + +int32_t +server_mknod_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode, + dev_t dev) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + state->loc.inode = inode_new (state->itable); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": MKNOD \'%"PRId64"/%s\'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_mknod_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->mknod, + &(state->loc), mode, dev); + + return 0; +} +/* + * server_mknod - mknod function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_mknod (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_mknod_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *mknod_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + + state->par = ntoh64 (req->par); + state->path = req->path; + if (IS_NOT_ROOT(pathlen)) + state->bname = req->bname + pathlen; + + state->mode = ntoh32 (req->mode); + state->dev = ntoh64 (req->dev); + } + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + + mknod_stub = fop_mknod_stub (frame, server_mknod_resume, + &(state->loc), state->mode, state->dev); + + if (state->loc.parent == NULL) { + do_path_lookup (mknod_stub, &(state->loc)); + } else { + call_resume (mknod_stub); + } + + return 0; +} + +int32_t +server_mkdir_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) + +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + state->loc.inode = inode_new (state->itable); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": MKDIR \'%"PRId64"/%s\'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_mkdir_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->mkdir, + &(state->loc), + state->mode); + + return 0; +} + +/* + * server_mkdir - mkdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_mkdir (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_mkdir_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *mkdir_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + state->mode = ntoh32 (req->mode); + + state->path = req->path; + state->bname = req->bname + pathlen; + state->par = ntoh64 (req->par); + } + + + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + + mkdir_stub = fop_mkdir_stub (frame, server_mkdir_resume, + &(state->loc), state->mode); + + if (state->loc.parent == NULL) { + do_path_lookup (mkdir_stub, &(state->loc)); + } else { + call_resume (mkdir_stub); + } + + return 0; +} + + +int32_t +server_rmdir_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + if (state->loc.inode == NULL) + state->loc.inode = inode_ref (loc->inode); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": RMDIR \'%"PRId64"/%s\'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_rmdir_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->rmdir, + loc); + return 0; +} + +/* + * server_rmdir - rmdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_rmdir (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *rmdir_stub = NULL; + gf_fop_rmdir_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + state->path = req->path; + state->par = ntoh64 (req->par); + state->bname = req->bname + pathlen; + } + + + ret = server_loc_fill (&(state->loc), state, + state->ino, state->par, state->bname, + state->path); + + rmdir_stub = fop_rmdir_stub (frame, + server_rmdir_resume, + &(state->loc)); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (rmdir_stub, &(state->loc)); + } else { + call_resume (rmdir_stub); + } + + return 0; +} + + + +int32_t +server_chown_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + uid_t uid, + gid_t gid) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": CHOWN \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, server_chown_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->chown, + loc, uid, gid); + return 0; +} + + +/* + * server_chown - chown function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_chown (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *chown_stub = NULL; + gf_fop_chown_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + state->uid = ntoh32 (req->uid); + state->gid = ntoh32 (req->gid); + } + + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + chown_stub = fop_chown_stub (frame, + server_chown_resume, + &(state->loc), + state->uid, + state->gid); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (chown_stub, &(state->loc)); + } else { + call_resume (chown_stub); + } + + return 0; +} + + +int32_t +server_chmod_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": CHMOD \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_chmod_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->chmod, + loc, + mode); + return 0; + +} + +/* + * server_chmod - chmod function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_chmod (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *chmod_stub = NULL; + gf_fop_chmod_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + + state->mode = ntoh32 (req->mode); + } + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + chmod_stub = fop_chmod_stub (frame, + server_chmod_resume, + &(state->loc), + state->mode); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (chmod_stub, &(state->loc)); + } else { + call_resume (chmod_stub); + } + + return 0; +} + + +int32_t +server_utimens_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + struct timespec *tv) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": UTIMENS \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_utimens_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->utimens, + loc, + tv); + return 0; +} + +/* + * server_utimens - utimens function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_utimens (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *utimens_stub = NULL; + gf_fop_utimens_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + + gf_timespec_to_timespec (req->tv, state->tv); + } + + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + utimens_stub = fop_utimens_stub (frame, + server_utimens_resume, + &(state->loc), + state->tv); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (utimens_stub, &(state->loc)); + } else { + call_resume (utimens_stub); + } + + return 0; +} + + + +int32_t +server_inodelk_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, int32_t cmd, + struct flock *flock) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + if (state->loc.inode == NULL) { + state->loc.inode = inode_ref (loc->inode); + } + + if (state->loc.parent == NULL) { + state->loc.parent = inode_ref (loc->parent); + } + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": INODELK \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_inodelk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->inodelk, + loc, cmd, flock); + return 0; + +} + + +int32_t +server_inodelk (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *inodelk_stub = NULL; + gf_fop_inodelk_req_t *req = NULL; + server_state_t *state = NULL; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->cmd = ntoh32 (req->cmd); + switch (state->cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + state->type = ntoh32 (req->type); + + pathlen = STRLEN_0(req->path); + + state->path = req->path; + state->ino = ntoh64 (req->ino); + + gf_flock_to_flock (&req->flock, &state->flock); + + switch (state->type) { + case GF_LK_F_RDLCK: + state->flock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + state->flock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + state->flock.l_type = F_UNLCK; + break; + } + + } + + server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + inodelk_stub = fop_inodelk_stub (frame, + server_inodelk_resume, + &state->loc, state->cmd, &state->flock); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (inodelk_stub, &(state->loc)); + } else { + call_resume (inodelk_stub); + } + + return 0; +} + + +int32_t +server_finodelk (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_finodelk_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->cmd = ntoh32 (req->cmd); + switch (state->cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + state->type = ntoh32 (req->type); + + gf_flock_to_flock (&req->flock, &state->flock); + + switch (state->type) { + case GF_LK_F_RDLCK: + state->flock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + state->flock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + state->flock.l_type = F_UNLCK; + break; + } + + } + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_finodelk_cbk (frame, NULL, frame->this, + -1, EINVAL); + return -1; + } + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": FINODELK \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, server_finodelk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->finodelk, + state->fd, state->cmd, &state->flock); + return 0; +} + + +int32_t +server_entrylk_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, const char *name, + entrylk_cmd cmd, entrylk_type type) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.inode == NULL) + state->loc.inode = inode_ref (loc->inode); + + if ((state->loc.parent == NULL) && + (loc->parent)) + state->loc.parent = inode_ref (loc->parent); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": ENTRYLK \'%s (%"PRId64") \'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_entrylk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->entrylk, + loc, name, cmd, type); + return 0; + +} + +/* + * server_entrylk - entrylk function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_entrylk (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_entrylk_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *entrylk_stub = NULL; + size_t pathlen = 0; + size_t namelen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + + state->path = req->path; + state->ino = ntoh64 (req->ino); + namelen = ntoh64 (req->namelen); + if (namelen) + state->name = req->name + pathlen; + + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + } + + + server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + entrylk_stub = fop_entrylk_stub (frame, + server_entrylk_resume, + &state->loc, state->name, state->cmd, + state->type); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (entrylk_stub, &(state->loc)); + } else { + call_resume (entrylk_stub); + } + + return 0; +} + + +int32_t +server_fentrylk (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_fentrylk_req_t *req = NULL; + server_state_t *state = NULL; + size_t namelen = 0; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + namelen = ntoh64 (req->namelen); + + if (namelen) + state->name = req->name; + } + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_fentrylk_cbk (frame, NULL, frame->this, + -1, EINVAL); + return -1; + } + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": FENTRYLK \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, server_fentrylk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->fentrylk, + state->fd, state->name, state->cmd, state->type); + return 0; +} + + +int32_t +server_access_resume (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t mask) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": ACCESS \'%s (%"PRId64")\'", + frame->root->unique, state->path, state->ino); + + STACK_WIND (frame, + server_access_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->access, + loc, + mask); + return 0; +} + +/* + * server_access - access function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_access (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + call_stub_t *access_stub = NULL; + gf_fop_access_req_t *req = NULL; + server_state_t *state = NULL; + int32_t ret = -1; + size_t pathlen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->mask = ntoh32 (req->mask); + + state->ino = ntoh64 (req->ino); + state->path = req->path; + pathlen = STRLEN_0(state->path); + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, state->path); + + access_stub = fop_access_stub (frame, + server_access_resume, + &(state->loc), + state->mask); + + if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || + (state->loc.inode == NULL)) { + do_path_lookup (access_stub, &(state->loc)); + } else { + call_resume (access_stub); + } + + return 0; +} + + +int32_t +server_symlink_resume (call_frame_t *frame, + xlator_t *this, + const char *linkname, + loc_t *loc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (loc->parent); + + state->loc.inode = inode_new (BOUND_XL(frame)->itable); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": SYMLINK \'%"PRId64"/%s \'", + frame->root->unique, state->par, state->bname); + + STACK_WIND (frame, + server_symlink_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->symlink, + linkname, + &(state->loc)); + + return 0; +} + +/* + * server_symlink- symlink function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_symlink (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_state_t *state = NULL; + gf_fop_symlink_req_t *req = NULL; + call_stub_t *symlink_stub = NULL; + int32_t ret = -1; + size_t pathlen = 0; + size_t baselen = 0; + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + pathlen = STRLEN_0(req->path); + baselen = STRLEN_0(req->bname + pathlen); + + state->par = ntoh64 (req->par); + state->path = req->path; + state->bname = req->bname + pathlen; + + state->name = (req->linkname + pathlen + baselen); + } + + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + + symlink_stub = fop_symlink_stub (frame, server_symlink_resume, + state->name, &(state->loc)); + + if (state->loc.parent == NULL) { + do_path_lookup (symlink_stub, &(state->loc)); + } else { + call_resume (symlink_stub); + } + + return 0; +} + +int32_t +server_link_resume (call_frame_t *frame, + xlator_t *this, + loc_t *oldloc, + loc_t *newloc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (oldloc->parent); + + if (state->loc.inode == NULL) { + state->loc.inode = inode_ref (oldloc->inode); + } else if (state->loc.inode != oldloc->inode) { + if (state->loc.inode) + inode_unref (state->loc.inode); + state->loc.inode = inode_ref (oldloc->inode); + } + + if (state->loc2.parent == NULL) + state->loc2.parent = inode_ref (newloc->parent); + + state->loc2.inode = inode_ref (state->loc.inode); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": LINK \'%"PRId64"/%s ==> %s (%"PRId64")\'", + frame->root->unique, state->par2, state->bname2, + state->path, state->ino); + + STACK_WIND (frame, + server_link_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->link, + &(state->loc), + &(state->loc2)); + return 0; +} + +/* + * server_link - link function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_link (call_frame_t *frame, + xlator_t *this, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_link_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *link_stub = NULL; + int32_t ret = -1; + size_t oldpathlen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + oldpathlen = STRLEN_0(req->oldpath); + newpathlen = STRLEN_0(req->newpath + oldpathlen); + newbaselen = STRLEN_0(req->newbname + oldpathlen + newpathlen); + + state->path = req->oldpath; + state->path2 = req->newpath + oldpathlen; + state->bname2 = req->newbname + oldpathlen + newpathlen; + state->ino = ntoh64 (req->oldino); + state->par2 = ntoh64 (req->newpar); + } + + ret = server_loc_fill (&(state->loc), state, + state->ino, 0, NULL, + state->path); + ret = server_loc_fill (&(state->loc2), state, + 0, state->par2, state->bname2, + state->path2); + + link_stub = fop_link_stub (frame, server_link_resume, + &(state->loc), &(state->loc2)); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)) { + do_path_lookup (link_stub, &(state->loc)); + } else if (state->loc2.parent == NULL) { + do_path_lookup (link_stub, &(state->loc2)); + } else { + call_resume (link_stub); + } + + return 0; +} + + +int32_t +server_rename_resume (call_frame_t *frame, + xlator_t *this, + loc_t *oldloc, + loc_t *newloc) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state->loc.parent == NULL) + state->loc.parent = inode_ref (oldloc->parent); + + if (state->loc.inode == NULL) { + state->loc.inode = inode_ref (oldloc->inode); + } + + if (state->loc2.parent == NULL) + state->loc2.parent = inode_ref (newloc->parent); + + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": RENAME %s (%"PRId64"/%s) ==> %s (%"PRId64"/%s)", + frame->root->unique, state->path, state->par, state->bname, + state->path2, state->par2, state->bname2); + + STACK_WIND (frame, + server_rename_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->rename, + &(state->loc), + &(state->loc2)); + return 0; +} + +/* + * server_rename - rename function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_rename (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_fop_rename_req_t *req = NULL; + server_state_t *state = NULL; + call_stub_t *rename_stub = NULL; + int32_t ret = -1; + size_t oldpathlen = 0; + size_t oldbaselen = 0; + size_t newpathlen = 0; + size_t newbaselen = 0; + + req = gf_param (hdr); + + state = CALL_STATE(frame); + { + oldpathlen = STRLEN_0(req->oldpath); + oldbaselen = STRLEN_0(req->oldbname + oldpathlen); + newpathlen = STRLEN_0(req->newpath + oldpathlen + oldbaselen); + newbaselen = STRLEN_0(req->newbname + oldpathlen + + oldbaselen + newpathlen); + + state->path = req->oldpath; + state->bname = req->oldbname + oldpathlen; + state->path2 = req->newpath + oldpathlen + oldbaselen; + state->bname2 = (req->newbname + oldpathlen + oldbaselen + + newpathlen); + + state->par = ntoh64 (req->oldpar); + state->par2 = ntoh64 (req->newpar); + } + + ret = server_loc_fill (&(state->loc), state, + 0, state->par, state->bname, + state->path); + ret = server_loc_fill (&(state->loc2), state, + 0, state->par2, state->bname2, + state->path2); + + rename_stub = fop_rename_stub (frame, + server_rename_resume, + &(state->loc), + &(state->loc2)); + + if ((state->loc.parent == NULL) || + (state->loc.inode == NULL)){ + do_path_lookup (rename_stub, &(state->loc)); + } else if ((state->loc2.parent == NULL)){ + do_path_lookup (rename_stub, &(state->loc2)); + } else { + /* we have found inode for both oldpath and newpath in + * inode cache. lets continue with fops->rename() */ + call_resume (rename_stub); + } + + return 0; +} + + +/* + * server_lk - lk function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_lk (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + struct flock lock = {0, }; + gf_fop_lk_req_t *req = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + { + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->cmd = ntoh32 (req->cmd); + state->type = ntoh32 (req->type); + } + + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_lk_cbk (frame, NULL, frame->this, + -1, EINVAL, NULL); + + goto out; + } + + switch (state->cmd) { + case GF_LK_GETLK: + state->cmd = F_GETLK; + break; + case GF_LK_SETLK: + state->cmd = F_SETLK; + break; + case GF_LK_SETLKW: + state->cmd = F_SETLKW; + break; + } + + switch (state->type) { + case GF_LK_F_RDLCK: + lock.l_type = F_RDLCK; + break; + case GF_LK_F_WRLCK: + lock.l_type = F_WRLCK; + break; + case GF_LK_F_UNLCK: + lock.l_type = F_UNLCK; + break; + default: + gf_log (bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): Unknown lock type: %"PRId32"!", + state->fd_no, state->fd->inode->ino, state->type); + break; + } + + gf_flock_to_flock (&req->flock, &lock); + + gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, + "%"PRId64": LK \'fd=%"PRId64" (%"PRId64")\'", + frame->root->unique, state->fd_no, state->fd->inode->ino); + + STACK_WIND (frame, server_lk_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->lk, + state->fd, state->cmd, &lock); + +out: + return 0; +} + + +/* + * server_writedir - + * + * @frame: + * @bound_xl: + * @params: + * + */ +int32_t +server_setdents (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + server_connection_t *conn = NULL; + gf_fop_setdents_req_t *req = NULL; + server_state_t *state = NULL; + dir_entry_t *entry = NULL; + dir_entry_t *trav = NULL; + dir_entry_t *prev = NULL; + int32_t count = 0; + int32_t i = 0; + int32_t bread = 0; + char *ender = NULL; + char *buffer_ptr = NULL; + char tmp_buf[512] = {0,}; + + conn = SERVER_CONNECTION(frame); + + req = gf_param (hdr); + state = CALL_STATE(frame); + + state->fd_no = ntoh64 (req->fd); + if (state->fd_no >= 0) + state->fd = gf_fd_fdptr_get (conn->fdtable, + state->fd_no); + + state->nr_count = ntoh32 (req->count); + + if (state->fd == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64": unresolved fd", + state->fd_no); + + server_setdents_cbk (frame, NULL, frame->this, + -1, EINVAL); + + goto out; + } + + if (buf == NULL) { + gf_log (frame->this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): received a null buffer, " + "returning EINVAL", + state->fd_no, state->fd->inode->ino); + + server_setdents_cbk (frame, NULL, frame->this, + -1, EINVAL); + + goto out; + } + + entry = CALLOC (1, sizeof (dir_entry_t)); + ERR_ABORT (entry); + prev = entry; + buffer_ptr = buf; + + for (i = 0; i < state->nr_count ; i++) { + bread = 0; + trav = CALLOC (1, sizeof (dir_entry_t)); + ERR_ABORT (trav); + + ender = strchr (buffer_ptr, '/'); + if (!ender) + break; + count = ender - buffer_ptr; + trav->name = CALLOC (1, count + 2); + ERR_ABORT (trav->name); + + strncpy (trav->name, buffer_ptr, count); + bread = count + 1; + buffer_ptr += bread; + + ender = strchr (buffer_ptr, '\n'); + if (!ender) + break; + count = ender - buffer_ptr; + strncpy (tmp_buf, buffer_ptr, count); + bread = count + 1; + buffer_ptr += bread; + + /* TODO: use str_to_stat instead */ + { + uint64_t dev; + uint64_t ino; + uint32_t mode; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint64_t rdev; + uint64_t size; + uint32_t blksize; + uint64_t blocks; + uint32_t atime; + uint32_t atime_nsec; + uint32_t mtime; + uint32_t mtime_nsec; + uint32_t ctime; + uint32_t ctime_nsec; + + sscanf (tmp_buf, GF_STAT_PRINT_FMT_STR, + &dev, + &ino, + &mode, + &nlink, + &uid, + &gid, + &rdev, + &size, + &blksize, + &blocks, + &atime, + &atime_nsec, + &mtime, + &mtime_nsec, + &ctime, + &ctime_nsec); + + trav->buf.st_dev = dev; + trav->buf.st_ino = ino; + trav->buf.st_mode = mode; + trav->buf.st_nlink = nlink; + trav->buf.st_uid = uid; + trav->buf.st_gid = gid; + trav->buf.st_rdev = rdev; + trav->buf.st_size = size; + trav->buf.st_blksize = blksize; + trav->buf.st_blocks = blocks; + + trav->buf.st_atime = atime; + trav->buf.st_mtime = mtime; + trav->buf.st_ctime = ctime; + + ST_ATIM_NSEC_SET(&trav->buf, atime_nsec); + ST_MTIM_NSEC_SET(&trav->buf, mtime_nsec); + ST_CTIM_NSEC_SET(&trav->buf, ctime_nsec); + + } + + ender = strchr (buffer_ptr, '\n'); + if (!ender) + break; + count = ender - buffer_ptr; + *ender = '\0'; + if (S_ISLNK (trav->buf.st_mode)) { + trav->link = strdup (buffer_ptr); + } else + trav->link = ""; + bread = count + 1; + buffer_ptr += bread; + + prev->next = trav; + prev = trav; + } + + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": SETDENTS \'fd=%"PRId64" (%"PRId64"); count=%"PRId64, + frame->root->unique, state->fd_no, state->fd->inode->ino, + (int64_t)state->nr_count); + + STACK_WIND (frame, + server_setdents_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->setdents, + state->fd, + state->flags, + entry, + state->nr_count); + + + /* Free the variables allocated in this fop here */ + trav = entry->next; + prev = entry; + while (trav) { + prev->next = trav->next; + FREE (trav->name); + if (S_ISLNK (trav->buf.st_mode)) + FREE (trav->link); + FREE (trav); + trav = prev->next; + } + FREE (entry); + +out: + return 0; +} + + + +/* xxx_MOPS */ + +/* Management Calls */ +/* + * mop_getspec - getspec function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + */ +int32_t +mop_getspec (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_hdr_common_t *_hdr = NULL; + gf_mop_getspec_rsp_t *rsp = NULL; + int32_t ret = -1; + int32_t op_errno = ENOENT; + int32_t gf_errno = 0; + int32_t spec_fd = -1; + size_t file_len = 0; + size_t _hdrlen = 0; + char tmp_filename[ZR_FILENAME_MAX] = {0,}; + char data_key[256] = {0,}; + char *filename = NULL; + struct stat stbuf = {0,}; + peer_info_t *peerinfo = NULL; + transport_t *trans = NULL; + + gf_mop_getspec_req_t *req = NULL; + uint32_t flags = 0; + uint32_t keylen = 0; + char *key = NULL; + + req = gf_param (hdr); + flags = ntoh32 (req->flags); + keylen = ntoh32 (req->keylen); + if (keylen) { + key = req->key; + } + + trans = TRANSPORT_FROM_FRAME(frame); + + peerinfo = &(trans->peerinfo); + /* Inform users that this option is changed now */ + ret = dict_get_str (frame->this->options, "client-volume-filename", + &filename); + if (ret == 0) { + gf_log (trans->xl->name, GF_LOG_WARNING, + "option 'client-volume-specfile' is changed to " + "'volume-filename.<key>' which now takes 'key' as an " + "option to choose/fetch different files from server. " + "Refer documentation or contact developers for more " + "info. Currently defaulting to given file '%s'", + filename); + } + + if (key && !filename) { + sprintf (data_key, "volume-filename.%s", key); + ret = dict_get_str (frame->this->options, data_key, &filename); + if (ret < 0) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to get corresponding volume file " + "for the key '%s'. using default file %s", + key, GLUSTERFSD_SPEC_PATH); + } + } + if (!filename) { + filename = GLUSTERFSD_SPEC_PATH; + if (!key) + gf_log (trans->xl->name, GF_LOG_WARNING, + "using default volume file %s", + GLUSTERFSD_SPEC_PATH); + } + + { + sprintf (tmp_filename, "%s.%s", + filename, peerinfo->identifier); + + /* Try for ip specific client volfile. + * If not found, then go for, regular client file. + */ + ret = open (tmp_filename, O_RDONLY); + spec_fd = ret; + if (spec_fd < 0) { + gf_log (trans->xl->name, GF_LOG_DEBUG, + "Unable to open %s (%s)", + tmp_filename, strerror (errno)); + /* fall back */ + ret = open (filename, O_RDONLY); + spec_fd = ret; + if (spec_fd < 0) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "Unable to open %s (%s)", + filename, strerror (errno)); + goto fail; + } + } else { + /* Successful */ + filename = tmp_filename; + } + } + + /* to allocate the proper buffer to hold the file data */ + { + ret = stat (filename, &stbuf); + if (ret < 0){ + gf_log (trans->xl->name, GF_LOG_ERROR, + "Unable to stat %s (%s)", + filename, strerror (errno)); + goto fail; + } + + file_len = stbuf.st_size; + } + +fail: + op_errno = errno; + + _hdrlen = gf_hdr_len (rsp, file_len + 1); + _hdr = gf_hdr_new (rsp, file_len + 1); + rsp = gf_param (_hdr); + + _hdr->rsp.op_ret = hton32 (ret); + gf_errno = gf_errno_to_error (op_errno); + _hdr->rsp.op_errno = hton32 (gf_errno); + + if (file_len) { + read (spec_fd, rsp->spec, file_len); + close (spec_fd); + } + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_GETSPEC, + _hdr, _hdrlen, NULL, 0, NULL); + + return 0; +} + +int32_t +server_checksum_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + uint8_t *fchecksum, + uint8_t *dchecksum) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_checksum_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + + hdrlen = gf_hdr_len (rsp, ZR_FILENAME_MAX + 1 + ZR_FILENAME_MAX + 1); + hdr = gf_hdr_new (rsp, ZR_FILENAME_MAX + 1 + ZR_FILENAME_MAX + 1); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + if (op_ret >= 0) { + memcpy (rsp->fchecksum, fchecksum, ZR_FILENAME_MAX); + rsp->fchecksum[ZR_FILENAME_MAX] = '\0'; + memcpy (rsp->dchecksum + ZR_FILENAME_MAX, + dchecksum, ZR_FILENAME_MAX); + rsp->dchecksum[ZR_FILENAME_MAX + ZR_FILENAME_MAX] = '\0'; + } + + protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +int32_t +server_checksum (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + loc_t loc = {0,}; + int32_t flag = 0; + gf_fop_checksum_req_t *req = NULL; + + req = gf_param (hdr); + + loc.path = req->path; + loc.ino = ntoh64 (req->ino); + loc.inode = NULL; + flag = ntoh32 (req->flag); + + gf_log (bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": CHECKSUM \'%s (%"PRId64")\'", + frame->root->unique, loc.path, loc.ino); + + STACK_WIND (frame, + server_checksum_cbk, + BOUND_XL(frame), + BOUND_XL(frame)->fops->checksum, + &loc, + flag); + + return 0; +} + + +/* + * mop_unlock - unlock management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int32_t +mop_getvolume (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + return 0; +} + +struct __get_xl_struct { + const char *name; + xlator_t *reply; +}; + +void __check_and_set (xlator_t *each, + void *data) +{ + if (!strcmp (each->name, + ((struct __get_xl_struct *) data)->name)) + ((struct __get_xl_struct *) data)->reply = each; +} + +static xlator_t * +get_xlator_by_name (xlator_t *some_xl, + const char *name) +{ + struct __get_xl_struct get = { + .name = name, + .reply = NULL + }; + + xlator_foreach (some_xl, __check_and_set, &get); + + return get.reply; +} + + +/* + * mop_setvolume - setvolume management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int +mop_setvolume (call_frame_t *frame, xlator_t *bound_xl, + gf_hdr_common_t *req_hdr, size_t req_hdrlen, + char *req_buf, size_t req_buflen) +{ + server_connection_t *conn = NULL; + server_conf_t *conf = NULL; + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_setvolume_req_t *req = NULL; + gf_mop_setvolume_rsp_t *rsp = NULL; + peer_info_t *peerinfo = NULL; + int32_t ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t gf_errno = 0; + dict_t *reply = NULL; + dict_t *config_params = NULL; + dict_t *params = NULL; + char *name = NULL; + char *version = NULL; + char *process_uuid = NULL; + xlator_t *xl = NULL; + transport_t *trans = NULL; + size_t rsp_hdrlen = -1; + size_t dict_len = -1; + size_t req_dictlen = -1; + + params = dict_new (); + reply = dict_new (); + + req = gf_param (req_hdr); + req_dictlen = ntoh32 (req->dict_len); + ret = dict_unserialize (req->buf, req_dictlen, ¶ms); + + config_params = dict_copy_with_ref (frame->this->options, NULL); + trans = TRANSPORT_FROM_FRAME(frame); + conf = SERVER_CONF(frame); + + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "Internal error: failed to unserialize " + "request dictionary"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_ERROR, + "failed to set error msg \"%s\"", + "Internal error: failed to unserialize " + "request dictionary"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + ret = dict_get_str (params, "process-uuid", &process_uuid); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "UUID not specified"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + + conn = server_connection_get (frame->this, process_uuid); + if (trans->xl_private != conn) + trans->xl_private = conn; + + ret = dict_get_str (params, "version", &version); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No version number specified"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + ret = strcmp (version, PACKAGE_VERSION); + if (ret != 0) { + char *msg = NULL; + asprintf (&msg, + "Version mismatch: client(%s) Vs server (%s)", + version, PACKAGE_VERSION); + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + + ret = dict_get_str (params, + "remote-subvolume", &name); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No remote-subvolume option specified"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + xl = get_xlator_by_name (frame->this, name); + if (xl == NULL) { + char *msg = NULL; + asprintf (&msg, "remote-subvolume \"%s\" is not found", name); + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = ENOENT; + goto fail; + } + + peerinfo = &trans->peerinfo; + ret = dict_set_static_ptr (params, "peer-info", peerinfo); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set peer-info"); + + if (conf->auth_modules == NULL) { + gf_log (trans->xl->name, GF_LOG_ERROR, + "Authentication module not initialized"); + } + + ret = gf_authenticate (params, config_params, + conf->auth_modules); + if (ret == AUTH_ACCEPT) { + gf_log (trans->xl->name, GF_LOG_INFO, + "accepted client from %s", + peerinfo->identifier); + op_ret = 0; + conn->bound_xl = xl; + ret = dict_set_str (reply, "ERROR", "Success"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + } else { + gf_log (trans->xl->name, GF_LOG_ERROR, + "Cannot authenticate client from %s", + peerinfo->identifier); + op_ret = -1; + op_errno = EACCES; + ret = dict_set_str (reply, "ERROR", "Authentication failed"); + if (ret < 0) + gf_log (bound_xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + goto fail; + } + + if (conn->bound_xl == NULL) { + ret = dict_set_str (reply, "ERROR", + "Check volfile and handshake " + "options in protocol/client"); + if (ret < 0) + gf_log (trans->xl->name, GF_LOG_ERROR, + "failed to set error msg"); + + op_ret = -1; + op_errno = EACCES; + goto fail; + } + + if ((conn->bound_xl != NULL) && + (ret >= 0) && + (conn->bound_xl->itable == NULL)) { + /* create inode table for this bound_xl, if one doesn't + already exist */ + int32_t lru_limit = 1024; + + lru_limit = INODE_LRU_LIMIT (frame->this); + + gf_log (trans->xl->name, GF_LOG_DEBUG, + "creating inode table with lru_limit=%"PRId32", " + "xlator=%s", lru_limit, conn->bound_xl->name); + + conn->bound_xl->itable = + inode_table_new (lru_limit, + conn->bound_xl); + } + + ret = dict_set_str (reply, "process-uuid", + xl->ctx->process_uuid); + +fail: + dict_len = dict_serialized_length (reply); + if (dict_len < 0) { + gf_log (xl->name, GF_LOG_ERROR, + "failed to get serialized length of reply dict"); + op_ret = -1; + op_errno = EINVAL; + dict_len = 0; + } + + rsp_hdr = gf_hdr_new (rsp, dict_len); + rsp_hdrlen = gf_hdr_len (rsp, dict_len); + rsp = gf_param (rsp_hdr); + + if (dict_len) { + ret = dict_serialize (reply, rsp->buf); + if (ret < 0) { + gf_log (xl->name, GF_LOG_ERROR, + "failed to serialize reply dict"); + op_ret = -1; + op_errno = -ret; + } + } + rsp->dict_len = hton32 (dict_len); + + rsp_hdr->rsp.op_ret = hton32 (op_ret); + gf_errno = gf_errno_to_error (op_errno); + rsp_hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_SETVOLUME, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + dict_unref (params); + dict_unref (reply); + dict_unref (config_params); + + return 0; +} + +/* + * server_mop_stats_cbk - stats callback for server management operation + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @stats:err + * + * not for external reference + */ + +int32_t +server_mop_stats_cbk (call_frame_t *frame, + void *cookie, + xlator_t *xl, + int32_t ret, + int32_t op_errno, + struct xlator_stats *stats) +{ + /* TODO: get this information from somewhere else, not extern */ + gf_hdr_common_t *hdr = NULL; + gf_mop_stats_rsp_t *rsp = NULL; + char buffer[256] = {0,}; + int64_t glusterfsd_stats_nr_clients = 0; + size_t hdrlen = 0; + size_t buf_len = 0; + int32_t gf_errno = 0; + + if (ret >= 0) { + sprintf (buffer, + "%"PRIx64",%"PRIx64",%"PRIx64 + ",%"PRIx64",%"PRIx64",%"PRIx64 + ",%"PRIx64",%"PRIx64"\n", + stats->nr_files, + stats->disk_usage, + stats->free_disk, + stats->total_disk_size, + stats->read_usage, + stats->write_usage, + stats->disk_speed, + glusterfsd_stats_nr_clients); + + buf_len = strlen (buffer); + } + + hdrlen = gf_hdr_len (rsp, buf_len + 1); + hdr = gf_hdr_new (rsp, buf_len + 1); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (ret); + gf_errno = gf_errno_to_error (op_errno); + hdr->rsp.op_errno = hton32 (gf_errno); + + strcpy (rsp->buf, buffer); + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_STATS, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + + +/* + * mop_unlock - unlock management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +static int32_t +mop_stats (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + int32_t flag = 0; + gf_mop_stats_req_t *req = NULL; + + req = gf_param (hdr); + + flag = ntoh32 (req->flags); + + STACK_WIND (frame, + server_mop_stats_cbk, + bound_xl, + bound_xl->mops->stats, + flag); + + return 0; +} + +int32_t +mop_ping (call_frame_t *frame, + xlator_t *bound_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen) +{ + gf_hdr_common_t *rsp_hdr = NULL; + gf_mop_ping_rsp_t *rsp = NULL; + size_t rsp_hdrlen = 0; + + rsp_hdrlen = gf_hdr_len (rsp, 0); + rsp_hdr = gf_hdr_new (rsp, 0); + + hdr->rsp.op_ret = 0; + + protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_PING, + rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + + return 0; +} +/* + * unknown_op_cbk - This function is called when a opcode for unknown + * type is called. Helps to keep the backward/forward + * compatiblity + * @frame: call frame + * @type: + * @opcode: + * + */ + +int32_t +unknown_op_cbk (call_frame_t *frame, + int32_t type, + int32_t opcode) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_flush_rsp_t *rsp = NULL; + size_t hdrlen = 0; + int32_t gf_errno = 0; + hdrlen = gf_hdr_len (rsp, 0); + hdr = gf_hdr_new (rsp, 0); + rsp = gf_param (hdr); + + hdr->rsp.op_ret = hton32 (-1); + gf_errno = gf_errno_to_error (ENOSYS); + hdr->rsp.op_errno = hton32 (gf_errno); + + protocol_server_reply (frame, type, opcode, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +} + +/* + * get_frame_for_transport - get call frame for specified transport object + * + * @trans: transport object + * + */ +static call_frame_t * +get_frame_for_transport (transport_t *trans) +{ + call_frame_t *frame = NULL; + call_pool_t *pool = NULL; + server_connection_t *conn = NULL; + server_state_t *state = NULL;; + + GF_VALIDATE_OR_GOTO("server", trans, out); + + if (trans->xl && trans->xl->ctx) + pool = trans->xl->ctx->pool; + GF_VALIDATE_OR_GOTO("server", pool, out); + + frame = create_frame (trans->xl, pool); + GF_VALIDATE_OR_GOTO("server", frame, out); + + state = CALLOC (1, sizeof (*state)); + GF_VALIDATE_OR_GOTO("server", state, out); + + conn = trans->xl_private; + if (conn) { + if (conn->bound_xl) + state->itable = conn->bound_xl->itable; + state->bound_xl = conn->bound_xl; + } + + state->trans = transport_ref (trans); + + frame->root->trans = conn; + frame->root->state = state; /* which socket */ + frame->root->unique = 0; /* which call */ + +out: + return frame; +} + +/* + * get_frame_for_call - create a frame into the capable of + * generating and replying the reply packet by itself. + * By making a call with this frame, the last UNWIND + * function will have all needed state from its + * frame_t->root to send reply. + * @trans: + * @blk: + * @params: + * + * not for external reference + */ +static call_frame_t * +get_frame_for_call (transport_t *trans, gf_hdr_common_t *hdr) +{ + call_frame_t *frame = NULL; + + frame = get_frame_for_transport (trans); + + frame->root->op = ntoh32 (hdr->op); + frame->root->type = ntoh32 (hdr->type); + + frame->root->uid = ntoh32 (hdr->req.uid); + frame->root->unique = ntoh64 (hdr->callid); /* which call */ + frame->root->gid = ntoh32 (hdr->req.gid); + frame->root->pid = ntoh32 (hdr->req.pid); + + return frame; +} + +/* + * prototype of operations function for each of mop and + * fop at server protocol level + * + * @frame: call frame pointer + * @bound_xl: the xlator that this frame is bound to + * @params: parameters dictionary + * + * to be used by protocol interpret, _not_ for exterenal reference + */ +typedef int32_t (*gf_op_t) (call_frame_t *frame, xlator_t *bould_xl, + gf_hdr_common_t *hdr, size_t hdrlen, + char *buf, size_t buflen); + + +static gf_op_t gf_fops[] = { + [GF_FOP_STAT] = server_stat, + [GF_FOP_READLINK] = server_readlink, + [GF_FOP_MKNOD] = server_mknod, + [GF_FOP_MKDIR] = server_mkdir, + [GF_FOP_UNLINK] = server_unlink, + [GF_FOP_RMDIR] = server_rmdir, + [GF_FOP_SYMLINK] = server_symlink, + [GF_FOP_RENAME] = server_rename, + [GF_FOP_LINK] = server_link, + [GF_FOP_CHMOD] = server_chmod, + [GF_FOP_CHOWN] = server_chown, + [GF_FOP_TRUNCATE] = server_truncate, + [GF_FOP_OPEN] = server_open, + [GF_FOP_READ] = server_readv, + [GF_FOP_WRITE] = server_writev, + [GF_FOP_STATFS] = server_statfs, + [GF_FOP_FLUSH] = server_flush, + [GF_FOP_FSYNC] = server_fsync, + [GF_FOP_SETXATTR] = server_setxattr, + [GF_FOP_GETXATTR] = server_getxattr, + [GF_FOP_REMOVEXATTR] = server_removexattr, + [GF_FOP_OPENDIR] = server_opendir, + [GF_FOP_GETDENTS] = server_getdents, + [GF_FOP_FSYNCDIR] = server_fsyncdir, + [GF_FOP_ACCESS] = server_access, + [GF_FOP_CREATE] = server_create, + [GF_FOP_FTRUNCATE] = server_ftruncate, + [GF_FOP_FSTAT] = server_fstat, + [GF_FOP_LK] = server_lk, + [GF_FOP_UTIMENS] = server_utimens, + [GF_FOP_FCHMOD] = server_fchmod, + [GF_FOP_FCHOWN] = server_fchown, + [GF_FOP_LOOKUP] = server_lookup, + [GF_FOP_SETDENTS] = server_setdents, + [GF_FOP_READDIR] = server_readdir, + [GF_FOP_INODELK] = server_inodelk, + [GF_FOP_FINODELK] = server_finodelk, + [GF_FOP_ENTRYLK] = server_entrylk, + [GF_FOP_FENTRYLK] = server_fentrylk, + [GF_FOP_CHECKSUM] = server_checksum, + [GF_FOP_XATTROP] = server_xattrop, + [GF_FOP_FXATTROP] = server_fxattrop, +}; + + + +static gf_op_t gf_mops[] = { + [GF_MOP_SETVOLUME] = mop_setvolume, + [GF_MOP_GETVOLUME] = mop_getvolume, + [GF_MOP_STATS] = mop_stats, + [GF_MOP_GETSPEC] = mop_getspec, + [GF_MOP_PING] = mop_ping, +}; + +static gf_op_t gf_cbks[] = { + [GF_CBK_FORGET] = server_forget, + [GF_CBK_RELEASE] = server_release, + [GF_CBK_RELEASEDIR] = server_releasedir +}; + +int +protocol_server_interpret (xlator_t *this, transport_t *trans, + char *hdr_p, size_t hdrlen, char *buf, + size_t buflen) +{ + server_connection_t *conn = NULL; + gf_hdr_common_t *hdr = NULL; + xlator_t *bound_xl = NULL; + call_frame_t *frame = NULL; + peer_info_t *peerinfo = NULL; + int32_t type = -1; + int32_t op = -1; + int32_t ret = -1; + + hdr = (gf_hdr_common_t *)hdr_p; + type = ntoh32 (hdr->type); + op = ntoh32 (hdr->op); + + conn = trans->xl_private; + if (conn) + bound_xl = conn->bound_xl; + + peerinfo = &trans->peerinfo; + switch (type) { + case GF_OP_TYPE_FOP_REQUEST: + if ((op < 0) || + (op > GF_FOP_MAXVALUE)) { + gf_log (this->name, GF_LOG_ERROR, + "invalid fop %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + if (bound_xl == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Received fop %"PRId32" before " + "authentication.", op); + break; + } + frame = get_frame_for_call (trans, hdr); + ret = gf_fops[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); + break; + + case GF_OP_TYPE_MOP_REQUEST: + if (op < 0 || op > GF_MOP_MAXVALUE) { + gf_log (this->name, GF_LOG_ERROR, + "invalid mop %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + frame = get_frame_for_call (trans, hdr); + ret = gf_mops[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); + break; + + case GF_OP_TYPE_CBK_REQUEST: + if (op < 0 || op > GF_CBK_MAXVALUE) { + gf_log (this->name, GF_LOG_ERROR, + "invalid cbk %"PRId32" from client %s", + op, peerinfo->identifier); + break; + } + if (bound_xl == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Received cbk %d before authentication.", op); + break; + } + + frame = get_frame_for_call (trans, hdr); + ret = gf_cbks[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); + break; + + default: + break; + } + + return ret; +} + + +/* + * server_nop_cbk - nop callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_nop_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + server_state_t *state = NULL; + + state = CALL_STATE(frame); + + if (state) + free_state (state); + STACK_DESTROY (frame->root); + return 0; +} + + +static void +get_auth_types (dict_t *this, + char *key, + data_t *value, + void *data) +{ + dict_t *auth_dict = data; + char *saveptr = NULL, *tmp = NULL; + char *key_cpy = NULL; + int32_t ret = -1; + + key_cpy = strdup (key); + GF_VALIDATE_OR_GOTO("server", key_cpy, out); + + tmp = strtok_r (key_cpy, ".", &saveptr); + ret = strcmp (tmp, "auth"); + if (ret == 0) { + tmp = strtok_r (NULL, ".", &saveptr); + if (strcmp (tmp, "ip") == 0) { + /* TODO: backward compatibility, remove when + newer versions are available */ + tmp = "addr"; + gf_log ("server", GF_LOG_WARNING, + "assuming 'auth.ip' to be 'auth.addr'"); + } + ret = dict_set_dynptr (auth_dict, tmp, NULL, 0); + if (ret < 0) { + gf_log ("server", GF_LOG_ERROR, + "failed to dict_set_dynptr"); + } + } + + FREE (key_cpy); +out: + return; +} + + +static int +validate_auth_options (xlator_t *this, dict_t *dict) +{ + int ret = -1; + int error = 0; + xlator_list_t *trav = NULL; + data_pair_t *pair = NULL; + char *saveptr = NULL, *tmp = NULL; + char *key_cpy = NULL; + + trav = this->children; + while (trav) { + error = -1; + for (pair = dict->members_list; pair; pair = pair->next) { + key_cpy = strdup (pair->key); + tmp = strtok_r (key_cpy, ".", &saveptr); + ret = strcmp (tmp, "auth"); + if (ret == 0) { + /* for module type */ + tmp = strtok_r (NULL, ".", &saveptr); + /* for volume name */ + tmp = strtok_r (NULL, ".", &saveptr); + } + + if (strcmp (tmp, trav->xlator->name) == 0) { + error = 0; + free (key_cpy); + break; + } + free (key_cpy); + } + if (-1 == error) { + gf_log (this->name, GF_LOG_ERROR, + "volume '%s' defined as subvolume, but no " + "authentication defined for the same", + trav->xlator->name); + break; + } + trav = trav->next; + } + + return error; +} + + +/* + * init - called during server protocol initialization + * + * @this: + * + */ +int +init (xlator_t *this) +{ + int32_t ret = -1; + transport_t *trans = NULL; + server_conf_t *conf = NULL; + + if (this->children == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "protocol/server should have subvolume"); + goto out; + } + + trans = transport_load (this->options, this); + if (trans == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "failed to load transport"); + goto out; + } + + ret = transport_listen (trans); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "failed to bind/listen on socket"); + goto out; + } + + conf = CALLOC (1, sizeof (server_conf_t)); + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + INIT_LIST_HEAD (&conf->conns); + pthread_mutex_init (&conf->mutex, NULL); + + conf->trans = trans; + + conf->auth_modules = dict_new (); + GF_VALIDATE_OR_GOTO(this->name, conf->auth_modules, out); + + dict_foreach (this->options, get_auth_types, + conf->auth_modules); + ret = validate_auth_options (this, this->options); + if (ret == -1) { + /* logging already done in validate_auth_options function. */ + goto out; + } + + ret = gf_auth_init (this, conf->auth_modules); + if (ret) { + dict_unref (conf->auth_modules); + goto out; + } + + this->private = conf; + + ret = dict_get_int32 (this->options, "inode-lru-limit", + &conf->inode_lru_limit); + if (ret < 0) { + conf->inode_lru_limit = 1024; + } + + ret = dict_get_int32 (this->options, "limits.transaction-size", + &conf->max_block_size); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "defaulting limits.transaction-size to %d", + DEFAULT_BLOCK_SIZE); + conf->max_block_size = DEFAULT_BLOCK_SIZE; + } + +#ifndef GF_DARWIN_HOST_OS + { + struct rlimit lim; + + lim.rlim_cur = 1048576; + lim.rlim_max = 1048576; + + if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { + gf_log (this->name, GF_LOG_WARNING, + "WARNING: Failed to set 'ulimit -n 1M': %s", + strerror(errno)); + lim.rlim_cur = 65536; + lim.rlim_max = 65536; + + if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set max open fd to 64k: %s", + strerror(errno)); + } else { + gf_log (this->name, GF_LOG_ERROR, + "max open fd set to 64k"); + } + } + } +#endif + this->ctx->top = this; + + ret = 0; +out: + return ret; +} + + + +int +protocol_server_pollin (xlator_t *this, transport_t *trans) +{ + char *hdr = NULL; + size_t hdrlen = 0; + char *buf = NULL; + size_t buflen = 0; + int ret = -1; + + + ret = transport_receive (trans, &hdr, &hdrlen, &buf, &buflen); + + if (ret == 0) + ret = protocol_server_interpret (this, trans, hdr, + hdrlen, buf, buflen); + + /* TODO: use mem-pool */ + FREE (hdr); + + return ret; +} + + +/* + * fini - finish function for server protocol, called before + * unloading server protocol. + * + * @this: + * + */ +void +fini (xlator_t *this) +{ + server_conf_t *conf = this->private; + + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + if (conf->auth_modules) { + dict_unref (conf->auth_modules); + } + + FREE (conf); + this->private = NULL; +out: + return; +} + +/* + * server_protocol_notify - notify function for server protocol + * @this: + * @trans: + * @event: + * + */ +int +notify (xlator_t *this, int32_t event, void *data, ...) +{ + int ret = 0; + transport_t *trans = data; + + switch (event) { + case GF_EVENT_POLLIN: + ret = protocol_server_pollin (this, trans); + break; + case GF_EVENT_POLLERR: + { + peer_info_t *peerinfo = NULL; + + peerinfo = &(trans->peerinfo); + gf_log (trans->xl->name, GF_LOG_INFO, "%s disconnected", + peerinfo->identifier); + + ret = -1; + transport_disconnect (trans); + } + break; + + case GF_EVENT_TRANSPORT_CLEANUP: + { + if (trans->xl_private) + server_connection_put (this, trans->xl_private); + } + break; + + default: + default_notify (this, event, data); + break; + } + + return ret; +} + + +struct xlator_mops mops = { +}; + +struct xlator_fops fops = { +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { + { .key = {"transport-type"}, + .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp", + "tcp/server", "ib-verbs/server"}, + .type = GF_OPTION_TYPE_STR + }, + { .key = {"volume-filename.*"}, + .type = GF_OPTION_TYPE_PATH, + }, + { .key = {"inode-lru-limit"}, + .type = GF_OPTION_TYPE_INT, + .min = 0, + .max = (1 * GF_UNIT_MB) + }, + { .key = {"client-volume-filename"}, + .type = GF_OPTION_TYPE_PATH + }, + { .key = {NULL} }, +}; diff --git a/xlators/protocol/server/src/server-protocol.h b/xlators/protocol/server/src/server-protocol.h new file mode 100644 index 00000000000..cc5f6f9512c --- /dev/null +++ b/xlators/protocol/server/src/server-protocol.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SERVER_PROTOCOL_H_ +#define _SERVER_PROTOCOL_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "call-stub.h" +#include "authenticate.h" +#include "fd.h" +#include "byte-order.h" + +#define DEFAULT_BLOCK_SIZE 4194304 /* 4MB */ +#define GLUSTERFSD_SPEC_PATH CONFDIR "/glusterfs-client.vol" + +typedef struct _server_state server_state_t; + +struct _locker { + struct list_head lockers; + loc_t loc; + fd_t *fd; + pid_t pid; +}; + +struct _lock_table { + struct list_head file_lockers; + struct list_head dir_lockers; + gf_lock_t lock; + size_t count; +}; + + +/* private structure per connection (transport object) + * used as transport_t->xl_private + */ +struct _server_connection { + struct list_head list; + char *id; + int ref; + pthread_mutex_t lock; + char disconnected; + fdtable_t *fdtable; + struct _lock_table *ltable; + xlator_t *bound_xl; +}; + +typedef struct _server_connection server_connection_t; + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id); + +void +server_connection_put (xlator_t *this, server_connection_t *conn); + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn); + +int +server_nop_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno); + + +typedef struct { + dict_t *auth_modules; + transport_t *trans; + int32_t max_block_size; + int32_t inode_lru_limit; + pthread_mutex_t mutex; + struct list_head conns; +} server_conf_t; + + +struct _server_state { + transport_t *trans; + xlator_t *bound_xl; + loc_t loc; + loc_t loc2; + int flags; + fd_t *fd; + size_t size; + off_t offset; + mode_t mode; + dev_t dev; + uid_t uid; + gid_t gid; + size_t nr_count; + int cmd; + int type; + char *name; + int name_len; + inode_table_t *itable; + int64_t fd_no; + ino_t ino; + ino_t par; + ino_t ino2; + ino_t par2; + char *path; + char *path2; + char *bname; + char *bname2; + int mask; + char is_revalidate; + dict_t *xattr_req; + struct flock flock; + struct timespec tv[2]; + char *resolved; +}; + + +int +server_stub_resume (call_stub_t *stub, int32_t op_ret, int32_t op_errno, + inode_t *inode, inode_t *parent); + +int +do_path_lookup (call_stub_t *stub, const loc_t *loc); + +#endif |