diff options
Diffstat (limited to 'xlators/protocol/legacy/client/src/client-protocol.c')
-rw-r--r-- | xlators/protocol/legacy/client/src/client-protocol.c | 6737 |
1 files changed, 6737 insertions, 0 deletions
diff --git a/xlators/protocol/legacy/client/src/client-protocol.c b/xlators/protocol/legacy/client/src/client-protocol.c new file mode 100644 index 000000000..50030f8cf --- /dev/null +++ b/xlators/protocol/legacy/client/src/client-protocol.c @@ -0,0 +1,6737 @@ +/* + Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.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 "statedump.h" +#include "client-mem-types.h" + +#include <sys/resource.h> +#include <inttypes.h> + +/* for default_*_cbk functions */ +#include "defaults.c" +#include "saved-frames.h" +#include "common-utils.h" + +int protocol_client_cleanup (transport_t *trans); +int protocol_client_interpret (xlator_t *this, transport_t *trans, + char *hdr_p, size_t hdrlen, + struct iobuf *iobuf); +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, + struct iobref *iobref); + +int +protocol_client_post_handshake (call_frame_t *frame, xlator_t *this); + +static gf_op_t gf_fops[GF_PROTO_FOP_MAXVALUE]; +static gf_op_t gf_mops[GF_MOP_MAXVALUE]; +static gf_op_t gf_cbks[GF_CBK_MAXVALUE]; + + +transport_t * +client_channel (xlator_t *this, int id) +{ + transport_t *trans = NULL; + client_conf_t *conf = NULL; + int i = 0; + struct client_connection *conn = NULL; + + conf = this->private; + + trans = conf->transport[id]; + conn = trans->xl_private; + + if (conn->connected == 1) + goto ret; + + for (i = 0; i < CHANNEL_MAX; i++) { + trans = conf->transport[i]; + conn = trans->xl_private; + if (conn->connected == 1) + break; + } + +ret: + return trans; +} + + +client_fd_ctx_t * +this_fd_del_ctx (fd_t *file, xlator_t *this) +{ + int dict_ret = -1; + uint64_t ctxaddr = 0; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, file, out); + + dict_ret = fd_ctx_del (file, this, &ctxaddr); + + if (dict_ret < 0) { + ctxaddr = 0; + } + +out: + return (client_fd_ctx_t *)(unsigned long)ctxaddr; +} + + +client_fd_ctx_t * +this_fd_get_ctx (fd_t *file, xlator_t *this) +{ + int dict_ret = -1; + uint64_t ctxaddr = 0; + + GF_VALIDATE_OR_GOTO ("client", this, out); + GF_VALIDATE_OR_GOTO (this->name, file, out); + + dict_ret = fd_ctx_get (file, this, &ctxaddr); + + if (dict_ret < 0) { + ctxaddr = 0; + } + +out: + return (client_fd_ctx_t *)(unsigned long)ctxaddr; +} + + +static void +this_fd_set_ctx (fd_t *file, xlator_t *this, loc_t *loc, client_fd_ctx_t *ctx) +{ + uint64_t oldaddr = 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, &oldaddr); + if (ret >= 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%s (%"PRId64"): trying duplicate remote fd set. ", + loc->path, loc->inode->ino); + } + + ret = fd_ctx_set (file, this, (uint64_t)(unsigned long)ctx); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%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); + + GF_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; + transport_t *trans = NULL; + struct list_head list; + struct saved_frame *saved_frame = NULL; + struct saved_frame *trav = NULL; + struct saved_frame *tmp = NULL; + call_frame_t *frame = NULL; + gf_hdr_common_t hdr = {0, }; + char **gf_op_list = NULL; + gf_op_t *gf_ops = NULL; + struct tm frame_sent_tm; + char frame_sent[32] = {0,}; + struct timeval timeout = {0,}; + gf_timer_cbk_t timer_cbk = NULL; + + GF_VALIDATE_OR_GOTO ("client", data, out); + trans = data; + + conn = trans->xl_private; + + gettimeofday (¤t, NULL); + INIT_LIST_HEAD (&list); + + pthread_mutex_lock (&conn->lock); + { + /* Chaining to get call-always functionality from + call-once timer */ + if (conn->timer) { + timer_cbk = conn->timer->callbk; + + 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"); + } + } + + do { + saved_frame = + saved_frames_get_timedout (conn->saved_frames, + GF_OP_TYPE_MOP_REQUEST, + conn->frame_timeout, + ¤t); + if (saved_frame) + list_add (&saved_frame->list, &list); + + } while (saved_frame); + + do { + saved_frame = + saved_frames_get_timedout (conn->saved_frames, + GF_OP_TYPE_FOP_REQUEST, + conn->frame_timeout, + ¤t); + if (saved_frame) + list_add (&saved_frame->list, &list); + } while (saved_frame); + + do { + saved_frame = + saved_frames_get_timedout (conn->saved_frames, + GF_OP_TYPE_CBK_REQUEST, + conn->frame_timeout, + ¤t); + if (saved_frame) + list_add (&saved_frame->list, &list); + } while (saved_frame); + } + pthread_mutex_unlock (&conn->lock); + + hdr.rsp.op_ret = hton32 (-1); + hdr.rsp.op_errno = hton32 (ENOTCONN); + + list_for_each_entry_safe (trav, tmp, &list, list) { + switch (trav->type) + { + case GF_OP_TYPE_FOP_REQUEST: + gf_ops = gf_fops; + gf_op_list = gf_fop_list; + break; + case GF_OP_TYPE_MOP_REQUEST: + gf_ops = gf_mops; + gf_op_list = gf_mop_list; + break; + case GF_OP_TYPE_CBK_REQUEST: + gf_ops = gf_cbks; + gf_op_list = gf_cbk_list; + break; + } + + localtime_r (&trav->saved_at.tv_sec, &frame_sent_tm); + strftime (frame_sent, 32, "%Y-%m-%d %H:%M:%S", &frame_sent_tm); + + gf_log (trans->xl->name, GF_LOG_ERROR, + "bailing out frame %s(%d) " + "frame sent = %s. frame-timeout = %d", + gf_op_list[trav->op], trav->op, + frame_sent, conn->frame_timeout); + + hdr.type = hton32 (trav->type); + hdr.op = hton32 (trav->op); + + frame = trav->frame; + + gf_ops[trav->op] (frame, &hdr, sizeof (hdr), NULL); + + list_del_init (&trav->list); + GF_FREE (trav); + } +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 && conn->frame_timeout) { + timeout.tv_sec = 10; + timeout.tv_usec = 0; + conn->timer = gf_timer_call_after (trans->xl->ctx, timeout, + call_bail, (void *) trans); + } +} + + + +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; + int disconnect = 0; + int transport_activity = 0; + struct timeval timeout = {0, }; + struct timeval current = {0, }; + + trans = data; + this = trans->xl; + conf = this->private; + conn = trans->xl_private; + + pthread_mutex_lock (&conn->lock); + { + if (conn->ping_timer) + gf_timer_call_cancel (trans->xl->ctx, + conn->ping_timer); + gettimeofday (¤t, NULL); + + pthread_mutex_lock (&conf->mutex); + { + if (((current.tv_sec - conf->last_received.tv_sec) < + conn->ping_timeout) + || ((current.tv_sec - conf->last_sent.tv_sec) < + conn->ping_timeout)) { + transport_activity = 1; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (transport_activity) { + gf_log (this->name, GF_LOG_TRACE, + "ping timer expired but transport activity " + "detected - not bailing transport"); + conn->transport_activity = 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_DEBUG, + "unable to setup timer"); + + } else { + conn->ping_started = 0; + conn->ping_timer = NULL; + disconnect = 1; + } + } + pthread_mutex_unlock (&conn->lock); + if (disconnect) { + gf_log (this->name, GF_LOG_ERROR, + "Server %s has not responded in the last %d " + "seconds, disconnecting.", + conf->transport[0]->peerinfo.identifier, + conn->ping_timeout); + + transport_disconnect (conf->transport[0]); + transport_disconnect (conf->transport[1]); + } +} + + +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; + int frame_count = 0; + + + trans = data; + this = trans->xl; + conf = this->private; + conn = trans->xl_private; + + if (!conn->ping_timeout) + return; + + pthread_mutex_lock (&conn->lock); + { + if (conn->ping_timer) + gf_timer_call_cancel (trans->xl->ctx, conn->ping_timer); + + conn->ping_timer = NULL; + conn->ping_started = 0; + + if (conn->saved_frames) + /* treat the case where conn->saved_frames is NULL + as no pending frames */ + frame_count = conn->saved_frames->count; + + if ((frame_count == 0) || !conn->connected) { + /* using goto looked ugly here, + * hence getting out this way */ + /* unlock */ + pthread_mutex_unlock (&conn->lock); + return; + } + + if (frame_count < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "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_DEBUG, + "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); + if (!hdr) + goto err; + + dummy_frame = create_frame (this, this->ctx->pool); + + if (!dummy_frame) + goto err; + + 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); + return; +err: + if (hdr) + GF_FREE (hdr); + + if (dummy_frame) + STACK_DESTROY (dummy_frame->root); + + return; +} + + +int +client_ping_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + xlator_t *this = NULL; + transport_t *trans = NULL; + client_connection_t *conn = NULL; + struct timeval timeout = {0, }; + int op_ret = 0; + + trans = frame->local; frame->local = NULL; + this = trans->xl; + 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_DEBUG, "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_DEBUG, + "gf_timer_call_after() returned NULL"); + } + pthread_mutex_unlock (&conn->lock); +out: + STACK_DESTROY (frame->root); + return 0; +} + +int +client_encode_groups (call_frame_t *frame, gf_hdr_common_t *hdr) +{ + int i = 0; + if ((!frame) || (!hdr)) + return -1; + + hdr->req.ngrps = hton32 (frame->root->ngrps); + if (frame->root->ngrps == 0) + return 0; + + for (; i < frame->root->ngrps; ++i) + hdr->req.groups[i] = hton32 (frame->root->groups[i]); + + 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, + struct iobref *iobref) +{ + 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, }; + + conf = this->private; + + if (!trans) { + /* default to bulk op since it is 'safer' */ + trans = conf->transport[CHANNEL_BULK]; + } + conn = trans->xl_private; + + 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); + hdr->req.lk_owner = hton64 (frame->root->lk_owner); + client_encode_groups (frame, hdr); + } + + 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, iobref); + } + + if ((ret >= 0) && frame) { + pthread_mutex_lock (&conf->mutex); + { + gettimeofday (&conf->last_sent, NULL); + } + pthread_mutex_unlock (&conf->mutex); + 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); + } else if (type == GF_OP_TYPE_MOP_REQUEST) { + rsphdr.type = GF_OP_TYPE_MOP_REPLY; + gf_mops[op] (frame, &rsphdr, sizeof (rsphdr), NULL); + } else { + rsphdr.type = GF_OP_TYPE_CBK_REPLY; + gf_cbks[op] (frame, &rsphdr, sizeof (rsphdr), NULL); + } + + GF_FREE (hdr); + } + + 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; + uint64_t gen = 0; + client_local_t *local = NULL; + + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + GF_VALIDATE_OR_GOTO (this->name, local, unwind); + + local->fd = fd_ref (fd); + loc_copy (&local->loc, loc); + local->flags = flags; + + frame->local = local; + + pathlen = STRLEN_0 (loc->path); + baselen = STRLEN_0 (loc->name); + + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "CREATE %"PRId64"/%s (%s): failed to get remote inode " + "number for parent inode", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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 (gf_flags_from_flags (flags)); + req->mode = hton32 (mode); + req->par = hton64 (par); + req->gen = hton64 (gen); + 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_PROTO_FOP_CREATE, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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, int32_t wbflags) +{ + 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; + uint64_t gen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + GF_VALIDATE_OR_GOTO (this->name, local, unwind); + + local->fd = fd_ref (fd); + loc_copy (&local->loc, loc); + local->flags = flags; + local->wbflags = wbflags; + + frame->local = local; + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "OPEN %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + req->flags = hton32 (gf_flags_from_flags (flags)); + req->wbflags = hton32 (wbflags); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_OPEN, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + ino_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "STAT %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_STAT, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "READLINK %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_READLINK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + STACK_UNWIND_STRICT (readlink, frame, -1, EINVAL, + NULL, 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 + */ +int +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; + uint64_t gen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + 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); + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "MKNOD %"PRId64"/%s (%s): failed to get remote inode " + "number for parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_MKNOD, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ +int +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; + uint64_t gen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + 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); + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "MKDIR %"PRId64"/%s (%s): failed to get remote inode " + "number for parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_MKDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + baselen = STRLEN_0 (loc->name); + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "UNLINK %"PRId64"/%s (%s): failed to get remote inode " + "number for parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_UNLINK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + baselen = STRLEN_0 (loc->name); + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "RMDIR %"PRId64"/%s (%s): failed to get remote inode " + "number for parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_RMDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + 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); + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "SYMLINK %"PRId64"/%s (%s): failed to get remote inode" + " number parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + + 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); + req->gen = hton64 (gen); + 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_PROTO_FOP_SYMLINK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t oldgen = 0; + ino_t newpar = 0; + uint64_t newgen = 0; + + oldpathlen = STRLEN_0 (oldloc->path); + oldbaselen = STRLEN_0 (oldloc->name); + newpathlen = STRLEN_0 (newloc->path); + newbaselen = STRLEN_0 (newloc->name); + ret = inode_ctx_get2 (oldloc->parent, this, &oldpar, &oldgen); + if (oldloc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "RENAME %"PRId64"/%s (%s): failed to get remote inode " + "number for source parent", + oldloc->parent->ino, oldloc->name, oldloc->path); + goto unwind; + } + + ret = inode_ctx_get2 (newloc->parent, this, &newpar, &newgen); + if (newloc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "CREATE %"PRId64"/%s (%s): failed to get remote inode " + "number for destination parent", + newloc->parent->ino, newloc->name, newloc->path); + goto unwind; + } + + 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->oldgen = hton64 (oldgen); + req->newpar = hton64 (newpar); + req->newgen = hton64 (newgen); + + 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_PROTO_FOP_RENAME, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t oldgen = 0; + ino_t newpar = 0; + uint64_t newgen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + 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); + + ret = inode_ctx_get2 (oldloc->inode, this, &oldino, &oldgen); + if (oldloc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "LINK %"PRId64"/%s (%s) ==> %"PRId64" (%s): " + "failed to get remote inode number for source inode", + newloc->parent->ino, newloc->name, newloc->path, + oldloc->ino, oldloc->path); + goto unwind; + } + + ret = inode_ctx_get2 (newloc->parent, this, &newpar, &newgen); + if (newloc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "LINK %"PRId64"/%s (%s) ==> %"PRId64" (%s): " + "failed to get remote inode number destination parent", + newloc->parent->ino, newloc->name, newloc->path, + oldloc->ino, oldloc->path); + goto unwind; + } + + 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->oldgen = hton64 (oldgen); + req->newpar = hton64 (newpar); + req->newgen = hton64 (newgen); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_LINK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + STACK_UNWIND (frame, -1, EINVAL, oldloc->inode, 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 + */ + +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "TRUNCATE %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_TRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx, EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL, 0, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx, EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL, 0, NULL); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_READ, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + GF_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 + */ + +int +client_writev (call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int32_t count, off_t offset, + struct iobref *iobref) +{ + 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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_WRITE, + hdr, hdrlen, vector, count, iobref); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + ino_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + + if (loc->inode) { + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "STATFS %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + } + + 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->gen = hton64 (gen); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_STATFS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_FLUSH, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_FSYNC, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + STACK_UNWIND (frame, -1, EINVAL); + return 0; + +} + +int +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; + uint64_t gen = 0; + char *buf = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, unwind); + + GF_VALIDATE_OR_GOTO (this->name, loc, unwind); + + if (dict) { + ret = dict_allocate_and_serialize (dict, &buf, &dict_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + } + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "XATTROP %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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) { + memcpy (req->dict, buf, dict_len); + GF_FREE (buf); + } + + req->ino = hton64 (ino); + req->gen = hton64 (gen); + strcpy (req->path + dict_len, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_XATTROP, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + + STACK_UNWIND (frame, -1, EINVAL, NULL); + return 0; +} + + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + if (dict) { + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + } + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. " + "returning EBADFD", + fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + ino = fd->inode->ino; + remote_fd = fdctx->remote_fd; + + 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_DEBUG, + "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_PROTO_FOP_FXATTROP, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "SETXATTR %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_DEBUG, + "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_PROTO_FOP_SETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + + STACK_UNWIND (frame, -1, EINVAL); + return 0; +} + +/** + * client_fsetxattr - fsetxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: fd + * @dict: dictionary which contains key:value to be set. + * @flags: + * + * external reference through client_protocol_xlator->fops->fsetxattr + */ + +int +client_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *dict, int32_t flags) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsetxattr_req_t *req = NULL; + size_t hdrlen = 0; + size_t dict_len = 0; + ino_t ino; + int ret = -1; + int64_t remote_fd = -1; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + dict_len = dict_serialized_length (dict); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict(%p)", + dict); + goto unwind; + } + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + ino = fd->inode->ino; + remote_fd = fdctx->remote_fd; + + 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->ino = hton64 (ino); + req->fd = hton64 (remote_fd); + 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_DEBUG, + "failed to serialize dictionary(%p)", + dict); + goto unwind; + } + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_FSETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + if (name) + namelen = STRLEN_0 (name); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "GETXATTR %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_GETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + + STACK_UNWIND (frame, -1, EINVAL, NULL); + return 0; +} + + +/** + * client_fgetxattr - fgetxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: fd + * + * external reference through client_protocol_xlator->fops->fgetxattr + */ + +int +client_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + gf_fop_fgetxattr_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + size_t namelen = 0; + ino_t ino = 0; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + if (name) + namelen = STRLEN_0 (name); + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get remote fd. EBADFD", + fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + ino = fd->inode->ino; + remote_fd = fdctx->remote_fd; + + hdrlen = gf_hdr_len (req, namelen); + hdr = gf_hdr_new (req, namelen); + + GF_VALIDATE_OR_GOTO (frame->this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->fd = hton64 (remote_fd); + req->namelen = hton32 (namelen); + + if (name) + strcpy (req->name, name); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_FGETXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + + pathlen = STRLEN_0 (loc->path); + namelen = STRLEN_0 (name); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "REMOVEXATTR %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_REMOVEXATTR, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + size_t pathlen = 0; + client_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + GF_VALIDATE_OR_GOTO (this->name, local, unwind); + + loc_copy (&local->loc, loc); + local->fd = fd_ref (fd); + + frame->local = local; + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "OPENDIR %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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); + req->gen = hton64 (gen); + strcpy (req->path, loc->path); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_OPENDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + STACK_UNWIND (frame, -1, EINVAL, fd); + return 0; + +} + +/** + * client_readdirp - readdirp function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdirp + */ + +int +client_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_readdirp_req_t *req = NULL; + size_t hdrlen = 0; + int64_t remote_fd = -1; + int ret = -1; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_READDIRP, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + GF_FREE (hdr); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + +} + + +/** + * client_readdir - readdir function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdir + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_READDIR, + hdr, hdrlen, NULL, 0, NULL); + + return 0; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + goto unwind; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_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 + */ + +int +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; + uint64_t gen = 0; + size_t pathlen = 0; + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "ACCESS %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + 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_PROTO_FOP_ACCESS, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_FTRUNCATE, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + goto unwind; + } + + remote_fd = fdctx->remote_fd; + 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_PROTO_FOP_FSTAT, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, "(%"PRId64"): failed to get" + " fd ctx. EBADFD", fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_DEBUG, + "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_PROTO_FOP_LK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +client_inodelk (call_frame_t *frame, xlator_t *this, const char *volume, + 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; + uint64_t gen = 0; + size_t pathlen = 0; + size_t vollen = 0; + + pathlen = STRLEN_0 (loc->path); + vollen = STRLEN_0 (volume); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "INODELK %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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_DEBUG, + "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 + vollen); + hdr = gf_hdr_new (req, pathlen + vollen); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + strcpy (req->path, loc->path); + strcpy (req->path + pathlen, volume); + + req->ino = hton64 (ino); + req->gen = hton64 (gen); + + 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_PROTO_FOP_INODELK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +client_finodelk (call_frame_t *frame, xlator_t *this, const char *volume, + 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; + size_t vollen = 0; + int32_t gf_cmd = 0; + int32_t gf_type = 0; + int64_t remote_fd = -1; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + vollen = STRLEN_0 (volume); + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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_DEBUG, + "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, vollen); + hdr = gf_hdr_new (req, vollen); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + strcpy (req->volume, volume); + + 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_PROTO_FOP_FINODELK, + hdr, hdrlen, NULL, 0, NULL); + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + + STACK_UNWIND (frame, -1, EINVAL); + return 0; +} + + +int +client_entrylk (call_frame_t *frame, xlator_t *this, const char *volume, + 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 vollen = 0; + size_t hdrlen = -1; + int ret = -1; + ino_t ino = 0; + uint64_t gen = 0; + size_t namelen = 0; + + pathlen = STRLEN_0 (loc->path); + vollen = STRLEN_0 (volume); + + if (name) + namelen = STRLEN_0 (name); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "ENTRYLK %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + hdrlen = gf_hdr_len (req, pathlen + vollen + namelen); + hdr = gf_hdr_new (req, pathlen + vollen + namelen); + GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + + req = gf_param (hdr); + + req->ino = hton64 (ino); + req->gen = hton64 (gen); + req->namelen = hton64 (namelen); + + strcpy (req->path, loc->path); + if (name) + strcpy (req->name + pathlen, name); + strcpy (req->volume + pathlen + namelen, volume); + + 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_PROTO_FOP_ENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_FREE (hdr); + + STACK_UNWIND (frame, -1, EINVAL); + return 0; + +} + + +int +client_fentrylk (call_frame_t *frame, xlator_t *this, const char *volume, + 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 vollen = 0; + size_t namelen = 0; + size_t hdrlen = -1; + int ret = -1; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + if (name) + namelen = STRLEN_0 (name); + + conf = this->private; + + vollen = STRLEN_0 (volume); + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD); + return 0; + } + + remote_fd = fdctx->remote_fd; + hdrlen = gf_hdr_len (req, namelen + vollen); + hdr = gf_hdr_new (req, namelen + vollen); + 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); + + strcpy (req->volume + namelen, volume); + + 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_PROTO_FOP_FENTRYLK, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + if (hdr) + GF_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 + */ + +int +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; + uint64_t gen = 0; + size_t dictlen = 0; + size_t pathlen = 0; + size_t baselen = 0; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + client_local_t *local = NULL; + char *buf = NULL; + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + 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 && loc->parent) { + ret = inode_ctx_get2 (loc->parent, this, &par, &gen); + if (loc->parent->ino && ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "LOOKUP %"PRId64"/%s (%s): failed to get " + "remote inode number for parent", + loc->parent->ino, loc->name, loc->path); + goto unwind; + } + 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) { + ret = dict_allocate_and_serialize (xattr_req, &buf, &dictlen); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict(%p)", + xattr_req); + 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->gen = hton64 (gen); + req->par = hton64 (par); + strcpy (req->path, loc->path); + if (baselen) + strcpy (req->path + pathlen, loc->name); + + if (dictlen > 0) { + memcpy (req->dict + pathlen + baselen, buf, dictlen); + GF_FREE (buf); + } + + req->dictlen = hton32 (dictlen); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_LOOKUP, + hdr, hdrlen, NULL, 0, NULL); + return ret; + +unwind: + STACK_UNWIND (frame, op_ret, op_errno, loc->inode, NULL, NULL); + return ret; +} + + +int +client_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_setattr_req_t *req = NULL; + size_t hdrlen = 0; + size_t pathlen = 0; + ino_t ino = 0; + uint64_t gen = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("client", this, unwind); + GF_VALIDATE_OR_GOTO (this->name, frame, unwind); + + pathlen = STRLEN_0 (loc->path); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "SETATTR %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + goto unwind; + } + + 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->gen = hton64 (gen); + strcpy (req->path, loc->path); + + gf_stat_from_iatt (&req->stbuf, stbuf); + req->valid = hton32 (valid); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_SETATTR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + STACK_UNWIND (frame, -1, EINVAL, NULL); + return 0; +} + + +int +client_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iatt *stbuf, int32_t valid) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_fsetattr_req_t *req = NULL; + size_t hdrlen = 0; + int ret = -1; + client_fd_ctx_t *fdctx = NULL; + int64_t remote_fd = -1; + client_conf_t *conf = NULL; + + GF_VALIDATE_OR_GOTO ("client", this, unwind); + GF_VALIDATE_OR_GOTO (this->name, frame, unwind); + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, NULL, NULL); + return 0; + } + + remote_fd = fdctx->remote_fd; + 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); + + gf_stat_from_iatt (&req->stbuf, stbuf); + req->valid = hton32 (valid); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_FSETATTR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +unwind: + STACK_UNWIND (frame, -1, EINVAL, NULL, NULL); + return 0; +} + + +int +client_fdctx_destroy (xlator_t *this, client_fd_ctx_t *fdctx) +{ + call_frame_t *fr = NULL; + int32_t ret = -1; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_cbk_release_req_t *req = NULL; + gf_cbk_releasedir_req_t *reqdir = NULL; + int64_t remote_fd = -1; + int op = 0; + + remote_fd = fdctx->remote_fd; + + if (remote_fd == -1) + goto out; + + if (fdctx->is_dir) { + hdrlen = gf_hdr_len (reqdir, 0); + hdr = gf_hdr_new (reqdir, 0); + op = GF_CBK_RELEASEDIR; + reqdir = gf_param (hdr); + reqdir->fd = hton64 (remote_fd); + } else { + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + op = GF_CBK_RELEASE; + req = gf_param (hdr); + req->fd = hton64 (remote_fd); + } + + fr = create_frame (this, this->ctx->pool); + + ret = protocol_client_xfer (fr, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_CBK_REQUEST, op, + hdr, hdrlen, NULL, 0, NULL); + +out: + inode_unref (fdctx->inode); + GF_FREE (fdctx); + + return ret; +} + + +/** + * client_releasedir - releasedir function for client protocol + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->cbks->releasedir + */ + +int +client_releasedir (xlator_t *this, fd_t *fd) +{ + int64_t remote_fd = -1; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_del_ctx (fd, this); + if (fdctx != NULL) { + remote_fd = fdctx->remote_fd; + + /* fdctx->remote_fd == -1 indicates a reopen attempt + in progress. Just mark ->released = 1 and let + reopen_cbk handle releasing + */ + + if (remote_fd != -1) + list_del_init (&fdctx->sfd_pos); + + fdctx->released = 1; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (remote_fd != -1) + client_fdctx_destroy (this, fdctx); + + return 0; +} + + +/** + * 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) +{ + int64_t remote_fd = -1; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_del_ctx (fd, this); + if (fdctx != NULL) { + remote_fd = fdctx->remote_fd; + + /* fdctx->remote_fd == -1 indicates a reopen attempt + in progress. Just mark ->released = 1 and let + reopen_cbk handle releasing + */ + + if (remote_fd != -1) + list_del_init (&fdctx->sfd_pos); + + fdctx->released = 1; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (remote_fd != -1) + client_fdctx_destroy (this, fdctx); + + return 0; +} + +/* + * MGMT_OPS + */ + +/* Callbacks */ + +int +client_fxattrop_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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_DEBUG, + "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) + GF_FREE (dictbuf); + + if (dict) + dict_unref (dict); + + return 0; +} + + +int +client_xattrop_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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_DEBUG, + "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) + GF_FREE (dictbuf); + if (dict) + dict_unref (dict); + + 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, + struct iobuf *iobuf) +{ + 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 iatt stbuf = {0, }; + struct iatt preparent = {0, }; + struct iatt postparent = {0, }; + int64_t remote_fd = 0; + int32_t ret = -1; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + ino_t ino = 0; + uint64_t gen = 0; + + 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_iatt (&rsp->stat, &stbuf); + + gf_stat_to_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + + ino = stbuf.ia_ino; + gen = stbuf.ia_gen; + } + + if (op_ret >= 0) { + ret = inode_ctx_put2 (local->loc.inode, frame->this, ino, gen); + + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "CREATE %"PRId64"/%s (%s): failed to set " + "remote inode number to inode ctx", + local->loc.parent->ino, local->loc.name, + local->loc.path); + op_ret = -1; + op_errno = EINVAL; + goto unwind_out; + } + + fdctx = GF_CALLOC (1, sizeof (*fdctx), + gf_client_mt_client_fd_ctx_t); + if (!fdctx) { + op_ret = -1; + op_errno = ENOMEM; + goto unwind_out; + } + + fdctx->remote_fd = remote_fd; + fdctx->inode = inode_ref (fd->inode); + fdctx->ino = ino; + fdctx->gen = gen; + fdctx->flags = local->flags; + + INIT_LIST_HEAD (&fdctx->sfd_pos); + + this_fd_set_ctx (fd, frame->this, &local->loc, fdctx); + + pthread_mutex_lock (&conf->mutex); + { + list_add_tail (&fdctx->sfd_pos, &conf->saved_fds); + } + pthread_mutex_unlock (&conf->mutex); + } +unwind_out: + STACK_UNWIND (frame, op_ret, op_errno, fd, inode, &stbuf, + &preparent, &postparent); + + client_local_wipe (local); + + return 0; +} + + +/* + * client_open_cbk - open callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_open_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + ino_t ino = 0; + uint64_t gen = 0; + + + local = frame->local; + + if (local->op) { + local->op (frame, hdr, hdrlen, iobuf); + return 0; + } + + 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) { + fdctx = GF_CALLOC (1, sizeof (*fdctx), + gf_client_mt_client_fd_ctx_t); + if (!fdctx) { + op_ret = -1; + op_errno = ENOMEM; + goto unwind_out; + } + + inode_ctx_get2 (fd->inode, frame->this, &ino, &gen); + + fdctx->remote_fd = remote_fd; + fdctx->inode = inode_ref (fd->inode); + fdctx->ino = ino; + fdctx->gen = gen; + fdctx->flags = local->flags; + fdctx->wbflags = local->wbflags; + + INIT_LIST_HEAD (&fdctx->sfd_pos); + + this_fd_set_ctx (fd, frame->this, &local->loc, fdctx); + + pthread_mutex_lock (&conf->mutex); + { + list_add_tail (&fdctx->sfd_pos, &conf->saved_fds); + } + pthread_mutex_unlock (&conf->mutex); + } +unwind_out: + 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, + struct iobuf *iobuf) +{ + struct iatt 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_iatt (&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 + */ + +int +client_mknod_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_mknod_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + int ret = 0; + struct iatt preparent = {0,}; + struct iatt postparent = {0,}; + + 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_iatt (&rsp->stat, &stbuf); + + ret = inode_ctx_put2 (local->loc.inode, frame->this, + stbuf.ia_ino, stbuf.ia_gen); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "MKNOD %"PRId64"/%s (%s): failed to set remote" + " inode number to inode ctx", + local->loc.parent->ino, local->loc.name, + local->loc.path); + + STACK_UNWIND (frame, -1, EINVAL, inode, NULL, + NULL, NULL); + return 0; + } + + gf_stat_to_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, + &preparent, &postparent); + + client_local_wipe (local); + + return 0; +} + +/* + * client_symlink_cbk - symlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_symlink_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_symlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt stbuf = {0, }; + struct iatt preparent = {0,}; + struct iatt postparent = {0,}; + inode_t *inode = NULL; + client_local_t *local = NULL; + int ret = 0; + + 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_iatt (&rsp->stat, &stbuf); + + ret = inode_ctx_put2 (inode, frame->this, + stbuf.ia_ino, stbuf.ia_gen); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "SYMLINK %"PRId64"/%s (%s): failed to set " + "remote inode number to inode ctx", + local->loc.parent->ino, local->loc.name, + local->loc.path); + STACK_UNWIND (frame, -1, EINVAL, inode, NULL, + NULL, NULL); + return 0; + } + gf_stat_to_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, + &preparent, &postparent); + + client_local_wipe (local); + + return 0; +} + +/* + * client_link_cbk - link callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_link_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_link_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + struct iatt preparent = {0,}; + struct iatt postparent = {0,}; + + 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_iatt (&rsp->stat, &stbuf); + + gf_stat_to_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, + &preparent, &postparent); + + client_local_wipe (local); + + return 0; +} + +/* + * client_truncate_cbk - truncate callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_truncate_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_truncate_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt prestat = {0, }; + struct iatt poststat = {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_iatt (&rsp->prestat, &prestat); + gf_stat_to_iatt (&rsp->poststat, &poststat); + } + + STACK_UNWIND (frame, op_ret, op_errno, &prestat, &poststat); + + return 0; +} + +/* client_fstat_cbk - fstat callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_fstat_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt 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_iatt (&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 + */ +int +client_ftruncate_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_ftruncate_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt prestat = {0, }; + struct iatt poststat = {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_iatt (&rsp->prestat, &prestat); + gf_stat_to_iatt (&rsp->poststat, &poststat); + } + + STACK_UNWIND (frame, op_ret, op_errno, &prestat, &poststat); + + return 0; +} + + +/* client_readv_cbk - readv callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external referece + */ + +int +client_readv_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_read_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iovec vector = {0, }; + struct iatt stbuf = {0, }; + struct iobref *iobref = 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) { + iobref = iobref_new (); + gf_stat_to_iatt (&rsp->stat, &stbuf); + vector.iov_len = op_ret; + + if (op_ret > 0) { + vector.iov_base = iobuf->ptr; + iobref_add (iobref, iobuf); + } + } + + STACK_UNWIND (frame, op_ret, op_errno, &vector, 1, &stbuf, iobref); + + if (iobref) + iobref_unref (iobref); + + if (iobuf) + iobuf_unref (iobuf); + + return 0; +} + +/* + * client_write_cbk - write callback for client protocol + * @frame: cal frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_write_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_write_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt prestat = {0, }; + struct iatt poststat = {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_iatt (&rsp->prestat, &prestat); + gf_stat_to_iatt (&rsp->poststat, &poststat); + } + + STACK_UNWIND (frame, op_ret, op_errno, &prestat, &poststat); + + return 0; +} + + +int +client_readdirp_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_readdirp_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; +} + + +int +client_readdir_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_fsync_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt prestat = {0, }; + struct iatt poststat = {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)); + + if (op_ret == 0) { + gf_stat_to_iatt (&rsp->prestat, &prestat); + gf_stat_to_iatt (&rsp->poststat, &poststat); + } + + STACK_UNWIND (frame, op_ret, op_errno, &prestat, &poststat); + + return 0; +} + +/* + * client_unlink_cbk - unlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_unlink_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_unlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt preparent = {0,}; + struct iatt postparent = {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_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, &preparent, &postparent); + + return 0; +} + +/* + * client_rename_cbk - rename callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_rename_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt stbuf = {0, }; + gf_fop_rename_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt preoldparent = {0, }; + struct iatt postoldparent = {0, }; + struct iatt prenewparent = {0, }; + struct iatt postnewparent = {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_iatt (&rsp->stat, &stbuf); + gf_stat_to_iatt (&rsp->preoldparent, &preoldparent); + gf_stat_to_iatt (&rsp->postoldparent, &postoldparent); + gf_stat_to_iatt (&rsp->prenewparent, &prenewparent); + gf_stat_to_iatt (&rsp->postnewparent, &postnewparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, &stbuf, &preoldparent, + &postoldparent, &prenewparent, &postnewparent); + + return 0; +} + + +/* + * client_readlink_cbk - readlink callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_readlink_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_readlink_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + char *link = NULL; + struct iatt 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) { + link = rsp->path; + gf_stat_to_iatt (&rsp->buf, &stbuf); + } + + STACK_UNWIND (frame, op_ret, op_errno, link, &stbuf); + return 0; +} + +/* + * client_mkdir_cbk - mkdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_mkdir_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_mkdir_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt stbuf = {0, }; + inode_t *inode = NULL; + client_local_t *local = NULL; + int ret = 0; + struct iatt preparent = {0,}; + struct iatt postparent = {0,}; + + 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_iatt (&rsp->stat, &stbuf); + + ret = inode_ctx_put2 (inode, frame->this, stbuf.ia_ino, + stbuf.ia_gen); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "MKDIR %"PRId64"/%s (%s): failed to set " + "remote inode number to inode ctx", + local->loc.parent->ino, local->loc.name, + local->loc.path); + STACK_UNWIND (frame, -1, EINVAL, inode, NULL, + NULL, NULL); + return 0; + } + + gf_stat_to_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, + &preparent, &postparent); + + client_local_wipe (local); + + return 0; +} + +/* + * client_flush_cbk - flush callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_flush_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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, + struct iobuf *iobuf) +{ + 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; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + ino_t ino = 0; + uint64_t gen = 0; + + + local = frame->local; + + if (local->op) { + local->op (frame, hdr, hdrlen, iobuf); + return 0; + } + + 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) { + fdctx = GF_CALLOC (1, sizeof (*fdctx), + gf_client_mt_client_fd_ctx_t); + if (!fdctx) { + op_ret = -1; + op_errno = ENOMEM; + goto unwind_out; + } + + inode_ctx_get2 (fd->inode, frame->this, &ino, &gen); + + fdctx->remote_fd = remote_fd; + fdctx->inode = inode_ref (fd->inode); + fdctx->ino = ino; + fdctx->gen = gen; + + fdctx->is_dir = 1; + + INIT_LIST_HEAD (&fdctx->sfd_pos); + + this_fd_set_ctx (fd, frame->this, &local->loc, fdctx); + + pthread_mutex_lock (&conf->mutex); + { + list_add_tail (&fdctx->sfd_pos, &conf->saved_fds); + } + pthread_mutex_unlock (&conf->mutex); + } +unwind_out: + 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, + struct iobuf *iobuf) +{ + gf_fop_rmdir_rsp_t *rsp = NULL; + int32_t op_ret = 0; + int32_t op_errno = 0; + struct iatt preparent = {0,}; + struct iatt postparent = {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_iatt (&rsp->preparent, &preparent); + gf_stat_to_iatt (&rsp->postparent, &postparent); + } + + STACK_UNWIND (frame, op_ret, op_errno, &preparent, &postparent); + + return 0; +} + +/* + * client_access_cbk - access callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_access_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_lookup_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt stbuf = {0, }; + struct iatt postparent = {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; + ino_t oldino = 0; + uint64_t oldgen = 0; + + local = frame->local; + inode = local->loc.inode; + frame->local = NULL; + + rsp = gf_param (hdr); + + op_ret = ntoh32 (hdr->rsp.op_ret); + + gf_stat_to_iatt (&rsp->postparent, &postparent); + + if (op_ret == 0) { + op_ret = -1; + gf_stat_to_iatt (&rsp->stat, &stbuf); + + ret = inode_ctx_get2 (inode, frame->this, &oldino, &oldgen); + if (oldino != stbuf.ia_ino || oldgen != stbuf.ia_gen) { + if (oldino) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "LOOKUP %"PRId64"/%s (%s): " + "inode number changed from " + "{%"PRId64",%"PRId64"} to {%"PRId64",%"PRId64"}", + local->loc.parent ? + local->loc.parent->ino : (uint64_t) 0, + local->loc.name, + local->loc.path, + oldgen, oldino, stbuf.ia_gen, stbuf.ia_ino); + op_errno = ESTALE; + goto fail; + } + + ret = inode_ctx_put2 (inode, frame->this, + stbuf.ia_ino, stbuf.ia_gen); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_DEBUG, + "LOOKUP %"PRId64"/%s (%s) : " + "failed to set remote inode " + "number to inode ctx", + local->loc.parent ? + local->loc.parent->ino : (uint64_t) 0, + local->loc.name, + local->loc.path); + op_errno = EINVAL; + goto fail; + } + } + + 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_DEBUG, + "%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, + &postparent); + + client_local_wipe (local); + + if (dictbuf) + GF_FREE (dictbuf); + + if (xattr) + dict_unref (xattr); + + return 0; +} + +static int32_t +client_setattr_cbk (call_frame_t *frame,gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt statpre = {0, }; + struct iatt statpost = {0, }; + gf_fop_setattr_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_iatt (&rsp->statpre, &statpre); + gf_stat_to_iatt (&rsp->statpost, &statpost); + } + + STACK_UNWIND (frame, op_ret, op_errno, &statpre, &statpost); + + return 0; +} + +static int32_t +client_fsetattr_cbk (call_frame_t *frame,gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + struct iatt statpre = {0, }; + struct iatt statpost = {0, }; + gf_fop_setattr_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_iatt (&rsp->statpre, &statpre); + gf_stat_to_iatt (&rsp->statpost, &statpost); + } + + STACK_UNWIND (frame, op_ret, op_errno, &statpre, &statpost); + + return 0; +} + + +int +gf_free_direntry (dir_entry_t *head) +{ + dir_entry_t *prev = NULL; + dir_entry_t *trav = NULL; + + prev = head; + GF_VALIDATE_OR_GOTO ("client-protocol", prev, fail); + + trav = head->next; + while (trav) { + prev->next = trav->next; + GF_FREE (trav->name); + if (IA_ISLNK (trav->buf.ia_type)) + GF_FREE (trav->link); + GF_FREE (trav); + trav = prev->next; + } + GF_FREE (head); +fail: + return 0; +} + +/* + * client_statfs_cbk - statfs callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_statfs_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_fsyncdir_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_setxattr_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_getxattr_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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_DEBUG, + "%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) + GF_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 + */ + +int +client_removexattr_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, + size_t hdrlen, struct iobuf *iobuf) +{ + 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 + */ + +int +client_lk_common_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_inodelk_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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; +} + + +int +client_finodelk_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + */ + +int +client_entrylk_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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; +} + +int +client_fentrylk_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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_getspec - getspec function for client protocol + * @frame: call frame + * @this: client protocol xlator structure + * @flag: + * + * external reference through client_protocol_xlator->fops->getspec + */ + +int +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) + GF_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 + */ + +int +client_getspec_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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; +} + +int +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; + ino_t ino = 0; + uint64_t gen = 0; + + hdrlen = gf_hdr_len (req, strlen (loc->path) + 1); + hdr = gf_hdr_new (req, strlen (loc->path) + 1); + req = gf_param (hdr); + + ret = inode_ctx_get2 (loc->inode, this, &ino, &gen); + if (loc->inode->ino && ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "CHECKSUM %"PRId64" (%s): " + "failed to get remote inode number", + loc->inode->ino, loc->path); + STACK_UNWIND (frame, -1, EINVAL, NULL, NULL); + return 0; + + } + + req->ino = hton64 (ino); + req->gen = hton64 (gen); + 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_PROTO_FOP_CHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +} + + +int +client_checksum_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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 + NAME_MAX; + } + + STACK_UNWIND (frame, op_ret, op_errno, fchecksum, dchecksum); + return 0; +} + + +int +client_rchecksum (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + int32_t len) +{ + gf_hdr_common_t *hdr = NULL; + gf_fop_rchecksum_req_t *req = NULL; + size_t hdrlen = -1; + int ret = -1; + + int64_t remote_fd = -1; + client_fd_ctx_t *fdctx = NULL; + client_conf_t *conf = NULL; + + hdrlen = gf_hdr_len (req, 0); + hdr = gf_hdr_new (req, 0); + req = gf_param (hdr); + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + fdctx = this_fd_get_ctx (fd, this); + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx == NULL) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, 0, NULL); + return 0; + } + + if (fdctx->remote_fd == -1) { + gf_log (this->name, GF_LOG_TRACE, + "(%"PRId64"): failed to get fd ctx. EBADFD", + fd->inode->ino); + STACK_UNWIND (frame, -1, EBADFD, 0, NULL); + return 0; + } + + remote_fd = fdctx->remote_fd; + + req->fd = hton64 (remote_fd); + req->offset = hton64 (offset); + req->len = hton32 (len); + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_BULK), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_RCHECKSUM, + hdr, hdrlen, NULL, 0, NULL); + + return ret; +} + + +int +client_rchecksum_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_fop_rchecksum_rsp_t *rsp = NULL; + + int32_t op_ret = 0; + int32_t op_errno = 0; + int32_t gf_errno = 0; + uint32_t weak_checksum = 0; + unsigned char *strong_checksum = 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) { + weak_checksum = rsp->weak_checksum; + strong_checksum = rsp->strong_checksum; + } + + STACK_UNWIND (frame, op_ret, op_errno, weak_checksum, strong_checksum); + + return 0; +} + + +/* + * client_setspec_cbk - setspec callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_setspec_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + 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; +} + + + +int +protocol_client_reopendir_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, + size_t hdrlen, struct iobuf *iobuf) +{ + int32_t op_ret = -1; + int32_t op_errno = ENOTCONN; + int64_t remote_fd = -1; + gf_fop_open_rsp_t *rsp = NULL; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + + + local = frame->local; frame->local = NULL; + conf = frame->this->private; + fdctx = local->fdctx; + + 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_log (frame->this->name, GF_LOG_DEBUG, + "reopendir on %s returned %d (%"PRId64")", + local->loc.path, op_ret, remote_fd); + + pthread_mutex_lock (&conf->mutex); + { + fdctx->remote_fd = remote_fd; + + if (!fdctx->released) { + list_add_tail (&fdctx->sfd_pos, &conf->saved_fds); + fdctx = NULL; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx) + client_fdctx_destroy (frame->this, fdctx); + + STACK_DESTROY (frame->root); + + client_local_wipe (local); + + return 0; +} + + + +int +protocol_client_reopendir (xlator_t *this, client_fd_ctx_t *fdctx) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_fop_opendir_req_t *req = NULL; + size_t pathlen = 0; + client_local_t *local = NULL; + inode_t *inode = NULL; + char *path = NULL; + call_frame_t *frame = NULL; + + inode = fdctx->inode; + + ret = inode_path (inode, NULL, &path); + if (ret < 0) { + goto out; + } + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + if (!local) { + goto out; + } + + local->fdctx = fdctx; + local->op = protocol_client_reopendir_cbk; + local->loc.path = path; path = NULL; + + frame = create_frame (this, this->ctx->pool); + if (!frame) { + goto out; + } + + pathlen = STRLEN_0 (local->loc.path); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + + req = gf_param (hdr); + + req->ino = hton64 (fdctx->ino); + req->gen = hton64 (fdctx->gen); + + strcpy (req->path, local->loc.path); + + gf_log (frame->this->name, GF_LOG_DEBUG, + "attempting reopendir on %s", local->loc.path); + + frame->local = local; local = NULL; + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_OPENDIR, + hdr, hdrlen, NULL, 0, NULL); + + return ret; + +out: + if (frame) + STACK_DESTROY (frame->root); + + if (local) + client_local_wipe (local); + + if (path) + GF_FREE (path); + + return 0; +} + + +int +protocol_client_reopen_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, + size_t hdrlen, struct iobuf *iobuf) +{ + int32_t op_ret = -1; + int32_t op_errno = ENOTCONN; + int64_t remote_fd = -1; + gf_fop_open_rsp_t *rsp = NULL; + client_local_t *local = NULL; + client_conf_t *conf = NULL; + client_fd_ctx_t *fdctx = NULL; + + + local = frame->local; frame->local = NULL; + conf = frame->this->private; + fdctx = local->fdctx; + + 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_log (frame->this->name, GF_LOG_DEBUG, + "reopen on %s returned %d (%"PRId64")", + local->loc.path, op_ret, remote_fd); + + pthread_mutex_lock (&conf->mutex); + { + fdctx->remote_fd = remote_fd; + + if (!fdctx->released) { + list_add_tail (&fdctx->sfd_pos, &conf->saved_fds); + fdctx = NULL; + } + } + pthread_mutex_unlock (&conf->mutex); + + if (fdctx) + client_fdctx_destroy (frame->this, fdctx); + + STACK_DESTROY (frame->root); + + client_local_wipe (local); + + return 0; +} + + +int +protocol_client_reopen (xlator_t *this, client_fd_ctx_t *fdctx) +{ + int ret = -1; + gf_hdr_common_t *hdr = NULL; + size_t hdrlen = 0; + gf_fop_open_req_t *req = NULL; + size_t pathlen = 0; + client_local_t *local = NULL; + inode_t *inode = NULL; + char *path = NULL; + call_frame_t *frame = NULL; + + inode = fdctx->inode; + + ret = inode_path (inode, NULL, &path); + if (ret < 0) { + goto out; + } + + local = GF_CALLOC (1, sizeof (*local), gf_client_mt_client_local_t); + if (!local) { + goto out; + } + + local->fdctx = fdctx; + local->op = protocol_client_reopen_cbk; + local->loc.path = path; path = NULL; + + frame = create_frame (this, this->ctx->pool); + if (!frame) { + goto out; + } + + pathlen = STRLEN_0 (local->loc.path); + + hdrlen = gf_hdr_len (req, pathlen); + hdr = gf_hdr_new (req, pathlen); + + req = gf_param (hdr); + + req->ino = hton64 (fdctx->ino); + req->gen = hton64 (fdctx->gen); + req->flags = hton32 (gf_flags_from_flags (fdctx->flags)); + req->wbflags = hton32 (fdctx->wbflags); + strcpy (req->path, local->loc.path); + + gf_log (frame->this->name, GF_LOG_DEBUG, + "attempting reopen on %s", local->loc.path); + + frame->local = local; local = NULL; + + ret = protocol_client_xfer (frame, this, + CLIENT_CHANNEL (this, CHANNEL_LOWLAT), + GF_OP_TYPE_FOP_REQUEST, GF_PROTO_FOP_OPEN, + hdr, hdrlen, NULL, 0, NULL); + + return ret; + +out: + if (frame) + STACK_DESTROY (frame->root); + + if (local) + client_local_wipe (local); + + if (path) + GF_FREE (path); + + return 0; + +} + + +int +protocol_client_post_handshake (call_frame_t *frame, xlator_t *this) +{ + client_conf_t *conf = NULL; + client_fd_ctx_t *tmp = NULL; + client_fd_ctx_t *fdctx = NULL; + xlator_list_t *parent = NULL; + struct list_head reopen_head; + + conf = this->private; + INIT_LIST_HEAD (&reopen_head); + + pthread_mutex_lock (&conf->mutex); + { + list_for_each_entry_safe (fdctx, tmp, &conf->saved_fds, + sfd_pos) { + if (fdctx->remote_fd != -1) + continue; + + list_del (&fdctx->sfd_pos); + list_add_tail (&fdctx->sfd_pos, &reopen_head); + } + } + pthread_mutex_unlock (&conf->mutex); + + list_for_each_entry_safe (fdctx, tmp, &reopen_head, sfd_pos) { + list_del_init (&fdctx->sfd_pos); + + if (fdctx->is_dir) + protocol_client_reopendir (this, fdctx); + else + protocol_client_reopen (this, fdctx); + } + + parent = this->parents; + + while (parent) { + xlator_notify (parent->xlator, GF_EVENT_CHILD_UP, + this); + parent = parent->next; + } + + 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, + struct iobuf *iobuf) +{ + client_conf_t *conf = NULL; + gf_mop_setvolume_rsp_t *rsp = NULL; + client_connection_t *conn = 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; + transport_t *peer_trans = NULL; + uint64_t peer_trans_int = 0; + + trans = frame->local; frame->local = NULL; + this = frame->this; + conn = trans->xl_private; + conf = this->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) { + gf_log (this->name, GF_LOG_DEBUG, + "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_DEBUG, + "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_DEBUG, + "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 == ESTALE) { + parent = trans->xl->parents; + while (parent) { + xlator_notify (parent->xlator, + GF_EVENT_VOLFILE_MODIFIED, + trans->xl); + parent = parent->next; + } + } + + } else { + ret = dict_get_str (this->options, "remote-subvolume", + &remote_subvol); + if (!remote_subvol) + goto out; + + ctx = this->ctx; + + if (process_uuid && !strcmp (ctx->process_uuid,process_uuid)) { + ret = dict_get_uint64 (reply, "transport-ptr", + &peer_trans_int); + + peer_trans = (void *) (long) (peer_trans_int); + + gf_log (this->name, GF_LOG_WARNING, + "attaching to the local volume '%s'", + remote_subvol); + + transport_setpeer (trans, peer_trans); + + } + + gf_log (trans->xl->name, GF_LOG_NORMAL, + "Connected to %s, attached " + "to remote volume '%s'.", + trans->peerinfo.identifier, remote_subvol); + + pthread_mutex_lock (&(conn->lock)); + { + conn->connected = 1; + } + pthread_mutex_unlock (&(conn->lock)); + + protocol_client_post_handshake (frame, frame->this); + } + + conf->connecting = 0; +out: + + if (-1 == op_ret) { + /* 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) { + xlator_notify (parent->xlator, + GF_EVENT_CHILD_CONNECTING, trans->xl); + parent = parent->next; + } + conf->connecting= 1; + } + + 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, + struct iobuf *iobuf) +{ + 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}; + int32_t ret = 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_TRACE, + "attempting reconnect"); + ret = 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_TRACE, + "breaking reconnect chain"); + } + } + pthread_mutex_unlock (&conn->lock); + + if (ret == -1 && errno != EINPROGRESS) { + default_notify (trans->xl, GF_EVENT_CHILD_DOWN, NULL); + } +} + +int +protocol_client_mark_fd_bad (xlator_t *this) +{ + client_conf_t *conf = NULL; + client_fd_ctx_t *tmp = NULL; + client_fd_ctx_t *fdctx = NULL; + + conf = this->private; + + pthread_mutex_lock (&conf->mutex); + { + list_for_each_entry_safe (fdctx, tmp, &conf->saved_fds, + sfd_pos) { + fdctx->remote_fd = -1; + } + } + pthread_mutex_unlock (&conf->mutex); + + return 0; +} + +/* + * 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_TRACE, + "cleaning up state in transport object %p", trans); + + pthread_mutex_lock (&conn->lock); + { + saved_frames = conn->saved_frames; + conn->saved_frames = saved_frames_new (); + + /* bailout logic cleanup */ + 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, struct iobuf *iobuf) +{ + STACK_DESTROY (frame->root); + return 0; +} + + +int +client_release_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + STACK_DESTROY (frame->root); + return 0; +} + + +int +client_forget_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_log ("", GF_LOG_CRITICAL, "fop not implemented"); + return 0; +} + + +int +client_log_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, + struct iobuf *iobuf) +{ + gf_log ("", GF_LOG_CRITICAL, "fop not implemented"); + return 0; +} + + +static gf_op_t gf_fops[] = { + [GF_PROTO_FOP_STAT] = client_stat_cbk, + [GF_PROTO_FOP_READLINK] = client_readlink_cbk, + [GF_PROTO_FOP_MKNOD] = client_mknod_cbk, + [GF_PROTO_FOP_MKDIR] = client_mkdir_cbk, + [GF_PROTO_FOP_UNLINK] = client_unlink_cbk, + [GF_PROTO_FOP_RMDIR] = client_rmdir_cbk, + [GF_PROTO_FOP_SYMLINK] = client_symlink_cbk, + [GF_PROTO_FOP_RENAME] = client_rename_cbk, + [GF_PROTO_FOP_LINK] = client_link_cbk, + [GF_PROTO_FOP_TRUNCATE] = client_truncate_cbk, + [GF_PROTO_FOP_OPEN] = client_open_cbk, + [GF_PROTO_FOP_READ] = client_readv_cbk, + [GF_PROTO_FOP_WRITE] = client_write_cbk, + [GF_PROTO_FOP_STATFS] = client_statfs_cbk, + [GF_PROTO_FOP_FLUSH] = client_flush_cbk, + [GF_PROTO_FOP_FSYNC] = client_fsync_cbk, + [GF_PROTO_FOP_SETXATTR] = client_setxattr_cbk, + [GF_PROTO_FOP_GETXATTR] = client_getxattr_cbk, + [GF_PROTO_FOP_REMOVEXATTR] = client_removexattr_cbk, + [GF_PROTO_FOP_OPENDIR] = client_opendir_cbk, + [GF_PROTO_FOP_FSYNCDIR] = client_fsyncdir_cbk, + [GF_PROTO_FOP_ACCESS] = client_access_cbk, + [GF_PROTO_FOP_CREATE] = client_create_cbk, + [GF_PROTO_FOP_FTRUNCATE] = client_ftruncate_cbk, + [GF_PROTO_FOP_FSTAT] = client_fstat_cbk, + [GF_PROTO_FOP_LK] = client_lk_common_cbk, + [GF_PROTO_FOP_LOOKUP] = client_lookup_cbk, + [GF_PROTO_FOP_READDIR] = client_readdir_cbk, + [GF_PROTO_FOP_READDIRP] = client_readdirp_cbk, + [GF_PROTO_FOP_INODELK] = client_inodelk_cbk, + [GF_PROTO_FOP_FINODELK] = client_finodelk_cbk, + [GF_PROTO_FOP_ENTRYLK] = client_entrylk_cbk, + [GF_PROTO_FOP_FENTRYLK] = client_fentrylk_cbk, + [GF_PROTO_FOP_CHECKSUM] = client_checksum_cbk, + [GF_PROTO_FOP_RCHECKSUM] = client_rchecksum_cbk, + [GF_PROTO_FOP_XATTROP] = client_xattrop_cbk, + [GF_PROTO_FOP_FXATTROP] = client_fxattrop_cbk, + [GF_PROTO_FOP_SETATTR] = client_setattr_cbk, + [GF_PROTO_FOP_FSETATTR] = client_fsetattr_cbk +}; + +static gf_op_t gf_mops[] = { + [GF_MOP_SETVOLUME] = client_setvolume_cbk, + [GF_MOP_GETVOLUME] = client_enosys_cbk, + [GF_MOP_SETSPEC] = client_setspec_cbk, + [GF_MOP_GETSPEC] = client_getspec_cbk, + [GF_MOP_PING] = client_ping_cbk, + [GF_MOP_LOG] = client_log_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, struct iobuf *iobuf) +{ + int ret = -1; + call_frame_t *frame = NULL; + gf_hdr_common_t *hdr = NULL; + uint64_t callid = 0; + int type = -1; + int op = -1; + client_connection_t *conn = NULL; + + conn = trans->xl_private; + + 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_WARNING, + "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_PROTO_FOP_MAXVALUE) || + (op < 0)) { + gf_log (trans->xl->name, GF_LOG_WARNING, + "invalid fop '%d'", op); + } else { + ret = gf_fops[op] (frame, hdr, hdrlen, iobuf); + } + 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, iobuf); + } + 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, iobuf); + } + break; + default: + gf_log (trans->xl->name, GF_LOG_DEBUG, + "invalid packet type: %d", type); + break; + } + + return ret; +} + +int32_t +mem_acct_init (xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_client_mt_end + 1); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, "Memory accounting init" + "failed"); + return ret; + } + + return ret; +} + + +/* + * init - initiliazation function. called during loading of client protocol + * @this: + * + */ + +int +init (xlator_t *this) +{ + transport_t *trans = NULL; + client_conf_t *conf = NULL; + client_connection_t *conn = NULL; + int32_t frame_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 any " + "subvolumes"); + goto out; + } + + if (!this->parents) { + gf_log (this->name, GF_LOG_WARNING, + "Volume is dangling. "); + } + + remote_subvolume = dict_get (this->options, "remote-subvolume"); + if (remote_subvolume == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Option 'remote-subvolume' is not specified."); + goto out; + } + + ret = dict_get_int32 (this->options, "frame-timeout", + &frame_timeout); + if (ret >= 0) { + gf_log (this->name, GF_LOG_DEBUG, + "setting frame-timeout to %d", frame_timeout); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "defaulting frame-timeout to 30mins"); + frame_timeout = 1800; + } + + 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 42"); + ping_timeout = GF_UNIVERSAL_ANSWER; + } + + conf = GF_CALLOC (1, sizeof (client_conf_t), + gf_client_mt_client_conf_t); + + protocol_common_init (); + + pthread_mutex_init (&conf->mutex, NULL); + INIT_LIST_HEAD (&conf->saved_fds); + + this->private = conf; + + for (i = 0; i < CHANNEL_MAX; i++) { + if (CHANNEL_LOWLAT == i) { + dict_set (this->options, "transport.socket.lowlat", + data_from_dynstr (gf_strdup ("true"))); + } + trans = transport_load (this->options, this); + if (trans == NULL) { + gf_log (this->name, GF_LOG_DEBUG, + "Failed to load transport"); + ret = -1; + goto out; + } + + conn = GF_CALLOC (1, sizeof (*conn), + gf_client_mt_client_connection_t); + + conn->saved_frames = saved_frames_new (); + + conn->callid = 1; + + conn->frame_timeout = frame_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_DEBUG, + "Failed to set max open fd to 64k: %s", + strerror(errno)); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "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) { + GF_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, "protocol-version", GF_PROTOCOL_VERSION); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to set protocol version(%s) in handshake msg", + GF_PROTOCOL_VERSION); + } + + ret = gf_asprintf (&process_uuid_xl, "%s-%s", this->ctx->process_uuid, + this->name); + if (-1 == ret) { + gf_log (this->name, GF_LOG_ERROR, + "asprintf failed while setting process_uuid"); + goto fail; + } + ret = dict_set_dynstr (options, "process-uuid", + process_uuid_xl); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to set process-uuid(%s) in handshake msg", + process_uuid_xl); + } + + if (this->ctx->cmd_args.volfile_server) { + if (this->ctx->cmd_args.volfile_id) + ret = dict_set_str (options, "volfile-key", + this->ctx->cmd_args.volfile_id); + ret = dict_set_uint32 (options, "volfile-checksum", + this->graph->volfile_checksum); + } + + dict_len = dict_serialized_length (options); + if (dict_len < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "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_DEBUG, + "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) + GF_FREE (hdr); + return ret; +} + + +int +protocol_client_pollout (xlator_t *this, transport_t *trans) +{ + client_conf_t *conf = NULL; + + conf = trans->xl->private; + + pthread_mutex_lock (&conf->mutex); + { + gettimeofday (&conf->last_sent, NULL); + } + pthread_mutex_unlock (&conf->mutex); + + return 0; +} + + +int +protocol_client_pollin (xlator_t *this, transport_t *trans) +{ + client_conf_t *conf = NULL; + int ret = -1; + struct iobuf *iobuf = NULL; + char *hdr = NULL; + size_t hdrlen = 0; + + conf = trans->xl->private; + + pthread_mutex_lock (&conf->mutex); + { + gettimeofday (&conf->last_received, NULL); + } + pthread_mutex_unlock (&conf->mutex); + + ret = transport_receive (trans, &hdr, &hdrlen, &iobuf); + + if (ret == 0) + { + ret = protocol_client_interpret (this, trans, hdr, hdrlen, + iobuf); + } + + /* TODO: use mem-pool */ + GF_FREE (hdr); + + return ret; +} + +int +client_priv_dump (xlator_t *this) +{ + client_conf_t *conf = NULL; + int ret = -1; + client_fd_ctx_t *tmp = NULL; + int i = 0; + char key[GF_DUMP_MAX_BUF_LEN]; + char key_prefix[GF_DUMP_MAX_BUF_LEN]; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + ret = pthread_mutex_trylock(&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to lock client %s" + " errno: %d", this->name, errno); + return -1; + } + + gf_proc_dump_build_key(key_prefix, "xlator.protocol.client", + "%s.priv", this->name); + + gf_proc_dump_add_section(key_prefix); + + list_for_each_entry(tmp, &conf->saved_fds, sfd_pos) { + gf_proc_dump_build_key(key, key_prefix, + "fd.%d.remote_fd", ++i); + gf_proc_dump_write(key, "%d", tmp->remote_fd); + } + + gf_proc_dump_build_key(key, key_prefix, "connecting"); + gf_proc_dump_write(key, "%d", conf->connecting); + gf_proc_dump_build_key(key, key_prefix, "last_sent"); + gf_proc_dump_write(key, "%s", ctime(&conf->last_sent.tv_sec)); + gf_proc_dump_build_key(key, key_prefix, "last_received"); + gf_proc_dump_write(key, "%s", ctime(&conf->last_received.tv_sec)); + + pthread_mutex_unlock(&conf->mutex); + + return 0; + +} + +int32_t +client_inodectx_dump (xlator_t *this, inode_t *inode) +{ + ino_t par = 0; + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!inode) + return -1; + + if (!this) + return -1; + + ret = inode_ctx_get (inode, this, &par); + + if (ret != 0) + return ret; + + gf_proc_dump_build_key(key, "xlator.protocol.client", + "%s.inode.%ld.par", + this->name,inode->ino); + gf_proc_dump_write(key, "%ld", par); + + return 0; +} + +/* + * client_protocol_notify - notify function for client protocol + * @this: + * @trans: transport object + * @event + * + */ + +int +notify (xlator_t *this, int32_t event, void *data, ...) +{ + int i = 0; + int ret = -1; + int child_down = 1; + int was_not_down = 0; + transport_t *trans = NULL; + client_connection_t *conn = NULL; + client_conf_t *conf = NULL; + xlator_list_t *parent = NULL; + + conf = this->private; + 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); + + if (conf->connecting == 0) { + /* 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; + } + conf->connecting = 1; + } + + was_not_down = 0; + for (i = 0; i < CHANNEL_MAX; i++) { + conn = conf->transport[i]->xl_private; + if (conn->connected == 1) + was_not_down = 1; + } + + conn = trans->xl_private; + if (conn->connected) { + conn->connected = 0; + if (conn->reconnect == 0) + client_protocol_reconnect (trans); + } + + child_down = 1; + for (i = 0; i < CHANNEL_MAX; i++) { + trans = conf->transport[i]; + conn = trans->xl_private; + if (conn->connected == 1) + child_down = 0; + } + + if (child_down && was_not_down) { + gf_log (this->name, GF_LOG_INFO, "disconnected"); + + protocol_client_mark_fd_bad (this); + + parent = this->parents; + while (parent) { + xlator_notify (parent->xlator, + GF_EVENT_CHILD_DOWN, this); + parent = parent->next; + } + } + } + break; + + case GF_EVENT_PARENT_UP: + { + 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); + } + } + 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, + .truncate = client_truncate, + .open = client_open, + .readv = client_readv, + .writev = client_writev, + .statfs = client_statfs, + .flush = client_flush, + .fsync = client_fsync, + .setxattr = client_setxattr, + .getxattr = client_getxattr, + .fsetxattr = client_fsetxattr, + .fgetxattr = client_fgetxattr, + .removexattr = client_removexattr, + .opendir = client_opendir, + .readdir = client_readdir, + .readdirp = client_readdirp, + .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, + .checksum = client_checksum, + .rchecksum = client_rchecksum, + .xattrop = client_xattrop, + .fxattrop = client_fxattrop, + .setattr = client_setattr, + .fsetattr = client_fsetattr, + .getspec = client_getspec, +}; + +struct xlator_cbks cbks = { + .release = client_release, + .releasedir = client_releasedir +}; + + +struct xlator_dumpops dumpops = { + .priv = client_priv_dump, + .inodectx = client_inodectx_dump, +}; + +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_INTERNET_ADDRESS + }, + { .key = {"remote-subvolume"}, + .type = GF_OPTION_TYPE_ANY + }, + { .key = {"frame-timeout"}, + .type = GF_OPTION_TYPE_TIME, + .min = 0, + .max = 86400, + }, + { .key = {"ping-timeout"}, + .type = GF_OPTION_TYPE_TIME, + .min = 1, + .max = 1013, + }, + { .key = {NULL} }, +}; |