summaryrefslogtreecommitdiffstats
path: root/xlators/protocol/client/src/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/protocol/client/src/client.c')
-rw-r--r--xlators/protocol/client/src/client.c2997
1 files changed, 2997 insertions, 0 deletions
diff --git a/xlators/protocol/client/src/client.c b/xlators/protocol/client/src/client.c
new file mode 100644
index 00000000000..0f31fea9511
--- /dev/null
+++ b/xlators/protocol/client/src/client.c
@@ -0,0 +1,2997 @@
+/*
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "client.h"
+#include <glusterfs/xlator.h>
+#include <glusterfs/defaults.h>
+#include <glusterfs/glusterfs.h>
+#include <glusterfs/statedump.h>
+#include <glusterfs/compat-errno.h>
+#include <glusterfs/gf-event.h>
+
+#include "xdr-rpc.h"
+#include "glusterfs3.h"
+#include "client-messages.h"
+
+extern rpc_clnt_prog_t clnt_handshake_prog;
+extern rpc_clnt_prog_t clnt_dump_prog;
+extern struct rpcclnt_cb_program gluster_cbk_prog;
+
+int
+client_handshake(xlator_t *this, struct rpc_clnt *rpc);
+static int
+client_destroy_rpc(xlator_t *this);
+
+static void
+client_filter_o_direct(clnt_conf_t *conf, int32_t *flags)
+{
+ if (conf->filter_o_direct)
+ *flags = (*flags & ~O_DIRECT);
+}
+
+static int
+client_fini_complete(xlator_t *this)
+{
+ GF_VALIDATE_OR_GOTO(this->name, this->private, out);
+
+ clnt_conf_t *conf = this->private;
+ if (!conf->destroy)
+ return 0;
+
+ pthread_mutex_lock(&conf->lock);
+ {
+ conf->fini_completed = _gf_true;
+ pthread_cond_broadcast(&conf->fini_complete_cond);
+ }
+ pthread_mutex_unlock(&conf->lock);
+
+out:
+ return 0;
+}
+
+static int
+client_is_last_child_down(xlator_t *this, int32_t event, struct rpc_clnt *rpc)
+{
+ rpc_clnt_connection_t *conn = NULL;
+ clnt_conf_t *conf = NULL;
+ int ret = 0;
+
+ if (!this || !rpc)
+ goto out;
+
+ conf = this->private;
+ if (!conf)
+ goto out;
+
+ if (!conf->parent_down)
+ goto out;
+
+ if (event != GF_EVENT_CHILD_DOWN)
+ goto out;
+
+ conn = &rpc->conn;
+ pthread_mutex_lock(&conn->lock);
+ {
+ if (!conn->reconnect && rpc->disabled) {
+ ret = 1;
+ }
+ }
+ pthread_mutex_unlock(&conn->lock);
+out:
+ return ret;
+}
+
+int
+client_notify_dispatch_uniq(xlator_t *this, int32_t event, void *data, ...)
+{
+ clnt_conf_t *conf = this->private;
+ glusterfs_ctx_t *ctx = this->ctx;
+ glusterfs_graph_t *graph = this->graph;
+
+ pthread_mutex_lock(&ctx->notify_lock);
+ {
+ while (ctx->notifying)
+ pthread_cond_wait(&ctx->notify_cond, &ctx->notify_lock);
+
+ if (client_is_last_child_down(this, event, data) && graph) {
+ pthread_mutex_lock(&graph->mutex);
+ {
+ graph->parent_down++;
+ if (graph->parent_down == graph_total_client_xlator(graph)) {
+ graph->used = 0;
+ pthread_cond_broadcast(&graph->child_down_cond);
+ }
+ }
+ pthread_mutex_unlock(&graph->mutex);
+ }
+ }
+ pthread_mutex_unlock(&ctx->notify_lock);
+
+ if (conf->last_sent_event == event)
+ return 0;
+
+ return client_notify_dispatch(this, event, data);
+
+ /* Please avoid any code that access xlator object here
+ * Because for a child down event, once we do the signal
+ * we will start cleanup.
+ */
+}
+
+int
+client_notify_dispatch(xlator_t *this, int32_t event, void *data, ...)
+{
+ int ret = -1;
+ glusterfs_ctx_t *ctx = this->ctx;
+
+ clnt_conf_t *conf = this->private;
+
+ pthread_mutex_lock(&ctx->notify_lock);
+ {
+ while (ctx->notifying)
+ pthread_cond_wait(&ctx->notify_cond, &ctx->notify_lock);
+ ctx->notifying = 1;
+ }
+ pthread_mutex_unlock(&ctx->notify_lock);
+
+ /* We assume that all translators in the graph handle notification
+ * events in sequence.
+ * */
+
+ ret = default_notify(this, event, data);
+
+ /* NB (Even) with MT-epoll and EPOLLET|EPOLLONESHOT we are guaranteed
+ * that there would be atmost one poller thread executing this
+ * notification function. This allows us to update last_sent_event
+ * without explicit synchronization. See epoll(7).
+ */
+ conf->last_sent_event = event;
+
+ pthread_mutex_lock(&ctx->notify_lock);
+ {
+ ctx->notifying = 0;
+ pthread_cond_signal(&ctx->notify_cond);
+ }
+ pthread_mutex_unlock(&ctx->notify_lock);
+
+ /* Please avoid any code that access xlator object here
+ * Because for a child down event, once we do the signal
+ * we will start cleanup.
+ */
+
+ return ret;
+}
+
+int
+client_submit_request(xlator_t *this, void *req, call_frame_t *frame,
+ rpc_clnt_prog_t *prog, int procnum, fop_cbk_fn_t cbkfn,
+ client_payload_t *cp, xdrproc_t xdrproc)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ struct iovec iov = {
+ 0,
+ };
+ struct iobuf *iobuf = NULL;
+ int count = 0;
+ struct iobref *new_iobref = NULL;
+ ssize_t xdr_size = 0;
+ struct rpc_req rpcreq = {
+ 0,
+ };
+
+ GF_VALIDATE_OR_GOTO("client", this, out);
+ GF_VALIDATE_OR_GOTO(this->name, prog, out);
+ GF_VALIDATE_OR_GOTO(this->name, frame, out);
+
+ conf = this->private;
+
+ /* If 'setvolume' is not successful, we should not send frames to
+ server, mean time we should be able to send 'DUMP' and 'SETVOLUME'
+ call itself even if its not connected */
+ if (!(conf->connected || ((prog->prognum == GLUSTER_DUMP_PROGRAM) ||
+ (prog->prognum == GLUSTER_PMAP_PROGRAM) ||
+ ((prog->prognum == GLUSTER_HNDSK_PROGRAM) &&
+ (procnum == GF_HNDSK_SETVOLUME))))) {
+ /* This particular error captured/logged in
+ functions calling this */
+ gf_msg_debug(this->name, 0, "connection in disconnected state");
+ goto out;
+ }
+
+ if (req && xdrproc) {
+ xdr_size = xdr_sizeof(xdrproc, req);
+ iobuf = iobuf_get2(this->ctx->iobuf_pool, xdr_size);
+ if (!iobuf) {
+ goto out;
+ }
+
+ new_iobref = iobref_new();
+ if (!new_iobref) {
+ goto out;
+ }
+
+ if (cp && cp->iobref != NULL) {
+ ret = iobref_merge(new_iobref, cp->iobref);
+ if (ret != 0) {
+ gf_smsg(this->name, GF_LOG_WARNING, ENOMEM,
+ PC_MSG_MERGE_IOBREF_FAILED, NULL);
+ }
+ }
+
+ ret = iobref_add(new_iobref, iobuf);
+ if (ret != 0) {
+ gf_smsg(this->name, GF_LOG_WARNING, ENOMEM, PC_MSG_ADD_IOBUF_FAILED,
+ NULL);
+ goto out;
+ }
+
+ iov.iov_base = iobuf->ptr;
+ iov.iov_len = iobuf_size(iobuf);
+
+ /* Create the xdr payload */
+ ret = xdr_serialize_generic(iov, req, xdrproc);
+ if (ret == -1) {
+ /* callingfn so that, we can get to know which xdr
+ function was called */
+ gf_log_callingfn(this->name, GF_LOG_WARNING,
+ "XDR payload creation failed");
+ goto out;
+ }
+ iov.iov_len = ret;
+ count = 1;
+ }
+
+ /* do not send all groups if they are resolved server-side */
+ if (!conf->send_gids) {
+ if (frame->root->ngrps <= SMALL_GROUP_COUNT) {
+ frame->root->groups_small[0] = frame->root->gid;
+ frame->root->groups = frame->root->groups_small;
+ }
+ frame->root->ngrps = 1;
+ }
+
+ /* Send the msg */
+ if (cp) {
+ ret = rpc_clnt_submit(conf->rpc, prog, procnum, cbkfn, &iov, count,
+ cp->payload, cp->payload_cnt, new_iobref, frame,
+ cp->rsphdr, cp->rsphdr_cnt, cp->rsp_payload,
+ cp->rsp_payload_cnt, cp->rsp_iobref);
+ } else {
+ ret = rpc_clnt_submit(conf->rpc, prog, procnum, cbkfn, &iov, count,
+ NULL, 0, new_iobref, frame, NULL, 0, NULL, 0,
+ NULL);
+ }
+
+ if (ret < 0) {
+ gf_msg_debug(this->name, 0, "rpc_clnt_submit failed");
+ }
+
+ ret = 0;
+
+ if (new_iobref)
+ iobref_unref(new_iobref);
+
+ if (iobuf)
+ iobuf_unref(iobuf);
+
+ return ret;
+
+out:
+ rpcreq.rpc_status = -1;
+
+ cbkfn(&rpcreq, NULL, 0, frame);
+
+ if (new_iobref)
+ iobref_unref(new_iobref);
+
+ if (iobuf)
+ iobuf_unref(iobuf);
+
+ return ret;
+}
+
+static int32_t
+client_forget(xlator_t *this, inode_t *inode)
+{
+ /* Nothing here */
+ return 0;
+}
+
+static int32_t
+client_releasedir(xlator_t *this, fd_t *fd)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_RELEASEDIR];
+ if (proc->fn) {
+ args.fd = fd;
+ ret = proc->fn(NULL, this, &args);
+ }
+out:
+ if (ret)
+ gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_RELEASE_DIR_OP_FAILED,
+ NULL);
+ return 0;
+}
+
+static int32_t
+client_release(xlator_t *this, fd_t *fd)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_RELEASE];
+ if (proc->fn) {
+ args.fd = fd;
+ ret = proc->fn(NULL, this, &args);
+ }
+out:
+ if (ret)
+ gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_FILE_OP_FAILED, NULL);
+ return 0;
+}
+
+static int32_t
+client_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_LOOKUP];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ /* think of avoiding a missing frame */
+ if (ret)
+ STACK_UNWIND_STRICT(lookup, frame, -1, ENOTCONN, NULL, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static int32_t
+client_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_STAT];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(stat, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_TRUNCATE];
+ if (proc->fn) {
+ args.loc = loc;
+ args.offset = offset;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(truncate, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FTRUNCATE];
+ if (proc->fn) {
+ args.fd = fd;
+ args.offset = offset;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(ftruncate, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_access(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_ACCESS];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mask = mask;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(access, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_readlink(call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_READLINK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.size = size;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(readlink, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int
+client_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
+ dev_t rdev, mode_t umask, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_MKNOD];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mode = mode;
+ args.rdev = rdev;
+ args.umask = umask;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(mknod, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static int
+client_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
+ mode_t umask, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_MKDIR];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mode = mode;
+ args.umask = umask;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(mkdir, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static int32_t
+client_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_UNLINK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ args.flags = xflag;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(unlink, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int flags,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_RMDIR];
+ if (proc->fn) {
+ args.loc = loc;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ /* think of avoiding a missing frame */
+ if (ret)
+ STACK_UNWIND_STRICT(rmdir, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int
+client_symlink(call_frame_t *frame, xlator_t *this, const char *linkpath,
+ loc_t *loc, mode_t umask, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_SYMLINK];
+ if (proc->fn) {
+ args.linkname = linkpath;
+ args.loc = loc;
+ args.umask = umask;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(symlink, frame, -1, ENOTCONN, NULL, NULL, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_RENAME];
+ if (proc->fn) {
+ args.oldloc = oldloc;
+ args.newloc = newloc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(rename, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_LINK];
+ if (proc->fn) {
+ args.oldloc = oldloc;
+ args.newloc = newloc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(link, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static int32_t
+client_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
+ mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_CREATE];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mode = mode;
+ args.fd = fd;
+ args.umask = umask;
+ args.xdata = xdata;
+ args.flags = flags;
+ client_filter_o_direct(conf, &args.flags);
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(create, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
+ fd_t *fd, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_OPEN];
+ if (proc->fn) {
+ args.loc = loc;
+ args.fd = fd;
+ args.xdata = xdata;
+ args.flags = flags;
+ client_filter_o_direct(conf, &args.flags);
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(open, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t offset, uint32_t flags, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_READ];
+ if (proc->fn) {
+ args.fd = fd;
+ args.size = size;
+ args.offset = offset;
+ args.flags = flags;
+ args.xdata = xdata;
+ client_filter_o_direct(conf, &args.flags);
+
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(readv, frame, -1, ENOTCONN, NULL, 0, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static int32_t
+client_writev(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ struct iovec *vector, int32_t count, off_t off, uint32_t flags,
+ struct iobref *iobref, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_WRITE];
+ if (proc->fn) {
+ args.fd = fd;
+ args.vector = vector;
+ args.count = count;
+ args.offset = off;
+ args.size = iov_length(vector, count);
+ args.flags = flags;
+ args.iobref = iobref;
+ args.xdata = xdata;
+ client_filter_o_direct(conf, &args.flags);
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(writev, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_flush(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FLUSH];
+ if (proc->fn) {
+ args.fd = fd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(flush, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fsync(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FSYNC];
+ if (proc->fn) {
+ args.fd = fd;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fsync, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fstat(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FSTAT];
+ if (proc->fn) {
+ args.fd = fd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fstat, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_opendir(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_OPENDIR];
+ if (proc->fn) {
+ args.loc = loc;
+ args.fd = fd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(opendir, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+int32_t
+client_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FSYNCDIR];
+ if (proc->fn) {
+ args.fd = fd;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fsyncdir, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_statfs(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_STATFS];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(statfs, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_copy_file_range(call_frame_t *frame, xlator_t *this, fd_t *fd_in,
+ off_t off_in, fd_t *fd_out, off_t off_out, size_t len,
+ uint32_t flags, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_COPY_FILE_RANGE];
+ if (proc->fn) {
+ args.fd = fd_in;
+ args.fd_out = fd_out;
+ args.offset = off_in;
+ args.off_out = off_out;
+ args.size = len;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(copy_file_range, frame, -1, ENOTCONN, NULL, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
+static gf_boolean_t
+is_client_rpc_init_command(dict_t *dict, xlator_t *this, char **value)
+{
+ gf_boolean_t ret = _gf_false;
+
+ int dict_ret = dict_get_str_sizen(dict, CLIENT_CMD_CONNECT, value);
+ if (dict_ret) {
+ gf_msg_trace(this->name, 0, "key %s not present", CLIENT_CMD_CONNECT);
+ goto out;
+ }
+
+ ret = _gf_true;
+
+out:
+ return ret;
+}
+
+static gf_boolean_t
+is_client_rpc_destroy_command(dict_t *dict, xlator_t *this)
+{
+ gf_boolean_t ret = _gf_false;
+ int dict_ret = -1;
+ char *dummy = NULL;
+
+ if (strncmp(this->name, "replace-brick", 13)) {
+ gf_msg_trace(this->name, 0, "name is !replace-brick");
+ goto out;
+ }
+
+ dict_ret = dict_get_str_sizen(dict, CLIENT_CMD_DISCONNECT, &dummy);
+ if (dict_ret) {
+ gf_msg_trace(this->name, 0, "key %s not present",
+ CLIENT_CMD_DISCONNECT);
+ goto out;
+ }
+
+ ret = _gf_true;
+
+out:
+ return ret;
+}
+
+static int
+client_set_remote_options(char *value, xlator_t *this)
+{
+ char *dup_value = NULL;
+ char *host = NULL;
+ char *subvol = NULL;
+ char *host_dup = NULL;
+ char *subvol_dup = NULL;
+ char *remote_port_str = NULL;
+ char *tmp = NULL;
+ int remote_port = 0;
+ int ret = -1;
+
+ dup_value = gf_strdup(value);
+ if (dup_value == NULL) {
+ goto out;
+ }
+ host = strtok_r(dup_value, ":", &tmp);
+ subvol = strtok_r(NULL, ":", &tmp);
+ remote_port_str = strtok_r(NULL, ":", &tmp);
+
+ if (host) {
+ host_dup = gf_strdup(host);
+ if (!host_dup) {
+ goto out;
+ }
+ ret = dict_set_dynstr_sizen(this->options, "remote-host", host_dup);
+ if (ret) {
+ gf_smsg(this->name, GF_LOG_WARNING, 0,
+ PC_MSG_REMOTE_HOST_SET_FAILED, "host=%s", host, NULL);
+ GF_FREE(host_dup);
+ goto out;
+ }
+ }
+
+ if (subvol) {
+ subvol_dup = gf_strdup(subvol);
+ if (!subvol_dup) {
+ goto out;
+ }
+
+ ret = dict_set_dynstr_sizen(this->options, "remote-subvolume",
+ subvol_dup);
+ if (ret) {
+ gf_smsg(this->name, GF_LOG_WARNING, 0,
+ PC_MSG_REMOTE_HOST_SET_FAILED, "host=%s", host, NULL);
+ GF_FREE(subvol_dup);
+ goto out;
+ }
+ }
+
+ if (remote_port_str) {
+ remote_port = atoi(remote_port_str);
+
+ ret = dict_set_int32_sizen(this->options, "remote-port", remote_port);
+ if (ret) {
+ gf_smsg(this->name, GF_LOG_ERROR, 0, PC_MSG_REMOTE_PORT_SET_FAILED,
+ "remote-port=%d", remote_port, NULL);
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ GF_FREE(dup_value);
+
+ return ret;
+}
+
+static int32_t
+client_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,
+ int32_t flags, dict_t *xdata)
+{
+ int ret = -1;
+ int op_ret = -1;
+ int op_errno = ENOTCONN;
+ int need_unwind = 0;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+ char *value = NULL;
+
+ if (is_client_rpc_init_command(dict, this, &value) == _gf_true) {
+ GF_ASSERT(value);
+ gf_smsg(this->name, GF_LOG_INFO, 0, PC_MSG_RPC_INIT, NULL);
+ ret = client_set_remote_options(value, this);
+ if (!ret) {
+ op_ret = 0;
+ op_errno = 0;
+ }
+ need_unwind = 1;
+ goto out;
+ }
+
+ if (is_client_rpc_destroy_command(dict, this) == _gf_true) {
+ gf_smsg(this->name, GF_LOG_INFO, 0, PC_MSG_RPC_DESTROY, NULL);
+ ret = client_destroy_rpc(this);
+ if (ret) {
+ op_ret = 0;
+ op_errno = 0;
+ }
+ need_unwind = 1;
+ goto out;
+ }
+
+ conf = this->private;
+ if (!conf || !conf->fops) {
+ op_errno = ENOTCONN;
+ need_unwind = 1;
+ goto out;
+ }
+
+ proc = &conf->fops->proctable[GF_FOP_SETXATTR];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xattr = dict;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ if (ret) {
+ need_unwind = 1;
+ }
+ }
+out:
+ if (need_unwind)
+ STACK_UNWIND_STRICT(setxattr, frame, op_ret, op_errno, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict,
+ int32_t flags, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FSETXATTR];
+ if (proc->fn) {
+ args.fd = fd;
+ args.xattr = dict;
+ args.flags = flags;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fsetxattr, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fgetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ const char *name, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FGETXATTR];
+ if (proc->fn) {
+ args.fd = fd;
+ args.name = name;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fgetxattr, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_getxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ const char *name, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_GETXATTR];
+ if (proc->fn) {
+ args.name = name;
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(getxattr, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_xattrop(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_XATTROP];
+ if (proc->fn) {
+ args.loc = loc;
+ args.flags = flags;
+ args.xattr = dict;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(xattrop, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fxattrop(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FXATTROP];
+ if (proc->fn) {
+ args.fd = fd;
+ args.flags = flags;
+ args.xattr = dict;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fxattrop, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ const char *name, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_REMOVEXATTR];
+ if (proc->fn) {
+ args.name = name;
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(removexattr, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ const char *name, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FREMOVEXATTR];
+ if (proc->fn) {
+ args.name = name;
+ args.fd = fd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fremovexattr, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_lease(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ struct gf_lease *lease, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_LEASE];
+ if (proc->fn) {
+ args.loc = loc;
+ args.lease = lease;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(lk, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd,
+ struct gf_flock *lock, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_LK];
+ if (proc->fn) {
+ args.fd = fd;
+ args.cmd = cmd;
+ args.flock = lock;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(lk, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_inodelk(call_frame_t *frame, xlator_t *this, const char *volume,
+ loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_INODELK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.cmd = cmd;
+ args.flock = lock;
+ args.volume = volume;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(inodelk, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_finodelk(call_frame_t *frame, xlator_t *this, const char *volume,
+ fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FINODELK];
+ if (proc->fn) {
+ args.fd = fd;
+ args.cmd = cmd;
+ args.flock = lock;
+ args.volume = volume;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(finodelk, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_entrylk(call_frame_t *frame, xlator_t *this, const char *volume,
+ loc_t *loc, const char *basename, entrylk_cmd cmd,
+ entrylk_type type, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_ENTRYLK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.basename = basename;
+ args.type = type;
+ args.volume = volume;
+ args.cmd_entrylk = cmd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(entrylk, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fentrylk(call_frame_t *frame, xlator_t *this, const char *volume,
+ fd_t *fd, const char *basename, entrylk_cmd cmd,
+ entrylk_type type, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FENTRYLK];
+ if (proc->fn) {
+ args.fd = fd;
+ args.basename = basename;
+ args.type = type;
+ args.volume = volume;
+ args.cmd_entrylk = cmd;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fentrylk, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_rchecksum(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ int32_t len, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_RCHECKSUM];
+ if (proc->fn) {
+ args.fd = fd;
+ args.offset = offset;
+ args.len = len;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(rchecksum, frame, -1, ENOTCONN, 0, NULL, NULL);
+
+ return 0;
+}
+
+int32_t
+client_readdir(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t off, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_READDIR];
+ if (proc->fn) {
+ if (off != 0)
+ off = gf_dirent_orig_offset(this, off);
+
+ args.fd = fd;
+ args.size = size;
+ args.offset = off;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(readdir, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
+ off_t off, dict_t *dict)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_READDIRP];
+ if (proc->fn) {
+ if (off != 0)
+ off = gf_dirent_orig_offset(this, off);
+
+ args.fd = fd;
+ args.size = size;
+ args.offset = off;
+ args.xdata = dict;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(readdirp, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ struct iatt *stbuf, int32_t valid, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_SETATTR];
+ if (proc->fn) {
+ args.loc = loc;
+ args.stbuf = stbuf;
+ args.valid = valid;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(setattr, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ struct iatt *stbuf, int32_t valid, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FSETATTR];
+ if (proc->fn) {
+ args.fd = fd;
+ args.stbuf = stbuf;
+ args.valid = valid;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fsetattr, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_FALLOCATE];
+ if (proc->fn) {
+ args.fd = fd;
+ args.flags = mode;
+ args.offset = offset;
+ args.size = len;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(fallocate, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ size_t len, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_DISCARD];
+ if (proc->fn) {
+ args.fd = fd;
+ args.offset = offset;
+ args.size = len;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(discard, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ off_t len, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_ZEROFILL];
+ if (proc->fn) {
+ args.fd = fd;
+ args.offset = offset;
+ args.size = len;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(zerofill, frame, -1, ENOTCONN, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_ipc(call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_IPC];
+ if (proc->fn) {
+ args.cmd = op;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(ipc, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_seek(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ gf_seek_what_t what, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_SEEK];
+ if (proc->fn) {
+ args.fd = fd;
+ args.offset = offset;
+ args.what = what;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(seek, frame, -1, ENOTCONN, 0, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_getactivelk(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_GETACTIVELK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(getactivelk, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_setactivelk(call_frame_t *frame, xlator_t *this, loc_t *loc,
+ lock_migration_info_t *locklist, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_SETACTIVELK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ args.locklist = locklist;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(setactivelk, frame, -1, ENOTCONN, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_getspec(call_frame_t *frame, xlator_t *this, const char *key,
+ int32_t flags)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops || !conf->handshake)
+ goto out;
+
+ /* For all other xlators, getspec is an fop, hence its in fops table */
+ proc = &conf->fops->proctable[GF_FOP_GETSPEC];
+ if (proc->fn) {
+ args.name = key;
+ args.flags = flags;
+ /* But at protocol level, this is handshake */
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(getspec, frame, -1, EINVAL, NULL);
+
+ return 0;
+}
+
+static int32_t
+client_compound(call_frame_t *frame, xlator_t *this, void *data, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ compound_args_t *args = data;
+ rpc_clnt_procedure_t *proc = NULL;
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_COMPOUND];
+ if (proc->fn) {
+ args->xdata = xdata;
+ ret = proc->fn(frame, this, args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(compound, frame, -1, ENOTCONN, NULL, NULL);
+
+ return 0;
+}
+
+int32_t
+client_namelink(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
+{
+ int32_t ret = -1;
+ clnt_conf_t *conf = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+ rpc_clnt_procedure_t *proc = NULL;
+
+ conf = this->private;
+ if (!conf || !conf->fops || !conf->handshake)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_NAMELINK];
+ if (proc->fn) {
+ args.loc = loc;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(namelink, frame, -1, EINVAL, NULL, NULL, NULL);
+ return 0;
+}
+
+static int32_t
+client_icreate(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
+ dict_t *xdata)
+{
+ int32_t ret = -1;
+ clnt_conf_t *conf = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+ rpc_clnt_procedure_t *proc = NULL;
+
+ conf = this->private;
+ if (!conf || !conf->fops || !conf->handshake)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_ICREATE];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mode = mode;
+ args.xdata = xdata;
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(icreate, frame, -1, EINVAL, NULL, NULL, NULL);
+ return 0;
+}
+
+static int32_t
+client_put(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
+ mode_t umask, uint32_t flags, struct iovec *vector, int32_t count,
+ off_t off, struct iobref *iobref, dict_t *xattr, dict_t *xdata)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ clnt_args_t args = {
+ 0,
+ };
+
+ conf = this->private;
+ if (!conf || !conf->fops)
+ goto out;
+
+ proc = &conf->fops->proctable[GF_FOP_PUT];
+ if (proc->fn) {
+ args.loc = loc;
+ args.mode = mode;
+ args.umask = umask;
+ args.flags = flags;
+ args.vector = vector;
+ args.count = count;
+ args.offset = off;
+ args.size = iov_length(vector, count);
+ args.iobref = iobref;
+ args.xattr = xattr;
+ args.xdata = xdata;
+
+ client_filter_o_direct(conf, &args.flags);
+ ret = proc->fn(frame, this, &args);
+ }
+out:
+ if (ret)
+ STACK_UNWIND_STRICT(put, frame, -1, ENOTCONN, NULL, NULL, NULL, NULL,
+ NULL);
+
+ return 0;
+}
+
+static void
+client_mark_fd_bad(xlator_t *this)
+{
+ clnt_conf_t *conf = this->private;
+ clnt_fd_ctx_t *tmp = NULL, *fdctx = NULL;
+
+ pthread_spin_lock(&conf->fd_lock);
+ {
+ list_for_each_entry_safe(fdctx, tmp, &conf->saved_fds, sfd_pos)
+ {
+ fdctx->remote_fd = -1;
+ }
+ }
+ pthread_spin_unlock(&conf->fd_lock);
+}
+
+int
+client_rpc_notify(struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event,
+ void *data)
+{
+ xlator_t *this = NULL;
+ clnt_conf_t *conf = NULL;
+ gf_boolean_t is_parent_down = _gf_false;
+ int ret = 0;
+
+ this = mydata;
+ if (!this || !this->private) {
+ gf_smsg("client", GF_LOG_ERROR, EINVAL, PC_MSG_XLATOR_NULL,
+ (this != NULL) ? "private structue" : "", NULL);
+ goto out;
+ }
+
+ conf = this->private;
+
+ switch (event) {
+ case RPC_CLNT_PING: {
+ if (conf->connection_to_brick) {
+ ret = default_notify(this, GF_EVENT_CHILD_PING, data);
+ if (ret)
+ gf_log(this->name, GF_LOG_INFO, "CHILD_PING notify failed");
+ conf->last_sent_event = GF_EVENT_CHILD_PING;
+ }
+ break;
+ }
+ case RPC_CLNT_CONNECT: {
+ conf->can_log_disconnect = 1;
+ // connect happened, send 'get_supported_versions' mop
+
+ gf_msg_debug(this->name, 0, "got RPC_CLNT_CONNECT");
+
+ ret = client_handshake(this, rpc);
+ if (ret)
+ gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_HANDSHAKE_RETURN,
+ "ret=%d", ret, NULL);
+ break;
+ }
+ case RPC_CLNT_DISCONNECT:
+ gf_msg_debug(this->name, 0, "got RPC_CLNT_DISCONNECT");
+
+ client_mark_fd_bad(this);
+
+ if (!conf->skip_notify) {
+ if (conf->can_log_disconnect) {
+ if (!conf->disconnect_err_logged) {
+ gf_smsg(this->name, GF_LOG_INFO, 0,
+ PC_MSG_CLIENT_DISCONNECTED, "conn-name=%s",
+ conf->rpc->conn.name, NULL);
+ } else {
+ gf_msg_debug(this->name, 0,
+ "disconnected from %s. "
+ "Client process will keep"
+ " trying to connect to "
+ "glusterd until brick's "
+ "port is available",
+ conf->rpc->conn.name);
+ }
+ if (conf->portmap_err_logged)
+ conf->disconnect_err_logged = 1;
+ }
+ /*
+ * Once we complete the child down notification,
+ * There is a chance that the graph might get freed,
+ * So it is not safe to access any xlator contens
+ * So here we are checking whether the parent is down
+ * or not.
+ */
+ pthread_mutex_lock(&conf->lock);
+ {
+ is_parent_down = conf->parent_down;
+ }
+ pthread_mutex_unlock(&conf->lock);
+
+ /* If the CHILD_DOWN event goes to parent xlator
+ multiple times, the logic of parent xlator notify
+ may get screwed up.. (eg. CHILD_MODIFIED event in
+ replicate), hence make sure events which are passed
+ to parent are genuine */
+ ret = client_notify_dispatch_uniq(this, GF_EVENT_CHILD_DOWN,
+ rpc);
+ if (is_parent_down) {
+ /* If parent is down, then there should not be any
+ * operation after a child down.
+ */
+ goto out;
+ }
+ if (ret)
+ gf_smsg(this->name, GF_LOG_INFO, 0,
+ PC_MSG_CHILD_DOWN_NOTIFY_FAILED, NULL);
+
+ } else {
+ if (conf->can_log_disconnect)
+ gf_msg_debug(this->name, 0,
+ "disconnected (skipped notify)");
+ }
+
+ conf->connected = 0;
+ conf->can_log_disconnect = 0;
+ conf->skip_notify = 0;
+
+ if (conf->quick_reconnect) {
+ conf->connection_to_brick = _gf_true;
+ conf->quick_reconnect = 0;
+ rpc_clnt_cleanup_and_start(rpc);
+
+ } else {
+ rpc->conn.config.remote_port = 0;
+ conf->connection_to_brick = _gf_false;
+ }
+ break;
+ case RPC_CLNT_DESTROY:
+ ret = client_fini_complete(this);
+ break;
+
+ default:
+ gf_msg_trace(this->name, 0, "got some other RPC event %d", event);
+
+ break;
+ }
+
+out:
+ return 0;
+}
+
+int
+notify(xlator_t *this, int32_t event, void *data, ...)
+{
+ clnt_conf_t *conf = NULL;
+ glusterfs_graph_t *graph = this->graph;
+ int ret = -1;
+
+ conf = this->private;
+ if (!conf)
+ return 0;
+
+ switch (event) {
+ case GF_EVENT_PARENT_UP: {
+ gf_smsg(this->name, GF_LOG_INFO, 0, PC_MSG_PARENT_UP, NULL);
+
+ rpc_clnt_start(conf->rpc);
+ break;
+ }
+
+ case GF_EVENT_PARENT_DOWN:
+ gf_smsg(this->name, GF_LOG_INFO, 0, PC_MSG_PARENT_DOWN, NULL);
+
+ pthread_mutex_lock(&conf->lock);
+ {
+ conf->parent_down = 1;
+ }
+ pthread_mutex_unlock(&conf->lock);
+
+ ret = rpc_clnt_disable(conf->rpc);
+ if (ret == -1 && graph) {
+ pthread_mutex_lock(&graph->mutex);
+ {
+ graph->parent_down++;
+ if (graph->parent_down ==
+ graph_total_client_xlator(graph)) {
+ graph->used = 0;
+ pthread_cond_broadcast(&graph->child_down_cond);
+ }
+ }
+ pthread_mutex_unlock(&graph->mutex);
+ }
+ break;
+
+ default:
+ gf_msg_debug(this->name, 0, "got %d, calling default_notify ()",
+ event);
+
+ default_notify(this, event, data);
+ conf->last_sent_event = event;
+ break;
+ }
+
+ return 0;
+}
+
+static int
+client_check_remote_host(xlator_t *this, dict_t *options)
+{
+ char *remote_host = NULL;
+ int ret = -1;
+
+ ret = dict_get_str_sizen(options, "remote-host", &remote_host);
+ if (ret < 0) {
+ gf_smsg(this->name, GF_LOG_INFO, EINVAL, PC_MSG_REMOTE_HOST_NOT_SET,
+ NULL);
+
+ if (!this->ctx->cmd_args.volfile_server) {
+ gf_smsg(this->name, GF_LOG_ERROR, EINVAL, PC_MSG_NOREMOTE_HOST,
+ NULL);
+ goto out;
+ }
+
+ ret = dict_set_str_sizen(options, "remote-host",
+ this->ctx->cmd_args.volfile_server);
+ if (ret == -1) {
+ gf_smsg(this->name, GF_LOG_ERROR, 0, PC_MSG_REMOTE_HOST_SET_FAILED,
+ NULL);
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int
+build_client_config(xlator_t *this, clnt_conf_t *conf)
+{
+ int ret = -1;
+
+ GF_OPTION_INIT("frame-timeout", conf->rpc_conf.rpc_timeout, int32, out);
+
+ GF_OPTION_INIT("remote-port", conf->rpc_conf.remote_port, int32, out);
+
+ GF_OPTION_INIT("ping-timeout", conf->opt.ping_timeout, int32, out);
+
+ GF_OPTION_INIT("remote-subvolume", conf->opt.remote_subvolume, path, out);
+ if (!conf->opt.remote_subvolume)
+ gf_smsg(this->name, GF_LOG_WARNING, EINVAL,
+ PC_MSG_REMOTE_SUBVOL_NOT_GIVEN, NULL);
+
+ GF_OPTION_INIT("filter-O_DIRECT", conf->filter_o_direct, bool, out);
+
+ GF_OPTION_INIT("send-gids", conf->send_gids, bool, out);
+
+ GF_OPTION_INIT("testing.old-protocol", conf->old_protocol, bool, out);
+ GF_OPTION_INIT("strict-locks", conf->strict_locks, bool, out);
+
+ conf->client_id = glusterfs_leaf_position(this);
+
+ ret = client_check_remote_host(this, this->options);
+ if (ret)
+ goto out;
+
+ ret = 0;
+out:
+ 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_smsg(this->name, GF_LOG_ERROR, ENOMEM, PC_MSG_NO_MEMORY, NULL);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int
+client_destroy_rpc(xlator_t *this)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+
+ conf = this->private;
+ if (!conf)
+ goto out;
+
+ if (conf->rpc) {
+ /* cleanup the saved-frames before last unref */
+ rpc_clnt_connection_cleanup(&conf->rpc->conn);
+
+ conf->rpc = rpc_clnt_unref(conf->rpc);
+ ret = 0;
+ gf_msg_debug(this->name, 0, "Client rpc conn destroyed");
+ goto out;
+ }
+
+ gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_RPC_INVALID_CALL, NULL);
+
+out:
+ return ret;
+}
+
+static int
+client_init_rpc(xlator_t *this)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+
+ conf = this->private;
+
+ if (conf->rpc) {
+ gf_smsg(this->name, GF_LOG_WARNING, 0, PC_MSG_RPC_INITED_ALREADY, NULL);
+ ret = -1;
+ goto out;
+ }
+
+ conf->rpc = rpc_clnt_new(this->options, this, this->name, 0);
+ if (!conf->rpc) {
+ gf_smsg(this->name, GF_LOG_ERROR, 0, PC_MSG_RPC_INIT_FAILED, NULL);
+ goto out;
+ }
+
+ ret = rpc_clnt_register_notify(conf->rpc, client_rpc_notify, this);
+ if (ret) {
+ gf_smsg(this->name, GF_LOG_ERROR, 0, PC_MSG_RPC_NOTIFY_FAILED, NULL);
+ goto out;
+ }
+
+ conf->handshake = &clnt_handshake_prog;
+ conf->dump = &clnt_dump_prog;
+
+ ret = rpcclnt_cbk_program_register(conf->rpc, &gluster_cbk_prog, this);
+ if (ret) {
+ gf_smsg(this->name, GF_LOG_ERROR, 0, PC_MSG_RPC_CBK_FAILED, NULL);
+ goto out;
+ }
+
+ ret = 0;
+
+ gf_msg_debug(this->name, 0, "client init successful");
+out:
+ return ret;
+}
+
+static int
+client_check_event_threads(xlator_t *this, clnt_conf_t *conf, int32_t old,
+ int32_t new)
+{
+ if (old == new)
+ return 0;
+
+ conf->event_threads = new;
+ return gf_event_reconfigure_threads(this->ctx->event_pool,
+ conf->event_threads);
+}
+
+int
+reconfigure(xlator_t *this, dict_t *options)
+{
+ clnt_conf_t *conf = NULL;
+ int ret = -1;
+ int subvol_ret = 0;
+ char *old_remote_subvol = NULL;
+ char *new_remote_subvol = NULL;
+ char *old_remote_host = NULL;
+ char *new_remote_host = NULL;
+ int32_t new_nthread = 0;
+ struct rpc_clnt_config rpc_config = {
+ 0,
+ };
+
+ conf = this->private;
+
+ GF_OPTION_RECONF("frame-timeout", conf->rpc_conf.rpc_timeout, options,
+ int32, out);
+
+ GF_OPTION_RECONF("ping-timeout", rpc_config.ping_timeout, options, int32,
+ out);
+
+ GF_OPTION_RECONF("event-threads", new_nthread, options, int32, out);
+ ret = client_check_event_threads(this, conf, conf->event_threads,
+ new_nthread);
+ if (ret)
+ goto out;
+
+ ret = client_check_remote_host(this, options);
+ if (ret)
+ goto out;
+
+ subvol_ret = dict_get_str_sizen(this->options, "remote-host",
+ &old_remote_host);
+
+ if (subvol_ret == 0) {
+ subvol_ret = dict_get_str_sizen(options, "remote-host",
+ &new_remote_host);
+ if (subvol_ret == 0) {
+ if (strcmp(old_remote_host, new_remote_host)) {
+ ret = 1;
+ goto out;
+ }
+ }
+ }
+
+ subvol_ret = dict_get_str_sizen(this->options, "remote-subvolume",
+ &old_remote_subvol);
+
+ if (subvol_ret == 0) {
+ subvol_ret = dict_get_str_sizen(options, "remote-subvolume",
+ &new_remote_subvol);
+ if (subvol_ret == 0) {
+ if (strcmp(old_remote_subvol, new_remote_subvol)) {
+ ret = 1;
+ goto out;
+ }
+ }
+ }
+
+ /* Reconfiguring client xlator's @rpc with new frame-timeout
+ * and ping-timeout */
+ rpc_clnt_reconfig(conf->rpc, &rpc_config);
+
+ GF_OPTION_RECONF("filter-O_DIRECT", conf->filter_o_direct, options, bool,
+ out);
+
+ GF_OPTION_RECONF("send-gids", conf->send_gids, options, bool, out);
+ GF_OPTION_RECONF("strict-locks", conf->strict_locks, options, bool, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int
+init(xlator_t *this)
+{
+ int ret = -1;
+ clnt_conf_t *conf = NULL;
+
+ if (this->children) {
+ gf_smsg(this->name, GF_LOG_ERROR, EINVAL, PC_MSG_FATAL_CLIENT_PROTOCOL,
+ NULL);
+ goto out;
+ }
+
+ if (!this->parents) {
+ gf_smsg(this->name, GF_LOG_WARNING, EINVAL, PC_MSG_VOL_DANGLING, NULL);
+ }
+
+ conf = GF_CALLOC(1, sizeof(*conf), gf_client_mt_clnt_conf_t);
+ if (!conf)
+ goto out;
+
+ pthread_mutex_init(&conf->lock, NULL);
+ pthread_cond_init(&conf->fini_complete_cond, NULL);
+ pthread_spin_init(&conf->fd_lock, 0);
+ INIT_LIST_HEAD(&conf->saved_fds);
+
+ conf->child_up = _gf_false;
+
+ /* Set event threads to the configured default */
+ GF_OPTION_INIT("event-threads", conf->event_threads, int32, out);
+ ret = client_check_event_threads(this, conf, STARTING_EVENT_THREADS,
+ conf->event_threads);
+ if (ret)
+ goto out;
+
+ LOCK_INIT(&conf->rec_lock);
+
+ conf->last_sent_event = -1; /* To start with we don't have any events */
+
+ this->private = conf;
+
+ /* If it returns -1, then its a failure, if it returns +1 we need
+ have to understand that 'this' is subvolume of a xlator which,
+ will set the remote host and remote subvolume in a setxattr
+ call.
+ */
+
+ ret = build_client_config(this, conf);
+ if (ret == -1)
+ goto out;
+
+ if (ret) {
+ ret = 0;
+ goto out;
+ }
+
+ this->local_pool = mem_pool_new(clnt_local_t, 64);
+ if (!this->local_pool) {
+ ret = -1;
+ gf_smsg(this->name, GF_LOG_ERROR, ENOMEM, PC_MSG_CREATE_MEM_POOL_FAILED,
+ NULL);
+ goto out;
+ }
+
+ ret = client_init_rpc(this);
+out:
+ if (ret)
+ this->fini(this);
+
+ return ret;
+}
+
+void
+fini(xlator_t *this)
+{
+ clnt_conf_t *conf = NULL;
+
+ conf = this->private;
+ if (!conf)
+ return;
+
+ conf->fini_completed = _gf_false;
+ conf->destroy = 1;
+ if (conf->rpc) {
+ /* cleanup the saved-frames before last unref */
+ rpc_clnt_connection_cleanup(&conf->rpc->conn);
+ rpc_clnt_unref(conf->rpc);
+ }
+
+ pthread_mutex_lock(&conf->lock);
+ {
+ while (!conf->fini_completed)
+ pthread_cond_wait(&conf->fini_complete_cond, &conf->lock);
+ }
+ pthread_mutex_unlock(&conf->lock);
+
+ pthread_spin_destroy(&conf->fd_lock);
+ pthread_mutex_destroy(&conf->lock);
+ pthread_cond_destroy(&conf->fini_complete_cond);
+ GF_FREE(conf);
+
+ /* Saved Fds */
+ /* TODO: */
+
+ return;
+}
+
+static void
+client_fd_lk_ctx_dump(xlator_t *this, fd_lk_ctx_t *lk_ctx, int nth_fd)
+{
+ gf_boolean_t use_try_lock = _gf_true;
+ int ret = -1;
+ int lock_no = 0;
+ fd_lk_ctx_t *lk_ctx_ref = NULL;
+ fd_lk_ctx_node_t *plock = NULL;
+ char key[GF_DUMP_MAX_BUF_LEN] = {
+ 0,
+ };
+
+ lk_ctx_ref = fd_lk_ctx_ref(lk_ctx);
+ if (!lk_ctx_ref)
+ return;
+
+ ret = client_fd_lk_list_empty(lk_ctx_ref, (use_try_lock = _gf_true));
+ if (ret != 0)
+ return;
+
+ gf_proc_dump_write("------", "------");
+
+ lock_no = 0;
+
+ ret = TRY_LOCK(&lk_ctx_ref->lock);
+ if (ret)
+ return;
+
+ list_for_each_entry(plock, &lk_ctx_ref->lk_list, next)
+ {
+ snprintf(key, sizeof(key), "granted-posix-lock[%d]", lock_no++);
+ gf_proc_dump_write(
+ key,
+ "owner = %s, cmd = %s "
+ "fl_type = %s, fl_start = %" PRId64 ", fl_end = %" PRId64
+ ", user_flock: l_type = %s, "
+ "l_start = %" PRId64 ", l_len = %" PRId64,
+ lkowner_utoa(&plock->user_flock.l_owner), get_lk_cmd(plock->cmd),
+ get_lk_type(plock->fl_type), plock->fl_start, plock->fl_end,
+ get_lk_type(plock->user_flock.l_type), plock->user_flock.l_start,
+ plock->user_flock.l_len);
+ }
+ UNLOCK(&lk_ctx_ref->lock);
+
+ gf_proc_dump_write("------", "------");
+
+ fd_lk_ctx_unref(lk_ctx_ref);
+}
+
+static int
+client_priv_dump(xlator_t *this)
+{
+ clnt_conf_t *conf = NULL;
+ int ret = -1;
+ clnt_fd_ctx_t *tmp = NULL;
+ int i = 0;
+ char key[GF_DUMP_MAX_BUF_LEN];
+ char key_prefix[GF_DUMP_MAX_BUF_LEN];
+ rpc_clnt_connection_t *conn = NULL;
+
+ if (!this)
+ return -1;
+
+ conf = this->private;
+ if (!conf)
+ return -1;
+
+ gf_proc_dump_build_key(key_prefix, "xlator.protocol.client", "%s.priv",
+ this->name);
+
+ gf_proc_dump_add_section("%s", key_prefix);
+
+ ret = pthread_mutex_trylock(&conf->lock);
+ if (ret)
+ return -1;
+
+ pthread_spin_lock(&conf->fd_lock);
+ list_for_each_entry(tmp, &conf->saved_fds, sfd_pos)
+ {
+ sprintf(key, "fd.%d.remote_fd", i);
+ gf_proc_dump_write(key, "%" PRId64, tmp->remote_fd);
+ client_fd_lk_ctx_dump(this, tmp->lk_ctx, i);
+ i++;
+ }
+ pthread_spin_unlock(&conf->fd_lock);
+
+ gf_proc_dump_write("connected", "%d", conf->connected);
+
+ if (conf->rpc) {
+ conn = &conf->rpc->conn;
+ gf_proc_dump_write("total_bytes_read", "%" PRIu64,
+ conn->trans->total_bytes_read);
+ gf_proc_dump_write("ping_timeout", "%" PRIu32, conn->ping_timeout);
+ gf_proc_dump_write("total_bytes_written", "%" PRIu64,
+ conn->trans->total_bytes_write);
+ gf_proc_dump_write("ping_msgs_sent", "%" PRIu64, conn->pingcnt);
+ gf_proc_dump_write("msgs_sent", "%" PRIu64, conn->msgcnt);
+ }
+ pthread_mutex_unlock(&conf->lock);
+
+ return 0;
+}
+
+int32_t
+client_inodectx_dump(xlator_t *this, inode_t *inode)
+{
+ if (!inode)
+ return -1;
+
+ if (!this)
+ return -1;
+
+ /*TODO*/
+
+ return 0;
+}
+
+struct xlator_cbks cbks = {.forget = client_forget,
+ .release = client_release,
+ .releasedir = client_releasedir};
+
+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,
+ .fremovexattr = client_fremovexattr,
+ .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,
+ .rchecksum = client_rchecksum,
+ .xattrop = client_xattrop,
+ .fxattrop = client_fxattrop,
+ .setattr = client_setattr,
+ .fsetattr = client_fsetattr,
+ .fallocate = client_fallocate,
+ .discard = client_discard,
+ .zerofill = client_zerofill,
+ .getspec = client_getspec,
+ .ipc = client_ipc,
+ .seek = client_seek,
+ .lease = client_lease,
+ .compound = client_compound,
+ .getactivelk = client_getactivelk,
+ .setactivelk = client_setactivelk,
+ .icreate = client_icreate,
+ .namelink = client_namelink,
+ .put = client_put,
+ .copy_file_range = client_copy_file_range,
+};
+
+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", "rdma"},
+ .type = GF_OPTION_TYPE_STR,
+ .default_value = "tcp",
+ },
+ {.key = {"remote-host"},
+ .type = GF_OPTION_TYPE_INTERNET_ADDRESS,
+ .default_value = "{{ brick.hostname }}"},
+ {
+ .key = {"remote-port"},
+ .type = GF_OPTION_TYPE_INT,
+ },
+ {.key = {"remote-subvolume"},
+ .type = GF_OPTION_TYPE_ANY,
+ .default_value = "{{ brick.path }}"},
+ {.key = {"frame-timeout", "rpc-timeout"},
+ .type = GF_OPTION_TYPE_TIME,
+ .min = 0,
+ .max = 86400,
+ .default_value = "1800",
+ .description = "Time frame after which the (file) operation would be "
+ "declared as dead, if the server does not respond for "
+ "a particular (file) operation.",
+ .op_version = {1},
+ .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC},
+ {.key = {"ping-timeout"},
+ .type = GF_OPTION_TYPE_TIME,
+ .min = 0,
+ .max = 1013,
+ .default_value = TOSTRING(GF_NETWORK_TIMEOUT),
+ .description = "Time duration for which the client waits to "
+ "check if the server is responsive.",
+ .op_version = {1},
+ .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC},
+ {.key = {"client-bind-insecure"}, .type = GF_OPTION_TYPE_BOOL},
+ {.key = {"tcp-window-size"},
+ .type = GF_OPTION_TYPE_SIZET,
+ .min = GF_MIN_SOCKET_WINDOW_SIZE,
+ .max = GF_MAX_SOCKET_WINDOW_SIZE,
+ .description = "Specifies the window size for tcp socket.",
+ .op_version = {1},
+ .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC},
+ {.key = {"filter-O_DIRECT"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "disable",
+ .description =
+ "If enabled, in open/creat/readv/writev fops, "
+ "O_DIRECT flag will be filtered at the client protocol level so "
+ "server will still continue to cache the file. This works similar to "
+ "NFS's behavior of O_DIRECT. Anon-fds can choose to readv/writev "
+ "using O_DIRECT",
+ .op_version = {2},
+ .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC},
+ {.key = {"send-gids"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "on",
+ .op_version = {GD_OP_VERSION_3_6_0},
+ .flags = OPT_FLAG_SETTABLE},
+ {.key = {"event-threads"},
+ .type = GF_OPTION_TYPE_INT,
+ .min = 1,
+ .max = 32,
+ .default_value = "2",
+ .description = "Specifies the number of event threads to execute "
+ "in parallel. Larger values would help process"
+ " responses faster, depending on available processing"
+ " power. Range 1-32 threads.",
+ .op_version = {GD_OP_VERSION_3_7_0},
+ .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC},
+
+ /* This option is required for running code-coverage tests with
+ old protocol */
+ {
+ .key = {"testing.old-protocol"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .op_version = {GD_OP_VERSION_7_0},
+ .flags = OPT_FLAG_SETTABLE,
+ },
+ {.key = {"strict-locks"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .op_version = {GD_OP_VERSION_7_0},
+ .flags = OPT_FLAG_SETTABLE,
+ .description = "When set, doesn't reopen saved fds after reconnect "
+ "if POSIX locks are held on them. Hence subsequent "
+ "operations on these fds will fail. This is "
+ "necessary for stricter lock complaince as bricks "
+ "cleanup any granted locks when a client "
+ "disconnects."},
+ {.key = {NULL}},
+};
+
+xlator_api_t xlator_api = {
+ .init = init,
+ .fini = fini,
+ .notify = notify,
+ .reconfigure = reconfigure,
+ .mem_acct_init = mem_acct_init,
+ .op_version = {1}, /* Present from the initial version */
+ .dumpops = &dumpops,
+ .fops = &fops,
+ .cbks = &cbks,
+ .options = options,
+ .identifier = "client",
+ .category = GF_MAINTAINED,
+};