diff options
Diffstat (limited to 'xlators/protocol')
| -rw-r--r-- | xlators/protocol/Makefile.am | 3 | ||||
| -rw-r--r-- | xlators/protocol/client/Makefile.am | 3 | ||||
| -rw-r--r-- | xlators/protocol/client/src/Makefile.am | 16 | ||||
| -rw-r--r-- | xlators/protocol/client/src/client-protocol.c | 6671 | ||||
| -rw-r--r-- | xlators/protocol/client/src/client-protocol.h | 173 | ||||
| -rw-r--r-- | xlators/protocol/client/src/saved-frames.c | 178 | ||||
| -rw-r--r-- | xlators/protocol/client/src/saved-frames.h | 74 | ||||
| -rw-r--r-- | xlators/protocol/server/Makefile.am | 3 | ||||
| -rw-r--r-- | xlators/protocol/server/src/Makefile.am | 18 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-dentry.c | 413 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-helpers.c | 586 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-helpers.h | 77 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-protocol.c | 7984 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-protocol.h | 143 | 
14 files changed, 16342 insertions, 0 deletions
diff --git a/xlators/protocol/Makefile.am b/xlators/protocol/Makefile.am new file mode 100644 index 00000000000..745e277c2a6 --- /dev/null +++ b/xlators/protocol/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = client server + +CLEANFILES =  diff --git a/xlators/protocol/client/Makefile.am b/xlators/protocol/client/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/protocol/client/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES =  diff --git a/xlators/protocol/client/src/Makefile.am b/xlators/protocol/client/src/Makefile.am new file mode 100644 index 00000000000..fb720942cc6 --- /dev/null +++ b/xlators/protocol/client/src/Makefile.am @@ -0,0 +1,16 @@ + +xlator_LTLIBRARIES = client.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/protocol + +client_la_LDFLAGS = -module -avoidversion + +client_la_SOURCES = client-protocol.c saved-frames.c +client_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = client-protocol.h saved-frames.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ +	-I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) + +CLEANFILES =  + diff --git a/xlators/protocol/client/src/client-protocol.c b/xlators/protocol/client/src/client-protocol.c new file mode 100644 index 00000000000..5c93bd6f135 --- /dev/null +++ b/xlators/protocol/client/src/client-protocol.c @@ -0,0 +1,6671 @@ +/* +  Copyright (c) 2006, 2007, 2008, 2009 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include <inttypes.h> + + +#include "glusterfs.h" +#include "client-protocol.h" +#include "compat.h" +#include "dict.h" +#include "protocol.h" +#include "transport.h" +#include "xlator.h" +#include "logging.h" +#include "timer.h" +#include "defaults.h" +#include "compat.h" +#include "compat-errno.h" + +#include <sys/resource.h> +#include <inttypes.h> + +/* for default_*_cbk functions */ +#include "defaults.c" +#include "saved-frames.h" + + +int protocol_client_cleanup (transport_t *trans); +int protocol_client_interpret (xlator_t *this, transport_t *trans, +                               char *hdr_p, size_t hdrlen, +                               char *buf_p, size_t buflen); +int +protocol_client_xfer (call_frame_t *frame, xlator_t *this, transport_t *trans, +                      int type, int op, +                      gf_hdr_common_t *hdr, size_t hdrlen, +                      struct iovec *vector, int count, +                      dict_t *refs); + +static gf_op_t gf_fops[]; +static gf_op_t gf_mops[]; +static gf_op_t gf_cbks[]; + + +static ino_t +this_ino_get_from_inode (inode_t *inode, xlator_t *this) +{ +	ino_t   ino = 0; +	int32_t ret = 0; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	GF_VALIDATE_OR_GOTO (this->name, inode, out); + +	if (inode->ino == 1) { +		ino = 1; +		goto out; +	} + +	ret = inode_ctx_get (inode, this, &ino); + +	if (inode->ino && ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"(%"PRId64"): failed to get remote inode number", +			inode->ino); +	} + +out: +	return ino; +} + + +static ino_t +this_ino_get (loc_t *loc, xlator_t *this, int32_t which) +{ +	ino_t    ino = 0; +	int32_t  ret = 0; +	inode_t *inode = NULL; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	 +	if (which == GF_CLIENT_INODE_SELF) { +		inode = loc->inode; +	} else if (which == GF_CLIENT_INODE_PARENT) { +		inode = loc->parent; +	} +	GF_VALIDATE_OR_GOTO (this->name, inode, out); + +	if (inode->ino == 1) { +		ino = 1; +		goto out; +	} + +	ret = inode_ctx_get (inode, this, &ino); + +	if (inode->ino && ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"%s(%s - %"PRId64") failed to get remote inode number", +			loc->path,  +			(which == GF_CLIENT_INODE_SELF? "self" : "parent"),  +			inode->ino); +	} + +out: +	return ino; +} + + +static void +this_ino_set (loc_t *loc, xlator_t *this, ino_t ino) +{ +	ino_t    old_ino = 0; +	int32_t  ret = -1; +	inode_t *inode = NULL; + +	GF_VALIDATE_OR_GOTO ("client", this, out); + +	inode = loc->inode; +	GF_VALIDATE_OR_GOTO (this->name, inode, out); + +	ret = inode_ctx_get (inode, this, &old_ino); + +	if (old_ino != ino) { +		if (old_ino) +			gf_log (this->name, GF_LOG_DEBUG, +				"%s: inode number changed from %"PRId64" " +				"to %"PRId64, +				loc->path, old_ino, ino); + +		ret = inode_ctx_put (inode, this, ino); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to set remote " +				"inode number to inode ctx", +				loc->path, ino); +		} +	} +out: +	return; +} + + +static int +this_fd_get (fd_t *file, xlator_t *this, int64_t *remote_fd) +{ +	int ret = 0; +	int dict_ret = -1; +	uint64_t tmp_fd = 0; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	GF_VALIDATE_OR_GOTO (this->name, file, out); +	GF_VALIDATE_OR_GOTO (this->name, remote_fd, out); + +	dict_ret = fd_ctx_get (file, this, &tmp_fd); + +	if (dict_ret < 0) { +		ret = -1; +	} +	*remote_fd = (int64_t)tmp_fd; +out: +	return ret; +} + + +static void +this_fd_set (fd_t *file, xlator_t *this, loc_t *loc, int64_t fd) +{ +	uint64_t old_fd = 0; +	int32_t ret = -1; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	GF_VALIDATE_OR_GOTO (this->name, file, out); + +	ret = fd_ctx_get (file, this, &old_fd); +	if (ret >= 0) { +		gf_log (this->name, GF_LOG_WARNING, +			"%s (%"PRId64"): trying duplicate remote fd set. " +			"%"PRId64" over-rides %"PRId64, +			loc->path, loc->inode->ino, fd, old_fd); +	} + +	ret = fd_ctx_set (file, this, (uint64_t)fd); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"%s (%"PRId64"): failed to set remote fd", +			loc->path, loc->inode->ino); +	} +out: +	return; +} + + +static int  +client_local_wipe (client_local_t *local) +{ +	if (local) { +		loc_wipe (&local->loc); + +		if (local->fd) +			fd_unref (local->fd); + +		free (local); +	}  +	 +	return 0; +} + +/* + * lookup_frame - lookup call frame corresponding to a given callid + * @trans: transport object + * @callid: call id of the frame + * + * not for external reference + */ + +static call_frame_t * +lookup_frame (transport_t *trans, int32_t op, int8_t type, int64_t callid) +{ +	client_connection_t *conn = NULL; +	call_frame_t        *frame = NULL; + +	conn = trans->xl_private; + +	pthread_mutex_lock (&conn->lock); +	{ +		frame = saved_frames_get (conn->saved_frames, +					  op, type, callid); +	} +	pthread_mutex_unlock (&conn->lock); + +	return frame; +} + + +static void +call_bail (void *data) +{ +	client_connection_t *conn = NULL; +	struct timeval       current; +	int32_t              bail_out = 0; +	transport_t         *trans = NULL; + +	GF_VALIDATE_OR_GOTO("client", data, out); +	trans = data; + +	conn = trans->xl_private; + +	gettimeofday (¤t, NULL); +	pthread_mutex_lock (&conn->lock); +	{ +		/* Chaining to get call-always functionality from  +		   call-once timer */ +		if (conn->timer) { +			struct timeval timeout = {0,}; +			gf_timer_cbk_t timer_cbk = conn->timer->cbk; + +			timeout.tv_sec = 10; +			timeout.tv_usec = 0; + +			gf_timer_call_cancel (trans->xl->ctx, conn->timer); +			conn->timer = gf_timer_call_after (trans->xl->ctx, +							       timeout, +							       timer_cbk, +							       trans); +			if (conn->timer == NULL) { +				gf_log (trans->xl->name, GF_LOG_DEBUG, +					"Cannot create bailout timer"); +			} +		} + +		if (((conn->saved_frames->count > 0) && +		     (RECEIVE_TIMEOUT(conn, current)) &&  +		     (SEND_TIMEOUT(conn, current)))) { + +			struct tm last_sent_tm, last_received_tm; +			char last_sent[32] = {0,}, last_received[32] = {0,}; + +			bail_out = 1; +			 +			localtime_r (&conn->last_sent.tv_sec,  +				     &last_sent_tm); +			localtime_r (&conn->last_received.tv_sec,  +				     &last_received_tm); +			 +			strftime (last_sent, 32,  +				  "%Y-%m-%d %H:%M:%S", &last_sent_tm); +			strftime (last_received, 32,  +				  "%Y-%m-%d %H:%M:%S", &last_received_tm); +			 +			gf_log (trans->xl->name, GF_LOG_ERROR, +				"activating bail-out. pending frames = %d. " +				"last sent = %s. last received = %s. " +				"transport-timeout = %d", +				(int32_t) conn->saved_frames->count, +				last_sent, last_received, +				conn->transport_timeout); +		} +	} + +	if (bail_out) { +		conn->ping_started = 0; +	} + +	pthread_mutex_unlock (&conn->lock); + +	if (bail_out) { +		gf_log (trans->xl->name, GF_LOG_CRITICAL, +			"bailing transport"); +		transport_disconnect (trans); +	} +out: +	return; +} + + +void +save_frame (transport_t *trans, call_frame_t *frame, +	    int32_t op, int8_t type, uint64_t callid) +{ +	client_connection_t *conn = NULL; +	struct timeval       timeout = {0, }; + + +	conn = trans->xl_private; + +	saved_frames_put (conn->saved_frames, frame, op, type, callid); + +	if (conn->timer == NULL) { +		timeout.tv_sec  = 10; +		timeout.tv_usec = 0; +		conn->timer = gf_timer_call_after (trans->xl->ctx, timeout, +						   call_bail, (void *) trans); +       } +} + + +int +client_get_forgets (xlator_t *this, client_forget_t *forget)  +{ +	call_frame_t        *fr = NULL; +	gf_hdr_common_t     *hdr = NULL; +	size_t               hdrlen = 0; +	gf_cbk_forget_req_t *req = NULL; +	int                  ret = -1; +	client_conf_t       *conf = NULL; +	int                  count = 0; +	int                  index = 0; + +	conf = this->private; + +	if (conf->forget.count > 0) { +		count = conf->forget.count; +		 +		hdrlen = gf_hdr_len (req, (count * sizeof (int64_t))); +		hdr    = gf_hdr_new (req, (count * sizeof (int64_t))); +		GF_VALIDATE_OR_GOTO (this->name, hdr, out); +			 +		req    = gf_param (hdr); +		 +		req->count = hton32 (count); +		for (index = 0; index < count; index++) { +			req->ino_array[index] =  +				hton64 (conf->forget.ino_array[index]); +		} +		 +		fr = create_frame (this, this->ctx->pool); +		GF_VALIDATE_OR_GOTO (this->name, fr, out); + +		conf->forget.frames_in_transit++; + +		forget->frame = fr; +		forget->hdr   = hdr; +		forget->hdrlen = hdrlen; +		 +		ret = count; + +		conf->forget.count = 0; +	} + out: +	return ret; +} + + +void  +client_ping_timer_expired (void *data) +{ +	xlator_t            *this = NULL; +	transport_t         *trans = NULL; +	client_conf_t       *conf = NULL; +	client_connection_t *conn = NULL; + +	trans = data; +	this  = trans->xl; +	conf  = this->private; +	conn  = trans->xl_private; + +	gf_log (this->name, GF_LOG_ERROR,  +		"ping timer expired! bailing transport"); + +	pthread_mutex_lock (&conn->lock); +	{ +		if (conn->ping_timer) +			gf_timer_call_cancel (trans->xl->ctx,  +					      conn->ping_timer); + +		conn->ping_started = 0; +		conn->ping_timer = NULL; +	} +	pthread_mutex_unlock (&conn->lock); +	transport_disconnect (trans); +} + + +void +client_start_ping (void *data) +{ +	xlator_t            *this = NULL; +	transport_t         *trans = NULL; +	client_conf_t       *conf = NULL; +	client_connection_t *conn = NULL; +	int32_t              ret = -1; +	gf_hdr_common_t     *hdr = NULL; +	struct timeval       timeout = {0, }; +	call_frame_t        *dummy_frame = NULL; +	size_t               hdrlen = -1; +	gf_mop_ping_req_t   *req = NULL; + + +	trans = data; +	this  = trans->xl; +	conf  = this->private; +	conn  = trans->xl_private; + +	pthread_mutex_lock (&conn->lock); +	{ +		if ((conn->saved_frames->count == 0) ||  +		    !conn->connected) { +			/* using goto looked ugly here,  +			 * hence getting out this way */ +			if (conn->ping_timer) +				gf_timer_call_cancel (trans->xl->ctx,  +						      conn->ping_timer); +			conn->ping_timer = NULL; +			conn->ping_started = 0; +			/* unlock */ +			pthread_mutex_unlock (&conn->lock); +			return; +		} + +		if (conn->saved_frames->count < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"saved_frames->count is %"PRId64,  +				conn->saved_frames->count); +			conn->saved_frames->count = 0; +		} +		timeout.tv_sec = conn->ping_timeout; +		timeout.tv_usec = 0; +		 +		conn->ping_timer =  +			gf_timer_call_after (trans->xl->ctx, timeout, +					     client_ping_timer_expired, +					     (void *) trans); + +		if (conn->ping_timer == NULL) { +			gf_log (this->name, GF_LOG_ERROR, +				"unable to setup timer"); +		} else +			conn->ping_started = 1; +	} +	pthread_mutex_unlock (&conn->lock); + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); + +	dummy_frame = create_frame (this, this->ctx->pool); +	dummy_frame->local = trans; + +	ret = protocol_client_xfer (dummy_frame, this, trans, +				    GF_OP_TYPE_MOP_REQUEST, GF_MOP_PING, +				    hdr, hdrlen, NULL, 0, NULL); +} + + +int +client_ping_cbk (call_frame_t *frame, gf_hdr_common_t *hdr, size_t hdrlen, +		 char *buf, size_t buflen) +{ +	xlator_t            *this = NULL; +	transport_t         *trans = NULL; +	client_conf_t       *conf = NULL; +	client_connection_t *conn = NULL; +	struct timeval       timeout = {0, }; +	int                  op_ret = 0; + +	trans  = frame->local; frame->local = NULL; +	this   = trans->xl; +	conf   = this->private; +	conn   = trans->xl_private; + +	op_ret = ntoh32 (hdr->rsp.op_ret); + +	if (op_ret == -1) { +		/* timer expired and transport bailed out */ +		gf_log (this->name, GF_LOG_ERROR, "timer must have expired"); +		goto out; +	} + +	pthread_mutex_lock (&conn->lock); +	{ +		timeout.tv_sec  = conn->ping_timeout; +		timeout.tv_usec = 0; + +		gf_timer_call_cancel (trans->xl->ctx,  +				      conn->ping_timer); +	 +		conn->ping_timer =  +			gf_timer_call_after (trans->xl->ctx, timeout, +					     client_start_ping, (void *)trans); +		if (conn->ping_timer == NULL) +			gf_log (this->name, GF_LOG_ERROR, +				"gf_timer_call_after() returned NULL"); +	} +	pthread_mutex_unlock (&conn->lock); +out: +	STACK_DESTROY (frame->root); +	return 0; +} + + +int +protocol_client_xfer (call_frame_t *frame, xlator_t *this, transport_t *trans, +                      int type, int op, +                      gf_hdr_common_t *hdr, size_t hdrlen, +                      struct iovec *vector, int count, +                      dict_t *refs) +{ +	client_conf_t        *conf = NULL; +	client_connection_t  *conn = NULL; +	uint64_t              callid = 0; +	int32_t               ret = -1; +	int                   start_ping = 0; +	gf_hdr_common_t       rsphdr = {0, }; +	client_forget_t       forget = {0, }; +	uint8_t               send_forget = 0; + + +	conf  = this->private; + +	if (!trans) { +		/* default to bulk op since it is 'safer' */ +		trans = conf->transport[CHANNEL_BULK]; +	} +	conn  = trans->xl_private; + +	if (!((type == GF_OP_TYPE_CBK_REQUEST) &&  +	      (op == GF_CBK_FORGET)))  +	{ +		LOCK (&conf->forget.lock); +		{ +			ret = client_get_forgets (this, &forget); +			if (ret <= 0) +				send_forget = 0; +			else +				send_forget = 1; +		} +		UNLOCK (&conf->forget.lock); + +		if (send_forget) { +			ret = protocol_client_xfer (forget.frame, this, NULL, +						    GF_OP_TYPE_CBK_REQUEST,  +						    GF_CBK_FORGET, +						    forget.hdr, forget.hdrlen,  +						    NULL, 0, NULL); +		} +	} + +	pthread_mutex_lock (&conn->lock); +	{ +		callid = ++conn->callid; + +		hdr->callid = hton64 (callid); +		hdr->op     = hton32 (op); +		hdr->type   = hton32 (type); + +		if (frame) { +			hdr->req.uid = hton32 (frame->root->uid); +			hdr->req.gid = hton32 (frame->root->gid); +			hdr->req.pid = hton32 (frame->root->pid); +		} + +		if (conn->connected == 0) +			transport_connect (trans); + +		ret = -1; + +		if (conn->connected || +		    ((type == GF_OP_TYPE_MOP_REQUEST) && +		     (op == GF_MOP_SETVOLUME))) { +			ret = transport_submit (trans, (char *)hdr, hdrlen, +						vector, count, refs); +		} +		 +		if ((ret >= 0) && frame) { +			/* TODO: check this logic */ +			gettimeofday (&conn->last_sent, NULL); +			save_frame (trans, frame, op, type, callid); +		} + +		if (!conn->ping_started && (ret >= 0)) { +			start_ping = 1; +		} +	} +	pthread_mutex_unlock (&conn->lock); + +	if (start_ping) +		client_start_ping ((void *) trans); + +	if (frame && (ret < 0)) { +		rsphdr.op = op; +		rsphdr.rsp.op_ret   = hton32 (-1); +		rsphdr.rsp.op_errno = hton32 (ENOTCONN); + +		if (type == GF_OP_TYPE_FOP_REQUEST) { +			rsphdr.type = GF_OP_TYPE_FOP_REPLY; +			gf_fops[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); +		} else if (type == GF_OP_TYPE_MOP_REQUEST) { +			rsphdr.type = GF_OP_TYPE_MOP_REPLY; +			gf_mops[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); +		} else { +			rsphdr.type = GF_OP_TYPE_CBK_REPLY; +			gf_cbks[op] (frame, &rsphdr, sizeof (rsphdr), NULL, 0); +		} +	} + +	return ret; +} + + + +/** + * client_create - create function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: complete path to file + * @flags: create flags + * @mode: create mode + * + * external reference through client_protocol_xlator->fops->create + */ + +int +client_create (call_frame_t *frame, xlator_t *this, +               loc_t *loc, int32_t flags, +               mode_t mode, fd_t *fd) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_create_req_t *req = NULL; +	size_t               hdrlen = 0; +	size_t               pathlen = 0; +	size_t               baselen = 0; +	int32_t              ret = -1; +	ino_t                par = 0; +	client_conf_t       *conf = NULL; +	client_local_t      *local = NULL; + + +	conf = this->private; + +	if (conf->child) { +		STACK_WIND (frame, default_create_cbk, +			    conf->child, +			    conf->child->fops->create, +			    loc, flags, mode, fd); +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	local->fd = fd_ref (fd); +	loc_copy (&local->loc, loc); +	 +	frame->local = local; + +	pathlen = STRLEN_0(loc->path); +	baselen = STRLEN_0(loc->name); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen); +	hdr    = gf_hdr_new (req, pathlen + baselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->flags   = hton32 (flags); +	req->mode    = hton32 (mode); +	req->par     = hton64 (par); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_CREATE, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, fd, NULL, NULL); +	return 0; + +} + +/** + * client_open - open function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location of file + * @flags: open flags + * @mode: open modes + * + * external reference through client_protocol_xlator->fops->open + */ +int +client_open (call_frame_t *frame, xlator_t *this, +             loc_t *loc, int32_t flags, fd_t *fd) +{ +	int                 ret = -1; +	gf_hdr_common_t    *hdr = NULL; +	size_t              hdrlen = 0; +	gf_fop_open_req_t  *req = NULL; +	size_t              pathlen = 0; +	ino_t               ino = 0; +	client_conf_t      *conf = NULL; +	client_local_t     *local = NULL; + +	conf = this->private; +	if (conf->child) { +		/* */ +		STACK_WIND (frame, default_open_cbk, +			    conf->child, +			    conf->child->fops->open, +			    loc, flags, fd); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	local->fd = fd_ref (fd); +	loc_copy (&local->loc, loc);	 + +	frame->local = local; + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino   = hton64 (ino); +	req->flags = hton32 (flags); +	strcpy (req->path, loc->path); +	 +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_OPEN, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, fd); +	return 0; + +} + + +/** + * client_stat - stat function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->stat + */ +int32_t +client_stat (call_frame_t *frame, +             xlator_t *this, +             loc_t *loc) +{ +	gf_hdr_common_t   *hdr = NULL; +	gf_fop_stat_req_t *req = NULL; +	size_t hdrlen = -1; +	int32_t ret = -1; +	size_t  pathlen = 0; +	ino_t   ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_stat_cbk, +			    conf->child, +			    conf->child->fops->stat, +			    loc); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino  = hton64 (ino); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_STAT, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_readlink - readlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @size: + * + * external reference through client_protocol_xlator->fops->readlink + */ +int32_t +client_readlink (call_frame_t *frame, +                 xlator_t *this, +                 loc_t *loc, +                 size_t size) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_readlink_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_readlink_cbk, +			    conf->child, +			    conf->child->fops->readlink, +			    loc, +			    size); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino  = hton64 (ino); +	req->size = hton32 (size); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_READLINK, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_mknod - mknod function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: pathname of node + * @mode: + * @dev: + * + * external reference through client_protocol_xlator->fops->mknod + */ +int32_t +client_mknod (call_frame_t *frame, +              xlator_t *this, +              loc_t *loc, +              mode_t mode, +              dev_t dev) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_mknod_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	size_t baselen = 0; +	ino_t  par = 0; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_mknod_cbk, +			    conf->child, +			    conf->child->fops->mknod, +			    loc, mode, dev); + +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	loc_copy (&local->loc, loc);	 + +	frame->local = local; + +	pathlen = STRLEN_0(loc->path); +	baselen = STRLEN_0(loc->name); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen); +	hdr    = gf_hdr_new (req, pathlen + baselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->par  = hton64 (par); +	req->mode = hton32 (mode); +	req->dev  = hton64 (dev); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_MKNOD, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); +	return 0; + +} + + +/** + * client_mkdir - mkdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @path: pathname of directory + * @mode: + * + * external reference through client_protocol_xlator->fops->mkdir + */ +int32_t +client_mkdir (call_frame_t *frame, +              xlator_t *this, +              loc_t *loc, +              mode_t mode) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_mkdir_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	size_t baselen = 0; +	ino_t  par = 0; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_mkdir_cbk, +			    conf->child, +			    conf->child->fops->mkdir, +			    loc, mode); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); +	 +	loc_copy (&local->loc, loc); + +	frame->local = local; + +	pathlen = STRLEN_0(loc->path); +	baselen = STRLEN_0(loc->name); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen); +	hdr    = gf_hdr_new (req, pathlen + baselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->par  = hton64 (par); +	req->mode = hton32 (mode); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); +	 +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_MKDIR, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); +	return 0; + +} + + + +/** + * client_unlink - unlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location of file + * + * external reference through client_protocol_xlator->fops->unlink + */ +int32_t +client_unlink (call_frame_t *frame, +               xlator_t *this, +               loc_t *loc) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_unlink_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	size_t baselen = 0; +	ino_t  par = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_unlink_cbk, +			    conf->child, +			    conf->child->fops->unlink, +			    loc); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	baselen = STRLEN_0(loc->name); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen); +	hdr    = gf_hdr_new (req, pathlen + baselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->par  = hton64 (par); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_UNLINK, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + +/** + * client_rmdir - rmdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->rmdir + */ +int32_t +client_rmdir (call_frame_t *frame, +              xlator_t *this, +              loc_t *loc) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_rmdir_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	size_t baselen = 0; +	ino_t  par = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_rmdir_cbk, +			    conf->child, +			    conf->child->fops->rmdir, +			    loc); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	baselen = STRLEN_0(loc->name); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen); +	hdr    = gf_hdr_new (req, pathlen + baselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->par  = hton64 (par); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_RMDIR, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + + + +/** + * client_symlink - symlink function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldpath: pathname of target + * @newpath: pathname of symlink + * + * external reference through client_protocol_xlator->fops->symlink + */ +int32_t +client_symlink (call_frame_t *frame, +                xlator_t *this, +                const char *linkname, +                loc_t *loc) +{ +	int ret = -1; +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_symlink_req_t *req = NULL; +	size_t hdrlen  = 0; +	size_t pathlen = 0; +	size_t newlen  = 0; +	size_t baselen = 0; +	ino_t par = 0; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_symlink_cbk, +			    conf->child, +			    conf->child->fops->symlink, +			    linkname, loc); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); +	 +	loc_copy (&local->loc, loc); + +	frame->local = local; + +	pathlen = STRLEN_0 (loc->path); +	baselen = STRLEN_0 (loc->name); +	newlen = STRLEN_0 (linkname); +	par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, pathlen + baselen + newlen); +	hdr    = gf_hdr_new (req, pathlen + baselen + newlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->par =  hton64 (par); +	strcpy (req->path, loc->path); +	strcpy (req->bname + pathlen, loc->name); +	strcpy (req->linkname + pathlen + baselen, linkname); +	 +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_SYMLINK, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, loc->inode, NULL); +	return 0; + +} + + +/** + * client_rename - rename function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldloc: location of old pathname + * @newloc: location of new pathname + * + * external reference through client_protocol_xlator->fops->rename + */ +int32_t +client_rename (call_frame_t *frame, +               xlator_t *this, +               loc_t *oldloc, +               loc_t *newloc) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_rename_req_t *req = NULL; +	size_t hdrlen = 0; +	size_t oldpathlen = 0; +	size_t oldbaselen = 0; +	size_t newpathlen = 0; +	size_t newbaselen = 0; +	ino_t  oldpar = 0; +	ino_t  newpar = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_rename_cbk, +			    conf->child, +			    conf->child->fops->rename, +			    oldloc, newloc); +		 +		return 0; +	} + +	oldpathlen = STRLEN_0(oldloc->path); +	oldbaselen = STRLEN_0(oldloc->name); +	newpathlen = STRLEN_0(newloc->path); +	newbaselen = STRLEN_0(newloc->name); +	oldpar = this_ino_get (oldloc, this, GF_CLIENT_INODE_PARENT); +	newpar = this_ino_get (newloc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, (oldpathlen + oldbaselen +  +				   newpathlen + newbaselen)); +	hdr    = gf_hdr_new (req, (oldpathlen + oldbaselen +  +				   newpathlen + newbaselen)); + +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->oldpar = hton64 (oldpar); +	req->newpar = hton64 (newpar); + +	strcpy (req->oldpath, oldloc->path); +	strcpy (req->oldbname + oldpathlen, oldloc->name); +	strcpy (req->newpath  + oldpathlen + oldbaselen, newloc->path); +	strcpy (req->newbname + oldpathlen + oldbaselen + newpathlen,  +		newloc->name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_RENAME, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + + +/** + * client_link - link function for client protocol + * @frame: call frame + * @this: this translator structure + * @oldloc: location of old pathname + * @newpath: new pathname + * + * external reference through client_protocol_xlator->fops->link + */ + +int32_t +client_link (call_frame_t *frame, +             xlator_t *this, +             loc_t *oldloc, +             loc_t *newloc) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_link_req_t *req = NULL; +	size_t hdrlen = 0; +	size_t oldpathlen = 0; +	size_t newpathlen = 0; +	size_t newbaselen = 0; +	ino_t  oldino = 0; +	ino_t  newpar = 0; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_link_cbk, +			    conf->child, +			    conf->child->fops->link, +			    oldloc, newloc); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	loc_copy (&local->loc, oldloc); + +	frame->local = local; + +	oldpathlen = STRLEN_0(oldloc->path); +	newpathlen = STRLEN_0(newloc->path); +	newbaselen = STRLEN_0(newloc->name); +	oldino = this_ino_get (oldloc, this, GF_CLIENT_INODE_SELF); +	newpar = this_ino_get (newloc, this, GF_CLIENT_INODE_PARENT); + +	hdrlen = gf_hdr_len (req, oldpathlen + newpathlen + newbaselen); +	hdr    = gf_hdr_new (req, oldpathlen + newpathlen + newbaselen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	strcpy (req->oldpath, oldloc->path); +	strcpy (req->newpath  + oldpathlen, newloc->path); +	strcpy (req->newbname + oldpathlen + newpathlen, newloc->name); + +	req->oldino = hton64 (oldino); +	req->newpar = hton64 (newpar); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_LINK, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, oldloc->inode, NULL); +	return 0; +} + + + +/** + * client_chmod - chmod function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @mode: + * + * external reference through client_protocol_xlator->fops->chmod + */ +int32_t +client_chmod (call_frame_t *frame, +              xlator_t *this, +              loc_t *loc, +              mode_t mode) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_chmod_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_chmod_cbk, +			    conf->child, +			    conf->child->fops->chmod, +			    loc, +			    mode); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino     = hton64 (ino); +	req->mode    = hton32 (mode); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHMOD, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_chown - chown function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @uid: uid of new owner + * @gid: gid of new owner group + * + * external reference through client_protocol_xlator->fops->chown + */ +int32_t +client_chown (call_frame_t *frame, +              xlator_t *this, +              loc_t *loc, +              uid_t uid, +              gid_t gid) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_chown_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_chown_cbk, +			    conf->child, +			    conf->child->fops->chown, +			    loc, +			    uid, +			    gid); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino = hton64 (ino); +	req->uid = hton32 (uid); +	req->gid = hton32 (gid); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHOWN, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + +/** + * client_truncate - truncate function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @offset: + * + * external reference through client_protocol_xlator->fops->truncate + */ +int32_t +client_truncate (call_frame_t *frame, +                 xlator_t *this, +                 loc_t *loc, +                 off_t offset) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_truncate_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_truncate_cbk, +			    conf->child, +			    conf->child->fops->truncate, +			    loc, +			    offset); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino    = hton64 (ino); +	req->offset = hton64 (offset); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_TRUNCATE, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + + +/** + * client_utimes - utimes function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @tvp: + * + * external reference through client_protocol_xlator->fops->utimes + */ +int32_t +client_utimens (call_frame_t *frame, +                xlator_t *this, +                loc_t *loc, +                struct timespec *tvp) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_utimens_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_utimens_cbk, +			    conf->child, +			    conf->child->fops->utimens, +			    loc, +			    tvp); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino = hton64 (ino); +	gf_timespec_from_timespec (req->tv, tvp); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_UTIMENS, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + + +/** + * client_readv - readv function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @size: + * @offset: + * + * external reference through client_protocol_xlator->fops->readv + */ +int32_t +client_readv (call_frame_t *frame, +              xlator_t *this, +              fd_t *fd, +              size_t size, +              off_t offset) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_read_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_readv_cbk, +			    conf->child, +			    conf->child->fops->readv, +			    fd, +			    size, +			    offset); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd, returning EBADFD", +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD, NULL, 0, NULL); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd     = hton64 (remote_fd); +	req->size   = hton32 (size); +	req->offset = hton64 (offset); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_READ, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL, 0, NULL); +	return 0; + +} + + +/** + * client_writev - writev function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @vector: + * @count: + * @offset: + * + * external reference through client_protocol_xlator->fops->writev + */ +int32_t +client_writev (call_frame_t *frame, +               xlator_t *this, +               fd_t *fd, +               struct iovec *vector, +               int32_t count, +               off_t offset) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_write_req_t *req = NULL; +	size_t  hdrlen = 0; +	int64_t remote_fd = -1; +	int     ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_writev_cbk, +			    conf->child, +			    conf->child->fops->writev, +			    fd, +			    vector, +			    count, +			    offset); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD", +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD, NULL); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd     = hton64 (remote_fd); +	req->size   = hton32 (iov_length (vector, count)); +	req->offset = hton64 (offset); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_WRITE, +				    hdr, hdrlen, vector, count, +				    frame->root->req_refs); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_statfs - statfs function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * + * external reference through client_protocol_xlator->fops->statfs + */ +int32_t +client_statfs (call_frame_t *frame, +               xlator_t *this, +               loc_t *loc) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_statfs_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_statfs_cbk, +			    conf->child, +			    conf->child->fops->statfs, +			    loc); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino = hton64 (ino); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_STATFS, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_flush - flush function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->fops->flush + */ + +int32_t +client_flush (call_frame_t *frame, +              xlator_t *this, +              fd_t *fd) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_flush_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_flush_cbk, +			    conf->child, +			    conf->child->fops->flush, +			    fd); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD", +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FLUSH, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + + + + +/** + * client_fsync - fsync function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @flags: + * + * external reference through client_protocol_xlator->fops->fsync + */ + +int32_t +client_fsync (call_frame_t *frame, +              xlator_t *this, +              fd_t *fd, +              int32_t flags) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fsync_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int32_t ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fsync_cbk, +			    conf->child, +			    conf->child->fops->fsync, +			    fd, +			    flags); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		STACK_UNWIND(frame, -1, EBADFD); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd   = hton64 (remote_fd); +	req->data = hton32 (flags); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSYNC, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + +int32_t +client_xattrop (call_frame_t *frame, +		xlator_t *this, +		loc_t *loc, +		gf_xattrop_flags_t flags, +		dict_t *dict) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_xattrop_req_t *req = NULL; +	size_t  hdrlen = 0; +	size_t  dict_len = 0; +	int32_t ret = -1; +	size_t  pathlen = 0; +	ino_t   ino = 0; +	client_conf_t *conf = NULL; + +	GF_VALIDATE_OR_GOTO("client", this, unwind); + +	conf = this->private; +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_xattrop_cbk, +			    conf->child, +			    conf->child->fops->xattrop, +			    loc, +			    flags, +			    dict); +		 +		return 0; +	} + +	GF_VALIDATE_OR_GOTO(this->name, loc, unwind); + +	if (dict) { +		dict_len = dict_serialized_length (dict); +		if (dict_len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to get serialized length of dict(%p)", +				dict); +			goto unwind; +		} +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, dict_len + pathlen); +	hdr    = gf_hdr_new (req, dict_len + pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->flags = hton32 (flags); +	req->dict_len = hton32 (dict_len); +	if (dict) { +		ret = dict_serialize (dict, req->dict); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to serialize dictionary(%p)", +				dict); +			goto unwind; +		} +	} +	req->ino = hton64 (ino); +	strcpy (req->path + dict_len, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_XATTROP, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; +} + + +int32_t +client_fxattrop (call_frame_t *frame, +		 xlator_t *this, +		 fd_t *fd, +		 gf_xattrop_flags_t flags, +		 dict_t *dict) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_fxattrop_req_t *req = NULL; +	size_t  hdrlen = 0; +	size_t  dict_len = 0; +	int64_t remote_fd = -1; +	int32_t ret = -1; +	ino_t   ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fxattrop_cbk, +			    conf->child, +			    conf->child->fops->fxattrop, +			    fd, +			    flags, +			    dict); +		 +		return 0; +	} + +	if (dict) { +		dict_len = dict_serialized_length (dict); +		if (dict_len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to get serialized length of dict(%p)", +				dict); +			goto unwind; +		} +	} + +	if (fd) { +		ret = this_fd_get (fd, this, &remote_fd); +		if (ret == -1) { +			gf_log (this->name, GF_LOG_DEBUG, +				"(%"PRId64"): failed to get remote fd. returning EBADFD",  +				fd->inode->ino); +			goto unwind; +		} +		ino = fd->inode->ino; +	} + +	hdrlen = gf_hdr_len (req, dict_len); +	hdr    = gf_hdr_new (req, dict_len); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->flags = hton32 (flags); +	req->dict_len = hton32 (dict_len); +	if (dict) { +		ret = dict_serialize (dict, req->dict); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to serialize dictionary(%p)", +				dict); +			goto unwind; +		} +	} +	req->fd = hton64 (remote_fd); +	req->ino = hton64 (ino); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FXATTROP, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND (frame, -1, EBADFD, NULL); +	return 0; + +} + + +/** + * client_setxattr - setxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location + * @dict: dictionary which contains key:value to be set. + * @flags: + * + * external reference through client_protocol_xlator->fops->setxattr + */ +int32_t +client_setxattr (call_frame_t *frame, +                 xlator_t *this, +                 loc_t *loc, +                 dict_t *dict, +                 int32_t flags) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_setxattr_req_t *req = NULL; +	size_t hdrlen = 0; +	size_t dict_len = 0; +	int    ret = -1; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_setxattr_cbk, +			    conf->child, +			    conf->child->fops->setxattr, +			    loc, +			    dict, +			    flags); +		 +		return 0; +	} + +	dict_len = dict_serialized_length (dict); +	if (dict_len < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to get serialized length of dict(%p)", +			dict); +		goto unwind; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, dict_len + pathlen); +	hdr    = gf_hdr_new (req, dict_len + pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino   = hton64 (ino); +	req->flags = hton32 (flags); +	req->dict_len = hton32 (dict_len); + +	ret = dict_serialize (dict, req->dict); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to serialize dictionary(%p)", +			dict); +		goto unwind; +	} + +	strcpy (req->path + dict_len, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_SETXATTR, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; +} + +/** + * client_getxattr - getxattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * + * external reference through client_protocol_xlator->fops->getxattr + */ +int32_t +client_getxattr (call_frame_t *frame, +                 xlator_t *this, +                 loc_t *loc, +                 const char *name) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_getxattr_req_t *req = NULL; +	size_t hdrlen = 0; +	size_t pathlen = 0; +	size_t namelen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_getxattr_cbk, +			    conf->child, +			    conf->child->fops->getxattr, +			    loc, +			    name); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	if (name) +		namelen = STRLEN_0(name); + +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen + namelen); +	hdr    = gf_hdr_new (req, pathlen + namelen); +	GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino   = hton64 (ino); +	req->namelen = hton32 (namelen); +	strcpy (req->path, loc->path); +	if (name) +		strcpy (req->name + pathlen, name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_GETXATTR, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; +} + +/** + * client_removexattr - removexattr function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * @name: + * + * external reference through client_protocol_xlator->fops->removexattr + */ +int32_t +client_removexattr (call_frame_t *frame, +                    xlator_t *this, +                    loc_t *loc, +                    const char *name) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_removexattr_req_t *req = NULL; +	size_t hdrlen = 0; +	size_t namelen = 0; +	size_t pathlen = 0; +	ino_t  ino = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_removexattr_cbk, +			    conf->child, +			    conf->child->fops->removexattr, +			    loc, +			    name); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	namelen = STRLEN_0(name); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen + namelen); +	hdr    = gf_hdr_new (req, pathlen + namelen); +	GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino   = hton64 (ino); +	strcpy (req->path, loc->path); +	strcpy (req->name + pathlen, name); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_REMOVEXATTR, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; +} + + +/** + * client_opendir - opendir function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * + * external reference through client_protocol_xlator->fops->opendir + */ +int32_t +client_opendir (call_frame_t *frame, +                xlator_t *this, +                loc_t *loc, +                fd_t *fd) +{ +	gf_fop_opendir_req_t *req = NULL; +	gf_hdr_common_t      *hdr = NULL; +	size_t hdrlen = 0; +	int    ret = -1; +	ino_t  ino = 0; +	size_t pathlen = 0; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_opendir_cbk, +			    conf->child, +			    conf->child->fops->opendir, +			    loc, fd); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	loc_copy (&local->loc, loc); +	local->fd = fd_ref (fd); + +	frame->local = local; +	 +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); +	pathlen = STRLEN_0(loc->path); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino = hton64 (ino); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_OPENDIR, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, fd); +	return 0; + +} + + +/** + * client_readdir - readdir function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdir + */ + +int32_t +client_getdents (call_frame_t *frame, +                 xlator_t *this, +                 fd_t *fd, +                 size_t size, +                 off_t offset, +                 int32_t flag) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_getdents_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_getdents_cbk, +			    conf->child, +			    conf->child->fops->getdents, +			    fd, +			    size, +			    offset, +			    flag); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD, NULL); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + +	req    = gf_param (hdr); +	GF_VALIDATE_OR_GOTO(frame->this->name, hdr, unwind); + +	req->fd     = hton64 (remote_fd); +	req->size   = hton32 (size); +	req->offset = hton64 (offset); +	req->flags  = hton32 (flag); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_GETDENTS, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; +unwind: +	STACK_UNWIND(frame, -1, EINVAL, NULL, 0); +	return 0; +} + +/** + * client_readdir - readdir function for client protocol + * @frame: call frame + * @this: this translator structure + * + * external reference through client_protocol_xlator->fops->readdir + */ + +int32_t +client_readdir (call_frame_t *frame, +		xlator_t *this, +		fd_t *fd, +		size_t size, +		off_t offset) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_readdir_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_readdir_cbk, +			    conf->child, +			    conf->child->fops->readdir, +			    fd, size, offset); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		goto unwind; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req->fd     = hton64 (remote_fd); +	req->size   = hton32 (size); +	req->offset = hton64 (offset); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_READDIR, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND (frame, -1, EBADFD, NULL); +	return 0; + +} + + + +/** + * client_fsyncdir - fsyncdir function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @flags: + * + * external reference through client_protocol_xlator->fops->fsyncdir + */ + +int32_t +client_fsyncdir (call_frame_t *frame, +                 xlator_t *this, +                 fd_t *fd, +                 int32_t flags) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fsyncdir_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int32_t ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fsyncdir_cbk, +			    conf->child, +			    conf->child->fops->fsyncdir, +			    fd, +			    flags); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		goto unwind; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->data = hton32 (flags); +	req->fd   = hton64 (remote_fd); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSYNCDIR, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	STACK_UNWIND (frame, -1, EBADFD); +	return 0; +} + + +/** + * client_access - access function for client protocol + * @frame: call frame + * @this: this translator structure + * @loc: location structure + * @mode: + * + * external reference through client_protocol_xlator->fops->access + */ +int32_t +client_access (call_frame_t *frame, +               xlator_t *this, +               loc_t *loc, +               int32_t mask) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_access_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	ino_t  ino = 0; +	size_t pathlen = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_access_cbk, +			    conf->child, +			    conf->child->fops->access, +			    loc, +			    mask); +		 +		return 0; +	} + +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); +	pathlen = STRLEN_0(loc->path); + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino  = hton64 (ino); +	req->mask = hton32 (mask); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_ACCESS, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + + +/** + * client_ftrucate - ftruncate function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @offset: offset to truncate to + * + * external reference through client_protocol_xlator->fops->ftruncate + */ + +int32_t +client_ftruncate (call_frame_t *frame, +                  xlator_t *this, +                  fd_t *fd, +                  off_t offset) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_ftruncate_req_t *req = NULL; +	int64_t remote_fd = -1; +	size_t hdrlen = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_ftruncate_cbk, +			    conf->child, +			    conf->child->fops->ftruncate, +			    fd, +			    offset); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD, NULL); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd     = hton64 (remote_fd); +	req->offset = hton64 (offset); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FTRUNCATE, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_fstat - fstat function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->fops->fstat + */ + +int32_t +client_fstat (call_frame_t *frame, +              xlator_t *this, +              fd_t *fd) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fstat_req_t *req = NULL; +	int64_t remote_fd = -1; +	size_t hdrlen = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fstat_cbk, +			    conf->child, +			    conf->child->fops->fstat, +			    fd); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD", +			fd->inode->ino); +		STACK_UNWIND (frame, -1, EBADFD, NULL); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FSTAT, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; + +} + + +/** + * client_lk - lk function for client protocol + * @frame: call frame + * @this: this translator structure + * @fd: file descriptor structure + * @cmd: lock command + * @lock: + * + * external reference through client_protocol_xlator->fops->lk + */ +int32_t +client_lk (call_frame_t *frame, +           xlator_t *this, +           fd_t *fd, +           int32_t cmd, +           struct flock *flock) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_lk_req_t *req = NULL; +	size_t hdrlen = 0; +	int64_t remote_fd = -1; +	int32_t gf_cmd = 0; +	int32_t gf_type = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_lk_cbk, +			    conf->child, +			    conf->child->fops->lk, +			    fd, +			    cmd, +			    flock); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD", +			fd->inode->ino); +		STACK_UNWIND(frame, -1, EBADFD, NULL); +		return 0; +	} + +	if (cmd == F_GETLK || cmd == F_GETLK64) +		gf_cmd = GF_LK_GETLK; +	else if (cmd == F_SETLK || cmd == F_SETLK64) +		gf_cmd = GF_LK_SETLK; +	else if (cmd == F_SETLKW || cmd == F_SETLKW64) +		gf_cmd = GF_LK_SETLKW; +	else { +		gf_log (this->name, GF_LOG_ERROR, +			"Unknown cmd (%d)!", gf_cmd); +		goto unwind; +	} + +	switch (flock->l_type) { +	case F_RDLCK: +		gf_type = GF_LK_F_RDLCK; +		break; +	case F_WRLCK: +		gf_type = GF_LK_F_WRLCK; +		break; +	case F_UNLCK: +		gf_type = GF_LK_F_UNLCK; +		break; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd   = hton64 (remote_fd); +	req->cmd  = hton32 (gf_cmd); +	req->type = hton32 (gf_type); +	gf_flock_from_flock (&req->flock, flock); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_LK, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; +} + + +/** + * client_inodelk - inodelk function for client protocol + * @frame: call frame + * @this: this translator structure + * @inode: inode structure + * @cmd: lock command + * @lock: flock struct + * + * external reference through client_protocol_xlator->fops->inodelk + */ +int32_t +client_inodelk (call_frame_t *frame, +		xlator_t *this, +		loc_t *loc, +		int32_t cmd, +		struct flock *flock) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_inodelk_req_t *req = NULL; +	size_t hdrlen = 0; +	int32_t gf_cmd = 0; +	int32_t gf_type = 0; +	ino_t   ino  = 0; +	size_t  pathlen = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_inodelk_cbk, +			    conf->child, +			    conf->child->fops->inodelk, +			    loc, cmd, flock); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	if (cmd == F_GETLK || cmd == F_GETLK64) +		gf_cmd = GF_LK_GETLK; +	else if (cmd == F_SETLK || cmd == F_SETLK64) +		gf_cmd = GF_LK_SETLK; +	else if (cmd == F_SETLKW || cmd == F_SETLKW64) +		gf_cmd = GF_LK_SETLKW; +	else { +		gf_log (this->name, GF_LOG_ERROR, +			"Unknown cmd (%d)!", gf_cmd); +		goto unwind; +	} + +	switch (flock->l_type) { +	case F_RDLCK: +		gf_type = GF_LK_F_RDLCK; +		break; +	case F_WRLCK: +		gf_type = GF_LK_F_WRLCK; +		break; +	case F_UNLCK: +		gf_type = GF_LK_F_UNLCK; +		break; +	} + +	hdrlen = gf_hdr_len (req, pathlen); +	hdr    = gf_hdr_new (req, pathlen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	strcpy (req->path, loc->path); + +	req->ino  = hton64 (ino); + +	req->cmd  = hton32 (gf_cmd); +	req->type = hton32 (gf_type); +	gf_flock_from_flock (&req->flock, flock); + + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, +				    GF_FOP_INODELK, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + + +/** + * client_finodelk - finodelk function for client protocol + * @frame: call frame + * @this: this translator structure + * @inode: inode structure + * @cmd: lock command + * @lock: flock struct + * + * external reference through client_protocol_xlator->fops->finodelk + */ +int32_t +client_finodelk (call_frame_t *frame, +		 xlator_t *this, +		 fd_t *fd, +		 int32_t cmd, +		 struct flock *flock) +{ +	int ret = -1; +	gf_hdr_common_t *hdr = NULL; +	gf_fop_finodelk_req_t *req = NULL; +	size_t hdrlen = 0; +	int32_t gf_cmd = 0; +	int32_t gf_type = 0; +	int64_t remote_fd = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_finodelk_cbk, +			    conf->child, +			    conf->child->fops->finodelk, +			    fd, cmd, flock); +		 +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		STACK_UNWIND(frame, -1, EBADFD); +		return 0; +	} + +	if (cmd == F_GETLK || cmd == F_GETLK64) +		gf_cmd = GF_LK_GETLK; +	else if (cmd == F_SETLK || cmd == F_SETLK64) +		gf_cmd = GF_LK_SETLK; +	else if (cmd == F_SETLKW || cmd == F_SETLKW64) +		gf_cmd = GF_LK_SETLKW; +	else { +		gf_log (this->name, GF_LOG_ERROR, +			"Unknown cmd (%d)!", gf_cmd); +		goto unwind; +	} + +	switch (flock->l_type) { +	case F_RDLCK: +		gf_type = GF_LK_F_RDLCK; +		break; +	case F_WRLCK: +		gf_type = GF_LK_F_WRLCK; +		break; +	case F_UNLCK: +		gf_type = GF_LK_F_UNLCK; +		break; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); + +	req->cmd  = hton32 (gf_cmd); +	req->type = hton32 (gf_type); +	gf_flock_from_flock (&req->flock, flock); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, +				    GF_FOP_FINODELK, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; +} + + +int32_t +client_entrylk (call_frame_t *frame, +		xlator_t *this, +		loc_t *loc, +		const char *name, +		entrylk_cmd cmd, +		entrylk_type type) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_entrylk_req_t *req = NULL; +	size_t pathlen = 0; +	size_t hdrlen = -1; +	int ret = -1; +	ino_t ino = 0; +	size_t namelen = 0; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, default_entrylk_cbk, +			    conf->child, +			    conf->child->fops->entrylk, +			    loc, name, cmd, type); +		 +		return 0; +	} + +	pathlen = STRLEN_0(loc->path); +	if (name) +		namelen = STRLEN_0(name); + +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); + +	hdrlen = gf_hdr_len (req, pathlen + namelen); +	hdr    = gf_hdr_new (req, pathlen + namelen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino  = hton64 (ino); +	req->namelen = hton64 (namelen); + +	strcpy (req->path, loc->path); +	if (name) +		strcpy (req->name + pathlen, name); + +	req->cmd  = hton32 (cmd); +	req->type = hton32 (type); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_ENTRYLK, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; + +} + + +int32_t +client_fentrylk (call_frame_t *frame, +		 xlator_t *this, +		 fd_t *fd, +		 const char *name, +		 entrylk_cmd cmd, +		 entrylk_type type) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fentrylk_req_t *req = NULL; +	int64_t remote_fd = -1; +	size_t namelen = 0; +	size_t hdrlen = -1; +	int ret = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, default_fentrylk_cbk, +			    conf->child, +			    conf->child->fops->fentrylk, +			    fd, name, cmd, type); +		 +		return 0; +	} + +	if (name) +		namelen = STRLEN_0(name); + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		STACK_UNWIND(frame, -1, EBADFD); +		return 0; +	} + +	hdrlen = gf_hdr_len (req, namelen); +	hdr    = gf_hdr_new (req, namelen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); +	req->namelen = hton64 (namelen); + +	if (name) +		strcpy (req->name, name); + +	req->cmd  = hton32 (cmd); +	req->type = hton32 (type); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FENTRYLK, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); + +	STACK_UNWIND(frame, -1, EINVAL); +	return 0; +} + + +/* + * client_lookup - lookup function for client protocol + * @frame: call frame + * @this: + * @loc: location + * + * not for external reference + */ +int32_t +client_lookup (call_frame_t *frame, +               xlator_t *this, +               loc_t *loc, +               dict_t *xattr_req) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_lookup_req_t *req = NULL; +	size_t hdrlen = -1; +	int    ret = -1; +	ino_t  ino = 0; +	ino_t  par = 0; +	size_t dictlen = 0; +	size_t pathlen = 0; +	size_t baselen = 0; +	int32_t op_ret = -1; +	int32_t op_errno = EINVAL; +	client_conf_t *conf = this->private; +	client_local_t *local = NULL; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_lookup_cbk, +			    conf->child, +			    conf->child->fops->lookup, +			    loc, +			    xattr_req); +		 +		return 0; +	} + +	local = calloc (1, sizeof (*local)); +	GF_VALIDATE_OR_GOTO(this->name, local, unwind); + +	loc_copy (&local->loc, loc); + +	frame->local = local; + +	GF_VALIDATE_OR_GOTO (this->name, loc, unwind); +	GF_VALIDATE_OR_GOTO (this->name, loc->path, unwind); + +	if (loc->ino != 1) { +		par = this_ino_get (loc, this, GF_CLIENT_INODE_PARENT); +		GF_VALIDATE_OR_GOTO (this->name, loc->name, unwind); +		baselen = STRLEN_0(loc->name); +	} else { +		ino = 1; +	} + +	pathlen = STRLEN_0(loc->path); +	 +	if (xattr_req) { +		dictlen = dict_serialized_length (xattr_req); +		if (dictlen < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to get serialized length of dict(%p)", +				xattr_req); +			ret = dictlen; +			goto unwind; +		} +	} + +	hdrlen = gf_hdr_len (req, pathlen + baselen + dictlen); +	hdr    = gf_hdr_new (req, pathlen + baselen + dictlen); +	GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->ino   = hton64 (ino); +	req->par   = hton64 (par); +	strcpy (req->path, loc->path); +	if (baselen) +		strcpy (req->path + pathlen, loc->name); +	 +	if (dictlen) { +		ret = dict_serialize (xattr_req, req->dict + baselen + pathlen); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"failed to serialize dictionary(%p)", +				xattr_req); +			goto unwind; +		} +	} + +	req->dictlen = hton32 (dictlen); +	 +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_LOOKUP, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; + +unwind: +	STACK_UNWIND (frame, op_ret, op_errno, loc->inode, NULL, NULL); +	return ret; +} + + + +/* + * client_fchmod + * + */ +int32_t +client_fchmod (call_frame_t *frame, +               xlator_t *this, +               fd_t *fd, +               mode_t mode) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fchmod_req_t *req = NULL; +	int64_t remote_fd = -1; +	size_t hdrlen = -1; +	int ret = -1; +	int32_t op_errno = EINVAL; +	int32_t op_ret   = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fchmod_cbk, +			    conf->child, +			    conf->child->fops->fchmod, +			    fd, +			    mode); +		 +		return 0; +	} + +	GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		op_errno = EBADFD; +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		goto unwind; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd   = hton64 (remote_fd); +	req->mode = hton32 (mode); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FCHMOD, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; + +unwind: +	STACK_UNWIND (frame, op_ret, op_errno, NULL); +	return 0; +} + + +/* + * client_fchown - + * + * @frame: + * @this: + * @fd: + * @uid: + * @gid: + * + */ +int32_t +client_fchown (call_frame_t *frame, +               xlator_t *this, +               fd_t *fd, +               uid_t uid, +               gid_t gid) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_fchown_req_t *req = NULL; +	int64_t remote_fd = 0; +	size_t  hdrlen   = -1; +	int32_t op_ret   = -1; +	int32_t op_errno = EINVAL; +	int32_t ret      = -1; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_fchown_cbk, +			    conf->child, +			    conf->child->fops->fchown, +			    fd, +			    uid, +			    gid); +		 +		return 0; +	} + +	GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		op_errno = EBADFD; +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		goto unwind; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd  = hton64 (remote_fd); +	req->uid = hton32 (uid); +	req->gid = hton32 (gid); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_LOWLAT), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_FCHOWN, +				    hdr, hdrlen, NULL, 0, NULL); + +	return 0; + +unwind: +	STACK_UNWIND (frame, op_ret, op_errno, NULL); +	return 0; + +} + +/** + * client_setdents - + */ +int32_t +client_setdents (call_frame_t *frame, +                 xlator_t *this, +                 fd_t *fd, +                 int32_t flags, +                 dir_entry_t *entries, +                 int32_t count) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_setdents_req_t *req = NULL; +	int64_t remote_fd = 0; +	char   *buffer = NULL; +	char *ptr = NULL; +	data_t *buf_data = NULL; +	dict_t *reply_dict = NULL; +	dir_entry_t *trav = NULL; +	uint32_t len = 0; +	int32_t  buf_len = 0; +	int32_t  ret = -1; +	int32_t  op_ret = -1; +	int32_t  op_errno = EINVAL; +	int32_t  vec_count = 0; +	size_t   hdrlen = -1; +	struct iovec vector[1]; +	client_conf_t *conf = this->private; + +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_setdents_cbk, +			    conf->child, +			    conf->child->fops->setdents, +			    fd, +			    flags, +			    entries, +			    count); +		 +		return 0; +	} + +	GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd. returning EBADFD",  +			fd->inode->ino); +		op_errno = EBADFD; +		goto unwind; +	} + +	GF_VALIDATE_OR_GOTO (this->name, entries, unwind); +	GF_VALIDATE_OR_GOTO (this->name, count, unwind); + +	trav = entries->next; +	while (trav) { +		len += strlen (trav->name); +		len += 1; +		len += strlen (trav->link); +		len += 1; +		len += 256; // max possible for statbuf; +		trav = trav->next; +	} +	buffer = CALLOC (1, len); +	GF_VALIDATE_OR_GOTO (this->name, buffer, unwind); + +	ptr = buffer; + +	trav = entries->next; +	while (trav) { +		int32_t this_len = 0; +		char *tmp_buf = NULL; +		struct stat *stbuf = &trav->buf; +		{ +			/* Convert the stat buf to string */ +			uint64_t dev = stbuf->st_dev; +			uint64_t ino = stbuf->st_ino; +			uint32_t mode = stbuf->st_mode; +			uint32_t nlink = stbuf->st_nlink; +			uint32_t uid = stbuf->st_uid; +			uint32_t gid = stbuf->st_gid; +			uint64_t rdev = stbuf->st_rdev; +			uint64_t size = stbuf->st_size; +			uint32_t blksize = stbuf->st_blksize; +			uint64_t blocks = stbuf->st_blocks; + +			uint32_t atime = stbuf->st_atime; +			uint32_t mtime = stbuf->st_mtime; +			uint32_t ctime = stbuf->st_ctime; + +			uint32_t atime_nsec = ST_ATIM_NSEC(stbuf); +			uint32_t mtime_nsec = ST_MTIM_NSEC(stbuf); +			uint32_t ctime_nsec = ST_CTIM_NSEC(stbuf); + +			asprintf (&tmp_buf, +				  GF_STAT_PRINT_FMT_STR, +				  dev, +				  ino, +				  mode, +				  nlink, +				  uid, +				  gid, +				  rdev, +				  size, +				  blksize, +				  blocks, +				  atime, +				  atime_nsec, +				  mtime, +				  mtime_nsec, +				  ctime, +				  ctime_nsec); +		} +		this_len = sprintf (ptr, "%s/%s%s\n", +				    trav->name, +				    tmp_buf, +				    trav->link); + +		FREE (tmp_buf); +		trav = trav->next; +		ptr += this_len; +	} +	buf_len = strlen (buffer); + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->fd    = hton64 (remote_fd); +	req->flags = hton32 (flags); +	req->count = hton32 (count); + +	{ +		buf_data = get_new_data (); +		GF_VALIDATE_OR_GOTO (this->name, buf_data, unwind); +		reply_dict = get_new_dict(); +		GF_VALIDATE_OR_GOTO (this->name, reply_dict, unwind); + +		buf_data->data = buffer; +		buf_data->len = buf_len; +		dict_set (reply_dict, NULL, buf_data); +		frame->root->rsp_refs = dict_ref (reply_dict); +		vector[0].iov_base = buffer; +		vector[0].iov_len = buf_len; +		vec_count = 1; +	} + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_SETDENTS, +				    hdr, hdrlen, vector, vec_count,  +				    frame->root->rsp_refs); + +	return ret; +unwind: +	STACK_UNWIND (frame, op_ret, op_errno); +	return 0; +} + + +/* + * CBKs + */ +/* + * client_forget - forget function for client protocol + * @this: + * @inode: + * + * not for external reference + */ +int32_t +client_forget (xlator_t *this, +               inode_t *inode) +{ +	ino_t            ino = 0; +	client_conf_t *conf = NULL; +	client_forget_t  forget = {0,}; +	uint8_t          send_forget = 0; +	int32_t          ret = -1; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	conf = this->private; + +	if (conf->child) { +		/* */ +		/* Yenu beda */ +		return 0; +	} + +	GF_VALIDATE_OR_GOTO (this->name, inode, out); +	ino = this_ino_get_from_inode (inode, this); + +	LOCK (&conf->forget.lock); +	{ +		conf->forget.ino_array[conf->forget.count++] = ino; + +		if ((!conf->forget.frames_in_transit) ||  +		    (conf->forget.count >= CLIENT_PROTO_FORGET_LIMIT)) { +			ret = client_get_forgets (this, &forget); +			if (ret <= 0) +				send_forget = 0; +			else +				send_forget = 1; +		} +	} +	UNLOCK (&conf->forget.lock); +	 +	if (send_forget) { +		ret = protocol_client_xfer (forget.frame, this, +					    CLIENT_CHANNEL (this,CHANNEL_BULK), +					    GF_OP_TYPE_CBK_REQUEST,  +					    GF_CBK_FORGET, +					    forget.hdr, forget.hdrlen,  +					    NULL, 0, NULL); +	} +out: +	return 0; +} + +/** + * client_releasedir - releasedir function for client protocol + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->cbks->releasedir + */ + +int32_t +client_releasedir (xlator_t *this, fd_t *fd) +{ +	call_frame_t            *fr = NULL; +	int32_t                  ret = -1; +	int64_t                  remote_fd = 0; +	char                     key[32] = {0,}; +	gf_hdr_common_t         *hdr = NULL; +	size_t                   hdrlen = 0; +	gf_cbk_releasedir_req_t *req  = NULL; +	client_conf_t           *conf = NULL; + + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	GF_VALIDATE_OR_GOTO (this->name, fd, out); + +	conf = this->private; +	if (conf->child) { +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1){ +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd.",  +			fd->inode->ino); +		goto out; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, out); + +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); + +	{ +		sprintf (key, "%p", fd); + +		pthread_mutex_lock (&conf->mutex); +		{ +			dict_del (conf->saved_fds, key); +		} +		pthread_mutex_unlock (&conf->mutex); +	} + +	fr = create_frame (this, this->ctx->pool); +	GF_VALIDATE_OR_GOTO (this->name, fr, out); + +	ret = protocol_client_xfer (fr, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_CBK_REQUEST, GF_CBK_RELEASEDIR, +				    hdr, hdrlen, NULL, 0, NULL); +out: +	return ret; +} + + +/** + * client_release - release function for client protocol + * @this: this translator structure + * @fd: file descriptor structure + * + * external reference through client_protocol_xlator->cbks->release + * + */ +int +client_release (xlator_t *this, fd_t *fd) +{ +	call_frame_t          *fr = NULL; +	int32_t                ret = -1; +	int64_t                remote_fd = 0; +	char                   key[32] = {0,}; +	gf_hdr_common_t       *hdr = NULL; +	size_t                 hdrlen = 0; +	gf_cbk_release_req_t  *req = NULL; +	client_conf_t         *conf = NULL; + +	GF_VALIDATE_OR_GOTO ("client", this, out); +	GF_VALIDATE_OR_GOTO (this->name, fd, out); + +	conf = this->private; + +	if (conf->child) { +		return 0; +	} + +	ret = this_fd_get (fd, this, &remote_fd); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_DEBUG, +			"(%"PRId64"): failed to get remote fd.",  +			fd->inode->ino); +		goto out; +	} + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, out); +	req    = gf_param (hdr); + +	req->fd = hton64 (remote_fd); + +	{ +		sprintf (key, "%p", fd); + +		pthread_mutex_lock (&conf->mutex); +		{ +			dict_del (conf->saved_fds, key); +		} +		pthread_mutex_unlock (&conf->mutex); +	} + +	fr = create_frame (this, this->ctx->pool); +	GF_VALIDATE_OR_GOTO (this->name, fr, out); + +	ret = protocol_client_xfer (fr, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_CBK_REQUEST, GF_CBK_RELEASE, +				    hdr, hdrlen, NULL, 0, NULL); +out: +	return ret; +} + +/* + * MGMT_OPS + */ + +/** + * client_stats - stats function for client protocol + * @frame: call frame + * @this: this translator structure + * @flags: + * + * external reference through client_protocol_xlator->mops->stats + */ + +int32_t +client_stats (call_frame_t *frame, +              xlator_t *this, +              int32_t flags) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_mop_stats_req_t *req = NULL; +	size_t hdrlen = -1; +	int ret = -1; +	client_conf_t *conf = NULL; + +	GF_VALIDATE_OR_GOTO ("client", this, unwind); + +	conf = this->private; +	if (conf->child) { +		/* */ +		STACK_WIND (frame, +			    default_stats_cbk, +			    conf->child, +			    conf->child->mops->stats, +			    flags); +		 +		return 0; +	} + + +	hdrlen = gf_hdr_len (req, 0); +	hdr    = gf_hdr_new (req, 0); +	GF_VALIDATE_OR_GOTO (this->name, hdr, unwind); + +	req    = gf_param (hdr); + +	req->flags = hton32 (flags); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_MOP_REQUEST, GF_MOP_STATS, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	STACK_UNWIND (frame, -1, EINVAL, NULL); +	return 0; +} + + +/* Callbacks */ + +int32_t +client_fxattrop_cbk (call_frame_t *frame, +		     gf_hdr_common_t *hdr, size_t hdrlen, +		     char *buf, size_t buflen) +{ +	gf_fop_xattrop_rsp_t *rsp = NULL; +	int32_t op_ret   = 0; +	int32_t gf_errno = 0; +	int32_t op_errno = 0; +	int32_t dict_len = 0; +	dict_t *dict = NULL; +	int32_t ret = -1; +	char *dictbuf = NULL; + +	rsp = gf_param (hdr); +	GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); + +	if (op_ret >= 0) { +		op_ret = -1; +		dict_len = ntoh32 (rsp->dict_len); + +		if (dict_len > 0) { +			dictbuf = memdup (rsp->dict, dict_len); +			GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + +			dict = dict_new(); +			GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); + +			ret = dict_unserialize (dictbuf, dict_len, &dict); +			if (ret < 0) { +				gf_log (frame->this->name, GF_LOG_ERROR, +					"failed to serialize dictionary(%p)", +					dict); +				op_errno = -ret; +				goto fail; +			} else { +				dict->extra_free = dictbuf; +				dictbuf = NULL; +			} +		} +		op_ret = 0; +	} +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); + +fail: +	STACK_UNWIND (frame, op_ret, op_errno, dict); +	 +	if (dictbuf) +		free (dictbuf); + +	if (dict) +		dict_unref (dict); + +	return 0; +} + +int32_t +client_xattrop_cbk (call_frame_t *frame, +		    gf_hdr_common_t *hdr, size_t hdrlen, +		    char *buf, size_t buflen) +{ +	gf_fop_xattrop_rsp_t *rsp = NULL; +	int32_t op_ret   = -1; +	int32_t gf_errno = EINVAL; +	int32_t op_errno = 0; +	int32_t dict_len = 0; +	dict_t *dict = NULL; +	int32_t ret = -1; +	char *dictbuf = NULL; + +	rsp = gf_param (hdr); +	GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	if (op_ret >= 0) { +		op_ret = -1; +		dict_len = ntoh32 (rsp->dict_len); + +		if (dict_len > 0) { +			dictbuf = memdup (rsp->dict, dict_len); +			GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + +			dict = get_new_dict(); +			GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); +			dict_ref (dict); +                                                +			ret = dict_unserialize (dictbuf, dict_len, &dict); +			if (ret < 0) { +				gf_log (frame->this->name, GF_LOG_ERROR, +					"failed to serialize dictionary(%p)", +					dict); +				goto fail; +			} else { +				dict->extra_free = dictbuf; +				dictbuf = NULL; +			} +		} +		op_ret = 0; +	} +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); + + +fail: +	STACK_UNWIND (frame, op_ret, op_errno, dict); +	 +	if (dictbuf) +		free (dictbuf); +	if (dict) +		dict_unref (dict); + +	return 0; +} + +/* + * client_chown_cbk - + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_fchown_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_fchown_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + + +/* + * client_fchmod_cbk + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_fchmod_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_fchmod_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + + +/* + * client_create_cbk - create callback function for client protocol + * @frame: call frame + * @args: arguments in dictionary + * + * not for external reference + */ + +int +client_create_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	gf_fop_create_rsp_t  *rsp = NULL; +	int32_t               op_ret = 0; +	int32_t               op_errno = 0; +	fd_t                 *fd = NULL; +	inode_t              *inode = NULL; +	struct stat           stbuf = {0, }; +	int64_t               remote_fd = 0; +	char                  key[32] = {0, }; +	int32_t               ret = -1; +	client_local_t       *local = NULL; +	client_conf_t        *conf = NULL; + + +	local = frame->local; frame->local = NULL; +	conf  = frame->this->private; +	fd    = local->fd; +	inode = local->loc.inode; + +	rsp = gf_param (hdr); + +	op_ret    = ntoh32 (hdr->rsp.op_ret); +	op_errno  = ntoh32 (hdr->rsp.op_errno); + +	if (op_ret >= 0) { +		remote_fd = ntoh64 (rsp->fd); +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	if (op_ret >= 0) { +		this_ino_set (&local->loc, frame->this, stbuf.st_ino); +		this_fd_set (fd, frame->this, &local->loc, remote_fd); + +		sprintf (key, "%p", fd); + +		pthread_mutex_lock (&conf->mutex); +		{ +			ret = dict_set_str (conf->saved_fds, key, ""); +		} +		pthread_mutex_unlock (&conf->mutex); + +		if (ret < 0) { +			free (key); +			gf_log (frame->this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to save remote fd",  +				local->loc.path, stbuf.st_ino); +		} +	} + +	STACK_UNWIND (frame, op_ret, op_errno, fd, inode, &stbuf); +	 +	client_local_wipe (local); + +	return 0; +} + + +/* + * client_open_cbk - open callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_open_cbk (call_frame_t *frame, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	int32_t              op_ret = -1; +	int32_t              op_errno = ENOTCONN; +	fd_t                *fd = NULL; +	int64_t              remote_fd = 0; +	gf_fop_open_rsp_t   *rsp = NULL; +	char                 key[32] = {0,}; +	int32_t              ret = -1; +	client_local_t      *local = NULL; +	client_conf_t       *conf = NULL; +	 + +	local = frame->local; frame->local = NULL; +	conf  = frame->this->private; +	fd    = local->fd; + +	rsp = gf_param (hdr); + +	op_ret    = ntoh32 (hdr->rsp.op_ret); +	op_errno  = ntoh32 (hdr->rsp.op_errno); + +	if (op_ret >= 0) { +		remote_fd = ntoh64 (rsp->fd); +	} + +	if (op_ret >= 0) { +		this_fd_set (fd, frame->this, &local->loc, remote_fd); + +		sprintf (key, "%p", fd); + +		pthread_mutex_lock (&conf->mutex); +		{ +			ret = dict_set_str (conf->saved_fds, key, ""); +		} +		pthread_mutex_unlock (&conf->mutex); + +		if (ret < 0) { +			gf_log (frame->this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to save remote fd",  +				local->loc.path, local->loc.inode->ino); +			free (key); +		} + +	} + +	STACK_UNWIND (frame, op_ret, op_errno, fd); +	 +	client_local_wipe (local); + +	return 0; +} + +/* + * client_stat_cbk - stat callback for client protocol + * @frame: call frame + * @args: arguments dictionary + * + * not for external reference + */ +int +client_stat_cbk (call_frame_t *frame, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	struct stat        stbuf = {0, }; +	gf_fop_stat_rsp_t *rsp = NULL; +	int32_t            op_ret = 0; +	int32_t            op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_utimens_cbk - utimens callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_utimens_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_utimens_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_chmod_cbk - chmod for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_chmod_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_chmod_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_chown_cbk - chown for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_chown_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_chown_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_mknod_cbk - mknod callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_mknod_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_mknod_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct stat stbuf = {0, }; +	inode_t *inode = NULL; +	client_local_t *local = NULL; + +	local = frame->local; +	frame->local = NULL; +	inode = local->loc.inode; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +		this_ino_set (&local->loc, frame->this, stbuf.st_ino); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); +	 +	client_local_wipe (local); + +	return 0; +} + +/* + * client_symlink_cbk - symlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_symlink_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	gf_fop_symlink_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct stat stbuf = {0, }; +	inode_t *inode = NULL; +	client_local_t *local = NULL; + +	local = frame->local; +	frame->local = NULL; +	inode = local->loc.inode; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +		this_ino_set (&local->loc, frame->this, stbuf.st_ino); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); +	 +	client_local_wipe (local); + +	return 0; +} + +/* + * client_link_cbk - link callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_link_cbk (call_frame_t *frame, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	gf_fop_link_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct stat stbuf = {0, }; +	inode_t *inode = NULL; +	client_local_t *local = NULL; + +	local = frame->local; +	frame->local = NULL; +	inode = local->loc.inode; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); +	 +	client_local_wipe (local); + +	return 0; +} + +/* + * client_truncate_cbk - truncate callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_truncate_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_truncate_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* client_fstat_cbk - fstat callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_fstat_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_fstat_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_ftruncate_cbk - ftruncate callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_ftruncate_cbk (call_frame_t *frame, +                      gf_hdr_common_t *hdr, size_t hdrlen, +                      char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_ftruncate_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* client_readv_cbk - readv callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external referece + */ + +int32_t +client_readv_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_read_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct iovec vector = {0, }; +	struct stat stbuf = {0, }; +	dict_t *refs = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret != -1) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +		vector.iov_base = buf; +		vector.iov_len  = buflen; + +		refs = get_new_dict (); +		dict_set (refs, NULL, data_from_dynptr (buf, 0)); +		frame->root->rsp_refs = dict_ref (refs); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &vector, 1, &stbuf); + +	if (refs) +		dict_unref (refs); + +	return 0; +} + +/* + * client_write_cbk - write callback for client protocol + * @frame: cal frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_write_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_write_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct stat stbuf = {0, }; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) +		gf_stat_to_stat (&rsp->stat, &stbuf); + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + + +int32_t +client_readdir_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	gf_fop_readdir_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	uint32_t buf_size = 0; +	gf_dirent_t entries; + +	rsp = gf_param (hdr); + +	op_ret    = ntoh32 (hdr->rsp.op_ret); +	op_errno  = ntoh32 (hdr->rsp.op_errno); + +	INIT_LIST_HEAD (&entries.list); +	if (op_ret > 0) { +		buf_size = ntoh32 (rsp->size); +		gf_dirent_unserialize (&entries, rsp->buf, buf_size); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &entries); + +	gf_dirent_free (&entries); + +	return 0; +} + +/* + * client_fsync_cbk - fsync callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_fsync_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_fsync_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + + +/* + * client_unlink_cbk - unlink callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_unlink_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	gf_fop_unlink_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_rename_cbk - rename callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_rename_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	gf_fop_rename_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + + +/* + * client_readlink_cbk - readlink callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_readlink_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	gf_fop_readlink_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	char *link = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret > 0) { +		link = rsp->path; +	} + +	STACK_UNWIND (frame, op_ret, op_errno, link); +	return 0; +} + +/* + * client_mkdir_cbk - mkdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_mkdir_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_mkdir_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	struct stat stbuf = {0, }; +	inode_t *inode = NULL; +	client_local_t *local = NULL; + +	local = frame->local; +	inode = local->loc.inode; +	frame->local = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) { +		gf_stat_to_stat (&rsp->stat, &stbuf); +		this_ino_set (&local->loc, frame->this, stbuf.st_ino); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf); +	 +	client_local_wipe (local); + +	return 0; +} + +/* + * client_flush_cbk - flush callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_flush_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + + +/* + * client_opendir_cbk - opendir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_opendir_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	int32_t               op_ret   = -1; +	int32_t               op_errno = ENOTCONN; +	fd_t                 *fd       = NULL; +	int64_t               remote_fd = 0; +	gf_fop_opendir_rsp_t *rsp       = NULL; +	char                  key[32] = {0,}; +	int32_t               ret     = -1; +	client_local_t       *local = NULL; +	client_conf_t        *conf = NULL; + + +	local = frame->local; frame->local = NULL; +	conf  = frame->this->private; +	fd    = local->fd; + +	rsp = gf_param (hdr); + +	op_ret    = ntoh32 (hdr->rsp.op_ret); +	op_errno  = ntoh32 (hdr->rsp.op_errno); + +	if (op_ret >= 0) { +		remote_fd = ntoh64 (rsp->fd); +	} + +	if (op_ret >= 0) { +		this_fd_set (fd, frame->this, &local->loc, remote_fd); + +		sprintf (key, "%p", fd); + +		pthread_mutex_lock (&conf->mutex); +		{ +			ret = dict_set_str (conf->saved_fds, key, ""); +		} +		pthread_mutex_unlock (&conf->mutex); + +		if (ret < 0) { +			free (key); +			gf_log (frame->this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to save remote fd",  +				local->loc.path, local->loc.inode->ino); +		} +	} + +	STACK_UNWIND (frame, op_ret, op_errno, fd); +	 +	client_local_wipe (local); + +	return 0; +} + + +/* + * client_rmdir_cbk - rmdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int +client_rmdir_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_rmdir_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_access_cbk - access callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_access_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	gf_fop_access_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + + + +/* + * client_lookup_cbk - lookup callback for client protocol + * + * @frame: call frame + * @args: arguments dictionary + * + * not for external reference + */ +int32_t +client_lookup_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	struct stat stbuf = {0, }; +	inode_t *inode = NULL; +	dict_t *xattr = NULL; +	gf_fop_lookup_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	size_t dict_len = 0; +	char *dictbuf = NULL; +	int32_t ret = -1; +	int32_t gf_errno = 0; +	client_local_t *local = NULL; + +	local = frame->local;  +	inode = local->loc.inode; +	frame->local = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); + +	if (op_ret == 0) { +		op_ret = -1; +		gf_stat_to_stat (&rsp->stat, &stbuf); +		this_ino_set (&local->loc, frame->this, stbuf.st_ino); + +		dict_len = ntoh32 (rsp->dict_len); + +		if (dict_len > 0) { +			dictbuf = memdup (rsp->dict, dict_len); +			GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); +			 +			xattr = dict_new(); +			GF_VALIDATE_OR_GOTO(frame->this->name, xattr, fail); + +			ret = dict_unserialize (dictbuf, dict_len, &xattr); +			if (ret < 0) { +				gf_log (frame->this->name, GF_LOG_ERROR, +					"%s (%"PRId64"): failed to unserialize dictionary", +					local->loc.path, inode->ino); +				goto fail; +			} else { +				xattr->extra_free = dictbuf; +				dictbuf = NULL; +			} +		} +		op_ret = 0; +	} +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); + +fail: +	STACK_UNWIND (frame, op_ret, op_errno, inode, &stbuf, xattr); +	 +	client_local_wipe (local); + +	if (dictbuf) +		free (dictbuf); + +	if (xattr) +		dict_unref (xattr); + +	return 0; +} + +static dir_entry_t * +gf_bin_to_direntry (char *buf, size_t count) +{ +	int32_t idx = 0, bread = 0; +	size_t rcount = 0; +	char *ender = NULL, *buffer = NULL; +	char tmp_buf[512] = {0,}; +	dir_entry_t *trav = NULL, *prev = NULL; +	dir_entry_t *thead = NULL, *head = NULL; + +	thead = CALLOC (1, sizeof (dir_entry_t)); +	GF_VALIDATE_OR_GOTO("client-protocol", thead, fail); + +	buffer = buf; +	prev = thead; + +	for (idx = 0; idx < count ; idx++) { +		bread = 0; +		trav = CALLOC (1, sizeof (dir_entry_t)); +		GF_VALIDATE_OR_GOTO("client-protocol", trav, fail); + +		ender = strchr (buffer, '/'); +		if (!ender) +			break; +		rcount = ender - buffer; +		trav->name = CALLOC (1, rcount + 2); +		GF_VALIDATE_OR_GOTO("client-protocol", trav->name, fail); + +		strncpy (trav->name, buffer, rcount); +		bread = rcount + 1; +		buffer += bread; + +		ender = strchr (buffer, '\n'); +		if (!ender) +			break; +		rcount = ender - buffer; +		strncpy (tmp_buf, buffer, rcount); +		bread = rcount + 1; +		buffer += bread; +			 +		gf_string_to_stat (tmp_buf, &trav->buf); + +		ender = strchr (buffer, '\n'); +		if (!ender) +			break; +		rcount = ender - buffer; +		*ender = '\0'; +		if (S_ISLNK (trav->buf.st_mode)) +			trav->link = strdup (buffer); +		else +			trav->link = ""; + +		bread = rcount + 1; +		buffer += bread; + +		prev->next = trav; +		prev = trav; +	} +	 +	head = thead; +fail: +	return head; +} + +int32_t +gf_free_direntry(dir_entry_t *head) +{ +	dir_entry_t *prev = NULL, *trav = NULL; + +	prev = head; +	GF_VALIDATE_OR_GOTO("client-protocol", prev, fail); + +	trav = head->next; +	while (trav) { +		prev->next = trav->next; +		FREE (trav->name); +		if (S_ISLNK (trav->buf.st_mode)) +			FREE (trav->link); +		FREE (trav); +		trav = prev->next; +	} +	FREE (head); +fail: +	return 0; +} +/* + * client_getdents_cbk - readdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_getdents_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	gf_fop_getdents_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	int32_t gf_errno = 0; +	int32_t nr_count = 0; +	dir_entry_t *entry = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); + +	if (op_ret >= 0) { +		nr_count = ntoh32 (rsp->count);		 +		entry = gf_bin_to_direntry(buf, nr_count); +		if (entry == NULL) { +			op_ret = -1; +			op_errno = EINVAL; +		} +	} + +	STACK_UNWIND (frame, op_ret, op_errno, entry, nr_count); + +	if (op_ret >= 0) { +		/* Free the buffer */ +		FREE (buf); +		gf_free_direntry(entry); +      	} + +	return 0; +} + +/* + * client_statfs_cbk - statfs callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_statfs_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	struct statvfs stbuf = {0, }; +	gf_fop_statfs_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret == 0) +	{ +		gf_statfs_to_statfs (&rsp->statfs, &stbuf); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stbuf); + +	return 0; +} + +/* + * client_fsyncdir_cbk - fsyncdir callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_fsyncdir_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_setxattr_cbk - setxattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_setxattr_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	gf_fop_setxattr_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_getxattr_cbk - getxattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_getxattr_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	gf_fop_getxattr_rsp_t *rsp = NULL; +	int32_t op_ret   = 0; +	int32_t gf_errno = 0; +	int32_t op_errno = 0; +	int32_t dict_len = 0; +	dict_t *dict = NULL; +	int32_t ret = -1; +	char *dictbuf = NULL; +	client_local_t *local = NULL; +	 +	local = frame->local; +	frame->local = NULL; + +	rsp = gf_param (hdr); +	GF_VALIDATE_OR_GOTO(frame->this->name, rsp, fail); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); + +	if (op_ret >= 0) { +		op_ret = -1; +		dict_len = ntoh32 (rsp->dict_len); + +		if (dict_len > 0) { +			dictbuf = memdup (rsp->dict, dict_len); +			GF_VALIDATE_OR_GOTO(frame->this->name, dictbuf, fail); + +			dict = dict_new(); +			GF_VALIDATE_OR_GOTO(frame->this->name, dict, fail); + +			ret = dict_unserialize (dictbuf, dict_len, &dict); +			if (ret < 0) { +				gf_log (frame->this->name, GF_LOG_ERROR, +					"%s (%"PRId64"): failed to " +					"unserialize xattr dictionary",  +					local->loc.path, local->loc.inode->ino); +				goto fail; +			} else { +				dict->extra_free = dictbuf; +				dictbuf = NULL; +			} +		} +		op_ret = 0; +	} +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); +fail: +	STACK_UNWIND (frame, op_ret, op_errno, dict); +	 +	client_local_wipe (local); + +	if (dictbuf) +		free (dictbuf); + +	if (dict) +		dict_unref (dict); + +	return 0; +} + +/* + * client_removexattr_cbk - removexattr callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_removexattr_cbk (call_frame_t *frame, +                        gf_hdr_common_t *hdr, size_t hdrlen, +                        char *buf, size_t buflen) +{ +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_lk_cbk - lk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_lk_common_cbk (call_frame_t *frame, +		      gf_hdr_common_t *hdr, size_t hdrlen, +		      char *buf, size_t buflen) +{ +	struct flock lock = {0,}; +	gf_fop_lk_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) { +		gf_flock_to_flock (&rsp->flock, &lock); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &lock); +	return 0; +} + + +/* + * client_gf_file_lk_cbk - gf_file_lk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_inodelk_cbk (call_frame_t *frame, +		    gf_hdr_common_t *hdr, size_t hdrlen, +		    char *buf, size_t buflen) +{ +	gf_fop_inodelk_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); +	return 0; +} + + +int32_t +client_finodelk_cbk (call_frame_t *frame, +		     gf_hdr_common_t *hdr, size_t hdrlen, +		     char *buf, size_t buflen) +{ +	gf_fop_finodelk_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); +	return 0; +} + + +/* + * client_entrylk_cbk - entrylk callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ +int32_t +client_entrylk_cbk (call_frame_t *frame, +		    gf_hdr_common_t *hdr, size_t hdrlen, +		    char *buf, size_t buflen) +{ +	gf_fop_entrylk_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); +	return 0; +} + +int32_t +client_fentrylk_cbk (call_frame_t *frame, +		     gf_hdr_common_t *hdr, size_t hdrlen, +		     char *buf, size_t buflen) +{ +	gf_fop_fentrylk_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); +	return 0; +} + + +/** + * client_writedir_cbk - + * + * @frame: + * @args: + * + * not for external reference + */ +int32_t +client_setdents_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + + + +/* + * client_stats_cbk - stats callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_stats_cbk (call_frame_t *frame, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	struct xlator_stats stats = {0,}; +	gf_mop_stats_rsp_t *rsp = NULL; +	char *buffer = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret >= 0) +	{ +		buffer = rsp->buf; + +		sscanf (buffer, "%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64 +			",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64"\n", +			&stats.nr_files, +			&stats.disk_usage, +			&stats.free_disk, +			&stats.total_disk_size, +			&stats.read_usage, +			&stats.write_usage, +			&stats.disk_speed, +			&stats.nr_clients); +	} + +	STACK_UNWIND (frame, op_ret, op_errno, &stats); +	return 0; +} + +/* + * client_getspec - getspec function for client protocol + * @frame: call frame + * @this: client protocol xlator structure + * @flag: + * + * external reference through client_protocol_xlator->fops->getspec + */ +int32_t +client_getspec (call_frame_t *frame, +                xlator_t *this, +		const char *key, +                int32_t flag) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_mop_getspec_req_t *req = NULL; +	size_t hdrlen = -1; +	int keylen = 0; +	int ret = -1; + +	if (key) +		keylen = STRLEN_0(key); + +	hdrlen = gf_hdr_len (req, keylen); +	hdr    = gf_hdr_new (req, keylen); +	GF_VALIDATE_OR_GOTO(this->name, hdr, unwind); + +	req        = gf_param (hdr); +	req->flags = hton32 (flag); +	req->keylen = hton32 (keylen); +	if (keylen) +		strcpy (req->key, key); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_MOP_REQUEST, GF_MOP_GETSPEC, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +unwind: +	if (hdr) +		free (hdr); +	STACK_UNWIND(frame, -1, EINVAL, NULL); +	return 0; +} + + +/* + * client_getspec_cbk - getspec callback for client protocol + * + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_getspec_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	gf_mop_getspec_rsp_t *rsp = NULL; +	char *spec_data = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	int32_t gf_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); +	rsp = gf_param (hdr); + +	if (op_ret >= 0) { +		spec_data = rsp->spec; +	} + +	STACK_UNWIND (frame, op_ret, op_errno, spec_data); +	return 0; +} + +int32_t +client_checksum (call_frame_t *frame, +                 xlator_t *this, +                 loc_t *loc, +                 int32_t flag) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_checksum_req_t *req = NULL; +	size_t hdrlen = -1; +	int ret = -1; +	client_conf_t *conf = this->private; +	ino_t ino = 0; + +	if (conf->child) { +		STACK_WIND (frame, +			    default_checksum_cbk, +			    conf->child, +			    conf->child->fops->checksum, +			    loc, +			    flag); + +		return 0; +	} + +	hdrlen = gf_hdr_len (req, strlen (loc->path) + 1); +	hdr    = gf_hdr_new (req, strlen (loc->path) + 1); +	req    = gf_param (hdr); +	 +	ino = this_ino_get (loc, this, GF_CLIENT_INODE_SELF); +	req->ino  = hton64 (ino); +	req->flag = hton32 (flag); +	strcpy (req->path, loc->path); + +	ret = protocol_client_xfer (frame, this, +				    CLIENT_CHANNEL (this, CHANNEL_BULK), +				    GF_OP_TYPE_FOP_REQUEST, GF_FOP_CHECKSUM, +				    hdr, hdrlen, NULL, 0, NULL); + +	return ret; +} + +int32_t +client_checksum_cbk (call_frame_t *frame, +                     gf_hdr_common_t *hdr, size_t hdrlen, +                     char *buf, size_t buflen) +{ +	gf_fop_checksum_rsp_t *rsp = NULL; +	int32_t op_ret = 0; +	int32_t op_errno = 0; +	int32_t gf_errno = 0; +	unsigned char *fchecksum = NULL; +	unsigned char *dchecksum = NULL; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	gf_errno = ntoh32 (hdr->rsp.op_errno); +	op_errno = gf_error_to_errno (gf_errno); + +	if (op_ret >= 0) { +		fchecksum = rsp->fchecksum; +		dchecksum = rsp->dchecksum + ZR_FILENAME_MAX; +	} + +	STACK_UNWIND (frame, op_ret, op_errno, fchecksum, dchecksum); +	return 0; +} + + +/* + * client_setspec_cbk - setspec callback for client protocol + * @frame: call frame + * @args: argument dictionary + * + * not for external reference + */ + +int32_t +client_setspec_cbk (call_frame_t *frame, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	int32_t op_ret = 0; +	int32_t op_errno = 0; + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	STACK_UNWIND (frame, op_ret, op_errno); + +	return 0; +} + +/* + * client_setvolume_cbk - setvolume callback for client protocol + * @frame:  call frame + * @args: argument dictionary + * + * not for external reference + */ +int +client_setvolume_cbk (call_frame_t *frame, +                      gf_hdr_common_t *hdr, size_t hdrlen, +                      char *buf, size_t buflen) +{ +	gf_mop_setvolume_rsp_t *rsp = NULL; +	client_connection_t    *conn = NULL; +	client_conf_t          *conf = NULL; +	glusterfs_ctx_t        *ctx = NULL;  +	xlator_t               *this = NULL; +	xlator_list_t          *parent = NULL; +	transport_t            *trans = NULL; +	dict_t                 *reply = NULL; +	char                   *remote_subvol = NULL; +	char                   *remote_error = NULL; +	char                   *process_uuid = NULL; +	int32_t                 ret = -1; +	int32_t                 op_ret   = -1; +	int32_t                 op_errno = EINVAL; +	int32_t                 dict_len = 0; + + +	trans = frame->local; frame->local = NULL; +	this  = frame->this; +	conf  = this->private; +	conn  = trans->xl_private; + +	rsp = gf_param (hdr); + +	op_ret   = ntoh32 (hdr->rsp.op_ret); +	op_errno = gf_error_to_errno (ntoh32 (hdr->rsp.op_errno)); + +	if (op_ret < 0 && op_errno == ENOTCONN) { +		gf_log (this->name, GF_LOG_ERROR, +			"setvolume failed (%s)", +			strerror (op_errno)); +		goto out; +	} + +	reply = dict_new (); +	GF_VALIDATE_OR_GOTO(this->name, reply, out); + +	dict_len = ntoh32 (rsp->dict_len); +	ret = dict_unserialize (rsp->buf, dict_len, &reply); +	if (ret < 0) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"failed to unserialize buffer(%p) to dictionary", +			rsp->buf); +		goto out; +	} +	 +	ret = dict_get_str (reply, "ERROR", &remote_error); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to get ERROR string from reply dictionary"); +	} + +	ret = dict_get_str (reply, "process-uuid", &process_uuid); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"failed to get 'process-uuid' from reply dictionary"); +	} + +	if (op_ret < 0) { +		gf_log (trans->xl->name, GF_LOG_ERROR, +			"SETVOLUME on remote-host failed: %s", +			remote_error ? remote_error : strerror (op_errno)); +		errno = op_errno; +		if (op_errno == ENOTCONN) +			goto out; +	} else { +		ctx = get_global_ctx_ptr (); +		if (process_uuid && !strcmp (ctx->process_uuid,process_uuid)) { +			ret = dict_get_str (this->options, "remote-subvolume", +					    &remote_subvol); +			if (!remote_subvol)  +				goto out; +			 +			gf_log (this->name, GF_LOG_WARNING,  +				"attaching to the local volume '%s'", +				remote_subvol); + +			/* TODO: */ +			conf->child = xlator_search_by_name (this,  +							     remote_subvol); +		} +		gf_log (trans->xl->name, GF_LOG_INFO, +			"connection and handshake succeeded"); + +		pthread_mutex_lock (&(conn->lock)); +		{ +			conn->connected = 1; +		} +		pthread_mutex_unlock (&(conn->lock)); + +		parent = trans->xl->parents; +		while (parent) { +			parent->xlator->notify (parent->xlator, +						GF_EVENT_CHILD_UP, +						trans->xl); +			parent = parent->next; +		} +	} + +out: +	STACK_DESTROY (frame->root); + +	if (reply) +		dict_unref (reply); + +	return op_ret; +} + +/* + * client_enosys_cbk - + * @frame: call frame + * + * not for external reference + */ +int +client_enosys_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	STACK_DESTROY (frame->root); +	return 0; +} + + +void +client_protocol_reconnect (void *trans_ptr) +{ +	transport_t         *trans = NULL; +	client_connection_t *conn = NULL; +	struct timeval       tv = {0, 0}; + +	trans = trans_ptr; +	conn  = trans->xl_private; +	pthread_mutex_lock (&conn->lock); +	{ +		if (conn->reconnect) +			gf_timer_call_cancel (trans->xl->ctx,  +					      conn->reconnect); +		conn->reconnect = 0; + +		if (conn->connected == 0) { +			tv.tv_sec = 10; + +			gf_log (trans->xl->name, GF_LOG_DEBUG, +				"attempting reconnect"); +			transport_connect (trans); + +			conn->reconnect =  +				gf_timer_call_after (trans->xl->ctx, tv, +						     client_protocol_reconnect, +						     trans); +		} else { +			gf_log (trans->xl->name, GF_LOG_DEBUG,  +				"breaking reconnect chain"); +		} +	} +	pthread_mutex_unlock (&conn->lock); +} + +/* + * client_protocol_cleanup - cleanup function + * @trans: transport object + * + */ +int +protocol_client_cleanup (transport_t *trans) +{ +	client_connection_t    *conn = NULL; +	struct saved_frames    *saved_frames = NULL; + +	conn = trans->xl_private; +			 +	gf_log (trans->xl->name, GF_LOG_DEBUG, +		"cleaning up state in transport object %p", trans); + +	pthread_mutex_lock (&conn->lock); +	{ +		saved_frames = conn->saved_frames; +		conn->saved_frames = saved_frames_new (); + +/* +		trav = conn->saved_fds->members_list; +		this = trans->xl; + +		while (trav) { +			fd_t *fd_tmp = (fd_t *)(long) strtoul (trav->key,  +							       NULL, 0); +			fd_ctx_del (fd_tmp, this, NULL); +			trav = trav->next; +		} + +		dict_destroy (conn->saved_fds); + +		conn->saved_fds = get_new_dict_full (64); +*/ +		/* bailout logic cleanup */ +		memset (&(conn->last_sent), 0,  +			sizeof (conn->last_sent)); + +		memset (&(conn->last_received), 0,  +			sizeof (conn->last_received)); + +		if (conn->timer) { +			gf_timer_call_cancel (trans->xl->ctx, conn->timer); +			conn->timer = NULL; +		} + +		if (conn->reconnect == NULL) { +			/* :O This part is empty.. any thing missing? */ +		} +	} +	pthread_mutex_unlock (&conn->lock); + +	saved_frames_destroy (trans->xl, saved_frames, +			      gf_fops, gf_mops, gf_cbks); + +	return 0; +} + + +/* cbk callbacks */ +int +client_releasedir_cbk (call_frame_t *frame, +		       gf_hdr_common_t *hdr, size_t hdrlen, +		       char *buf, size_t buflen) +{ +	STACK_DESTROY (frame->root); +	return 0; +} + + +int +client_release_cbk (call_frame_t *frame, +		    gf_hdr_common_t *hdr, size_t hdrlen, +		    char *buf, size_t buflen) +{ +	STACK_DESTROY (frame->root); +	return 0; +} + + +int +client_forget_cbk (call_frame_t *frame, +                   gf_hdr_common_t *hdr, size_t hdrlen, +                   char *buf, size_t buflen) +{ +	client_conf_t   *conf = NULL; +	client_forget_t  forget = {0, }; +	uint8_t          send_forget = 0; +	int32_t          ret = -1; + + +	conf = frame->this->private; +	LOCK (&conf->forget.lock); +	{ +		conf->forget.frames_in_transit--; + +		ret = client_get_forgets (frame->this, &forget); +		if (ret <= 0) +			send_forget = 0; +		else +			send_forget = 1; +	} +	UNLOCK (&conf->forget.lock); + +	if (send_forget) { +		ret = protocol_client_xfer (forget.frame, frame->this, +					    CLIENT_CHANNEL (frame->this, +							    CHANNEL_BULK), +					    GF_OP_TYPE_CBK_REQUEST,  +					    GF_CBK_FORGET, +					    forget.hdr, forget.hdrlen,  +					    NULL, 0, NULL); +	} +	 +	STACK_DESTROY (frame->root); +	return 0; +} + + +static gf_op_t gf_fops[] = { +	[GF_FOP_STAT]           =  client_stat_cbk, +	[GF_FOP_READLINK]       =  client_readlink_cbk, +	[GF_FOP_MKNOD]          =  client_mknod_cbk, +	[GF_FOP_MKDIR]          =  client_mkdir_cbk, +	[GF_FOP_UNLINK]         =  client_unlink_cbk, +	[GF_FOP_RMDIR]          =  client_rmdir_cbk, +	[GF_FOP_SYMLINK]        =  client_symlink_cbk, +	[GF_FOP_RENAME]         =  client_rename_cbk, +	[GF_FOP_LINK]           =  client_link_cbk, +	[GF_FOP_CHMOD]          =  client_chmod_cbk, +	[GF_FOP_CHOWN]          =  client_chown_cbk, +	[GF_FOP_TRUNCATE]       =  client_truncate_cbk, +	[GF_FOP_OPEN]           =  client_open_cbk, +	[GF_FOP_READ]           =  client_readv_cbk, +	[GF_FOP_WRITE]          =  client_write_cbk, +	[GF_FOP_STATFS]         =  client_statfs_cbk, +	[GF_FOP_FLUSH]          =  client_flush_cbk, +	[GF_FOP_FSYNC]          =  client_fsync_cbk, +	[GF_FOP_SETXATTR]       =  client_setxattr_cbk, +	[GF_FOP_GETXATTR]       =  client_getxattr_cbk, +	[GF_FOP_REMOVEXATTR]    =  client_removexattr_cbk, +	[GF_FOP_OPENDIR]        =  client_opendir_cbk, +	[GF_FOP_GETDENTS]       =  client_getdents_cbk, +	[GF_FOP_FSYNCDIR]       =  client_fsyncdir_cbk, +	[GF_FOP_ACCESS]         =  client_access_cbk, +	[GF_FOP_CREATE]         =  client_create_cbk, +	[GF_FOP_FTRUNCATE]      =  client_ftruncate_cbk, +	[GF_FOP_FSTAT]          =  client_fstat_cbk, +	[GF_FOP_LK]             =  client_lk_common_cbk, +	[GF_FOP_UTIMENS]        =  client_utimens_cbk, +	[GF_FOP_FCHMOD]         =  client_fchmod_cbk, +	[GF_FOP_FCHOWN]         =  client_fchown_cbk, +	[GF_FOP_LOOKUP]         =  client_lookup_cbk, +	[GF_FOP_SETDENTS]       =  client_setdents_cbk, +	[GF_FOP_READDIR]        =  client_readdir_cbk, +	[GF_FOP_INODELK]        =  client_inodelk_cbk, +	[GF_FOP_FINODELK]       =  client_finodelk_cbk, +	[GF_FOP_ENTRYLK]        =  client_entrylk_cbk, +	[GF_FOP_FENTRYLK]       =  client_fentrylk_cbk, +	[GF_FOP_CHECKSUM]       =  client_checksum_cbk, +	[GF_FOP_XATTROP]        =  client_xattrop_cbk, +	[GF_FOP_FXATTROP]       =  client_fxattrop_cbk, +}; + +static gf_op_t gf_mops[] = { +	[GF_MOP_SETVOLUME]        =  client_setvolume_cbk, +	[GF_MOP_GETVOLUME]        =  client_enosys_cbk, +	[GF_MOP_STATS]            =  client_stats_cbk, +	[GF_MOP_SETSPEC]          =  client_setspec_cbk, +	[GF_MOP_GETSPEC]          =  client_getspec_cbk, +	[GF_MOP_PING]             =  client_ping_cbk, +}; + +static gf_op_t gf_cbks[] = { +	[GF_CBK_FORGET]           = client_forget_cbk, +	[GF_CBK_RELEASE]          = client_release_cbk, +	[GF_CBK_RELEASEDIR]       = client_releasedir_cbk +}; + +/* + * client_protocol_interpret - protocol interpreter + * @trans: transport object + * @blk: data block + * + */ +int +protocol_client_interpret (xlator_t *this, transport_t *trans, +                           char *hdr_p, size_t hdrlen, +                           char *buf_p, size_t buflen) +{ +	int ret = -1; +	call_frame_t *frame = NULL; +	gf_hdr_common_t *hdr = NULL; +	uint64_t callid = 0; +	int type = -1; +	int op = -1; + + +	hdr  = (gf_hdr_common_t *)hdr_p; + +	type   = ntoh32 (hdr->type); +	op     = ntoh32 (hdr->op); +	callid = ntoh64 (hdr->callid); + +	frame  = lookup_frame (trans, op, type, callid); +	if (frame == NULL) { +		gf_log (this->name, GF_LOG_ERROR, +			"no frame for callid=%"PRId64" type=%d op=%d", +			callid, type, op); +		return 0; +	} + +	switch (type) { +	case GF_OP_TYPE_FOP_REPLY: +		if ((op > GF_FOP_MAXVALUE) ||  +		    (op < 0)) { +			gf_log (trans->xl->name, GF_LOG_WARNING, +				"invalid fop '%d'", op); +		} else { +			ret = gf_fops[op] (frame, hdr, hdrlen, buf_p, buflen); +		} +		break; +	case GF_OP_TYPE_MOP_REPLY: +		if ((op > GF_MOP_MAXVALUE) ||  +		    (op < 0)) { +			gf_log (trans->xl->name, GF_LOG_WARNING, +				"invalid fop '%d'", op); +		} else { +			ret = gf_mops[op] (frame, hdr, hdrlen, buf_p, buflen); +		} +		break; +	case GF_OP_TYPE_CBK_REPLY: +		if ((op > GF_CBK_MAXVALUE) ||  +		    (op < 0)) { +			gf_log (trans->xl->name, GF_LOG_WARNING, +				"invalid cbk '%d'", op); +		} else { +			ret = gf_cbks[op] (frame, hdr, hdrlen, buf_p, buflen); +		} +		break; +	default: +		gf_log (trans->xl->name, GF_LOG_ERROR, +			"invalid packet type: %d", type); +		break; +	} + +	return ret; +} + +/* + * init - initiliazation function. called during loading of client protocol + * @this: + * + */ +int32_t +init (xlator_t *this) +{ +	transport_t               *trans = NULL; +	client_conf_t             *conf = NULL; +	client_connection_t       *conn = NULL; +	int32_t                    transport_timeout = 0; +	int32_t                    ping_timeout = 0; +	data_t                    *remote_subvolume = NULL; +	int32_t                    ret = -1; +	int                        i = 0; + +	if (this->children) { +		gf_log (this->name, GF_LOG_ERROR, +			"FATAL: client protocol translator cannot have " +			"subvolumes"); +		goto out; +	} +	 +	if (!this->parents) { +		gf_log (this->name, GF_LOG_WARNING, +			"dangling volume. check volfile "); +	} + +	remote_subvolume = dict_get (this->options, "remote-subvolume"); +	if (remote_subvolume == NULL) { +		gf_log (this->name, GF_LOG_ERROR, +			"missing 'option remote-subvolume'."); +		goto out; +	} + +	ret = dict_get_int32 (this->options, "transport-timeout",  +			      &transport_timeout); +	if (ret >= 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"setting transport-timeout to %d", transport_timeout); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"defaulting transport-timeout to 42"); +		transport_timeout = 42; +	} +	 +	ret = dict_get_int32 (this->options, "ping-timeout",  +			      &ping_timeout); +	if (ret >= 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"setting ping-timeout to %d", ping_timeout); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"defaulting ping-timeout to 10"); +		ping_timeout = 10; +	} +	 +	conf = CALLOC (1, sizeof (client_conf_t)); + +	LOCK_INIT (&conf->forget.lock); +	pthread_mutex_init (&conf->mutex, NULL); +	conf->saved_fds = get_new_dict_full (64); + +	this->private = conf; + +	for (i = 0; i < CHANNEL_MAX; i++) { +		trans = transport_load (this->options, this); +		if (trans == NULL) { +			gf_log (this->name, GF_LOG_ERROR,  +				"Failed to load transport"); +			ret = -1; +			goto out; +		} + +		conn = CALLOC (1, sizeof (*conn)); + +		conn->saved_frames = saved_frames_new (); + +		conn->callid = 1; + +		memset (&(conn->last_sent), 0, sizeof (conn->last_sent)); +		memset (&(conn->last_received), 0, +			sizeof (conn->last_received)); + +		conn->transport_timeout = transport_timeout; +		conn->ping_timeout = ping_timeout; + +		pthread_mutex_init (&conn->lock, NULL); + +		trans->xl_private = conn; +		conf->transport[i] = transport_ref (trans); +	} + +#ifndef GF_DARWIN_HOST_OS +	{ +		struct rlimit lim; + +		lim.rlim_cur = 1048576; +		lim.rlim_max = 1048576; +		 +		ret = setrlimit (RLIMIT_NOFILE, &lim); +		if (ret == -1) { +			gf_log (this->name, GF_LOG_WARNING, +				"WARNING: Failed to set 'ulimit -n 1M': %s", +				strerror(errno)); +			lim.rlim_cur = 65536; +			lim.rlim_max = 65536; +			 +			ret = setrlimit (RLIMIT_NOFILE, &lim); +			if (ret == -1) { +				gf_log (this->name, GF_LOG_ERROR, +					"Failed to set max open fd to 64k: %s", +					strerror(errno)); +			} else { +				gf_log (this->name, GF_LOG_ERROR, +					"max open fd set to 64k"); +			} + +		} +	} +#endif +	ret = 0; +out: +	return ret; +} + +/* + * fini - finish function called during unloading of client protocol + * @this: + * + */ +void +fini (xlator_t *this) +{ +	/* TODO: Check if its enough.. how to call transport's fini () */ +	client_conf_t *conf = NULL; + +	conf = this->private; +	this->private = NULL; + +	if (conf) { +		LOCK_DESTROY (&conf->forget.lock); +		FREE (conf); +	} +	return; +} + + +int +protocol_client_handshake (xlator_t *this, transport_t *trans) +{ +	gf_hdr_common_t        *hdr = NULL; +	gf_mop_setvolume_req_t *req = NULL; +	dict_t                 *options = NULL; +	int32_t                 ret = -1; +	int                     hdrlen = 0; +	int                     dict_len = 0; +	call_frame_t           *fr = NULL; +	char                   *process_uuid_xl; + +	options = this->options; +	ret = dict_set_str (options, "version", PACKAGE_VERSION); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to set version(%s) in options dictionary", +			PACKAGE_VERSION); +	} + +	asprintf (&process_uuid_xl, "%s-%s", this->ctx->process_uuid, +		  this->name); +	ret = dict_set_dynstr (options, "process-uuid", +			       process_uuid_xl); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to set process-uuid(%s) in options dictionary", +			PACKAGE_VERSION); +	} + +	dict_len = dict_serialized_length (options); +	if (dict_len < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to get serialized length of dict(%p)", +			options); +		ret = dict_len; +		goto fail; +	} + +	hdrlen = gf_hdr_len (req, dict_len); +	hdr    = gf_hdr_new (req, dict_len); +	GF_VALIDATE_OR_GOTO(this->name, hdr, fail); + +	req    = gf_param (hdr); + +	ret = dict_serialize (options, req->buf); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to serialize dictionary(%p)", +			options); +		goto fail; +	} + +	req->dict_len = hton32 (dict_len); +	fr  = create_frame (this, this->ctx->pool); +	GF_VALIDATE_OR_GOTO(this->name, fr, fail); + +	fr->local = trans; +	ret = protocol_client_xfer (fr, this, trans, +				    GF_OP_TYPE_MOP_REQUEST, GF_MOP_SETVOLUME, +				    hdr, hdrlen, NULL, 0, NULL); +	return ret; +fail: +	if (hdr) +		free (hdr); +	return ret; +} + + +int +protocol_client_pollout (xlator_t *this, transport_t *trans) +{ +	client_connection_t *conn = NULL; + +	conn = trans->xl_private; + +	pthread_mutex_lock (&conn->lock); +	{ +		gettimeofday (&conn->last_sent, NULL); +	} +	pthread_mutex_unlock (&conn->lock); + +	return 0; +} + + +int +protocol_client_pollin (xlator_t *this, transport_t *trans) +{ +	client_connection_t *conn = NULL; +	int ret = -1; +	char *buf = NULL; +	size_t buflen = 0; +	char *hdr = NULL; +	size_t hdrlen = 0; +	int connected = 0; + +	conn = trans->xl_private; + +	pthread_mutex_lock (&conn->lock); +	{ +		gettimeofday (&conn->last_received, NULL); +		connected = conn->connected; +	} +	pthread_mutex_unlock (&conn->lock); + +	ret = transport_receive (trans, &hdr, &hdrlen, &buf, &buflen); + +	if (ret == 0) +	{ +		ret = protocol_client_interpret (this, trans, hdr, hdrlen, +						 buf, buflen); +	} + +	/* TODO: use mem-pool */ +	FREE (hdr); + +	return ret; +} + + +/* + * client_protocol_notify - notify function for client protocol + * @this: + * @trans: transport object + * @event + * + */ + +int32_t +notify (xlator_t *this, +        int32_t event, +        void *data, +        ...) +{ +	int ret = -1; +	transport_t *trans = NULL; +	client_connection_t *conn = NULL; + +	trans = data; + +	switch (event) { +	case GF_EVENT_POLLOUT: +	{ +		ret = protocol_client_pollout (this, trans); + +		break; +	} +	case GF_EVENT_POLLIN: +	{ +		ret = protocol_client_pollin (this, trans); + +		break; +	} +	/* no break for ret check to happen below */ +	case GF_EVENT_POLLERR: +	{ +		ret = -1; +		protocol_client_cleanup (trans); +	} + +	conn = trans->xl_private; +	if (conn->connected) { +		xlator_list_t *parent = NULL; + +		gf_log (this->name, GF_LOG_INFO, "disconnected"); + +		parent = this->parents; +		while (parent) { +			parent->xlator->notify (parent->xlator, +						GF_EVENT_CHILD_DOWN, +						this); +			parent = parent->next; +		} + +		conn->connected = 0; +		if (conn->reconnect == 0) +			client_protocol_reconnect (trans); +	} +	break; + +	case GF_EVENT_PARENT_UP: +	{ +		xlator_list_t *parent = NULL; +		client_conf_t *conf = NULL; +		int            i = 0; +		transport_t   *trans = NULL; + +		conf = this->private; +		for (i = 0; i < CHANNEL_MAX; i++) { +			trans = conf->transport[i]; +			if (!trans) { +				gf_log (this->name, GF_LOG_DEBUG, +					"transport init failed"); +				return -1; +			} + +			conn = trans->xl_private; + +			gf_log (this->name, GF_LOG_DEBUG, +				"got GF_EVENT_PARENT_UP, attempting connect " +				"on transport"); + +			client_protocol_reconnect (trans); +		} + +		/* Let the connection/re-connection happen in  +		 * background, for now, don't hang here, +		 * tell the parents that i am all ok.. +		 */ +		parent = trans->xl->parents; +		while (parent) { +			parent->xlator->notify (parent->xlator, +						GF_EVENT_CHILD_CONNECTING, +						trans->xl); +			parent = parent->next; +		} +	} +	break; + +	case GF_EVENT_CHILD_UP: +	{ +		char *handshake = NULL; + +		ret = dict_get_str (this->options, "disable-handshake",  +				    &handshake); +		gf_log (this->name, GF_LOG_DEBUG,  +			"got GF_EVENT_CHILD_UP"); +		if ((ret < 0) || +		    (strcasecmp (handshake, "on"))) { +			ret = protocol_client_handshake (this, trans); +		} else { +			conn = trans->xl_private; +			conn->connected = 1; +			ret = default_notify (this, event, trans); +		} + +		if (ret) +			transport_disconnect (trans); + +	} +	break; + +	default: +		gf_log (this->name, GF_LOG_DEBUG, +			"got %d, calling default_notify ()", event); + +		default_notify (this, event, data); +		break; +	} + +	return ret; +} + + +struct xlator_fops fops = { +	.stat        = client_stat, +	.readlink    = client_readlink, +	.mknod       = client_mknod, +	.mkdir       = client_mkdir, +	.unlink      = client_unlink, +	.rmdir       = client_rmdir, +	.symlink     = client_symlink, +	.rename      = client_rename, +	.link        = client_link, +	.chmod       = client_chmod, +	.chown       = client_chown, +	.truncate    = client_truncate, +	.utimens     = client_utimens, +	.open        = client_open, +	.readv       = client_readv, +	.writev      = client_writev, +	.statfs      = client_statfs, +	.flush       = client_flush, +	.fsync       = client_fsync, +	.setxattr    = client_setxattr, +	.getxattr    = client_getxattr, +	.removexattr = client_removexattr, +	.opendir     = client_opendir, +	.readdir     = client_readdir, +	.fsyncdir    = client_fsyncdir, +	.access      = client_access, +	.ftruncate   = client_ftruncate, +	.fstat       = client_fstat, +	.create      = client_create, +	.lk          = client_lk, +	.inodelk     = client_inodelk, +	.finodelk    = client_finodelk, +	.entrylk     = client_entrylk, +	.fentrylk    = client_fentrylk, +	.lookup      = client_lookup, +	.fchmod      = client_fchmod, +	.fchown      = client_fchown, +	.setdents    = client_setdents, +	.getdents    = client_getdents, +	.checksum    = client_checksum, +	.xattrop     = client_xattrop, +	.fxattrop    = client_fxattrop, +}; + +struct xlator_mops mops = { +	.stats     = client_stats, +	.getspec   = client_getspec, +}; + +struct xlator_cbks cbks = { +	.forget     = client_forget, +	.release    = client_release, +	.releasedir = client_releasedir +}; + + +struct volume_options options[] = { + 	{ .key   = {"username"},  +	  .type  = GF_OPTION_TYPE_ANY  +	}, + 	{ .key   = {"password"},  +	  .type  = GF_OPTION_TYPE_ANY  +	}, + 	{ .key   = {"transport-type"},  +	  .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp",  +		    "tcp/client", "ib-verbs/client"}, +	  .type  = GF_OPTION_TYPE_STR  +	}, + 	{ .key   = {"remote-host"},  +	  .type  = GF_OPTION_TYPE_ANY  +	}, + 	{ .key   = {"remote-subvolume"},  +	  .type  = GF_OPTION_TYPE_ANY  +	}, + 	{ .key   = {"transport-timeout"},  +	  .type  = GF_OPTION_TYPE_TIME,  +	  .min   = 5,  +	  .max   = 1013,  +	},  +	{ .key   = {"ping-timeout"}, +	  .type  = GF_OPTION_TYPE_TIME, +	  .min   = 5, +	  .max   = 1013, +	}, +	{ .key   = {NULL} }, +}; diff --git a/xlators/protocol/client/src/client-protocol.h b/xlators/protocol/client/src/client-protocol.h new file mode 100644 index 00000000000..c90cc980d83 --- /dev/null +++ b/xlators/protocol/client/src/client-protocol.h @@ -0,0 +1,173 @@ +/* +  Copyright (c) 2006, 2007 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CLIENT_PROTOCOL_H +#define _CLIENT_PROTOCOL_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <arpa/inet.h> +#include "inode.h" +#include "timer.h" +#include "byte-order.h" + +#define CLIENT_PROTO_FORGET_LIMIT  128 +#define CLIENT_PORT_CIELING        1023 + +#define GF_CLIENT_INODE_SELF   0 +#define GF_CLIENT_INODE_PARENT 1 + +#define CLIENT_CONF(this) ((client_conf_t *)(this->private)) + +#define RECEIVE_TIMEOUT(_cprivate,_current)         \ +		((_cprivate->last_received.tv_sec + \ +                  _cprivate->transport_timeout) <   \ +                  _current.tv_sec) + +#define SEND_TIMEOUT(_cprivate,_current)          \ +		((_cprivate->last_sent.tv_sec +   \ +                  _cprivate->transport_timeout) < \ +                  _current.tv_sec) + +enum { +	CHANNEL_BULK = 0, +	CHANNEL_LOWLAT = 1, +	CHANNEL_MAX +}; +#define CLIENT_CHANNEL(xl,id) \ +	(((client_conf_t *)(xl->private))->transport[id]) + +struct client_connection; +typedef struct client_connection client_connection_t; + +#include "stack.h" +#include "xlator.h" +#include "transport.h" +#include "protocol.h" + +struct _client_conf { +	transport_t          *transport[CHANNEL_MAX]; +	xlator_t             *child; + +	/* enhancement for 'forget', a must required where lot  +	   of stats happening */ +	struct { +		uint64_t  ino_array[CLIENT_PROTO_FORGET_LIMIT + 4]; +		uint32_t  count; +		uint32_t  frames_in_transit; +		gf_lock_t lock; +	} forget; +	dict_t              *saved_fds; +	pthread_mutex_t      mutex; +}; +typedef struct _client_conf client_conf_t; + +/* This will be stored in transport_t->xl_private */ +struct client_connection { +	pthread_mutex_t      lock; +	uint64_t             callid; +	struct saved_frames *saved_frames; +	int32_t              transport_timeout; +	int32_t              ping_started; +	int32_t              ping_timeout; +	gf_timer_t          *reconnect; +	char                 connected; +	uint64_t             max_block_size; +	struct timeval       last_sent; +	struct timeval       last_received; +	gf_timer_t          *timer; +	gf_timer_t          *ping_timer; +}; + +typedef struct { +	loc_t loc; +	loc_t loc2; +	fd_t *fd; +} client_local_t; + +typedef struct { +	gf_hdr_common_t *hdr; +	size_t           hdrlen; +	call_frame_t    *frame; +} client_forget_t; + +static inline void +gf_string_to_stat(char *string, struct stat *stbuf) +{ +	uint64_t dev        = 0; +	uint64_t ino        = 0; +	uint32_t mode       = 0; +	uint32_t nlink      = 0; +	uint32_t uid        = 0; +	uint32_t gid        = 0; +	uint64_t rdev       = 0; +	uint64_t size       = 0; +	uint32_t blksize    = 0; +	uint64_t blocks     = 0; +	uint32_t atime      = 0; +	uint32_t atime_nsec = 0; +	uint32_t mtime      = 0; +	uint32_t mtime_nsec = 0; +	uint32_t ctime      = 0; +	uint32_t ctime_nsec = 0; + +	sscanf (string, GF_STAT_PRINT_FMT_STR, +		&dev, +		&ino, +		&mode, +		&nlink, +		&uid, +		&gid, +		&rdev, +		&size, +		&blksize, +		&blocks, +		&atime, +		&atime_nsec, +		&mtime, +		&mtime_nsec, +		&ctime, +		&ctime_nsec); +	 +	stbuf->st_dev   = dev; +	stbuf->st_ino   = ino; +	stbuf->st_mode  = mode; +	stbuf->st_nlink = nlink; +	stbuf->st_uid   = uid; +	stbuf->st_gid   = gid; +	stbuf->st_rdev  = rdev; +	stbuf->st_size  = size; +	stbuf->st_blksize = blksize; +	stbuf->st_blocks  = blocks; +	 +	stbuf->st_atime = atime; +	stbuf->st_mtime = mtime; +	stbuf->st_ctime = ctime; +	 +	ST_ATIM_NSEC_SET(stbuf, atime_nsec); +	ST_MTIM_NSEC_SET(stbuf, mtime_nsec); +	ST_CTIM_NSEC_SET(stbuf, ctime_nsec); + +} + +#endif diff --git a/xlators/protocol/client/src/saved-frames.c b/xlators/protocol/client/src/saved-frames.c new file mode 100644 index 00000000000..0d1366d8222 --- /dev/null +++ b/xlators/protocol/client/src/saved-frames.c @@ -0,0 +1,178 @@ +/* +  Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#include "saved-frames.h" +#include "common-utils.h" +#include "protocol.h" +#include "xlator.h" + + + +struct saved_frames * +saved_frames_new (void) +{ +	struct saved_frames *saved_frames = NULL; + +	saved_frames = CALLOC (sizeof (*saved_frames), 1); +	if (!saved_frames) { +		return NULL; +	} + +	INIT_LIST_HEAD (&saved_frames->fops.list); +	INIT_LIST_HEAD (&saved_frames->mops.list); +	INIT_LIST_HEAD (&saved_frames->cbks.list); + +	return saved_frames; +} + + +struct saved_frame * +get_head_frame_for_type (struct saved_frames *frames, int8_t type) +{ +	struct saved_frame *head_frame = NULL; + +	switch (type) { +	case GF_OP_TYPE_FOP_REQUEST: +	case GF_OP_TYPE_FOP_REPLY: +		head_frame = &frames->fops; +		break; +	case GF_OP_TYPE_MOP_REQUEST: +	case GF_OP_TYPE_MOP_REPLY: +		head_frame = &frames->mops; +		break; +	case GF_OP_TYPE_CBK_REQUEST: +	case GF_OP_TYPE_CBK_REPLY: +		head_frame = &frames->cbks; +		break; +	} + +	return head_frame; +} + + +int +saved_frames_put (struct saved_frames *frames, call_frame_t *frame, +		  int32_t op, int8_t type, int64_t callid) +{ +	struct saved_frame *saved_frame = NULL; +	struct saved_frame *head_frame = NULL; + +	head_frame = get_head_frame_for_type (frames, type); + +	saved_frame = CALLOC (sizeof (*saved_frame), 1); +	if (!saved_frame) { +		return -ENOMEM; +	} + +	INIT_LIST_HEAD (&saved_frame->list); +	saved_frame->frame  = frame; +	saved_frame->op     = op; +	saved_frame->type   = type; +	saved_frame->callid = callid; + +//	gettimeofday (&saved_frame->saved_at, NULL); + +	list_add (&saved_frame->list, &head_frame->list); +	frames->count++; + +	return 0; +} + + +call_frame_t * +saved_frames_get (struct saved_frames *frames, int32_t op, +		  int8_t type, int64_t callid) +{ +	struct saved_frame *saved_frame = NULL; +	struct saved_frame *tmp = NULL; +	struct saved_frame *head_frame = NULL; +	call_frame_t       *frame = NULL; + +	head_frame = get_head_frame_for_type (frames, type); + +	list_for_each_entry (tmp, &head_frame->list, list) { +		if (tmp->callid == callid) { +			list_del_init (&tmp->list); +			frames->count--; +			saved_frame = tmp; +			break; +		} +	} + +	if (saved_frame) +		frame = saved_frame->frame; + +	FREE (saved_frame); + +	return frame; +} + + +void +saved_frames_unwind (xlator_t *this, struct saved_frames *saved_frames, +		     struct saved_frame *head, +		     gf_op_t gf_ops[], char *gf_op_list[]) +{ +	struct saved_frame   *trav = NULL; +	struct saved_frame   *tmp = NULL; + +	gf_hdr_common_t       hdr = {0, }; +	call_frame_t         *frame = NULL; +	dict_t               *reply = NULL; + +	reply = get_new_dict(); +	dict_ref (reply); + +	hdr.rsp.op_ret   = hton32 (-1); +	hdr.rsp.op_errno = hton32 (ENOTCONN); + +	list_for_each_entry_safe (trav, tmp, &head->list, list) { +		gf_log (this->name, GF_LOG_ERROR, +			"forced unwinding frame type(%d) op(%s)", +			trav->type, gf_op_list[trav->op]); + +		hdr.type = hton32 (trav->type); +		hdr.op   = hton32 (trav->op); + +		frame = trav->frame; +		frame->root->rsp_refs = reply; + +		saved_frames->count--; + +		gf_ops[trav->op] (frame, &hdr, sizeof (hdr), NULL, 0); + +		list_del_init (&trav->list); +		FREE (trav); +	} + +	dict_unref (reply); +} + + +void +saved_frames_destroy (xlator_t *this, struct saved_frames *frames, +		      gf_op_t gf_fops[], gf_op_t gf_mops[], gf_op_t gf_cbks[]) +{ +	saved_frames_unwind (this, frames, &frames->fops, gf_fops, gf_fop_list); +	saved_frames_unwind (this, frames, &frames->mops, gf_mops, gf_mop_list); +	saved_frames_unwind (this, frames, &frames->cbks, gf_cbks, gf_cbk_list); + +	FREE (frames); +} diff --git a/xlators/protocol/client/src/saved-frames.h b/xlators/protocol/client/src/saved-frames.h new file mode 100644 index 00000000000..e402feba33b --- /dev/null +++ b/xlators/protocol/client/src/saved-frames.h @@ -0,0 +1,74 @@ +/* +  Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SAVED_FRAMES_H +#define _SAVED_FRAMES_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <sys/time.h> +#include "stack.h" +#include "list.h" +#include "protocol.h" + +/* UGLY: have common typedef b/w saved-frames.c and protocol-client.c */ +typedef int32_t (*gf_op_t) (call_frame_t *frame, +                            gf_hdr_common_t *hdr, size_t hdrlen, +                            char *buf, size_t buflen); + + +struct saved_frame { +	union { +		struct list_head list; +		struct { +			struct saved_frame *frame_next; +			struct saved_frame *frame_prev; +		}; +	}; + +	struct timeval  saved_at; +	call_frame_t   *frame; +	int32_t         op; +	int8_t          type; +	uint64_t        callid; +}; + + +struct saved_frames { +	int64_t            count; +	struct saved_frame fops; +	struct saved_frame mops; +	struct saved_frame cbks; +}; + + +struct saved_frames *saved_frames_new (); +int saved_frames_put (struct saved_frames *frames, call_frame_t *frame, +		      int32_t op, int8_t type, int64_t callid); +call_frame_t *saved_frames_get (struct saved_frames *frames, int32_t op, +				int8_t type, int64_t callid); +void saved_frames_destroy (xlator_t *this, struct saved_frames *frames, +			   gf_op_t gf_fops[], gf_op_t gf_mops[], +			   gf_op_t gf_cbks[]); + +#endif /* _SAVED_FRAMES_H */ diff --git a/xlators/protocol/server/Makefile.am b/xlators/protocol/server/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/protocol/server/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES =  diff --git a/xlators/protocol/server/src/Makefile.am b/xlators/protocol/server/src/Makefile.am new file mode 100644 index 00000000000..dcd92aeedd9 --- /dev/null +++ b/xlators/protocol/server/src/Makefile.am @@ -0,0 +1,18 @@ + +xlator_LTLIBRARIES = server.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/protocol + +server_la_LDFLAGS = -module -avoidversion + +server_la_SOURCES = server-protocol.c server-dentry.c server-helpers.c +server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = server-protocol.h server-helpers.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ +	-I$(top_srcdir)/libglusterfs/src -shared -nostartfiles \ +	-DDATADIR=\"$(localstatedir)\" -DCONFDIR=\"$(sysconfdir)/glusterfs\"  \ +	$(GF_CFLAGS) + +CLEANFILES =  + diff --git a/xlators/protocol/server/src/server-dentry.c b/xlators/protocol/server/src/server-dentry.c new file mode 100644 index 00000000000..d3a69a393fc --- /dev/null +++ b/xlators/protocol/server/src/server-dentry.c @@ -0,0 +1,413 @@ +#include "glusterfs.h" +#include "xlator.h" +#include "server-protocol.h" +#include "server-helpers.h" +#include <libgen.h> + +/* SERVER_DENTRY_STATE_PREPARE - prepare a fresh state for use + * + * @state    - an empty state + * @loc      - loc_t which needs to resolved + * @parent   - most immediate parent of @loc available in dentry cache + * @resolved - component of @loc->path which has been resolved + *             through dentry cache + */ +#define SERVER_DENTRY_STATE_PREPARE(_state,_loc,_parent,_resolved) do {	\ +		size_t pathlen = 0;					\ +		size_t resolvedlen = 0;					\ +		char *path = NULL;					\ +		int pad = 0;						\ +		pathlen   = strlen (_loc->path) + 1;			\ +		path = CALLOC (1, pathlen);				\ +		_state->loc.parent = inode_ref (_parent);		\ +		_state->loc.inode  = inode_new (_state->itable);	\ +		if (_resolved) {					\ +			resolvedlen = strlen (_resolved);		\ +			strncpy (path, _resolved, resolvedlen);		\ +			_state->resolved = memdup (path, pathlen);	\ +			if (resolvedlen == 1) /* only root resolved */	\ +				pad = 0;				\ +			else {						\ +				pad = 1;				\ +				path[resolvedlen] = '/';		\ +			}						\ +			strcpy_till (path + resolvedlen + pad, loc->path + resolvedlen + pad, '/'); \ +		} else {						\ +			strncpy (path, _loc->path, pathlen);		\ +		}							\ +		_state->loc.path = path;				\ +		_state->loc.name = strrchr (path, '/');			\ +		if (_state->loc.name)					\ +			_state->loc.name++;				\ +		_state->path = strdup (_loc->path);			\ +	}while (0); + +/* SERVER_DENTRY_UPDATE_STATE - update a server_state_t, to prepare state + *                              for new lookup + * + * @state - state to be updated. + */ +#define SERVER_DENTRY_UPDATE_STATE(_state) do {				\ +		char *path = NULL;					\ +		size_t pathlen = 0;					\ +		strcpy (_state->resolved, _state->loc.path);		\ +		pathlen = strlen (_state->loc.path);			\ +		if (!strcmp (_state->resolved, _state->path)) {		\ +			free (_state->resolved);			\ +			_state->resolved = NULL;			\ +			goto resume;					\ +		}							\ +									\ +		path = (char *)(_state->loc.path + pathlen);		\ +		path[0] = '/';						\ +		strcpy_till (path + 1,					\ +			     _state->path + pathlen + 1, '/');		\ +		_state->loc.name = strrchr (_state->loc.path, '/');	\ +		if (_state->loc.name)					\ +			_state->loc.name++;				\ +		inode_unref (_state->loc.parent);			\ +		_state->loc.parent = inode_ref (_state->loc.inode);	\ +		inode_unref (_state->loc.inode);			\ +		_state->loc.inode = inode_new (_state->itable);		\ +	}while (0); + +/* NOTE: should be used only for a state which was created by __do_path_resolve + *       using any other state will result in double free corruption. + */ +#define SERVER_STATE_CLEANUP(_state) do {	\ +		if (_state->resolved)		\ +			free (_state->resolved);	\ +		if (_state->path)		\ +			free (_state->path);	\ +		server_loc_wipe (&_state->loc);	\ +		free_state (_state);		\ +	} while (0); + +/* strcpy_till - copy @dname to @dest, until 'delim' is encountered in @dest + * @dest - destination string + * @dname - source string + * @delim - delimiter character + * + * return - NULL is returned if '0' is encountered in @dname, otherwise returns + *          a pointer to remaining string begining in @dest. + */ +static char * +strcpy_till (char *dest, const char *dname, char delim) +{ +	char *src = NULL; +	int idx = 0; +	char *ret = NULL; + +	src = (char *)dname; +	while (src[idx] && (src[idx] != delim)) { +		dest[idx] = src[idx]; +		idx++; +	} + +	dest[idx] = 0; + +	if (src[idx] == 0) +		ret = NULL; +	else +		ret = &(src[idx]); + +	return ret; +} + +/* __server_path_to_parenti - derive parent inode for @path. if immediate parent is + *                            not available in the dentry cache, return nearest + *                            available parent inode and set @reslv to the path of + *                            the returned directory. + * + * @itable - inode table + * @path   - path whose parent has to be looked up. + * @reslv  - if immediate parent is not available, reslv will be set to path of the + *           resolved parent. + * + * return - should never return NULL. should at least return '/' inode. + */ +static inode_t * +__server_path_to_parenti (inode_table_t *itable, +                          const char *path, +                          char **reslv) +{ +        char *resolved_till = NULL; +        char *strtokptr = NULL; +        char *component = NULL; +        char *next_component = NULL; +        char *pathdup = NULL; +        inode_t *curr = NULL; +        inode_t *parent = NULL; +        size_t pathlen = 0; + + +        pathlen = STRLEN_0 (path); +        resolved_till = CALLOC (1, pathlen); + +        GF_VALIDATE_OR_GOTO("server-dentry", resolved_till, out); +        pathdup = strdup (path); +        GF_VALIDATE_OR_GOTO("server-dentry", pathdup, out); + +        parent = inode_ref (itable->root); +        curr = NULL; + +        component = strtok_r (pathdup, "/", &strtokptr); + +        while (component) { +                curr = inode_search (itable, parent->ino, component); +                if (!curr) { +                        /* if current component was the last component +                           set it to NULL                                                            +			*/ +                        component = strtok_r (NULL, "/", &strtokptr); +                        break; +                } + +                /* It is OK to append the component even if it is the                                +                   last component in the path, because, if 'next_component' +                   returns NULL, @parent will remain the same and +                   @resolved_till will not be sent back                                              +		*/ + +                strcat (resolved_till, "/"); +                strcat (resolved_till, component); + +                next_component = strtok_r (NULL, "/", &strtokptr); + +                if (next_component) { +                        inode_unref (parent); +                        parent = curr; +                        curr = NULL; +                } else { +                        /* will break */ +                        inode_unref (curr); +                } + +                component = next_component; +        } + +        free (pathdup); + +        if (component) { +                *reslv = resolved_till; +        } else { +                free (resolved_till); +        } +out: +        return parent; +} + + +/* __do_path_resolve_cbk - + * + * @frame - + * @cookie - + * @this - + * @op_ret - + * @op_errno - + * @inode - + * @stbuf - + * @dict - + * + */ +static int32_t +__do_path_resolve_cbk (call_frame_t *frame, +		       void *cookie, +		       xlator_t *this, +		       int32_t op_ret, +		       int32_t op_errno, +		       inode_t *inode, +		       struct stat *stbuf, +		       dict_t *dict) +{ +	server_state_t *state = NULL; +	call_stub_t *stub = NULL; +	inode_t *parent = NULL; + +	stub = frame->local; +	state = CALL_STATE(frame); +	 +	parent = state->loc.parent; + +	if (op_ret == -1) { +		if (strcmp (state->path, state->loc.path)) +			parent = NULL; +		 +		server_stub_resume (stub, op_ret, op_errno, NULL, parent); +		goto cleanup; +	} else { +		if (inode->ino == 0) { +			gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +				"looked up for %s (%"PRId64"/%s)", +				state->loc.path, state->loc.parent->ino, state->loc.name); +			inode_link (inode, state->loc.parent, state->loc.name, stbuf); +			inode_lookup (inode); +		} + +		if (state->resolved) { +			SERVER_DENTRY_UPDATE_STATE(state); + +			gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +				"looking up for %s (%"PRId64"/%s)", +				state->loc.path, state->loc.parent->ino, state->loc.name); + +			STACK_WIND (frame, +				    __do_path_resolve_cbk, +				    BOUND_XL(frame), +				    BOUND_XL(frame)->fops->lookup, +				    &(state->loc), +				    0); + +			goto out; +		} +	resume: +		/* we are done, call stub_resume() to do rest of the job */ +		server_stub_resume (stub, op_ret, op_errno, inode, parent); +	cleanup: +		SERVER_STATE_CLEANUP(state); +		/* stub will be freed by stub_resume, leave no traces */ +		frame->local = NULL; +		STACK_DESTROY (frame->root); +	} +out: +	return 0; +} + +/* __do_path_resolve - resolve @loc->path into @loc->inode and @loc->parent. also + *                     update the dentry cache + * + * @stub - call stub to resume after resolving @loc->path + * @loc  - loc to resolve before resuming @stub. + * + * return - return value of __do_path_resolve doesn't matter to the caller, if @stub + *          is not NULL. + */ +static int32_t +__do_path_resolve (call_stub_t *stub, +		   const loc_t *loc) +{ +	int32_t         ret = -1; +	char           *resolved  = NULL; +	call_frame_t   *new_frame = NULL; +	server_state_t *state = NULL, *new_state = NULL; +	inode_t        *parent = NULL; +	 +	state = CALL_STATE(stub->frame); +	parent = loc->parent; +	if (parent) { +		inode_ref (parent); +		gf_log (BOUND_XL(stub->frame)->name, GF_LOG_DEBUG, +			"loc->parent(%"PRId64") already present. sending lookup " +			"for %"PRId64"/%s", parent->ino, parent->ino, loc->name); +		resolved = strdup (loc->path); +		resolved = dirname (resolved); +	} else { +		parent = __server_path_to_parenti (state->itable, loc->path, &resolved); +	} + +	if (parent == NULL) { +		/* fire in the bush.. run! run!! run!!! */ +		gf_log ("server", +			GF_LOG_CRITICAL, +			"failed to get parent inode number"); +		goto panic; +	}		 + +	if (resolved) { +		gf_log (BOUND_XL(stub->frame)->name, +			GF_LOG_DEBUG, +			"resolved path(%s) till %"PRId64"(%s). " +			"sending lookup for remaining path", +			loc->path, parent->ino, resolved); +	} +	 +	{ +		new_frame = server_copy_frame (stub->frame); +		new_state = CALL_STATE(new_frame); + +		SERVER_DENTRY_STATE_PREPARE(new_state, loc, parent, resolved); +		 +		if (parent) +			inode_unref (parent); /* __server_path_to_parenti()'s  inode_ref */ +		free (resolved); +		/* now interpret state as: +		 * state->path - compelete pathname to resolve +		 * state->resolved - pathname resolved from dentry cache +		 */ +		new_frame->local = stub; +		STACK_WIND (new_frame, +			    __do_path_resolve_cbk, +			    BOUND_XL(new_frame), +			    BOUND_XL(new_frame)->fops->lookup, +			    &(new_state->loc), +			    0); +		goto out; +	} +panic: +	server_stub_resume (stub, -1, ENOENT, NULL, NULL);	 +out: +	return ret; +} + + +/* + * do_path_lookup - transform a pathname into inode, with the compelete + *                  dentry tree upto inode built. + * + * @stub - call stub to resume after completing pathname to inode transform + * @loc  - location. valid fields that do_path_lookup() uses in @loc are + *         @loc->path - pathname + *         @loc->ino  - inode number + * + * return - do_path_lookup returns only after complete dentry tree is built + *          upto @loc->path. + */ +int32_t +do_path_lookup (call_stub_t *stub, +		const loc_t *loc) +{ +	char       *pathname  = NULL; +	char       *directory = NULL; +	inode_t    *inode = NULL; +	inode_t    *parent = NULL; +	server_state_t *state = NULL; +	 +	state = CALL_STATE(stub->frame); + +	inode = inode_from_path (state->itable, loc->path); +	pathname  = strdup (loc->path); +	directory = dirname (pathname); +	parent = inode_from_path (state->itable, directory); +	 +	if (inode && parent) { +		gf_log (BOUND_XL(stub->frame)->name, +			GF_LOG_DEBUG, +			"resolved path(%s) to %"PRId64"/%"PRId64"(%s)", +			loc->path, parent->ino, inode->ino, loc->name); +		server_stub_resume (stub, 0, 0, inode, parent); +		inode_unref (inode); +		inode_unref (parent); +	} else { +		gf_log (BOUND_XL(stub->frame)->name, +			GF_LOG_DEBUG, +			"resolved path(%s) to %p(%"PRId64")/%p(%"PRId64")", +			loc->path, parent, (parent ? parent->ino : 0),  +			inode, (inode ? inode->ino : 0)); +		if (parent) { +			inode_unref (parent); +		} else if (inode) { +			inode_unref (inode); +			gf_log (BOUND_XL(stub->frame)->name, +				GF_LOG_ERROR, +				"undesired behaviour. inode(%"PRId64") for %s " +				"exists without parent (%s)",  +				inode->ino, loc->path, directory); +		} +		__do_path_resolve (stub, loc); +	} +	 +	if (pathname) +		free (pathname); + +	return 0; +} diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c new file mode 100644 index 00000000000..b51c11aa994 --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.c @@ -0,0 +1,586 @@ +/* +  Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server-protocol.h" +#include "server-helpers.h" + + +/* server_loc_fill - derive a loc_t for a given inode number + * + * NOTE: make sure that @loc is empty, because any pointers it holds with reference will + *       be leaked after returning from here. + */ +int +server_loc_fill (loc_t *loc, server_state_t *state, +  		 ino_t ino, ino_t par, +  		 const char *name, const char *path) +{ +  	inode_t *inode = NULL; +  	inode_t *parent = NULL; +  	int32_t  ret = -1; +	char    *dentry_path = NULL; + + +  	GF_VALIDATE_OR_GOTO ("server", loc, out); +  	GF_VALIDATE_OR_GOTO ("server", state, out); +  	GF_VALIDATE_OR_GOTO ("server", path, out); + +  	/* anything beyond this point is success */ +  	ret = 0; +	loc->ino = ino; +  	inode = loc->inode; +  	if (inode == NULL) { +  		if (ino) +  			inode = inode_search (state->itable, ino, NULL); + +  		if ((inode == NULL) && +  		    (par && name)) +  			inode = inode_search (state->itable, par, name); + +  		loc->inode = inode; +  		if (inode) +  			loc->ino = inode->ino; +  	} + +  	parent = loc->parent; +	if (parent == NULL) { +		if (inode) +			parent = inode_parent (inode, par, name); +		else +			parent = inode_search (state->itable, par, NULL); +		loc->parent = parent; +	} + +	if (name && parent) { +		ret = inode_path (parent, name, &dentry_path); +		if (ret < 0) { +			gf_log (state->bound_xl->name, GF_LOG_DEBUG, +				"failed to build path for %"PRId64"/%s: %s", +				parent->ino, name, strerror (-ret)); +		} +	} else if (inode) { +		ret = inode_path (inode, NULL, &dentry_path); +		if (ret < 0) { +			gf_log (state->bound_xl->name, GF_LOG_DEBUG, +				"failed to build path for %"PRId64": %s", +				inode->ino, strerror (-ret)); + +			inode_unref (loc->inode); +			loc->inode = NULL; +		} +	} + +	if (dentry_path) { +		if (strcmp (dentry_path, path)) { +			gf_log (state->bound_xl->name, GF_LOG_DEBUG, +				"paths differ for inode(%"PRId64"): " +				"client path = %s. dentry path = %s", +				ino, path, dentry_path); +		} + +		loc->path = dentry_path; +		loc->name = strrchr (loc->path, '/'); +		if (loc->name) +			loc->name++; +	} else { +		loc->path = strdup (path); +		loc->name = strrchr (loc->path, '/'); +		if (loc->name) +			loc->name++; +	} + +out: +  	return ret; +} + +/* + * stat_to_str - convert struct stat to a ASCII string + * @stbuf: struct stat pointer + * + * not for external reference + */ +char * +stat_to_str (struct stat *stbuf) +{ +	char *tmp_buf = NULL; + +	uint64_t dev = stbuf->st_dev; +	uint64_t ino = stbuf->st_ino; +	uint32_t mode = stbuf->st_mode; +	uint32_t nlink = stbuf->st_nlink; +	uint32_t uid = stbuf->st_uid; +	uint32_t gid = stbuf->st_gid; +	uint64_t rdev = stbuf->st_rdev; +	uint64_t size = stbuf->st_size; +	uint32_t blksize = stbuf->st_blksize; +	uint64_t blocks = stbuf->st_blocks; +	uint32_t atime = stbuf->st_atime; +	uint32_t mtime = stbuf->st_mtime; +	uint32_t ctime = stbuf->st_ctime; + +	uint32_t atime_nsec = ST_ATIM_NSEC(stbuf); +	uint32_t mtime_nsec = ST_MTIM_NSEC(stbuf); +	uint32_t ctime_nsec = ST_CTIM_NSEC(stbuf); + + +	asprintf (&tmp_buf, +		  GF_STAT_PRINT_FMT_STR, +		  dev, +		  ino, +		  mode, +		  nlink, +		  uid, +		  gid, +		  rdev, +		  size, +		  blksize, +		  blocks, +		  atime, +		  atime_nsec, +		  mtime, +		  mtime_nsec, +		  ctime, +		  ctime_nsec); + +	return tmp_buf; +} + + +void +server_loc_wipe (loc_t *loc) +{ +	if (loc->parent) +		inode_unref (loc->parent); +	if (loc->inode) +		inode_unref (loc->inode); +	if (loc->path) +		free ((char *)loc->path); +} + +void +free_state (server_state_t *state) +{ +	transport_t *trans = NULL;	 + +	trans    = state->trans; + +	if (state->fd) +		fd_unref (state->fd); + +	transport_unref (trans); +	 +	if (state->xattr_req) +		dict_unref (state->xattr_req); + +	FREE (state); +} + + +call_frame_t * +server_copy_frame (call_frame_t *frame) +{ +	call_frame_t *new_frame = NULL; +	server_state_t *state = NULL, *new_state = NULL; + +	state = frame->root->state; + +	new_frame = copy_frame (frame); + +	new_state = CALLOC (1, sizeof (server_state_t)); + +	new_frame->root->op    = frame->root->op; +	new_frame->root->type  = frame->root->type; +	new_frame->root->trans = state->trans; +	new_frame->root->state = new_state; + +	new_state->bound_xl = state->bound_xl; +	new_state->trans    = transport_ref (state->trans); +	new_state->itable   = state->itable; + +	return new_frame; +} + +int32_t +gf_add_locker (struct _lock_table *table, +	       loc_t *loc, +	       fd_t *fd, +	       pid_t pid) +{ +	int32_t ret = -1; +	struct _locker *new = NULL; +	uint8_t dir = 0; + +	new = CALLOC (1, sizeof (struct _locker)); +	if (new == NULL) { +		gf_log ("server", GF_LOG_ERROR, +			"failed to allocate memory for \'struct _locker\'"); +		goto out; +	} +	INIT_LIST_HEAD (&new->lockers); + +	if (fd == NULL) { +		loc_copy (&new->loc, loc); +		dir = S_ISDIR (new->loc.inode->st_mode); +	} else { +		new->fd = fd_ref (fd); +		dir = S_ISDIR (fd->inode->st_mode); +	} + +	new->pid = pid; + +	LOCK (&table->lock); +	{ +		if (dir) +			list_add_tail (&new->lockers, &table->dir_lockers); +		else +			list_add_tail (&new->lockers, &table->file_lockers); +	} +	UNLOCK (&table->lock); +out: +	return ret; +} + +int32_t +gf_del_locker (struct _lock_table *table, +	       loc_t *loc, +	       fd_t *fd, +	       pid_t pid) +{ +	struct _locker *locker = NULL, *tmp = NULL; +	int32_t ret = 0; +	uint8_t dir = 0; +	struct list_head *head = NULL; +	struct list_head del; + +	INIT_LIST_HEAD (&del); + +	if (fd) { +		dir = S_ISDIR (fd->inode->st_mode); +	} else { +		dir = S_ISDIR (loc->inode->st_mode); +	} + +	LOCK (&table->lock); +	{ +		if (dir) { +			head = &table->dir_lockers; +		} else { +			head = &table->file_lockers; +		} + +		list_for_each_entry_safe (locker, tmp, head, lockers) { +			if (locker->fd && +			    fd && +			    (locker->fd == fd) && (locker->pid == pid)) { +				list_move_tail (&locker->lockers, &del); +			} else if (locker->loc.inode &&  +				   loc && +				   (locker->loc.inode == loc->inode) && +				   (locker->pid == pid)) { +				list_move_tail (&locker->lockers, &del); +			} +		} +	} +	UNLOCK (&table->lock); + +	tmp = NULL; +	locker = NULL; + +	list_for_each_entry_safe (locker, tmp, &del, lockers) { +		list_del_init (&locker->lockers); +		if (locker->fd) +			fd_unref (locker->fd); +		else +			loc_wipe (&locker->loc); + +		free (locker); +	} + +	return ret; +} + +int32_t +gf_direntry_to_bin (dir_entry_t *head, +		    char **bufferp) +{ +	dir_entry_t *trav = NULL; +	uint32_t len = 0; +	uint32_t this_len = 0; +	char *buffer = NULL; +	size_t buflen = -1; +	char *ptr = NULL; +	char *tmp_buf = NULL; + +	trav = head->next; +	while (trav) { +		len += strlen (trav->name); +		len += 1; +		len += strlen (trav->link); +		len += 1; /* for '\n' */ +		len += 256; // max possible for statbuf; +		trav = trav->next; +	} + +	buffer = CALLOC (1, len); +	if (buffer == NULL) { +		gf_log ("server", GF_LOG_ERROR, +			"failed to allocate memory for buffer"); +		goto out; +	} + +	ptr = buffer; +	trav = head->next; +	while (trav) { +		tmp_buf = stat_to_str (&trav->buf); +		/* tmp_buf will have \n before \0 */ + +		this_len = sprintf (ptr, "%s/%s%s\n", +				    trav->name, tmp_buf, +				    trav->link); + +		FREE (tmp_buf); +		trav = trav->next; +		ptr += this_len; +	} +	if (bufferp) +		*bufferp = buffer; +	buflen = strlen (buffer); +	 +out: +	return buflen; +} + + +static struct _lock_table * +gf_lock_table_new (void) +{ +	struct _lock_table *new = NULL; + +	new = CALLOC (1, sizeof (struct _lock_table)); +	if (new == NULL) { +		gf_log ("server-protocol", GF_LOG_CRITICAL, +			"failed to allocate memory for new lock table"); +		goto out; +	} +	INIT_LIST_HEAD (&new->dir_lockers); +	INIT_LIST_HEAD (&new->file_lockers); +	LOCK_INIT (&new->lock); +out: +	return new; +} + + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn) +{ + +	call_frame_t      *frame = NULL, *tmp_frame = NULL; +	xlator_t          *bound_xl = NULL; +	int32_t            ret = -1; +	server_state_t    *state = NULL; +	struct list_head   file_lockers; +	struct list_head   dir_lockers; +	struct _lock_table *ltable = NULL; +	struct _locker     *locker = NULL, *tmp = NULL; +	struct flock        flock = {0,}; + + +	bound_xl = (xlator_t *) (conn->bound_xl); + +	if (bound_xl) { +		/* trans will have ref_count = 1 after this call, but its  +		   ok since this function is called in  +		   GF_EVENT_TRANSPORT_CLEANUP */ +		frame = create_frame (this, this->ctx->pool); + +		pthread_mutex_lock (&(conn->lock)); +		{ +			if (conn->ltable) { +				ltable = conn->ltable; +				conn->ltable = NULL; +			} +		} +		pthread_mutex_unlock (&conn->lock); + +		INIT_LIST_HEAD (&file_lockers); +		INIT_LIST_HEAD (&dir_lockers); + +		LOCK (<able->lock); +		{ +			list_splice_init (<able->file_lockers,  +					  &file_lockers); + +			list_splice_init (<able->dir_lockers, &dir_lockers); +		} +		UNLOCK (<able->lock); +		free (ltable); + +		flock.l_type  = F_UNLCK; +		flock.l_start = 0; +		flock.l_len   = 0; +		list_for_each_entry_safe (locker,  +					  tmp, &file_lockers, lockers) { +			tmp_frame = copy_frame (frame); +			/*  +			   pid = 0 is a special case that tells posix-locks +			   to release all locks from this transport +			*/ +			tmp_frame->root->pid = 0; +			tmp_frame->root->trans = conn; + +			if (locker->fd) { +				STACK_WIND (tmp_frame, server_nop_cbk, +					    bound_xl, +					    bound_xl->fops->finodelk, +					    locker->fd, F_SETLK, &flock); +				fd_unref (locker->fd); +			} else { +				STACK_WIND (tmp_frame, server_nop_cbk, +					    bound_xl, +					    bound_xl->fops->inodelk, +					    &(locker->loc), F_SETLK, &flock); +				loc_wipe (&locker->loc); +			} + +			list_del_init (&locker->lockers); +			free (locker); +		} + +		tmp = NULL; +		locker = NULL; +		list_for_each_entry_safe (locker, tmp, &dir_lockers, lockers) { +			tmp_frame = copy_frame (frame); + +			tmp_frame->root->pid = 0; +			tmp_frame->root->trans = conn; + +			if (locker->fd) { +				STACK_WIND (tmp_frame, server_nop_cbk, +					    bound_xl, +					    bound_xl->fops->fentrylk, +					    locker->fd, NULL,  +					    ENTRYLK_UNLOCK, ENTRYLK_WRLCK); +				fd_unref (locker->fd); +			} else { +				STACK_WIND (tmp_frame, server_nop_cbk, +					    bound_xl, +					    bound_xl->fops->entrylk, +					    &(locker->loc), NULL,  +					    ENTRYLK_UNLOCK, ENTRYLK_WRLCK); +				loc_wipe (&locker->loc); +			} + +			list_del_init (&locker->lockers); +			free (locker); +		} + +		state = CALL_STATE (frame); +		if (state) +			free (state); +		STACK_DESTROY (frame->root); + +		pthread_mutex_lock (&(conn->lock)); +		{ +			if (conn->fdtable) { +				gf_fd_fdtable_destroy (conn->fdtable); +				conn->fdtable = NULL; +			} +		} +		pthread_mutex_unlock (&conn->lock); + +	} + +	gf_log (this->name, GF_LOG_INFO, "destroyed connection of %s", +		conn->id); + +	FREE (conn->id); +	FREE (conn); + +	return ret; +} + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id) +{ +	server_connection_t *conn = NULL; +	server_connection_t *trav = NULL; +	server_conf_t       *conf = NULL; + +	conf = this->private; + +	pthread_mutex_lock (&conf->mutex); +	{ +		list_for_each_entry (trav, &conf->conns, list) { +			if (!strcmp (id, trav->id)) { +				conn = trav; +				break; +			} +		} + +		if (!conn) { +			conn = (void *) CALLOC (1, sizeof (*conn)); + +			conn->id = strdup (id); +			conn->fdtable = gf_fd_fdtable_alloc (); +			conn->ltable  = gf_lock_table_new (); + +			pthread_mutex_init (&conn->lock, NULL); + +			list_add (&conn->list, &conf->conns); +		} + +		conn->ref++; +	} +	pthread_mutex_unlock (&conf->mutex); + +	return conn; +} + + +void +server_connection_put (xlator_t *this, server_connection_t *conn) +{ +	server_conf_t       *conf = NULL; +	server_connection_t *todel = NULL; + +	conf = this->private; + +	pthread_mutex_lock (&conf->mutex); +	{ +		conn->ref--; + +		if (!conn->ref) { +			list_del_init (&conn->list); +			todel = conn; +		} +	} +	pthread_mutex_unlock (&conf->mutex); + +	if (todel) { +		server_connection_destroy (this, todel); +	} + +	return; +} diff --git a/xlators/protocol/server/src/server-helpers.h b/xlators/protocol/server/src/server-helpers.h new file mode 100644 index 00000000000..36c0ce98e40 --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.h @@ -0,0 +1,77 @@ +/* +  Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef __SERVER_HELPERS_H__ +#define __SERVER_HELPERS_H__ + +#define CALL_STATE(frame)   ((server_state_t *)frame->root->state) + +#define BOUND_XL(frame)     ((xlator_t *) CALL_STATE(frame)->bound_xl) + +#define TRANSPORT_FROM_FRAME(frame) ((transport_t *) CALL_STATE(frame)->trans) + +#define SERVER_CONNECTION(frame)  \ +	((server_connection_t *) TRANSPORT_FROM_FRAME(frame)->xl_private) + +#define SERVER_CONF(frame) \ +	((server_conf_t *)TRANSPORT_FROM_FRAME(frame)->xl->private) + +#define TRANSPORT_FROM_XLATOR(this) ((((server_conf_t *)this->private))->trans) + +#define INODE_LRU_LIMIT(this)						\ +	(((server_conf_t *)(this->private))->inode_lru_limit) + +#define IS_ROOT_INODE(inode) (inode == inode->table->root) + +#define IS_NOT_ROOT(pathlen) ((pathlen > 2)? 1 : 0) + +int32_t +server_loc_fill (loc_t *loc, +  		 server_state_t *state, +  		 ino_t ino, +  		 ino_t par, +  		 const char *name, +  		 const char *path); + +char * +stat_to_str (struct stat *stbuf); + +call_frame_t * +server_copy_frame (call_frame_t *frame); + +void free_state (server_state_t *state); + +void server_loc_wipe (loc_t *loc); + +int32_t +gf_add_locker (struct _lock_table *table, +	       loc_t *loc, +	       fd_t *fd, +	       pid_t pid); + +int32_t +gf_del_locker (struct _lock_table *table, +	       loc_t *loc, +	       fd_t *fd, +	       pid_t pid); + +int32_t +gf_direntry_to_bin (dir_entry_t *head, +		    char **bufferp); +#endif /* __SERVER_HELPERS_H__ */ diff --git a/xlators/protocol/server/src/server-protocol.c b/xlators/protocol/server/src/server-protocol.c new file mode 100644 index 00000000000..a5198c1ed07 --- /dev/null +++ b/xlators/protocol/server/src/server-protocol.c @@ -0,0 +1,7984 @@ +/* +  Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include <time.h> +#include <sys/uio.h> +#include <sys/resource.h> + +#include <libgen.h> + +#include "transport.h" +#include "fnmatch.h" +#include "xlator.h" +#include "protocol.h" +#include "server-protocol.h" +#include "server-helpers.h" +#include "call-stub.h" +#include "defaults.h" +#include "list.h" +#include "dict.h" +#include "compat.h" +#include "compat-errno.h" + + +static void +protocol_server_reply (call_frame_t *frame, +                       int type, int op, +                       gf_hdr_common_t *hdr, size_t hdrlen, +                       struct iovec *vector, int count, +                       dict_t *refs) +{ +	server_state_t *state = NULL; +	xlator_t *bound_xl = NULL; +	transport_t *trans = NULL; + +	bound_xl = BOUND_XL(frame); +	state    = CALL_STATE(frame); +	trans    = state->trans; + +	hdr->callid = hton64 (frame->root->unique); +	hdr->type   = hton32 (type); +	hdr->op     = hton32 (op); + +	transport_submit (trans, (char *)hdr, hdrlen, vector, count, refs); +	/* TODO: If transport submit fails, there is no reply sent to client,  +	 * its bailed out as of now.. loggically, only this frame should fail.  +	 */ + +	STACK_DESTROY (frame->root); + +	if (state) +		free_state (state); + +} + + +/* + * server_fchmod_cbk + */ +int32_t +server_fchmod_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   struct stat *stbuf) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_fchmod_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FCHMOD %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FCHMOD, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_fchmod + * + */ +int32_t +server_fchmod (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_fop_fchmod_req_t *req = NULL; +	server_state_t *state = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->mode   = ntoh32 (req->mode); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	STACK_WIND (frame, +		    server_fchmod_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->fchmod, +		    state->fd, +		    state->mode); + +	return 0; +fail: +	server_fchmod_cbk (frame, NULL, frame->this, +			   -1, EINVAL, NULL); +	return 0; +} + + +/* + * server_fchown_cbk + */ +int32_t +server_fchown_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   struct stat *stbuf) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_fchown_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); +	 +	hdr->rsp.op_ret   = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else {  +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FCHOWN %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FCHOWN, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_fchown + * + */ +int32_t +server_fchown (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_fop_fchown_req_t *req = NULL; +	server_state_t *state = NULL; + +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->uid   = ntoh32 (req->uid); +		state->gid   = ntoh32 (req->gid); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	STACK_WIND (frame, +		    server_fchown_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->fchown, +		    state->fd, +		    state->uid, +		    state->gid); + +	return 0; +fail: +	server_fchown_cbk (frame, NULL, frame->this, +			   -1, EINVAL, NULL); +	return 0; +} + +/* + * server_setdents_cbk - writedir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_setdents_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_setdents_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret   = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SETDENTS, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_lk_cbk - lk callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int32_t +server_lk_cbk (call_frame_t *frame, +               void *cookie, +               xlator_t *this, +               int32_t op_ret, +               int32_t op_errno, +               struct flock *lock) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_lk_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_flock_from_flock (&rsp->flock, lock); +	} else if (op_errno != ENOSYS) { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": LK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LK, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +int32_t +server_inodelk_cbk (call_frame_t *frame, void *cookie, +		    xlator_t *this, int32_t op_ret, int32_t op_errno) +{ +	server_connection_t *conn = NULL; + 	gf_hdr_common_t *hdr = NULL; + 	gf_fop_inodelk_rsp_t *rsp = NULL; +	server_state_t *state = NULL; + 	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	 +	conn = SERVER_CONNECTION(frame); + +	state = CALL_STATE(frame); + + 	hdrlen = gf_hdr_len (rsp, 0); + 	hdr    = gf_hdr_new (rsp, 0); + 	rsp    = gf_param (hdr); + + 	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); + 	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		if (state->flock.l_type == F_UNLCK) +			gf_del_locker (conn->ltable, +				       &state->loc, NULL, frame->root->pid); +		else +			gf_add_locker (conn->ltable, +				       &state->loc, NULL, frame->root->pid); +	} else if (op_errno != ENOSYS) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, op_ret, +			strerror (op_errno)); +	} +	 +	server_loc_wipe (&state->loc); + + 	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_INODELK, + 			       hdr, hdrlen, NULL, 0, NULL); + + 	return 0; +} + + +int32_t +server_finodelk_cbk (call_frame_t *frame, void *cookie, +		     xlator_t *this, int32_t op_ret, int32_t op_errno) +{ +	server_connection_t *conn = NULL; + 	gf_hdr_common_t *hdr = NULL; + 	gf_fop_finodelk_rsp_t *rsp = NULL; +	server_state_t *state = NULL; + 	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	 +	conn = SERVER_CONNECTION(frame); + + 	hdrlen = gf_hdr_len (rsp, 0); + 	hdr    = gf_hdr_new (rsp, 0); + 	rsp    = gf_param (hdr); + + 	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); + 	hdr->rsp.op_errno = hton32 (gf_errno); +	 +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		if (state->flock.l_type == F_UNLCK) +			gf_del_locker (conn->ltable, +				       NULL, state->fd, frame->root->pid); +		else +			gf_add_locker (conn->ltable, +				       NULL, state->fd, frame->root->pid); +	} else if (op_errno != ENOSYS) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FINODELK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + + 	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FINODELK, + 			       hdr, hdrlen, NULL, 0, NULL); + + 	return 0; +} + + +/* + * server_entrylk_cbk -  + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @lock: + * + * not for external reference + */ +int32_t +server_entrylk_cbk (call_frame_t *frame, void *cookie, +		    xlator_t *this, int32_t op_ret, int32_t op_errno) +{ +	server_connection_t *conn = NULL; + 	gf_hdr_common_t      *hdr = NULL; + 	gf_fop_entrylk_rsp_t *rsp = NULL; +	server_state_t *state = NULL; + 	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	conn = SERVER_CONNECTION(frame); + +	state = CALL_STATE(frame); + + 	hdrlen = gf_hdr_len (rsp, 0); + 	hdr    = gf_hdr_new (rsp, 0); + 	rsp    = gf_param (hdr); + + 	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); + 	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		if (state->cmd == ENTRYLK_UNLOCK) +			gf_del_locker (conn->ltable, +				       &state->loc, NULL, frame->root->pid); +		else +			gf_add_locker (conn->ltable, +				       &state->loc, NULL, frame->root->pid); +	} else if (op_errno != ENOSYS) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": INODELK %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, op_ret, +			strerror (op_errno)); +	} +	 +	server_loc_wipe (&state->loc); + + 	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_ENTRYLK, + 			       hdr, hdrlen, NULL, 0, NULL); + + 	return 0; +} + + +int32_t +server_fentrylk_cbk (call_frame_t *frame, void *cookie, +		     xlator_t *this, int32_t op_ret, int32_t op_errno) +{ +	server_connection_t *conn = NULL; + 	gf_hdr_common_t       *hdr = NULL; + 	gf_fop_fentrylk_rsp_t *rsp = NULL; +	server_state_t *state = NULL; + 	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	conn = SERVER_CONNECTION(frame); + + 	hdrlen = gf_hdr_len (rsp, 0); + 	hdr    = gf_hdr_new (rsp, 0); + 	rsp    = gf_param (hdr); + + 	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); + 	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		state = CALL_STATE(frame); +		if (state->cmd == ENTRYLK_UNLOCK) +			gf_del_locker (conn->ltable, +				       NULL, state->fd, frame->root->pid); +		else +			gf_add_locker (conn->ltable, +				       NULL, state->fd, frame->root->pid); +	} else if (op_errno != ENOSYS) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FENTRYLK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + + 	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FENTRYLK, + 			       hdr, hdrlen, NULL, 0, NULL); + + 	return 0; +} + + +/* + * server_access_cbk - access callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_access_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_access_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_ACCESS, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_utimens_cbk - utimens callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_utimens_cbk (call_frame_t *frame, +                    void *cookie, +                    xlator_t *this, +                    int32_t op_ret, +                    int32_t op_errno, +                    struct stat *stbuf) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_utimens_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) +		gf_stat_from_stat (&rsp->stat, stbuf); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_UTIMENS, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_chmod_cbk - chmod callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_chmod_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  struct stat *stbuf) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_chmod_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) +		gf_stat_from_stat (&rsp->stat, stbuf); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHMOD, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_chown_cbk - chown callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_chown_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  struct stat *stbuf) +{ +	gf_hdr_common_t *hdr = NULL; +	gf_fop_chown_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	int32_t gf_errno = 0; +	size_t  hdrlen = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) +		gf_stat_from_stat (&rsp->stat, stbuf); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHOWN, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_rmdir_cbk - rmdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_rmdir_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_rmdir_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	int32_t gf_errno = 0; +	size_t  hdrlen = 0; + +	state = CALL_STATE(frame); + +	if (op_ret == 0) { +		inode_unlink (state->loc.inode, state->loc.parent,  +			      state->loc.name); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": RMDIR %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_RMDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_mkdir_cbk - mkdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_mkdir_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  inode_t *inode, +                  struct stat *stbuf) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_mkdir_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +		inode_link (inode, state->loc.parent, state->loc.name, stbuf); +		inode_lookup (inode); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": MKDIR %s  ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_MKDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_mknod_cbk - mknod callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_mknod_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  inode_t *inode, +                  struct stat *stbuf) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_mknod_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	int32_t gf_errno = 0; +	size_t  hdrlen = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +		inode_link (inode, state->loc.parent, state->loc.name, stbuf); +		inode_lookup (inode); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": MKNOD %s ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_MKNOD, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_fsyncdir_cbk - fsyncdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_fsyncdir_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_fsyncdir_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); +	 +	if (op_ret < 0) { +		state = CALL_STATE(frame); +		 +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FSYNCDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSYNCDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_getdents_cbk - readdir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @entries: + * @count: + * + * not for external reference + */ +int32_t +server_getdents_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno, +                     dir_entry_t *entries, +                     int32_t count) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_getdents_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t vec_count = 0; +	int32_t gf_errno = 0; +	int32_t ret = -1; +	dict_t *reply_dict = NULL; +	char   *buffer = NULL; +	size_t  buflen = 0; +	struct iovec vector[1]; +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		buflen = gf_direntry_to_bin (entries, &buffer); +		if (buflen < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to convert " +				"entries list to string buffer", +				state->fd_no, state->fd->inode->ino); +			op_ret = -1; +			op_errno = EINVAL; +			goto out; +		} + +		reply_dict = dict_new (); +		if (reply_dict == NULL) { +			gf_log (this->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to get new dict", +				state->fd_no, state->fd->inode->ino); +			op_ret = -1; +			op_errno = ENOMEM; +			goto out; +		} +		 +		ret = dict_set_dynptr (reply_dict, NULL,  +				       buffer, buflen); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to set read buffer " +				"to reply dictionary", +				state->fd_no, state->fd->inode->ino); +			op_ret = -1; +			op_errno = -ret; +			goto out; +		} +		frame->root->rsp_refs = reply_dict; +		vector[0].iov_base = buffer; +		vector[0].iov_len = buflen; +		vec_count = 1; +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": GETDENTS %"PRId64" (%"PRId64"): %"PRId32" (%s)", +			frame->root->unique, +			state->fd_no,  +			state->fd ? state->fd->inode->ino : 0,  +			op_ret, strerror (op_errno)); +		vector[0].iov_base = NULL; +		vector[0].iov_len = 0; +	} + +out: +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	rsp->count = hton32 (count); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_GETDENTS, +			       hdr, hdrlen, vector, vec_count,  +			       frame->root->rsp_refs); +	 +	if (reply_dict) +		dict_unref (reply_dict); + +	return 0; +} + + +/* + * server_readdir_cbk - getdents callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_readdir_cbk (call_frame_t *frame, +                    void *cookie, +                    xlator_t *this, +                    int32_t op_ret, +                    int32_t op_errno, +                    gf_dirent_t *entries) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_readdir_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	size_t  buf_size = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	if (op_ret > 0) +		buf_size = gf_dirent_serialize (entries, NULL, 0); + +	hdrlen = gf_hdr_len (rsp, buf_size); +	hdr    = gf_hdr_new (rsp, buf_size); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret > 0) { +		rsp->size = hton32 (buf_size); +		gf_dirent_serialize (entries, rsp->buf, buf_size); +	} else { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": READDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_releasedir_cbk - releasedir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_releasedir_cbk (call_frame_t *frame, +		       void *cookie, +		       xlator_t *this, +		       int32_t op_ret, +		       int32_t op_errno) +{ +	gf_hdr_common_t         *hdr = NULL; +	gf_cbk_releasedir_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASEDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_opendir_cbk - opendir callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @fd: file descriptor structure of opened directory + * + * not for external reference + */ +int32_t +server_opendir_cbk (call_frame_t *frame, +                    void *cookie, +                    xlator_t *this, +                    int32_t op_ret, +                    int32_t op_errno, +                    fd_t *fd) +{ +	server_connection_t *conn = NULL; +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_opendir_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t   hdrlen = 0; +	int32_t  gf_errno = 0; + +	conn = SERVER_CONNECTION(frame); + +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		fd_bind (fd); + +		state->fd_no = gf_fd_unused_get (conn->fdtable, fd); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": OPENDIR %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); + +		/* NOTE: corresponding to fd_create()'s ref */ +		if (state->fd) +			fd_unref (state->fd); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); +	rsp->fd           = hton64 (state->fd_no); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_OPENDIR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_statfs_cbk - statfs callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @buf: + * + * not for external reference + */ +int32_t +server_statfs_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   struct statvfs *buf) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_statfs_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		gf_statfs_from_statfs (&rsp->statfs, buf); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_STATFS, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_removexattr_cbk - removexattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_removexattr_cbk (call_frame_t *frame, +                        void *cookie, +                        xlator_t *this, +                        int32_t op_ret, +                        int32_t op_errno) +{ +	gf_hdr_common_t          *hdr = NULL; +	gf_fop_removexattr_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_REMOVEXATTR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_getxattr_cbk - getxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @value: + * + * not for external reference + */ +int32_t +server_getxattr_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno, +                     dict_t *dict) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_getxattr_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t len = 0; +	int32_t gf_errno = 0; +	int32_t ret = -1; + +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		len = dict_serialized_length (dict); +		if (len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to get serialized length of " +				"reply dict", +				state->loc.path, state->ino); +			op_ret   = -1; +			op_errno = EINVAL; +			len = 0; +		} +	} + +	hdrlen = gf_hdr_len (rsp, len + 1); +	hdr    = gf_hdr_new (rsp, len + 1); +	rsp    = gf_param (hdr); + +	if (op_ret >= 0) { +		ret = dict_serialize (dict, rsp->dict); +		if (len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to serialize reply dict", +				state->loc.path, state->ino); +			op_ret = -1; +			op_errno = -ret; +		} +	} +	rsp->dict_len = hton32 (len); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_GETXATTR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_setxattr_cbk - setxattr callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_setxattr_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_setxattr_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SETXATTR, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_rename_cbk - rename callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_rename_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   struct stat *stbuf) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_rename_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		stbuf->st_ino  = state->loc.inode->ino; +		stbuf->st_mode = state->loc.inode->st_mode; + +		gf_log (state->bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": RENAME_CBK (%"PRId64") %"PRId64"/%s " +			"==> %"PRId64"/%s", +			frame->root->unique, state->loc.inode->ino,  +			state->loc.parent->ino,	state->loc.name, +			state->loc2.parent->ino, state->loc2.name); +			 +		inode_rename (state->itable, +			      state->loc.parent, state->loc.name, +			      state->loc2.parent, state->loc2.name, +			      state->loc.inode, stbuf); +		gf_stat_from_stat (&rsp->stat, stbuf); +	} + +	server_loc_wipe (&(state->loc)); +	server_loc_wipe (&(state->loc2)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_RENAME, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_unlink_cbk - unlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_unlink_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_unlink_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	if (op_ret == 0) { +		gf_log (state->bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": UNLINK_CBK %"PRId64"/%s (%"PRId64")", +			frame->root->unique, state->loc.parent->ino,  +			state->loc.name, state->loc.inode->ino); + +		inode_unlink (state->loc.inode, state->loc.parent,  +			      state->loc.name); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": UNLINK %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_UNLINK, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_symlink_cbk - symlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int32_t +server_symlink_cbk (call_frame_t *frame, +                    void *cookie, +                    xlator_t *this, +                    int32_t op_ret, +                    int32_t op_errno, +                    inode_t *inode, +                    struct stat *stbuf) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_symlink_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + +	if (op_ret >= 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +		inode_link (inode, state->loc.parent, state->loc.name, stbuf); +		inode_lookup (inode); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": SYMLINK %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_SYMLINK, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_link_cbk - link callback for server protocol + * @frame: call frame + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_link_cbk (call_frame_t *frame, +                 void *cookie, +                 xlator_t *this, +                 int32_t op_ret, +                 int32_t op_errno, +                 inode_t *inode, +                 struct stat *stbuf) +{ +	gf_hdr_common_t   *hdr = NULL; +	gf_fop_link_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	int32_t gf_errno = 0; +	size_t  hdrlen = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		stbuf->st_ino = state->loc.inode->ino; +		gf_stat_from_stat (&rsp->stat, stbuf); +		gf_log (state->bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s", +			frame->root->unique, inode->ino, state->loc2.parent->ino,  +			state->loc2.name, state->loc.parent->ino, state->loc.name); + +		inode_link (inode, state->loc2.parent,  +			    state->loc2.name, stbuf); +	} else { +		gf_log (state->bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s " +			" ==> %"PRId32" (%s)", +			frame->root->unique, inode->ino, state->loc2.parent->ino,  +			state->loc2.name, state->loc.parent->ino, state->loc.name, +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); +	server_loc_wipe (&(state->loc2)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LINK, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_truncate_cbk - truncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_truncate_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno, +                     struct stat *stbuf) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_truncate_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": TRUNCATE %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_TRUNCATE, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_fstat_cbk - fstat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_fstat_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  struct stat *stbuf) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_fstat_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		state = CALL_STATE(frame); +		 +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FSTAT %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSTAT, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_ftruncate_cbk - ftruncate callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_ftruncate_cbk (call_frame_t *frame, +                      void *cookie, +                      xlator_t *this, +                      int32_t op_ret, +                      int32_t op_errno, +                      struct stat *stbuf) +{ +	gf_hdr_common_t        *hdr = NULL; +	gf_fop_ftruncate_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FTRUNCATE %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FTRUNCATE, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_flush_cbk - flush callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_flush_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_flush_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	if (op_ret < 0) { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FLUSH %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); +	 +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FLUSH, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_fsync_cbk - fsync callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_fsync_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_fsync_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	if (op_ret < 0) { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FSYNC %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FSYNC, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_release_cbk - rleease callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_release_cbk (call_frame_t *frame, +		    void *cookie, +		    xlator_t *this, +		    int32_t op_ret, +		    int32_t op_errno) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_cbk_release_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_RELEASE, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_writev_cbk - writev callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ + +int32_t +server_writev_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   struct stat *stbuf) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_write_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + +	if (op_ret >= 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": WRITEV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, +			       GF_OP_TYPE_FOP_REPLY, GF_FOP_WRITE, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_readv_cbk - readv callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @vector: + * @count: + * + * not for external reference + */ +int32_t +server_readv_cbk (call_frame_t *frame, +                  void *cookie, +                  xlator_t *this, +                  int32_t op_ret, +                  int32_t op_errno, +                  struct iovec *vector, +                  int32_t count, +                  struct stat *stbuf) +{ +	gf_hdr_common_t   *hdr = NULL; +	gf_fop_read_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	server_state_t *state = NULL; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		state = CALL_STATE(frame); + +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": READV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READ, +			       hdr, hdrlen, vector, count,  +			       frame->root->rsp_refs); + +	return 0; +} + + +/* + * server_open_cbk - open callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @fd: + * + * not for external reference + */ +int32_t +server_open_cbk (call_frame_t *frame, +                 void *cookie, +                 xlator_t *this, +                 int32_t op_ret, +                 int32_t op_errno, +                 fd_t *fd) +{ +	server_connection_t *conn = NULL; +	gf_hdr_common_t   *hdr = NULL; +	gf_fop_open_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	conn = SERVER_CONNECTION(frame); + +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		fd_bind (fd); +		 +		state->fd_no = gf_fd_unused_get (conn->fdtable, fd); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": OPEN %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); + +		/* NOTE: corresponding to fd_create()'s ref */ +		if (state->fd) +			fd_unref (state->fd); +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); +	rsp->fd           = hton64 (state->fd_no); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_OPEN, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_create_cbk - create callback for server + * @frame: call frame + * @cookie: + * @this:  translator structure + * @op_ret: + * @op_errno: + * @fd: file descriptor + * @inode: inode structure + * @stbuf: struct stat of created file + * + * not for external reference + */ +int32_t +server_create_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   fd_t *fd, +                   inode_t *inode, +                   struct stat *stbuf) +{ +	server_connection_t *conn = NULL; +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_create_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	 +	conn = SERVER_CONNECTION(frame); + +	state = CALL_STATE(frame); + +	if (op_ret >= 0) { +		gf_log (state->bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": CREATE %"PRId64"/%s (%"PRId64")", +			frame->root->unique, state->loc.parent->ino,  +			state->loc.name, stbuf->st_ino); + +		inode_link (inode, state->loc.parent, state->loc.name, stbuf); +		inode_lookup (inode); +		 +		fd_bind (fd); + +		state->fd_no = gf_fd_unused_get (conn->fdtable, fd); + +		if ((state->fd_no < 0) || (fd == 0)) { +			op_ret = state->fd_no; +			op_errno = errno; +		} +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": CREATE %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +		 +                /* NOTE: corresponding to fd_create()'s ref */ +		if (state->fd) +			fd_unref (state->fd); + +	} + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); +	rsp->fd           = hton64 (state->fd_no); + +	if (op_ret >= 0) +		gf_stat_from_stat (&rsp->stat, stbuf); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CREATE, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_readlink_cbk - readlink callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @buf: + * + * not for external reference + */ +int32_t +server_readlink_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno, +                     const char *buf) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_readlink_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	size_t  linklen = 0; +	int32_t gf_errno = 0; + +	state  = CALL_STATE(frame); + +	if (op_ret >= 0) { +		linklen = strlen (buf) + 1; +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": READLINK %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	hdrlen = gf_hdr_len (rsp, linklen); +	hdr    = gf_hdr_new (rsp, linklen); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + +	if (op_ret >= 0) +		strcpy (rsp->path, buf); + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_READLINK, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_stat_cbk - stat callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @stbuf: + * + * not for external reference + */ +int32_t +server_stat_cbk (call_frame_t *frame, +                 void *cookie, +                 xlator_t *this, +                 int32_t op_ret, +                 int32_t op_errno, +                 struct stat *stbuf) +{ +	gf_hdr_common_t   *hdr = NULL; +	gf_fop_stat_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	state  = CALL_STATE(frame); + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno_to_error (op_errno)); + +	if (op_ret == 0) { +		gf_stat_from_stat (&rsp->stat, stbuf); +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": STAT %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_STAT, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_forget_cbk - forget callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * + * not for external reference + */ +int32_t +server_forget_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_cbk_forget_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_CBK_REPLY, GF_CBK_FORGET, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * server_lookup_cbk - lookup callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: + * @op_errno: + * @inode: + * @stbuf: + * + * not for external reference + */ +int32_t +server_lookup_cbk (call_frame_t *frame, +                   void *cookie, +                   xlator_t *this, +                   int32_t op_ret, +                   int32_t op_errno, +                   inode_t *inode, +                   struct stat *stbuf, +                   dict_t *dict) +{ +	gf_hdr_common_t     *hdr = NULL; +	gf_fop_lookup_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	inode_t *root_inode = NULL; +	int32_t  dict_len = 0; +	size_t   hdrlen = 0; +	int32_t  gf_errno = 0; +	int32_t  ret = -1; + +	state = CALL_STATE(frame); +	if ((op_errno == ESTALE) && (op_ret == -1)) { +		/* Send lookup again with new ctx dictionary */ +		loc_t loc = {0,}; + +		root_inode = BOUND_XL(frame)->itable->root; +		if (state->loc.inode != root_inode) { +			if (state->loc.inode) +				inode_unref (state->loc.inode); +			state->loc.inode = inode_new (BOUND_XL(frame)->itable); +		} +		loc.inode = state->loc.inode; +		loc.path = state->path; +		state->is_revalidate = 2; +		STACK_WIND (frame, server_lookup_cbk, +			    BOUND_XL(frame), +			    BOUND_XL(frame)->fops->lookup, +			    &loc, +			    state->xattr_req); +		return 0; +	} + +	if (dict) { +		dict_len = dict_serialized_length (dict); +		if (dict_len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to get serialized " +				"length of reply dict", +				state->loc.path, state->loc.inode->ino); +			op_ret   = -1; +			op_errno = EINVAL; +			dict_len = 0; +		} +	} + +	hdrlen = gf_hdr_len (rsp, dict_len); +	hdr    = gf_hdr_new (rsp, dict_len); +	rsp    = gf_param (hdr); + +	if ((op_ret >= 0) && dict) { +		ret = dict_serialize (dict, rsp->dict); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to serialize reply dict", +				state->loc.path, state->loc.inode->ino); +			op_ret = -1; +			op_errno = -ret; +			dict_len = 0; +		}  +	} +	rsp->dict_len = hton32 (dict_len); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret == 0) { +		root_inode = BOUND_XL(frame)->itable->root; +		if (inode == root_inode) { +			/* we just looked up root ("/") */ +			stbuf->st_ino = 1; +			if (inode->st_mode == 0) +				inode->st_mode = stbuf->st_mode; +		} + +		gf_stat_from_stat (&rsp->stat, stbuf); + +		if (inode->ino == 0) { +			inode_link (inode, state->loc.parent,  +				    state->loc.name, stbuf); +			inode_lookup (inode); +		} +	} else { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": LOOKUP %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	server_loc_wipe (&state->loc); +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_LOOKUP, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +int32_t +server_xattrop_cbk (call_frame_t *frame, +		    void *cookie, +		    xlator_t *this, +		    int32_t op_ret, +		    int32_t op_errno, +		    dict_t *dict) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_xattrop_rsp_t *rsp = NULL; +	server_state_t *state = NULL; +	size_t  hdrlen = 0; +	int32_t len = 0; +	int32_t gf_errno = 0; +	int32_t ret = -1; + +	state = CALL_STATE(frame); +	 +	if (op_ret < 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": XATTROP %s (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->loc.path,  +			state->loc.inode ? state->loc.inode->ino : 0, +			op_ret, strerror (op_errno)); +	} + +	if ((op_ret >= 0) && dict) { +		len = dict_serialized_length (dict); +		if (len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to get serialized length" +				" for reply dict",  +				state->loc.path, state->loc.inode->ino); +			op_ret = -1; +			op_errno = EINVAL; +			len = 0; +		} +	}  + +	hdrlen = gf_hdr_len (rsp, len + 1); +	hdr    = gf_hdr_new (rsp, len + 1); +	rsp    = gf_param (hdr); + +	if ((op_ret >= 0) && dict) { +		ret = dict_serialize (dict, rsp->dict); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to serialize reply dict",  +				state->loc.path, state->loc.inode->ino); +			op_ret = -1; +			op_errno = -ret; +			len = 0; +		} +	} +	rsp->dict_len = hton32 (len); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); +	 +	server_loc_wipe (&(state->loc)); + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_XATTROP, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +int32_t +server_fxattrop_cbk (call_frame_t *frame, +		     void *cookie, +		     xlator_t *this, +		     int32_t op_ret, +		     int32_t op_errno, +		     dict_t *dict) +{ +	gf_hdr_common_t      *hdr = NULL; +	gf_fop_xattrop_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t len = 0; +	int32_t gf_errno = 0; +	int32_t ret = -1; +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); +	 +	if (op_ret < 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"%"PRId64": FXATTROP %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", +			frame->root->unique, state->fd_no,  +			state->fd ? state->fd->inode->ino : 0, op_ret, +			strerror (op_errno)); +	} + +	if ((op_ret >= 0) && dict) { +		len = dict_serialized_length (dict); +		if (len < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to get " +				"serialized length for reply dict",  +				state->fd_no, state->fd->inode->ino); +			op_ret = -1; +			op_errno = EINVAL; +			len = 0;				 +		} +	} + +	hdrlen = gf_hdr_len (rsp, len + 1); +	hdr    = gf_hdr_new (rsp, len + 1); +	rsp    = gf_param (hdr); + +	if ((op_ret >= 0) && dict) { +		ret = dict_serialize (dict, rsp->dict); +		if (ret < 0) { +			gf_log (this->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to " +				"serialize reply dict",  +				state->fd_no, state->fd->inode->ino); +			op_ret = -1; +			op_errno = -ret; +			len = 0; +		} +	} +	rsp->dict_len = hton32 (len); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_FXATTROP, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * server_stub_resume - this is callback function used whenever an fop does + *                   STACK_WIND to fops->lookup in order to lookup the inode + *                   for a pathname. this case of doing fops->lookup arises + *                   when fop searches in inode table for pathname and search + *                   fails. + * + * @stub: call stub + * @op_ret: + * @op_errno: + * @inode: + * @parent: + * + * not for external reference + */ +int32_t +server_stub_resume (call_stub_t *stub, +		    int32_t op_ret, +		    int32_t op_errno, +		    inode_t *inode, +		    inode_t *parent) +{ +	inode_t *server_inode = inode; + +	if (!stub) { +		return 0; +	} +	switch (stub->fop) +	{ +	case GF_FOP_RENAME: +		if (stub->args.rename.old.inode == NULL) { +			loc_t *newloc = NULL; +			/* now we are called by lookup of oldpath. */ +			if (op_ret < 0) { +				gf_log (stub->frame->this->name, GF_LOG_ERROR, +					"%"PRId64": RENAME (%s -> %s) on %s " +					"returning error: " +					"%"PRId32" (%"PRId32")", +					stub->frame->root->unique, +					stub->args.rename.old.path, +					stub->args.rename.new.path, +					BOUND_XL(stub->frame)->name, +					op_ret, op_errno); +				 +				/* lookup of oldpath failed, UNWIND to +				 * server_rename_cbk with ret=-1 and  +				 * errno=ENOENT  +				 */ +				server_rename_cbk (stub->frame, +						   NULL, +						   stub->frame->this, +						   -1, +						   ENOENT, +						   NULL); +				server_loc_wipe (&stub->args.rename.old); +				server_loc_wipe (&stub->args.rename.new); +				FREE (stub); +				return 0; +			} +			 +			if (stub->args.rename.old.parent == NULL) +				stub->args.rename.old.parent =  +					inode_ref (parent); +			 +			/* store inode information of oldpath in our stub  +			 * and search for newpath in inode table.  +			 */ +			if (server_inode) { +				stub->args.rename.old.inode =  +					inode_ref (server_inode); +				 +				stub->args.rename.old.ino = +					server_inode->ino; +			} + +			/* now lookup for newpath */ +			newloc = &stub->args.rename.new; + +			if (newloc->parent == NULL) { +				/* lookup for newpath */ +				do_path_lookup (stub, newloc); +				break; +			} else { +				/* found newpath in inode cache */ +				call_resume (stub); +				break; +			} +		} else { +			/* we are called by the lookup of newpath */ +			if (stub->args.rename.new.parent == NULL) +				stub->args.rename.new.parent =  +					inode_ref (parent); +		} +		 +		/* after looking up for oldpath as well as newpath, +		 * we are ready to resume */ +		{ +			call_resume (stub); +		} +		break; +		 +	case GF_FOP_OPEN: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": OPEN (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.open.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			 +			server_open_cbk (stub->frame, +					 NULL, +					 stub->frame->this, +					 -1, +					 ENOENT, +					 NULL); +			FREE (stub->args.open.loc.path); +			FREE (stub); +			return 0; +		} +		if (stub->args.open.loc.parent == NULL) +			stub->args.open.loc.parent = inode_ref (parent); +		 +		if (server_inode && (stub->args.open.loc.inode == NULL)) { +			stub->args.open.loc.inode = inode_ref (server_inode); +			stub->args.open.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} +	 +	case GF_FOP_LOOKUP: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, +				GF_LOG_DEBUG, +				"%"PRId64": LOOKUP (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.lookup.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			 +			server_lookup_cbk (stub->frame, +					   NULL, +					   stub->frame->this, +					   -1, ENOENT, +					   NULL, NULL, +					   NULL); +			server_loc_wipe (&stub->args.lookup.loc); +			FREE (stub); +			return 0; +		} +		 +		if (stub->args.lookup.loc.parent == NULL) +			stub->args.lookup.loc.parent = inode_ref (parent); +		 +		if (server_inode && (stub->args.lookup.loc.inode == NULL)) { +			stub->args.lookup.loc.inode = inode_ref (server_inode); +			stub->args.lookup.loc.ino = server_inode->ino; +		} +		 +		call_resume (stub); +		 +		break; +	} +	 +	case GF_FOP_STAT: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": STAT (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.stat.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_stat_cbk (stub->frame, +					 NULL, +					 stub->frame->this, +					 -1, ENOENT, +					 NULL); +			server_loc_wipe (&stub->args.stat.loc); +			FREE (stub); +			return 0; +		} + +		/* TODO:reply from here only, we already have stat structure */ +		if (stub->args.stat.loc.parent == NULL) +			stub->args.stat.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.stat.loc.inode == NULL)) { +			stub->args.stat.loc.inode = inode_ref (server_inode); +			stub->args.stat.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_XATTROP: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": XATTROP (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.xattrop.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_xattrop_cbk (stub->frame, +					    NULL, +					    stub->frame->this, +					    -1, ENOENT, +					    NULL); +			server_loc_wipe (&stub->args.xattrop.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.xattrop.loc.parent == NULL) +			stub->args.xattrop.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.xattrop.loc.inode == NULL)) { +			stub->args.xattrop.loc.inode =  +				inode_ref (server_inode); + +			stub->args.xattrop.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_UNLINK: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": UNLINK (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.unlink.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_unlink_cbk (stub->frame, NULL, +					   stub->frame->this,  +					   -1, ENOENT); +			server_loc_wipe (&stub->args.unlink.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.unlink.loc.parent == NULL) +			stub->args.unlink.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.unlink.loc.inode == NULL)) { +			stub->args.unlink.loc.inode = inode_ref (server_inode); +			stub->args.unlink.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_SYMLINK: +	{ +		if ((op_ret < 0) && (parent == NULL)) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": SYMLINK (%s -> %s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.symlink.loc.path, +				stub->args.symlink.linkname, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_symlink_cbk (stub->frame, NULL, +					    stub->frame->this,  +					    -1, ENOENT, +					    NULL, NULL); +			server_loc_wipe (&stub->args.symlink.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.symlink.loc.parent == NULL) +			stub->args.symlink.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.symlink.loc.inode == NULL)) { +			stub->args.symlink.loc.inode =  +				inode_ref (server_inode); +			stub->args.symlink.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_RMDIR: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": RMDIR (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.rmdir.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_rmdir_cbk (stub->frame, +					  NULL, +					  stub->frame->this, +					  -1, +					  ENOENT); +			server_loc_wipe (&stub->args.rmdir.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.rmdir.loc.parent == NULL) +			stub->args.rmdir.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.rmdir.loc.inode == NULL)) { +			stub->args.rmdir.loc.inode = inode_ref (server_inode); +			stub->args.rmdir.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_CHMOD: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": CHMOD (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.chmod.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_chmod_cbk (stub->frame, +					  NULL, +					  stub->frame->this, +					  -1, +					  ENOENT, +					  NULL); +			server_loc_wipe (&stub->args.chmod.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.chmod.loc.parent == NULL) +			stub->args.chmod.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.chmod.loc.inode == NULL)) { +			stub->args.chmod.loc.inode = inode_ref (server_inode); +			stub->args.chmod.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_CHOWN: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": CHOWN (%s) on %s returning ENOENT: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.chown.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); +			server_chown_cbk (stub->frame, +					  NULL, +					  stub->frame->this, +					  -1, +					  ENOENT, +					  NULL); +			server_loc_wipe (&stub->args.chown.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.chown.loc.parent == NULL) +			stub->args.chown.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.chown.loc.inode == NULL)) { +			stub->args.chown.loc.inode = inode_ref (server_inode); +			stub->args.chown.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_LINK: +	{ +		if (stub->args.link.oldloc.inode == NULL) { +			if (op_ret < 0) { +				gf_log (stub->frame->this->name, GF_LOG_ERROR, +					"%"PRId64": LINK (%s -> %s) on %s returning " +					"error for oldloc: " +					"%"PRId32" (%"PRId32")", +					stub->frame->root->unique, +					stub->args.link.oldloc.path, +					stub->args.link.newloc.path, +					BOUND_XL(stub->frame)->name, +					op_ret, op_errno); + +				server_link_cbk (stub->frame, +						 NULL, +						 stub->frame->this, +						 -1, ENOENT, +						 NULL, NULL); +				server_loc_wipe (&stub->args.link.oldloc); +				server_loc_wipe (&stub->args.link.newloc); +				FREE (stub); +				return 0; +			} + +			if (stub->args.link.oldloc.parent == NULL) +				stub->args.link.oldloc.parent =  +					inode_ref (parent); + +			if (server_inode &&  +			    (stub->args.link.oldloc.inode == NULL)) { +				stub->args.link.oldloc.inode =  +					inode_ref (server_inode); +				stub->args.link.oldloc.ino = server_inode->ino; +			} + +			if (stub->args.link.newloc.parent == NULL) { +				do_path_lookup (stub,  +						&(stub->args.link.newloc)); +				break; +			} +		} else { +			/* we are called by the lookup of newpath */ +			if ((op_ret < 0) && (parent == NULL)) { +				gf_log (stub->frame->this->name, GF_LOG_ERROR, +					"%"PRId64": LINK (%s -> %s) on %s returning " +					"error for newloc: " +					"%"PRId32" (%"PRId32")", +					stub->frame->root->unique, +					stub->args.link.oldloc.path, +					stub->args.link.newloc.path, +					BOUND_XL(stub->frame)->name, +					op_ret, op_errno); + +				server_link_cbk (stub->frame, NULL, +						 stub->frame->this,  +						 -1, ENOENT,  +						 NULL, NULL); + +				server_loc_wipe (&stub->args.link.oldloc); +				server_loc_wipe (&stub->args.link.newloc); +				FREE (stub); +				break; +			} + +			if (stub->args.link.newloc.parent == NULL) { +				stub->args.link.newloc.parent =  +					inode_ref (parent); +			} + +			if (server_inode &&  +			    (stub->args.link.newloc.inode == NULL)) { +				/* as new.inode doesn't get forget, it +				 * needs to be unref'd here */ +				stub->args.link.newloc.inode =  +					inode_ref (server_inode); +				stub->args.link.newloc.ino = server_inode->ino; +			} +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_TRUNCATE: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": TRUNCATE (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.truncate.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_truncate_cbk (stub->frame, +					     NULL, +					     stub->frame->this, +					     -1, ENOENT, +					     NULL); +			server_loc_wipe (&stub->args.truncate.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.truncate.loc.parent == NULL) +			stub->args.truncate.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.truncate.loc.inode == NULL)) { +			stub->args.truncate.loc.inode =  +				inode_ref (server_inode); +			stub->args.truncate.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_STATFS: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": STATFS (%s) on %s returning ENOENT: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.statfs.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_statfs_cbk (stub->frame, +					   NULL, +					   stub->frame->this, +					   -1, ENOENT, +					   NULL); +			server_loc_wipe (&stub->args.statfs.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.statfs.loc.parent == NULL) +			stub->args.statfs.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.statfs.loc.inode == NULL)) { +			stub->args.statfs.loc.inode = inode_ref (server_inode); +			stub->args.statfs.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_SETXATTR: +	{ +		dict_t *dict = stub->args.setxattr.dict; +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": SETXATTR (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.setxattr.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_setxattr_cbk (stub->frame, +					     NULL, +					     stub->frame->this, +					     -1, ENOENT); + +			server_loc_wipe (&stub->args.setxattr.loc); +			dict_unref (dict); +			FREE (stub); +			return 0; +		} + +		if (stub->args.setxattr.loc.parent == NULL) +			stub->args.setxattr.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.setxattr.loc.inode == NULL)) { +			stub->args.setxattr.loc.inode =  +				inode_ref (server_inode); +			stub->args.setxattr.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_GETXATTR: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": GETXATTR (%s) on %s for key %s " +				"returning error: %"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.getxattr.loc.path, +				BOUND_XL(stub->frame)->name, +				stub->args.getxattr.name ?  +				stub->args.getxattr.name : "<nul>", +				op_ret, op_errno); + +			server_getxattr_cbk (stub->frame, +					     NULL, +					     stub->frame->this, +					     -1, ENOENT, +					     NULL); +			server_loc_wipe (&stub->args.getxattr.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.getxattr.loc.parent == NULL) +			stub->args.getxattr.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.getxattr.loc.inode == NULL)) { +			stub->args.getxattr.loc.inode =  +				inode_ref (server_inode); +			stub->args.getxattr.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_REMOVEXATTR: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": REMOVEXATTR (%s) on %s for key %s " +				"returning error: %"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.removexattr.loc.path, +				BOUND_XL(stub->frame)->name, +				stub->args.removexattr.name, +				op_ret, op_errno); + +			server_removexattr_cbk (stub->frame, +						NULL, +						stub->frame->this, +						-1, +						ENOENT); +			server_loc_wipe (&stub->args.removexattr.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.removexattr.loc.parent == NULL) +			stub->args.removexattr.loc.parent = inode_ref (parent); + +		if (server_inode &&  +		    (stub->args.removexattr.loc.inode == NULL)) { +			stub->args.removexattr.loc.inode =  +				inode_ref (server_inode); +			stub->args.removexattr.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_OPENDIR: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": OPENDIR (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.opendir.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_opendir_cbk (stub->frame, +					    NULL, +					    stub->frame->this, +					    -1, ENOENT, +					    NULL); +			server_loc_wipe (&stub->args.opendir.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.opendir.loc.parent == NULL) +			stub->args.opendir.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.opendir.loc.inode == NULL)) { +			stub->args.opendir.loc.inode =  +				inode_ref (server_inode); +			stub->args.opendir.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_ACCESS: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": ACCESS (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.access.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_access_cbk (stub->frame, +					   NULL, +					   stub->frame->this, +					   -1, ENOENT); +			server_loc_wipe (&stub->args.access.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.access.loc.parent == NULL) +			stub->args.access.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.access.loc.inode == NULL)) { +			stub->args.access.loc.inode = inode_ref (server_inode); +			stub->args.access.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + + +	case GF_FOP_UTIMENS: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": UTIMENS (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.utimens.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_utimens_cbk (stub->frame, +					    NULL, +					    stub->frame->this, +					    -1, ENOENT, +					    NULL); +			server_loc_wipe (&stub->args.utimens.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.utimens.loc.parent == NULL) +			stub->args.utimens.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.utimens.loc.inode == NULL)) { +			stub->args.utimens.loc.inode =  +				inode_ref (server_inode); +			stub->args.utimens.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} + +	case GF_FOP_READLINK: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": READLINK (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.readlink.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_readlink_cbk (stub->frame, +					     NULL, +					     stub->frame->this, +					     -1, ENOENT, +					     NULL); +			server_loc_wipe (&stub->args.readlink.loc); +			FREE (stub); +			return 0; +		} + +		if (stub->args.readlink.loc.parent == NULL) +			stub->args.readlink.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.readlink.loc.inode == NULL)) { +			stub->args.readlink.loc.inode =  +				inode_ref (server_inode); +			stub->args.readlink.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} +	case GF_FOP_MKDIR: +	{ +		if ((op_ret < 0) && (parent == NULL)) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": MKDIR (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.mkdir.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_mkdir_cbk (stub->frame, +					  NULL, +					  stub->frame->this, +					  -1, ENOENT, +					  NULL, NULL); +			server_loc_wipe (&stub->args.mkdir.loc); +			FREE (stub); +			break; +		} + +		if (stub->args.mkdir.loc.parent == NULL) +			stub->args.mkdir.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.mkdir.loc.inode == NULL)) { +			stub->args.mkdir.loc.inode = inode_ref (server_inode); +			stub->args.mkdir.loc.ino = server_inode->ino; +		} + +		call_resume (stub); +		break; +	} + +	case GF_FOP_CREATE: +	{ +		if ((op_ret < 0) && (parent == NULL)) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": CREATE (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.create.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_create_cbk (stub->frame, +					   NULL, +					   stub->frame->this, +					   -1, ENOENT, +					   NULL, NULL, +					   NULL); +			if (stub->args.create.fd) +				fd_unref (stub->args.create.fd); +			server_loc_wipe (&stub->args.create.loc); +			FREE (stub); +			break; +		} + +		if (stub->args.create.loc.parent == NULL) +			stub->args.create.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.create.loc.inode == NULL)) { +			stub->args.create.loc.inode = inode_ref (server_inode); +			stub->args.create.loc.ino = server_inode->ino; +		} + +		call_resume (stub); +		break; +	} + +	case GF_FOP_MKNOD: +	{ +		if ((op_ret < 0) && (parent == NULL)) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": MKNOD (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.mknod.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_mknod_cbk (stub->frame, +					  NULL, +					  stub->frame->this, +					  -1, ENOENT, +					  NULL, NULL); +			server_loc_wipe (&stub->args.mknod.loc); +			FREE (stub); +			break; +		} + +		if (stub->args.mknod.loc.parent == NULL) +			stub->args.mknod.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.mknod.loc.inode == NULL)) { +			stub->args.mknod.loc.inode = inode_ref (server_inode); +			stub->args.mknod.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} +	case GF_FOP_ENTRYLK: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": ENTRYLK (%s) on %s for key %s returning " +				"error: %"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.entrylk.loc.path, +				BOUND_XL(stub->frame)->name, +				stub->args.entrylk.name ? +				stub->args.entrylk.name : "<nul>", +				op_ret, op_errno); + +			server_entrylk_cbk (stub->frame, +					    NULL, +					    stub->frame->this, +					    -1, ENOENT); +			server_loc_wipe (&stub->args.entrylk.loc); +			FREE (stub); +			break; +		} + +		if (stub->args.entrylk.loc.parent == NULL) +			stub->args.entrylk.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.entrylk.loc.inode == NULL)) { +			stub->args.entrylk.loc.inode = inode_ref (server_inode); +			stub->args.entrylk.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} +	case GF_FOP_INODELK: +	{ +		if (op_ret < 0) { +			gf_log (stub->frame->this->name, GF_LOG_ERROR, +				"%"PRId64": INODELK (%s) on %s returning error: " +				"%"PRId32" (%"PRId32")", +				stub->frame->root->unique, +				stub->args.inodelk.loc.path, +				BOUND_XL(stub->frame)->name, +				op_ret, op_errno); + +			server_inodelk_cbk (stub->frame, +					    NULL, +					    stub->frame->this, +					    -1, ENOENT); +			server_loc_wipe (&stub->args.inodelk.loc); +			FREE (stub); +			break; +		} + +		if (stub->args.inodelk.loc.parent == NULL) +			stub->args.inodelk.loc.parent = inode_ref (parent); + +		if (server_inode && (stub->args.inodelk.loc.inode == NULL)) { +			stub->args.inodelk.loc.inode =  +				inode_ref (server_inode); +			stub->args.inodelk.loc.ino = server_inode->ino; +		} +		call_resume (stub); +		break; +	} +	default: +		call_resume (stub); +	} + +	return 0; +} + +static int +server_lookup_resume (call_frame_t *frame, +		      xlator_t *this, +		      loc_t *loc, +		      dict_t *xattr_req) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if ((state->loc.parent == NULL) &&  +	    (loc->parent)) +		state->loc.parent = inode_ref (loc->parent); + +	if (state->loc.inode == NULL) { +		if (loc->inode == NULL) +			state->loc.inode = inode_new (state->itable); +		else +			/* FIXME: why another lookup? */ +			state->loc.inode = inode_ref (loc->inode); +	} else { +		if (loc->inode && (state->loc.inode != loc->inode)) { +			if (state->loc.inode) +				inode_unref (state->loc.inode); +			state->loc.inode = inode_ref (loc->inode); +		} +	} + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": LOOKUP \'%"PRId64"/%s\'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_lookup_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->lookup, +		    &(state->loc), +		    xattr_req); +	return 0; +} + +/* + * server_lookup - lookup function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int +server_lookup (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	gf_fop_lookup_req_t *req = NULL; +	server_state_t      *state = NULL; +	call_stub_t *lookup_stub = NULL; +	int32_t      ret = -1; +	size_t pathlen = 0, baselen = 0; +	size_t dictlen = 0; +	dict_t *xattr_req = NULL; +	char   *req_dictbuf = NULL; + +	req = gf_param (hdr); + +	state = CALL_STATE(frame); +	{ + +		pathlen = STRLEN_0 (req->path); +		dictlen = ntoh32 (req->dictlen); +		 +		/* NOTE: lookup() uses req->ino only to identify if a lookup() +		 *       is requested for 'root' or not  +		 */ +		state->ino    = ntoh64 (req->ino); +		if (state->ino != 1) +			state->ino = 0; + +		state->par    = ntoh64 (req->par); +		state->path   = req->path; +		if (IS_NOT_ROOT(pathlen)) { +			state->bname = req->bname + pathlen; +			baselen = STRLEN_0 (state->bname); +		} + +		if (dictlen) { +			/* Unserialize the dictionary */ +			req_dictbuf = memdup (req->dict + pathlen + baselen, dictlen); +			GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); +			 +			xattr_req = dict_new (); +			GF_VALIDATE_OR_GOTO(bound_xl->name, xattr_req, fail); + +			ret = dict_unserialize (req_dictbuf, dictlen, &xattr_req); +			if (ret < 0) { +				gf_log (bound_xl->name, GF_LOG_ERROR, +					"%"PRId64": %s (%"PRId64"): failed to " +					"unserialize request buffer to dictionary",  +					frame->root->unique, state->loc.path,  +					state->ino); +				free (req_dictbuf); +				goto fail; +			} else{ +				xattr_req->extra_free = req_dictbuf; +				state->xattr_req = xattr_req; +				xattr_req = NULL; +			} +		} +	} + +	ret = server_loc_fill (&state->loc, state, +			       state->ino, state->par, state->bname, +			       state->path); + + 	if (state->loc.inode) { +		/* revalidate */ +		state->is_revalidate = 1; +	} else { +		/* fresh lookup or inode was previously pruned out */ +		state->is_revalidate = -1; +	} + +	lookup_stub = fop_lookup_stub (frame, server_lookup_resume, +				       &(state->loc), state->xattr_req); +	GF_VALIDATE_OR_GOTO(bound_xl->name, lookup_stub, fail); + +	if ((state->loc.parent == NULL) &&  +	    IS_NOT_ROOT(pathlen)) +		do_path_lookup (lookup_stub, &(state->loc)); +	else +		call_resume (lookup_stub); +	 +	return 0; +fail: +	server_lookup_cbk (frame, NULL, frame->this, +			   -1,EINVAL, +			   NULL, NULL, NULL); +	if (xattr_req) +		dict_unref (xattr_req); + +	return 0; +} + + +/* + * server_forget - forget function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_forget (call_frame_t *frame, xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	int index = 0; +	ino_t ino = 0; +	int32_t count = 0; +	inode_t *inode = NULL; +	gf_cbk_forget_req_t *req = NULL; + +	req = gf_param (hdr); +	count = ntoh32 (req->count); + +	for (index = 0; index < count; index++) { +		 +		ino = ntoh64 (req->ino_array[index]); +		 +		if (!ino) +			continue; + +		inode = inode_search (bound_xl->itable, ino, NULL); + +		if (inode) { +			inode_forget (inode, 0); +			inode_unref (inode); +		} else { +			gf_log (bound_xl->name, GF_LOG_DEBUG, +				"%"PRId64": FORGET %"PRId64" not found " +				"in inode table", +				frame->root->unique, ino); +		} +		 +		gf_log (bound_xl->name, GF_LOG_DEBUG, +			"%"PRId64": FORGET \'%"PRId64"\'",  +			frame->root->unique, ino); +	} + +	server_forget_cbk (frame, NULL, bound_xl, 0, 0); + +	return 0; +} + + + +int32_t +server_stat_resume (call_frame_t *frame, +                    xlator_t *this, +                    loc_t *loc) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": STAT \'%s (%"PRId64")\'",  +		frame->root->unique, state->loc.path, state->loc.ino); + +	STACK_WIND (frame, +		    server_stat_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->stat, +		    loc); +	return 0; +} + +/* + * server_stat - stat function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_stat (call_frame_t *frame, +             xlator_t *bound_xl, +             gf_hdr_common_t *hdr, size_t hdrlen, +             char *buf, size_t buflen) +{ +	call_stub_t *stat_stub = NULL; +	gf_fop_stat_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req = gf_param (hdr); +	state = CALL_STATE(frame); + +	state->ino  = ntoh64 (req->ino); +	state->path = req->path; +	pathlen = STRLEN_0(state->path); + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, state->par, state->bname, +			       state->path); + +	stat_stub = fop_stat_stub (frame, +				   server_stat_resume, +				   &(state->loc)); +	GF_VALIDATE_OR_GOTO(bound_xl->name, stat_stub, fail); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) ||  +	    (state->loc.inode == NULL)) { +		do_path_lookup (stat_stub, &(state->loc)); +	} else { +		call_resume (stat_stub); +	} +	return 0; +fail: +	server_stat_cbk (frame, NULL, frame->this, +			 -1, EINVAL, +			 NULL); +	return 0; +} + + +int32_t +server_readlink_resume (call_frame_t *frame, +                        xlator_t *this, +                        loc_t *loc, +                        size_t size) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": READLINK \'%s (%"PRId64")\'",  +		frame->root->unique, state->loc.path, state->loc.ino); + +	STACK_WIND (frame, +		    server_readlink_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->readlink, +		    loc, +		    size); +	return 0; +} + +/* + * server_readlink - readlink function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_readlink (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	call_stub_t *readlink_stub = NULL; +	gf_fop_readlink_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); + +	state->size  = ntoh32 (req->size); + +	state->ino  = ntoh64 (req->ino); +	state->path = req->path; + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	readlink_stub = fop_readlink_stub (frame, +					   server_readlink_resume, +					   &(state->loc), +					   state->size); +	GF_VALIDATE_OR_GOTO(bound_xl->name, readlink_stub, fail); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (readlink_stub, &(state->loc)); +	} else { +		call_resume (readlink_stub); +	} +	return 0; +fail: +	server_readlink_cbk (frame, NULL,frame->this, +			     -1, EINVAL, +			     NULL); +	return 0; +} + +int32_t +server_create_resume (call_frame_t *frame, +		      xlator_t *this, +		      loc_t *loc, +		      int32_t flags, +		      mode_t mode, +		      fd_t *fd) +{ +	server_state_t *state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	state->loc.inode = inode_new (state->itable); +	GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, state->loc.inode, fail); + +	state->fd = fd_create (state->loc.inode, frame->root->pid); +	GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, state->fd, fail); + +	state->fd->flags = flags; +	state->fd = fd_ref (state->fd); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": CREATE \'%"PRId64"/%s\'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_create_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->create, +		    &(state->loc), +		    flags, +		    mode, +		    state->fd); + +	return 0; +fail: +	server_create_cbk (frame, NULL, frame->this, +			   -1, EINVAL, +			   NULL, NULL, NULL); +	return 0; +} + + +/* + * server_create - create function for server + * @frame: call frame + * @bound_xl: translator this server is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_create (call_frame_t *frame, xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	gf_fop_create_req_t *req = NULL; +	server_state_t      *state = NULL; +	call_stub_t         *create_stub = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		 +		state->par  = ntoh64 (req->par); +		state->path = req->path; +		if (IS_NOT_ROOT(pathlen)) +			state->bname = req->bname + pathlen; + +		state->mode  = ntoh32 (req->mode); +		state->flags = ntoh32 (req->flags); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); + +	create_stub = fop_create_stub (frame, server_create_resume, +				       &(state->loc), state->flags,  +				       state->mode, state->fd); +	GF_VALIDATE_OR_GOTO(bound_xl->name, create_stub, fail); + +	if (state->loc.parent == NULL) { +		do_path_lookup (create_stub, &state->loc); +	} else { +		call_resume (create_stub); +	} +	return 0; +fail: +	server_create_cbk (frame, NULL, frame->this, +			   -1, EINVAL, +			   NULL, NULL, NULL); +	return 0; +} + + +int32_t +server_open_resume (call_frame_t *frame, +                    xlator_t *this, +                    loc_t *loc, +                    int32_t flags, +                    fd_t *fd) +{ +	server_state_t *state = CALL_STATE(frame); +	fd_t *new_fd = NULL; + +	new_fd = fd_create (loc->inode, frame->root->pid); +	GF_VALIDATE_OR_GOTO(BOUND_XL(frame)->name, new_fd, fail); + +	new_fd->flags = flags; + +	state->fd = fd_ref (new_fd); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": OPEN \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_open_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->open, +		    loc, +		    flags, +		    state->fd); + +	return 0; +fail: +	server_open_cbk (frame, NULL, frame->this, +			 -1, EINVAL, +			 NULL); +	return 0; +} + +/* + * server_open - open function for server protocol + * @frame: call frame + * @bound_xl: translator this server protocol is bound to + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_open (call_frame_t *frame, xlator_t *bound_xl, +             gf_hdr_common_t *hdr, size_t hdrlen, +             char *buf, size_t buflen) +{ +	call_stub_t *open_stub = NULL; +	gf_fop_open_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->ino   = ntoh64 (req->ino); +		state->path  = req->path; +		pathlen = STRLEN_0(state->path); +		state->flags = ntoh32 (req->flags); +	} +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	open_stub = fop_open_stub (frame, +				   server_open_resume, +				   &(state->loc), state->flags, NULL); +	GF_VALIDATE_OR_GOTO(bound_xl->name, open_stub, fail); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) ||  +	    (state->loc.inode == NULL)) { +		do_path_lookup (open_stub, &state->loc); +	} else { +		call_resume (open_stub); +	} +	return 0; +fail: +	server_open_cbk (frame, NULL, frame->this, +			 -1, EINVAL, +			 NULL); +	return 0; +} + + +/* + * server_readv - readv function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_readv (call_frame_t *frame, xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_read_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req = gf_param (hdr); +   +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->size   = ntoh32 (req->size); +		state->offset = ntoh64 (req->offset); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": READV \'fd=%"PRId64" (%"PRId64"); " +		"offset=%"PRId64"; size=%"PRId64, +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		state->offset, (int64_t)state->size); + +	STACK_WIND (frame, +		    server_readv_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->readv, +		    state->fd, state->size, state->offset); +	return 0; +fail: +	server_readv_cbk (frame, NULL, frame->this, +			  -1, EINVAL, NULL, 0, NULL); +	return 0; +} + + +/* + * server_writev - writev function for server + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_writev (call_frame_t *frame, xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_fop_write_req_t *req = NULL; +	struct iovec iov = {0, }; +	dict_t *refs = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->offset = ntoh64 (req->offset); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	iov.iov_base = buf; +	iov.iov_len = buflen; + +	refs = dict_new (); +	GF_VALIDATE_OR_GOTO(bound_xl->name, refs, fail); + +	ret = dict_set_dynptr (refs, NULL, buf, buflen); +	if (ret < 0) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64" (%"PRId64"): failed to set buffer entry " +			"to req_refs", +			state->fd_no, state->fd->inode->ino); +		goto fail; +	} else { +		buf = NULL; +	} + +	frame->root->req_refs = refs; + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": WRITEV \'fd=%"PRId64" (%"PRId64"); " +		"offset=%"PRId64"; size=%"PRId64, +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		state->offset, (int64_t)buflen); + +	STACK_WIND (frame, +		    server_writev_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->writev, +		    state->fd, &iov, 1, state->offset); +	 +	if (refs) +		dict_unref (refs); +	return 0; +fail: +	server_writev_cbk (frame, NULL, frame->this, +			   -1, EINVAL, NULL); +	 +	if (buf) +		free (buf); + +	if (refs) +		dict_unref (refs); + +	return 0; +} + + + +/* + * server_release - release function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_release (call_frame_t *frame, xlator_t *bound_xl, +		gf_hdr_common_t *hdr, size_t hdrlen, +		char *buf, size_t buflen) +{ +	gf_cbk_release_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req = gf_param (hdr); +	state = CALL_STATE(frame); +	 +	state->fd_no = ntoh64 (req->fd); +	state->fd = gf_fd_fdptr_get (conn->fdtable,  +				     state->fd_no); +	 +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	gf_fd_put (conn->fdtable,  +		   state->fd_no); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": RELEASE \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_release_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->flush, +		    state->fd); +	return 0; +fail: +	server_release_cbk (frame, NULL, frame->this, +			    -1, EINVAL); +	return 0; +} + + +/* + * server_fsync - fsync function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_fsync (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_fsync_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->flags = ntoh32 (req->data); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FSYNC \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_fsync_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->fsync, +		    state->fd, state->flags); +	return 0; +fail: +	server_fsync_cbk (frame, NULL, frame->this, +			  -1, EINVAL); + +	return 0; +} + + +/* + * server_flush - flush function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_flush (call_frame_t *frame, xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_flush_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FLUSH \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_flush_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->flush, +		    state->fd); +	return 0; + +fail: +	server_flush_cbk (frame, NULL, frame->this, +			  -1, EINVAL); + +	return 0; +} + + +/* + * server_ftruncate - ftruncate function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameters dictionary + * + * not for external reference + */ +int32_t +server_ftruncate (call_frame_t *frame, +                  xlator_t *bound_xl, +                  gf_hdr_common_t *hdr, size_t hdrlen, +                  char *buf, size_t buflen) +{ +	gf_fop_ftruncate_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req = gf_param (hdr); + +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->offset = ntoh64 (req->offset); +	} + +	GF_VALIDATE_OR_GOTO(bound_xl->name, state->fd, fail); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FTRUNCATE \'fd=%"PRId64" (%"PRId64"); " +		"offset=%"PRId64"\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		state->offset); + +	STACK_WIND (frame, +		    server_ftruncate_cbk, +		    bound_xl, +		    bound_xl->fops->ftruncate, +		    state->fd, +		    state->offset); +	return 0; +fail: +	server_ftruncate_cbk (frame, NULL, frame->this, +			      -1, EINVAL, NULL); + +	return 0; +} + + +/* + * server_fstat - fstat function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_fstat (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_fstat_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); +	} + + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_fstat_cbk (frame, NULL, frame->this, +				  -1, EINVAL, NULL); + +		goto out; +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FSTAT \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_fstat_cbk, +		    bound_xl, +		    bound_xl->fops->fstat, +		    state->fd); +out: +	return 0; +} + + +int32_t +server_truncate_resume (call_frame_t *frame, +                        xlator_t *this, +                        loc_t *loc, +                        off_t offset) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": TRUNCATE \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_truncate_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->truncate, +		    loc, +		    offset); +	return 0; +} + + +/* + * server_truncate - truncate function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_truncate (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	call_stub_t *truncate_stub = NULL; +	gf_fop_truncate_req_t *req = NULL; +	server_state_t *state = NULL; +  	int32_t ret = -1; +	size_t pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		state->offset = ntoh64 (req->offset); + +		state->path = req->path; +		state->ino  = ntoh64 (req->ino); +	} + + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	truncate_stub = fop_truncate_stub (frame, +					   server_truncate_resume, +					   &(state->loc), +					   state->offset); +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (truncate_stub, &(state->loc)); +	} else { +		call_resume (truncate_stub); +	} + +	return 0; +} + + + + + +int32_t +server_unlink_resume (call_frame_t *frame, +                      xlator_t *this, +                      loc_t *loc) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	if (state->loc.inode == NULL) +		state->loc.inode = inode_ref (loc->inode); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": UNLINK \'%"PRId64"/%s (%"PRId64")\'",  +		frame->root->unique, state->par, state->path,  +		state->loc.inode->ino); + +	STACK_WIND (frame, +		    server_unlink_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->unlink, +		    loc); +	return 0; +} + +/* + * server_unlink - unlink function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_unlink (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	call_stub_t *unlink_stub = NULL; +	gf_fop_unlink_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); + +	pathlen = STRLEN_0(req->path); +	 +	state->par   = ntoh64 (req->par); +	state->path  = req->path; +	if (IS_NOT_ROOT(pathlen)) +		state->bname = req->bname + pathlen; + +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); + +	unlink_stub = fop_unlink_stub (frame, +				       server_unlink_resume, +				       &(state->loc)); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (unlink_stub, &state->loc); +	} else { +		call_resume (unlink_stub); +	} + +	return 0; +} + + + + + +int32_t +server_setxattr_resume (call_frame_t *frame, +                        xlator_t *this, +                        loc_t *loc, +                        dict_t *dict, +                        int32_t flags) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": SETXATTR \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_setxattr_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->setxattr, +		    loc, +		    dict, +		    flags); +	return 0; +} + +/* + * server_setxattr - setxattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_setxattr (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	call_stub_t *setxattr_stub = NULL; +	gf_fop_setxattr_req_t *req = NULL; +	dict_t *dict = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; +	size_t dict_len = 0; +	char *req_dictbuf = NULL; + +	req = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		dict_len = ntoh32 (req->dict_len); + +		state->path     = req->path + dict_len; + +		pathlen = STRLEN_0(state->path); +		state->ino   = ntoh64 (req->ino); + +		state->flags = ntoh32 (req->flags); +	} +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	{ +		/* Unserialize the dictionary */ +		req_dictbuf = memdup (req->dict, dict_len); +		GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + +		dict = dict_new (); +		GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + +		ret = dict_unserialize (req_dictbuf, dict_len, &dict); +		if (ret < 0) { +			gf_log (bound_xl->name, GF_LOG_ERROR, +				"%"PRId64": %s (%"PRId64"): failed to " +				"unserialize request buffer to dictionary",  +				frame->root->unique, state->loc.path,  +				state->ino); +			free (req_dictbuf); +			goto fail; +		} else{ +			dict->extra_free = req_dictbuf; +		} +	} + +	setxattr_stub = fop_setxattr_stub (frame, +					   server_setxattr_resume, +					   &(state->loc), +					   dict, +					   state->flags); +	GF_VALIDATE_OR_GOTO(bound_xl->name, setxattr_stub, fail); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (setxattr_stub, &(state->loc)); +	} else { +		call_resume (setxattr_stub); +	} +	 +	if (dict) +		dict_unref (dict); + +	return 0; +fail: +	if (dict) +		dict_unref (dict); + +	server_setxattr_cbk (frame, NULL, frame->this, +			     -1, ENOENT); +	return 0; +	 +} + + + +int32_t +server_fxattrop (call_frame_t *frame, +		xlator_t *bound_xl, +		gf_hdr_common_t *hdr, size_t hdrlen, +		char *buf, size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_fop_fxattrop_req_t *req = NULL; +	dict_t *dict = NULL; +	server_state_t *state = NULL; +	size_t dict_len = 0; +	char *req_dictbuf = NULL; +	int32_t ret = -1; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		dict_len = ntoh32 (req->dict_len); +		state->ino = ntoh64 (req->ino); +		state->flags = ntoh32 (req->flags); +	} + +	if (dict_len) { +		/* Unserialize the dictionary */ +		req_dictbuf = memdup (req->dict, dict_len); +		GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + +		dict = dict_new (); +		GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + +		ret = dict_unserialize (req_dictbuf, dict_len, &dict); +		if (ret < 0) { +			gf_log (bound_xl->name, GF_LOG_ERROR, +				"fd - %"PRId64" (%"PRId64"): failed to unserialize " +				"request buffer to dictionary",  +				state->fd_no, state->fd->inode->ino); +			free (req_dictbuf); +			goto fail; +		} else { +			dict->extra_free = req_dictbuf; +		} +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FXATTROP \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_fxattrop_cbk, +		    bound_xl, +		    bound_xl->fops->fxattrop, +		    state->fd, +		    state->flags, +		    dict); +	if (dict) +		dict_unref (dict); +	return 0; +fail: +	if (dict) +		dict_unref (dict); + +	server_fxattrop_cbk (frame, NULL, frame->this, +			     -1, EINVAL, NULL); +	return 0; +} + +int32_t +server_xattrop_resume (call_frame_t *frame, +		       xlator_t *this, +		       loc_t *loc, +		       gf_xattrop_flags_t flags, +		       dict_t *dict) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": XATTROP \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_xattrop_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->xattrop, +		    loc, +		    flags, +		    dict); +	return 0; +} + +int32_t +server_xattrop (call_frame_t *frame, +		xlator_t *bound_xl, +		gf_hdr_common_t *hdr, size_t hdrlen, +		char *buf, size_t buflen) +{ +	gf_fop_xattrop_req_t *req = NULL; +	dict_t *dict = NULL; +	server_state_t *state = NULL; +	call_stub_t *xattrop_stub = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; +	size_t dict_len = 0; +	char *req_dictbuf = NULL; +	 +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		dict_len = ntoh32 (req->dict_len); +		state->ino = ntoh64 (req->ino); +		state->path  = req->path + dict_len; +		pathlen = STRLEN_0(state->path); +		state->flags = ntoh32 (req->flags); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); +	 +	if (dict_len) { +		/* Unserialize the dictionary */ +		req_dictbuf = memdup (req->dict, dict_len); +		GF_VALIDATE_OR_GOTO(bound_xl->name, req_dictbuf, fail); + +		dict = dict_new (); +		GF_VALIDATE_OR_GOTO(bound_xl->name, dict, fail); + +		ret = dict_unserialize (req_dictbuf, dict_len, &dict); +		if (ret < 0) { +			gf_log (bound_xl->name, GF_LOG_ERROR, +				"%s (%"PRId64"): failed to unserialize " +				"request buffer to dictionary",  +				state->loc.path, state->ino); +			goto fail; +		} else {  +			dict->extra_free = req_dictbuf; +		} +	} +	xattrop_stub = fop_xattrop_stub (frame, +					 server_xattrop_resume, +					 &(state->loc), +					 state->flags, +					 dict); +	GF_VALIDATE_OR_GOTO(bound_xl->name, xattrop_stub, fail); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (xattrop_stub, &(state->loc)); +	} else { +		call_resume (xattrop_stub); +	} + +	if (dict) +		dict_unref (dict); +	return 0; +fail: +	if (dict) +		dict_unref (dict); + +	server_xattrop_cbk (frame, NULL, frame->this, +			    -1, EINVAL, +			    NULL); +	return 0; +} + + +int32_t +server_getxattr_resume (call_frame_t *frame, +                        xlator_t *this, +                        loc_t *loc, +                        const char *name) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": GETXATTR \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_getxattr_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->getxattr, +		    loc, +		    name); +	return 0; +} + +/* + * server_getxattr - getxattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_getxattr (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	gf_fop_getxattr_req_t *req = NULL; +	call_stub_t *getxattr_stub = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t namelen = 0; +	size_t pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); + +		state->path = req->path; +		state->ino  = ntoh64 (req->ino); + +		namelen = ntoh32 (req->namelen); +		if (namelen) +			state->name = (req->name + pathlen); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	getxattr_stub = fop_getxattr_stub (frame, +					   server_getxattr_resume, +					   &(state->loc), +					   state->name); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (getxattr_stub, &(state->loc)); +	} else { +		call_resume (getxattr_stub); +	} + +	return 0; +} + + + +int32_t +server_removexattr_resume (call_frame_t *frame, +                           xlator_t *this, +                           loc_t *loc, +                           const char *name) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": REMOVEXATTR \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_removexattr_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->removexattr, +		    loc, +		    name); +	return 0; +} + +/* + * server_removexattr - removexattr function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_removexattr (call_frame_t *frame, +                    xlator_t *bound_xl, +                    gf_hdr_common_t *hdr, size_t hdrlen, +                    char *buf, size_t buflen) +{ +	gf_fop_removexattr_req_t *req = NULL; +	call_stub_t *removexattr_stub = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); + +		state->path = req->path; +		state->ino  = ntoh64 (req->ino); + +		state->name = (req->name + pathlen); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	removexattr_stub = fop_removexattr_stub (frame, +						 server_removexattr_resume, +						 &(state->loc), +						 state->name); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (removexattr_stub, &(state->loc)); +	} else { +		call_resume (removexattr_stub); +	} + +	return 0; +} + + +/* + * server_statfs - statfs function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_statfs (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	gf_fop_statfs_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; + +	req = gf_param (hdr); + +	state = CALL_STATE(frame); +	state->ino  = ntoh64 (req->ino); +	state->path = req->path; + +	ret = server_loc_fill (&state->loc, state, +			       state->ino, 0, NULL, state->path); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": STATFS \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_statfs_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->statfs, +		    &(state->loc)); + +	return 0; +} + + + +int32_t +server_opendir_resume (call_frame_t *frame, +                       xlator_t *this, +                       loc_t *loc, +                       fd_t *fd) +{ +	server_state_t *state = CALL_STATE(frame); +	fd_t *new_fd = NULL; + +	new_fd = fd_create (loc->inode, frame->root->pid); +	state->fd = fd_ref (new_fd); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": OPENDIR \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_opendir_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->opendir, +		    loc, +		    state->fd); +	return 0; +} + + +/* + * server_opendir - opendir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_opendir (call_frame_t *frame, xlator_t *bound_xl, +                gf_hdr_common_t *hdr, size_t hdrlen, +                char *buf, size_t buflen) +{ +	call_stub_t *opendir_stub = NULL; +	gf_fop_opendir_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->path  = req->path; +		pathlen = STRLEN_0(state->path); +		state->ino   = ntoh64 (req->ino); +	} + +	ret = server_loc_fill (&state->loc, state, +			       state->ino, 0, NULL, state->path); + +	opendir_stub = fop_opendir_stub (frame, +					 server_opendir_resume, +					 &(state->loc), +					 NULL); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (opendir_stub, &(state->loc)); +	} else { +		call_resume (opendir_stub); +	} + +	return 0; +} + + +/* + * server_releasedir - releasedir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_releasedir (call_frame_t *frame, xlator_t *bound_xl, +		   gf_hdr_common_t *hdr, size_t hdrlen, +		   char *buf, size_t buflen) +{ +	gf_cbk_releasedir_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req = gf_param (hdr); +	state = CALL_STATE(frame); + +	state->fd_no = ntoh64 (req->fd); +	state->fd    = gf_fd_fdptr_get (conn->fdtable,  +					state->fd_no); + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_releasedir_cbk (frame, NULL, frame->this, +				       -1, EINVAL); +		goto out; +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": RELEASEDIR \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	gf_fd_put (conn->fdtable, state->fd_no); + +	server_releasedir_cbk (frame, NULL, frame->this, +			       0, 0); +out: +	return 0; +} + + +/* + * server_readdir - readdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_getdents (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	gf_fop_getdents_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->size = ntoh32 (req->size); +		state->offset = ntoh64 (req->offset); +		state->flags = ntoh32 (req->flags); +	} + + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_getdents_cbk (frame, NULL, frame->this, +				     -1, EINVAL, NULL, 0); + +		goto out; +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": GETDENTS \'fd=%"PRId64" (%"PRId64"); " +		"offset=%"PRId64"; size=%"PRId64,  +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		state->offset, (int64_t)state->size); + +	STACK_WIND (frame, +		    server_getdents_cbk, +		    bound_xl, +		    bound_xl->fops->getdents, +		    state->fd, +		    state->size, +		    state->offset, +		    state->flags); +out: +	return 0; +} + + +/* + * server_readdir - readdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_readdir (call_frame_t *frame, xlator_t *bound_xl, +                gf_hdr_common_t *hdr, size_t hdrlen, +                char *buf, size_t buflen) +{ +	gf_fop_readdir_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->size   = ntoh32 (req->size); +		state->offset = ntoh64 (req->offset); +	} + + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_readdir_cbk (frame, NULL, frame->this, +				    -1, EINVAL, NULL); + +		goto out; +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": READDIR \'fd=%"PRId64" (%"PRId64"); " +		"offset=%"PRId64"; size=%"PRId64, +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		state->offset, (int64_t)state->size); + +	STACK_WIND (frame, +		    server_readdir_cbk, +		    bound_xl, +		    bound_xl->fops->readdir, +		    state->fd, state->size, state->offset); +out: +	return 0; +} + + + +/* + * server_fsyncdir - fsyncdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_fsyncdir (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	gf_fop_fsyncdir_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->flags = ntoh32 (req->data); +	} + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_fsyncdir_cbk (frame, NULL, frame->this, +				     -1, EINVAL); +		goto out; +	} + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": FSYNCDIR \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, +		    server_fsyncdir_cbk, +		    bound_xl, +		    bound_xl->fops->fsyncdir, +		    state->fd, state->flags); +out: +	return 0; +} + + +int32_t +server_mknod_resume (call_frame_t *frame, +		     xlator_t *this, +		     loc_t *loc, +		     mode_t mode, +		     dev_t dev) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	state->loc.inode = inode_new (state->itable); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": MKNOD \'%"PRId64"/%s\'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_mknod_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->mknod, +		    &(state->loc), mode, dev); + +	return 0; +} +/* + * server_mknod - mknod function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_mknod (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_mknod_req_t *req = NULL; +	server_state_t *state = NULL; +	call_stub_t *mknod_stub = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; +		 +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		 +		state->par  = ntoh64 (req->par); +		state->path = req->path; +		if (IS_NOT_ROOT(pathlen)) +			state->bname = req->bname + pathlen; + +		state->mode = ntoh32 (req->mode); +		state->dev  = ntoh64 (req->dev); +	} +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); + +	mknod_stub = fop_mknod_stub (frame, server_mknod_resume, +				     &(state->loc), state->mode, state->dev); + +	if (state->loc.parent == NULL) { +		do_path_lookup (mknod_stub, &(state->loc)); +	} else { +		call_resume (mknod_stub); +	} + +	return 0; +} + +int32_t +server_mkdir_resume (call_frame_t *frame, +		     xlator_t *this, +		     loc_t *loc, +		     mode_t mode) + +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	state->loc.inode = inode_new (state->itable); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": MKDIR \'%"PRId64"/%s\'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_mkdir_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->mkdir, +		    &(state->loc), +		    state->mode); + +	return 0; +} + +/* + * server_mkdir - mkdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_mkdir (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	gf_fop_mkdir_req_t *req = NULL; +	server_state_t *state = NULL; +	call_stub_t *mkdir_stub = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; +		 +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		state->mode = ntoh32 (req->mode); + +		state->path     = req->path; +		state->bname = req->bname + pathlen; +		state->par      = ntoh64 (req->par); +	} + + +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); + +	mkdir_stub = fop_mkdir_stub (frame, server_mkdir_resume, +				     &(state->loc), state->mode); + +	if (state->loc.parent == NULL) { +		do_path_lookup (mkdir_stub, &(state->loc)); +	} else { +		call_resume (mkdir_stub); +	} + +	return 0; +} + + +int32_t +server_rmdir_resume (call_frame_t *frame, +                     xlator_t *this, +                     loc_t *loc) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	if (state->loc.inode == NULL) +		state->loc.inode = inode_ref (loc->inode); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": RMDIR \'%"PRId64"/%s\'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_rmdir_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->rmdir, +		    loc); +	return 0; +} + +/* + * server_rmdir - rmdir function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_rmdir (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	call_stub_t *rmdir_stub = NULL; +	gf_fop_rmdir_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		state->path = req->path; +		state->par  = ntoh64 (req->par); +		state->bname = req->bname + pathlen; +	} + + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, state->par, state->bname, +			       state->path); + +	rmdir_stub = fop_rmdir_stub (frame, +				     server_rmdir_resume, +				     &(state->loc)); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (rmdir_stub, &(state->loc)); +	} else { +		call_resume (rmdir_stub); +	} + +	return 0; +} + + + +int32_t +server_chown_resume (call_frame_t *frame, +                     xlator_t *this, +                     loc_t *loc, +                     uid_t uid, +                     gid_t gid) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": CHOWN \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, server_chown_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->chown, +		    loc, uid, gid); +	return 0; +} + + +/* + * server_chown - chown function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_chown (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	call_stub_t *chown_stub = NULL; +	gf_fop_chown_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->ino  = ntoh64 (req->ino); +		state->path = req->path; +		pathlen = STRLEN_0(state->path); +		state->uid   = ntoh32 (req->uid); +		state->gid   = ntoh32 (req->gid); +	} + + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	chown_stub = fop_chown_stub (frame, +				     server_chown_resume, +				     &(state->loc), +				     state->uid, +				     state->gid); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (chown_stub, &(state->loc)); +	} else { +		call_resume (chown_stub); +	} + +	return 0; +} + + +int32_t +server_chmod_resume (call_frame_t *frame, +                     xlator_t *this, +                     loc_t *loc, +                     mode_t mode) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": CHMOD \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_chmod_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->chmod, +		    loc, +		    mode); +	return 0; + +} + +/* + * server_chmod - chmod function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_chmod (call_frame_t *frame, +              xlator_t *bound_xl, +              gf_hdr_common_t *hdr, size_t hdrlen, +              char *buf, size_t buflen) +{ +	call_stub_t *chmod_stub = NULL; +	gf_fop_chmod_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req       = gf_param (hdr); + +	state = CALL_STATE(frame); +	{ +		state->ino  = ntoh64 (req->ino); +		state->path = req->path; +		pathlen = STRLEN_0(state->path); + +		state->mode = ntoh32 (req->mode); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	chmod_stub = fop_chmod_stub (frame, +				     server_chmod_resume, +				     &(state->loc), +				     state->mode); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (chmod_stub, &(state->loc)); +	} else { +		call_resume (chmod_stub); +	} + +	return 0; +} + + +int32_t +server_utimens_resume (call_frame_t *frame, +                       xlator_t *this, +                       loc_t *loc, +                       struct timespec *tv) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": UTIMENS \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_utimens_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->utimens, +		    loc, +		    tv); +	return 0; +} + +/* + * server_utimens - utimens function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_utimens (call_frame_t *frame, +                xlator_t *bound_xl, +                gf_hdr_common_t *hdr, size_t hdrlen, +                char *buf, size_t buflen) +{ +	call_stub_t *utimens_stub = NULL; +	gf_fop_utimens_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->ino  = ntoh64 (req->ino); +		state->path = req->path; +		pathlen = STRLEN_0(state->path); + +		gf_timespec_to_timespec (req->tv, state->tv); +	} + + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	utimens_stub = fop_utimens_stub (frame, +					 server_utimens_resume, +					 &(state->loc), +					 state->tv); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (utimens_stub, &(state->loc)); +	} else { +		call_resume (utimens_stub); +	} + +	return 0; +} + + + +int32_t +server_inodelk_resume (call_frame_t *frame, +		       xlator_t *this, +		       loc_t *loc, int32_t cmd, +		       struct flock *flock) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); +	if (state->loc.inode == NULL) { +		state->loc.inode = inode_ref (loc->inode); +	} + +	if (state->loc.parent == NULL) { +		state->loc.parent = inode_ref (loc->parent); +	} + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": INODELK \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + + 	STACK_WIND (frame, + 		    server_inodelk_cbk, + 		    BOUND_XL(frame), + 		    BOUND_XL(frame)->fops->inodelk, + 		    loc, cmd, flock); + 	return 0; + +} + + +int32_t +server_inodelk (call_frame_t *frame, +		xlator_t *bound_xl, +		gf_hdr_common_t *hdr, size_t hdrlen, +		char *buf, size_t buflen) +{ + 	call_stub_t *inodelk_stub = NULL; + 	gf_fop_inodelk_req_t *req = NULL; + 	server_state_t *state = NULL; +	size_t pathlen = 0; + + 	req   = gf_param (hdr); + 	state = CALL_STATE(frame); +	{ +		state->cmd = ntoh32 (req->cmd); +		switch (state->cmd) { +		case GF_LK_GETLK: +			state->cmd = F_GETLK; +			break; +		case GF_LK_SETLK: +			state->cmd = F_SETLK; +			break; +		case GF_LK_SETLKW: +			state->cmd = F_SETLKW; +			break; +		} + +		state->type = ntoh32 (req->type); + +		pathlen = STRLEN_0(req->path); + +		state->path = req->path; +		state->ino  = ntoh64 (req->ino); + +		gf_flock_to_flock (&req->flock, &state->flock); + +		switch (state->type) { +		case GF_LK_F_RDLCK:  +			state->flock.l_type = F_RDLCK;  +			break; +		case GF_LK_F_WRLCK:  +			state->flock.l_type = F_WRLCK;  +			break; +		case GF_LK_F_UNLCK:  +			state->flock.l_type = F_UNLCK;  +			break; +		} + +	} + +	server_loc_fill (&(state->loc), state,  +			 state->ino, 0, NULL, state->path); + + 	inodelk_stub = fop_inodelk_stub (frame, +					 server_inodelk_resume, +					 &state->loc, state->cmd, &state->flock); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (inodelk_stub, &(state->loc)); +	} else { +		call_resume (inodelk_stub); +	} + + 	return 0; +} + + +int32_t +server_finodelk (call_frame_t *frame, +		 xlator_t *bound_xl, +		 gf_hdr_common_t *hdr, size_t hdrlen, +		 char *buf, size_t buflen) +{ + 	gf_fop_finodelk_req_t *req = NULL; + 	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + + 	req   = gf_param (hdr); + 	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->cmd = ntoh32 (req->cmd); +		switch (state->cmd) { +		case GF_LK_GETLK: +			state->cmd = F_GETLK; +			break; +		case GF_LK_SETLK: +			state->cmd = F_SETLK; +			break; +		case GF_LK_SETLKW: +			state->cmd = F_SETLKW; +			break; +		} + +		state->type = ntoh32 (req->type); + +		gf_flock_to_flock (&req->flock, &state->flock); + +		switch (state->type) { +		case GF_LK_F_RDLCK:  +			state->flock.l_type = F_RDLCK;  +			break; +		case GF_LK_F_WRLCK:  +			state->flock.l_type = F_WRLCK;  +			break; +		case GF_LK_F_UNLCK:  +			state->flock.l_type = F_UNLCK;  +			break; +		} + +	} + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); +		 +		server_finodelk_cbk (frame, NULL, frame->this, +				     -1, EINVAL); +		return -1; +  	}  + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": FINODELK \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, server_finodelk_cbk, +		    BOUND_XL(frame),  +		    BOUND_XL(frame)->fops->finodelk, +		    state->fd, state->cmd, &state->flock); + 	return 0; +} +   +  +int32_t +server_entrylk_resume (call_frame_t *frame, +		       xlator_t *this, +		       loc_t *loc, const char *name, +		       entrylk_cmd cmd, entrylk_type type) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.inode == NULL) +		state->loc.inode = inode_ref (loc->inode); + +	if ((state->loc.parent == NULL) && +	    (loc->parent)) +		state->loc.parent = inode_ref (loc->parent); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": ENTRYLK \'%s (%"PRId64") \'",  +		frame->root->unique, state->path, state->ino); + + 	STACK_WIND (frame, + 		    server_entrylk_cbk, + 		    BOUND_XL(frame), + 		    BOUND_XL(frame)->fops->entrylk, + 		    loc, name, cmd, type); + 	return 0; + +} + +/* + * server_entrylk - entrylk function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_entrylk (call_frame_t *frame, +		xlator_t *bound_xl, +		gf_hdr_common_t *hdr, size_t hdrlen, +		char *buf, size_t buflen) +{ + 	gf_fop_entrylk_req_t *req = NULL; + 	server_state_t *state = NULL; + 	call_stub_t *entrylk_stub = NULL; +	size_t pathlen = 0; +	size_t namelen = 0; + + 	req   = gf_param (hdr); + 	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); + +		state->path = req->path; +		state->ino  = ntoh64 (req->ino); +		namelen = ntoh64 (req->namelen); +		if (namelen) +			state->name = req->name + pathlen; + +		state->cmd  = ntoh32 (req->cmd); +		state->type = ntoh32 (req->type); +	} + + + 	server_loc_fill (&(state->loc), state,  +			 state->ino, 0, NULL, state->path); + +  	entrylk_stub = fop_entrylk_stub (frame, +					 server_entrylk_resume, +					 &state->loc, state->name, state->cmd, +					 state->type); + + 	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { + 		do_path_lookup (entrylk_stub, &(state->loc)); + 	} else { + 		call_resume (entrylk_stub); + 	} + + 	return 0; +} + + +int32_t +server_fentrylk (call_frame_t *frame, +		 xlator_t *bound_xl, +		 gf_hdr_common_t *hdr, size_t hdrlen, +		 char *buf, size_t buflen) +{ + 	gf_fop_fentrylk_req_t *req = NULL; + 	server_state_t *state = NULL; +	size_t  namelen = 0; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + + 	req   = gf_param (hdr); + 	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->cmd  = ntoh32 (req->cmd); +		state->type = ntoh32 (req->type); +		namelen = ntoh64 (req->namelen); +		 +		if (namelen) +			state->name = req->name; +	} + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); +		 +		server_fentrylk_cbk (frame, NULL, frame->this, +				     -1, EINVAL); +		return -1; +  	}  + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": FENTRYLK \'fd=%"PRId64" (%"PRId64")\'",  +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, server_fentrylk_cbk, +		    BOUND_XL(frame),  +		    BOUND_XL(frame)->fops->fentrylk, +		    state->fd, state->name, state->cmd, state->type); + 	return 0; +} + + +int32_t +server_access_resume (call_frame_t *frame, +                      xlator_t *this, +                      loc_t *loc, +                      int32_t mask) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": ACCESS \'%s (%"PRId64")\'",  +		frame->root->unique, state->path, state->ino); + +	STACK_WIND (frame, +		    server_access_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->access, +		    loc, +		    mask); +	return 0; +} + +/* + * server_access - access function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_access (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	call_stub_t *access_stub = NULL; +	gf_fop_access_req_t *req = NULL; +	server_state_t *state = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); + +	state->mask  = ntoh32 (req->mask); + +	state->ino  = ntoh64 (req->ino); +	state->path = req->path; +	pathlen = STRLEN_0(state->path); + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, state->path); + +	access_stub = fop_access_stub (frame, +				       server_access_resume, +				       &(state->loc), +				       state->mask); + +	if (((state->loc.parent == NULL) && IS_NOT_ROOT(pathlen)) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (access_stub, &(state->loc)); +	} else { +		call_resume (access_stub); +	} + +	return 0; +} + + +int32_t +server_symlink_resume (call_frame_t *frame, +		       xlator_t *this, +		       const char *linkname, +		       loc_t *loc) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (loc->parent); + +	state->loc.inode = inode_new (BOUND_XL(frame)->itable); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": SYMLINK \'%"PRId64"/%s \'",  +		frame->root->unique, state->par, state->bname); + +	STACK_WIND (frame, +		    server_symlink_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->symlink, +		    linkname, +		    &(state->loc)); + +	return 0; +} + +/* + * server_symlink- symlink function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_symlink (call_frame_t *frame, +                xlator_t *bound_xl, +                gf_hdr_common_t *hdr, size_t hdrlen, +                char *buf, size_t buflen) +{ +	server_state_t *state = NULL; +	gf_fop_symlink_req_t *req = NULL; +	call_stub_t *symlink_stub = NULL; +	int32_t ret = -1; +	size_t  pathlen = 0; +	size_t  baselen = 0; + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		pathlen = STRLEN_0(req->path); +		baselen = STRLEN_0(req->bname + pathlen); +		 +		state->par  = ntoh64 (req->par); +		state->path = req->path; +		state->bname = req->bname + pathlen; + +		state->name = (req->linkname + pathlen + baselen); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); + +	symlink_stub = fop_symlink_stub (frame, server_symlink_resume, +					 state->name, &(state->loc)); + +	if (state->loc.parent == NULL) { +		do_path_lookup (symlink_stub, &(state->loc)); +	} else { +		call_resume (symlink_stub); +	} + +	return 0; +} + +int32_t +server_link_resume (call_frame_t *frame, +                    xlator_t *this, +                    loc_t *oldloc, +		    loc_t *newloc) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (oldloc->parent); + +	if (state->loc.inode == NULL) { +		state->loc.inode = inode_ref (oldloc->inode); +	} else if (state->loc.inode != oldloc->inode) { +		if (state->loc.inode) +			inode_unref (state->loc.inode); +		state->loc.inode = inode_ref (oldloc->inode); +	} + +	if (state->loc2.parent == NULL) +		state->loc2.parent = inode_ref (newloc->parent); + +	state->loc2.inode = inode_ref (state->loc.inode); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": LINK \'%"PRId64"/%s ==> %s (%"PRId64")\'",  +		frame->root->unique, state->par2, state->bname2,  +		state->path, state->ino); + +	STACK_WIND (frame, +		    server_link_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->link, +		    &(state->loc), +		    &(state->loc2)); +	return 0; +} + +/* + * server_link - link function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + * not for external reference + */ +int32_t +server_link (call_frame_t *frame, +             xlator_t *this, +             gf_hdr_common_t *hdr, size_t hdrlen, +             char *buf, size_t buflen) +{ +	gf_fop_link_req_t *req = NULL; +	server_state_t *state = NULL; +	call_stub_t    *link_stub = NULL; +	int32_t ret = -1; +	size_t  oldpathlen = 0; +	size_t  newpathlen = 0; +	size_t  newbaselen = 0; + +	req   = gf_param (hdr); + +	state = CALL_STATE(frame); +	{ +		oldpathlen = STRLEN_0(req->oldpath); +		newpathlen = STRLEN_0(req->newpath     + oldpathlen); +		newbaselen = STRLEN_0(req->newbname + oldpathlen + newpathlen); + +		state->path      = req->oldpath; +		state->path2     = req->newpath     + oldpathlen; +		state->bname2 = req->newbname + oldpathlen + newpathlen; +		state->ino   = ntoh64 (req->oldino); +		state->par2  = ntoh64 (req->newpar); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       state->ino, 0, NULL, +			       state->path); +	ret = server_loc_fill (&(state->loc2), state, +			       0, state->par2, state->bname2, +			       state->path2); + +	link_stub = fop_link_stub (frame, server_link_resume, +				   &(state->loc), &(state->loc2)); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)) { +		do_path_lookup (link_stub, &(state->loc)); +	} else if (state->loc2.parent == NULL) { +		do_path_lookup (link_stub, &(state->loc2)); +	} else { +		call_resume (link_stub); +	} + +	return 0; +} + + +int32_t +server_rename_resume (call_frame_t *frame, +                      xlator_t *this, +                      loc_t *oldloc, +                      loc_t *newloc) +{ +	server_state_t *state = NULL; + +	state = CALL_STATE(frame); + +	if (state->loc.parent == NULL) +		state->loc.parent = inode_ref (oldloc->parent); + +	if (state->loc.inode == NULL) { +		state->loc.inode = inode_ref (oldloc->inode); +	} + +	if (state->loc2.parent == NULL) +		state->loc2.parent = inode_ref (newloc->parent); + + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": RENAME %s (%"PRId64"/%s) ==> %s (%"PRId64"/%s)",  +		frame->root->unique, state->path, state->par, state->bname, +		state->path2, state->par2, state->bname2); + +	STACK_WIND (frame, +		    server_rename_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->rename, +		    &(state->loc), +		    &(state->loc2)); +	return 0; +} + +/* + * server_rename - rename function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ +int32_t +server_rename (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	gf_fop_rename_req_t *req = NULL; +	server_state_t *state = NULL; +	call_stub_t    *rename_stub = NULL; +	int32_t ret = -1; +	size_t  oldpathlen = 0; +	size_t  oldbaselen = 0; +	size_t  newpathlen = 0; +	size_t  newbaselen = 0; + +	req = gf_param (hdr); + +	state = CALL_STATE(frame); +	{ +		oldpathlen = STRLEN_0(req->oldpath); +		oldbaselen = STRLEN_0(req->oldbname + oldpathlen); +		newpathlen = STRLEN_0(req->newpath  + oldpathlen + oldbaselen); +		newbaselen = STRLEN_0(req->newbname + oldpathlen +  +				      oldbaselen + newpathlen); + +		state->path   = req->oldpath; +		state->bname  = req->oldbname + oldpathlen; +		state->path2  = req->newpath  + oldpathlen + oldbaselen; +		state->bname2 = (req->newbname + oldpathlen + oldbaselen +  +				 newpathlen); + +		state->par   = ntoh64 (req->oldpar); +		state->par2  = ntoh64 (req->newpar); +	} + +	ret = server_loc_fill (&(state->loc), state, +			       0, state->par, state->bname, +			       state->path); +	ret = server_loc_fill (&(state->loc2), state, +			       0, state->par2, state->bname2, +			       state->path2); + +	rename_stub = fop_rename_stub (frame, +				       server_rename_resume, +				       &(state->loc), +				       &(state->loc2)); + +	if ((state->loc.parent == NULL) || +	    (state->loc.inode == NULL)){ +		do_path_lookup (rename_stub, &(state->loc)); +	} else if ((state->loc2.parent == NULL)){ +		do_path_lookup (rename_stub, &(state->loc2)); +	} else { +		/* we have found inode for both oldpath and newpath in +		 * inode cache. lets continue with fops->rename() */ +		call_resume (rename_stub); +	} + +	return 0; +} + + +/* + * server_lk - lk function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + * not for external reference + */ + +int32_t +server_lk (call_frame_t *frame, +           xlator_t *bound_xl, +           gf_hdr_common_t *hdr, size_t hdrlen, +           char *buf, size_t buflen) +{ +	struct flock lock = {0, }; +	gf_fop_lk_req_t *req = NULL; +	server_state_t *state = NULL; +	server_connection_t *conn = NULL; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); +	{ +		state->fd_no = ntoh64 (req->fd); +		if (state->fd_no >= 0) +			state->fd = gf_fd_fdptr_get (conn->fdtable,  +						     state->fd_no); + +		state->cmd =  ntoh32 (req->cmd); +		state->type = ntoh32 (req->type); +	} + + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_lk_cbk (frame, NULL, frame->this, +			       -1, EINVAL, NULL); + +		goto out; +	} + +	switch (state->cmd) { +	case GF_LK_GETLK: +		state->cmd = F_GETLK; +		break; +	case GF_LK_SETLK: +		state->cmd = F_SETLK; +		break; +	case GF_LK_SETLKW: +		state->cmd = F_SETLKW; +		break; +	} + +	switch (state->type) { +	case GF_LK_F_RDLCK: +		lock.l_type = F_RDLCK; +		break; +	case GF_LK_F_WRLCK: +		lock.l_type = F_WRLCK; +		break; +	case GF_LK_F_UNLCK: +		lock.l_type = F_UNLCK; +		break; +	default: +		gf_log (bound_xl->name, GF_LOG_ERROR,  +			"fd - %"PRId64" (%"PRId64"): Unknown lock type: %"PRId32"!",  +			state->fd_no, state->fd->inode->ino, state->type); +		break; +	} + +	gf_flock_to_flock (&req->flock, &lock); + +	gf_log (BOUND_XL(frame)->name, GF_LOG_DEBUG, +		"%"PRId64": LK \'fd=%"PRId64" (%"PRId64")\'", +		frame->root->unique, state->fd_no, state->fd->inode->ino); + +	STACK_WIND (frame, server_lk_cbk, +		    BOUND_XL(frame),  +		    BOUND_XL(frame)->fops->lk, +		    state->fd, state->cmd, &lock); + +out: +	return 0; +} + + +/* + * server_writedir - + * + * @frame: + * @bound_xl: + * @params: + * + */ +int32_t +server_setdents (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_fop_setdents_req_t       *req   = NULL; +	server_state_t              *state = NULL; +	dir_entry_t *entry = NULL; +	dir_entry_t *trav = NULL; +	dir_entry_t *prev = NULL; +	int32_t count = 0; +	int32_t i = 0; +	int32_t bread = 0; +	char *ender = NULL; +	char *buffer_ptr = NULL; +	char tmp_buf[512] = {0,}; +	 +	conn = SERVER_CONNECTION(frame); + +	req   = gf_param (hdr); +	state = CALL_STATE(frame); + +	state->fd_no = ntoh64 (req->fd); +	if (state->fd_no >= 0) +		state->fd = gf_fd_fdptr_get (conn->fdtable,  +					     state->fd_no); +	 +	state->nr_count = ntoh32 (req->count); + +	if (state->fd == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64": unresolved fd",  +			state->fd_no); + +		server_setdents_cbk (frame, NULL, frame->this, +				     -1, EINVAL); + +		goto out; +	} +	 +	if (buf == NULL) { +		gf_log (frame->this->name, GF_LOG_ERROR, +			"fd - %"PRId64" (%"PRId64"): received a null buffer, " +			"returning EINVAL", +			state->fd_no, state->fd->inode->ino); + +		server_setdents_cbk (frame, NULL, frame->this, +				     -1, EINVAL); + +		goto out; +	} + +	entry = CALLOC (1, sizeof (dir_entry_t)); +	ERR_ABORT (entry); +	prev = entry; +	buffer_ptr = buf; + +	for (i = 0; i < state->nr_count ; i++) { +		bread = 0; +		trav = CALLOC (1, sizeof (dir_entry_t)); +		ERR_ABORT (trav); +		 +		ender = strchr (buffer_ptr, '/'); +		if (!ender) +			break; +		count = ender - buffer_ptr; +		trav->name = CALLOC (1, count + 2); +		ERR_ABORT (trav->name); +		 +		strncpy (trav->name, buffer_ptr, count); +		bread = count + 1; +		buffer_ptr += bread; +		 +		ender = strchr (buffer_ptr, '\n'); +		if (!ender) +			break; +		count = ender - buffer_ptr; +		strncpy (tmp_buf, buffer_ptr, count); +		bread = count + 1; +		buffer_ptr += bread; +		 +		/* TODO: use str_to_stat instead */ +		{ +			uint64_t dev; +			uint64_t ino; +			uint32_t mode; +			uint32_t nlink; +			uint32_t uid; +			uint32_t gid; +			uint64_t rdev; +			uint64_t size; +			uint32_t blksize; +			uint64_t blocks; +			uint32_t atime; +			uint32_t atime_nsec; +			uint32_t mtime; +			uint32_t mtime_nsec; +			uint32_t ctime; +			uint32_t ctime_nsec; +			 +			sscanf (tmp_buf, GF_STAT_PRINT_FMT_STR, +				&dev, +				&ino, +				&mode, +				&nlink, +				&uid, +				&gid, +				&rdev, +				&size, +				&blksize, +				&blocks, +				&atime, +				&atime_nsec, +				&mtime, +				&mtime_nsec, +				&ctime, +				&ctime_nsec); +			 +			trav->buf.st_dev = dev; +			trav->buf.st_ino = ino; +			trav->buf.st_mode = mode; +			trav->buf.st_nlink = nlink; +			trav->buf.st_uid = uid; +			trav->buf.st_gid = gid; +			trav->buf.st_rdev = rdev; +			trav->buf.st_size = size; +			trav->buf.st_blksize = blksize; +			trav->buf.st_blocks = blocks; +			 +			trav->buf.st_atime = atime; +			trav->buf.st_mtime = mtime; +			trav->buf.st_ctime = ctime; +			 +			ST_ATIM_NSEC_SET(&trav->buf, atime_nsec); +			ST_MTIM_NSEC_SET(&trav->buf, mtime_nsec); +			ST_CTIM_NSEC_SET(&trav->buf, ctime_nsec); + +		} +		 +		ender = strchr (buffer_ptr, '\n'); +		if (!ender) +			break; +		count = ender - buffer_ptr; +		*ender = '\0'; +		if (S_ISLNK (trav->buf.st_mode)) { +			trav->link = strdup (buffer_ptr); +		} else +			trav->link = ""; +		bread = count + 1; +		buffer_ptr += bread; +		 +		prev->next = trav; +		prev = trav; +	} + + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": SETDENTS \'fd=%"PRId64" (%"PRId64"); count=%"PRId64, +		frame->root->unique, state->fd_no, state->fd->inode->ino,  +		(int64_t)state->nr_count); +	 +	STACK_WIND (frame, +		    server_setdents_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->setdents, +		    state->fd, +		    state->flags, +		    entry, +		    state->nr_count); +	 +	 +	/* Free the variables allocated in this fop here */ +	trav = entry->next; +	prev = entry; +	while (trav) { +		prev->next = trav->next; +		FREE (trav->name); +		if (S_ISLNK (trav->buf.st_mode)) +			FREE (trav->link); +		FREE (trav); +		trav = prev->next; +	} +	FREE (entry); + +out: +	return 0; +} + + + +/* xxx_MOPS */ + +/* Management Calls */ +/* + * mop_getspec - getspec function for server protocol + * @frame: call frame + * @bound_xl: + * @params: + * + */ +int32_t +mop_getspec (call_frame_t *frame, +             xlator_t *bound_xl, +             gf_hdr_common_t *hdr, size_t hdrlen, +             char *buf, size_t buflen) +{ +	gf_hdr_common_t      *_hdr = NULL; +	gf_mop_getspec_rsp_t *rsp = NULL; +	int32_t ret = -1; +	int32_t op_errno = ENOENT; +	int32_t gf_errno = 0; +	int32_t spec_fd = -1; +	size_t  file_len = 0; +	size_t _hdrlen = 0; +	char  tmp_filename[ZR_FILENAME_MAX] = {0,}; +	char  data_key[256] = {0,}; +	char *filename = NULL; +	struct stat stbuf = {0,}; +	peer_info_t *peerinfo = NULL; +	transport_t *trans = NULL; + +	gf_mop_getspec_req_t *req = NULL; +	uint32_t flags  = 0; +	uint32_t keylen = 0; +	char *key = NULL; + +	req   = gf_param (hdr); +	flags = ntoh32 (req->flags); +	keylen = ntoh32 (req->keylen); +	if (keylen) { +		key = req->key; +	} + +	trans = TRANSPORT_FROM_FRAME(frame); + +	peerinfo = &(trans->peerinfo); +	/* Inform users that this option is changed now */ +	ret = dict_get_str (frame->this->options, "client-volume-filename",  +			    &filename); +	if (ret == 0) { +		gf_log (trans->xl->name, GF_LOG_WARNING, +			"option 'client-volume-specfile' is changed to " +			"'volume-filename.<key>' which now takes 'key' as an " +			"option to choose/fetch different files from server. " +			"Refer documentation or contact developers for more " +			"info. Currently defaulting to given file '%s'",  +			filename); +	} +	 +	if (key && !filename) { +		sprintf (data_key, "volume-filename.%s", key); +		ret = dict_get_str (frame->this->options, data_key, &filename); +		if (ret < 0) { +			gf_log (trans->xl->name, GF_LOG_ERROR, +				"failed to get corresponding volume file " +				"for the key '%s'. using default file %s",  +				key, GLUSTERFSD_SPEC_PATH); +		}  +	} +	if (!filename) { +		filename = GLUSTERFSD_SPEC_PATH; +		if (!key) +			gf_log (trans->xl->name, GF_LOG_WARNING, +				"using default volume file %s",  +				GLUSTERFSD_SPEC_PATH); +	} + +	{ +		sprintf (tmp_filename, "%s.%s",  +			 filename, peerinfo->identifier); + +		/* Try for ip specific client volfile. +		 * If not found, then go for, regular client file. +		 */ +		ret = open (tmp_filename, O_RDONLY); +		spec_fd = ret; +		if (spec_fd < 0) { +			gf_log (trans->xl->name, GF_LOG_DEBUG, +				"Unable to open %s (%s)",  +				tmp_filename, strerror (errno)); +			/* fall back */ +			ret = open (filename, O_RDONLY); +			spec_fd = ret; +			if (spec_fd < 0) { +				gf_log (trans->xl->name, GF_LOG_ERROR, +					"Unable to open %s (%s)",  +					filename, strerror (errno)); +				goto fail; +			} +		} else { +			/* Successful */ +			filename = tmp_filename; +		} +	} + +	/* to allocate the proper buffer to hold the file data */ +	{ +		ret = stat (filename, &stbuf); +		if (ret < 0){ +			gf_log (trans->xl->name, GF_LOG_ERROR, +				"Unable to stat %s (%s)",  +				filename, strerror (errno)); +			goto fail; +		} + +		file_len = stbuf.st_size; +	} + +fail: +	op_errno = errno; + +	_hdrlen = gf_hdr_len (rsp, file_len + 1); +	_hdr    = gf_hdr_new (rsp, file_len + 1); +	rsp     = gf_param (_hdr); + +	_hdr->rsp.op_ret = hton32 (ret); +	gf_errno         = gf_errno_to_error (op_errno); +	_hdr->rsp.op_errno = hton32 (gf_errno); + +	if (file_len) { +		read (spec_fd, rsp->spec, file_len); +		close (spec_fd); +	} +	protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_GETSPEC, +			       _hdr, _hdrlen, NULL, 0, NULL); + +	return 0; +} + +int32_t +server_checksum_cbk (call_frame_t *frame, +                     void *cookie, +                     xlator_t *this, +                     int32_t op_ret, +                     int32_t op_errno, +                     uint8_t *fchecksum, +                     uint8_t *dchecksum) +{ +	gf_hdr_common_t       *hdr = NULL; +	gf_fop_checksum_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; + +	hdrlen = gf_hdr_len (rsp, ZR_FILENAME_MAX + 1 + ZR_FILENAME_MAX + 1); +	hdr    = gf_hdr_new (rsp, ZR_FILENAME_MAX + 1 + ZR_FILENAME_MAX + 1); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	if (op_ret >= 0) { +		memcpy (rsp->fchecksum, fchecksum, ZR_FILENAME_MAX); +		rsp->fchecksum[ZR_FILENAME_MAX] =  '\0'; +		memcpy (rsp->dchecksum + ZR_FILENAME_MAX,  +			dchecksum, ZR_FILENAME_MAX); +		rsp->dchecksum[ZR_FILENAME_MAX + ZR_FILENAME_MAX] = '\0'; +	}  + +	protocol_server_reply (frame, GF_OP_TYPE_FOP_REPLY, GF_FOP_CHECKSUM, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +int32_t +server_checksum (call_frame_t *frame, +                 xlator_t *bound_xl, +                 gf_hdr_common_t *hdr, size_t hdrlen, +                 char *buf, size_t buflen) +{ +	loc_t loc = {0,}; +	int32_t flag = 0; +	gf_fop_checksum_req_t *req = NULL; + +	req = gf_param (hdr); + +	loc.path  = req->path; +	loc.ino   = ntoh64 (req->ino); +	loc.inode = NULL; +	flag      = ntoh32 (req->flag); + +	gf_log (bound_xl->name, GF_LOG_DEBUG, +		"%"PRId64": CHECKSUM \'%s (%"PRId64")\'",  +		frame->root->unique, loc.path, loc.ino); + +	STACK_WIND (frame, +		    server_checksum_cbk, +		    BOUND_XL(frame), +		    BOUND_XL(frame)->fops->checksum, +		    &loc, +		    flag); + +	return 0; +} + + +/* + * mop_unlock - unlock management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int32_t +mop_getvolume (call_frame_t *frame, +               xlator_t *bound_xl, +               gf_hdr_common_t *hdr, size_t hdrlen, +               char *buf, size_t buflen) +{ +	return 0; +} + +struct __get_xl_struct { +	const char *name; +	xlator_t *reply; +}; + +void __check_and_set (xlator_t *each, +                      void *data) +{ +	if (!strcmp (each->name, +		     ((struct __get_xl_struct *) data)->name)) +		((struct __get_xl_struct *) data)->reply = each; +} + +static xlator_t * +get_xlator_by_name (xlator_t *some_xl, +                    const char *name) +{ +	struct __get_xl_struct get = { +		.name = name, +		.reply = NULL +	}; + +	xlator_foreach (some_xl, __check_and_set, &get); + +	return get.reply; +} + + +/* + * mop_setvolume - setvolume management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +int +mop_setvolume (call_frame_t *frame, xlator_t *bound_xl, +               gf_hdr_common_t *req_hdr, size_t req_hdrlen, +               char *req_buf, size_t req_buflen) +{ +	server_connection_t *conn = NULL; +	server_conf_t               *conf = NULL; +	gf_hdr_common_t             *rsp_hdr = NULL; +	gf_mop_setvolume_req_t      *req = NULL; +	gf_mop_setvolume_rsp_t      *rsp = NULL; +	peer_info_t                 *peerinfo = NULL; +	int32_t                      ret = -1; +	int32_t                      op_ret = -1; +	int32_t                      op_errno = EINVAL; +	int32_t                      gf_errno = 0; +	dict_t                      *reply = NULL; +	dict_t                      *config_params = NULL; +	dict_t                      *params = NULL; +	char                        *name = NULL; +	char                        *version = NULL; +	char                        *process_uuid = NULL; +	xlator_t                    *xl = NULL; +	transport_t                 *trans = NULL; +	size_t                       rsp_hdrlen = -1; +	size_t                       dict_len = -1; +	size_t                       req_dictlen = -1; + +	params = dict_new (); +	reply  = dict_new (); + +	req    = gf_param (req_hdr); +	req_dictlen = ntoh32 (req->dict_len); +	ret = dict_unserialize (req->buf, req_dictlen, ¶ms); + +	config_params = dict_copy_with_ref (frame->this->options, NULL); +	trans         = TRANSPORT_FROM_FRAME(frame); +	conf          = SERVER_CONF(frame); + +	if (ret < 0) { +		ret = dict_set_str (reply, "ERROR", +				    "Internal error: failed to unserialize " +				    "request dictionary"); +		if (ret < 0) +			gf_log (bound_xl->name, GF_LOG_ERROR,  +				"failed to set error msg \"%s\"", +				"Internal error: failed to unserialize " +				"request dictionary"); + +		op_ret = -1; +		op_errno = EINVAL; +		goto fail; +	} + +	ret = dict_get_str (params, "process-uuid", &process_uuid); +	if (ret < 0) { +		ret = dict_set_str (reply, "ERROR", +				    "UUID not specified"); +		if (ret < 0) +			gf_log (bound_xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = EINVAL; +		goto fail; +	} +	 + +	conn = server_connection_get (frame->this, process_uuid); +	if (trans->xl_private != conn) +		trans->xl_private = conn; + +	ret = dict_get_str (params, "version", &version); +	if (ret < 0) { +		ret = dict_set_str (reply, "ERROR", +				    "No version number specified"); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = EINVAL; +		goto fail; +	} +	 +	ret = strcmp (version, PACKAGE_VERSION); +	if (ret != 0) { +		char *msg = NULL; +		asprintf (&msg, +			  "Version mismatch: client(%s) Vs server (%s)", +			  version, PACKAGE_VERSION); +		ret = dict_set_dynstr (reply, "ERROR", msg); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = EINVAL; +		goto fail; +	} + + +	ret = dict_get_str (params, +			    "remote-subvolume", &name); +	if (ret < 0) { +		ret = dict_set_str (reply, "ERROR", +				    "No remote-subvolume option specified"); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = EINVAL; +		goto fail; +	} + +	xl = get_xlator_by_name (frame->this, name); +	if (xl == NULL) { +		char *msg = NULL; +		asprintf (&msg, "remote-subvolume \"%s\" is not found", name); +		ret = dict_set_dynstr (reply, "ERROR", msg); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = ENOENT; +		goto fail; +	} + +	peerinfo = &trans->peerinfo; +	ret = dict_set_static_ptr (params, "peer-info", peerinfo); +	if (ret < 0) +		gf_log (trans->xl->name, GF_LOG_ERROR,  +			"failed to set peer-info"); + +	if (conf->auth_modules == NULL) { +		gf_log (trans->xl->name, GF_LOG_ERROR, +			"Authentication module not initialized"); +	} + +	ret = gf_authenticate (params, config_params,  +			       conf->auth_modules); +	if (ret == AUTH_ACCEPT) { +		gf_log (trans->xl->name, GF_LOG_INFO, +			"accepted client from %s", +			peerinfo->identifier); +		op_ret = 0; +		conn->bound_xl = xl; +		ret = dict_set_str (reply, "ERROR", "Success"); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); +	} else { +		gf_log (trans->xl->name, GF_LOG_ERROR, +			"Cannot authenticate client from %s", +			peerinfo->identifier); +		op_ret = -1; +		op_errno = EACCES; +		ret = dict_set_str (reply, "ERROR", "Authentication failed"); +		if (ret < 0) +			gf_log (bound_xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		goto fail; +	} + +	if (conn->bound_xl == NULL) { +		ret = dict_set_str (reply, "ERROR", +				    "Check volfile and handshake " +				    "options in protocol/client"); +		if (ret < 0) +			gf_log (trans->xl->name, GF_LOG_ERROR,  +				"failed to set error msg"); + +		op_ret = -1; +		op_errno = EACCES; +		goto fail; +	} + +	if ((conn->bound_xl != NULL) && +	    (ret >= 0)                   && +	    (conn->bound_xl->itable == NULL)) { +		/* create inode table for this bound_xl, if one doesn't  +		   already exist */ +		int32_t lru_limit = 1024; + +		lru_limit = INODE_LRU_LIMIT (frame->this); + +		gf_log (trans->xl->name, GF_LOG_DEBUG, +			"creating inode table with lru_limit=%"PRId32", " +			"xlator=%s", lru_limit, conn->bound_xl->name); + +		conn->bound_xl->itable =  +			inode_table_new (lru_limit, +					 conn->bound_xl); +	} + +	ret = dict_set_str (reply, "process-uuid",  +			    xl->ctx->process_uuid); + +fail: +	dict_len = dict_serialized_length (reply); +	if (dict_len < 0) { +		gf_log (xl->name, GF_LOG_ERROR, +			"failed to get serialized length of reply dict"); +		op_ret   = -1; +		op_errno = EINVAL; +		dict_len = 0; +	} + +	rsp_hdr    = gf_hdr_new (rsp, dict_len); +	rsp_hdrlen = gf_hdr_len (rsp, dict_len); +	rsp = gf_param (rsp_hdr); + +	if (dict_len) { +		ret = dict_serialize (reply, rsp->buf); +		if (ret < 0) { +			gf_log (xl->name, GF_LOG_ERROR, +				"failed to serialize reply dict"); +			op_ret = -1; +			op_errno = -ret; +		} +	} +	rsp->dict_len = hton32 (dict_len); + +	rsp_hdr->rsp.op_ret = hton32 (op_ret); +	gf_errno = gf_errno_to_error (op_errno); +	rsp_hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_SETVOLUME, +			       rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + +	dict_unref (params); +	dict_unref (reply); +	dict_unref (config_params); + +	return 0; +} + +/* + * server_mop_stats_cbk - stats callback for server management operation + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * @stats:err + * + * not for external reference + */ + +int32_t +server_mop_stats_cbk (call_frame_t *frame, +                      void *cookie, +                      xlator_t *xl, +                      int32_t ret, +                      int32_t op_errno, +                      struct xlator_stats *stats) +{ +	/* TODO: get this information from somewhere else, not extern */ +	gf_hdr_common_t    *hdr = NULL; +	gf_mop_stats_rsp_t *rsp = NULL; +	char buffer[256] = {0,}; +	int64_t glusterfsd_stats_nr_clients = 0; +	size_t  hdrlen = 0; +	size_t  buf_len = 0; +	int32_t gf_errno = 0; + +	if (ret >= 0) { +		sprintf (buffer, +			 "%"PRIx64",%"PRIx64",%"PRIx64 +			 ",%"PRIx64",%"PRIx64",%"PRIx64 +			 ",%"PRIx64",%"PRIx64"\n", +			 stats->nr_files, +			 stats->disk_usage, +			 stats->free_disk, +			 stats->total_disk_size, +			 stats->read_usage, +			 stats->write_usage, +			 stats->disk_speed, +			 glusterfsd_stats_nr_clients); + +		buf_len = strlen (buffer); +	} + +	hdrlen = gf_hdr_len (rsp, buf_len + 1); +	hdr    = gf_hdr_new (rsp, buf_len + 1); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (ret); +	gf_errno        = gf_errno_to_error (op_errno); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	strcpy (rsp->buf, buffer); + +	protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_STATS, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + + +/* + * mop_unlock - unlock management function for server protocol + * @frame: call frame + * @bound_xl: + * @params: parameter dictionary + * + */ +static int32_t +mop_stats (call_frame_t *frame, +           xlator_t *bound_xl, +           gf_hdr_common_t *hdr, size_t hdrlen, +           char *buf, size_t buflen) +{ +	int32_t flag = 0; +	gf_mop_stats_req_t *req = NULL; + +	req = gf_param (hdr); + +	flag = ntoh32 (req->flags); + +	STACK_WIND (frame, +		    server_mop_stats_cbk, +		    bound_xl, +		    bound_xl->mops->stats, +		    flag); + +	return 0; +} + +int32_t +mop_ping (call_frame_t *frame, +           xlator_t *bound_xl, +           gf_hdr_common_t *hdr, size_t hdrlen, +           char *buf, size_t buflen) +{ +	gf_hdr_common_t     *rsp_hdr = NULL; +	gf_mop_ping_rsp_t   *rsp = NULL; +	size_t  rsp_hdrlen = 0; + +	rsp_hdrlen = gf_hdr_len (rsp, 0); +	rsp_hdr    = gf_hdr_new (rsp, 0); + +	hdr->rsp.op_ret = 0; + +	protocol_server_reply (frame, GF_OP_TYPE_MOP_REPLY, GF_MOP_PING, +			       rsp_hdr, rsp_hdrlen, NULL, 0, NULL); + +	return 0; +} +/* + * unknown_op_cbk - This function is called when a opcode for unknown  + *                  type is called. Helps to keep the backward/forward + *                  compatiblity + * @frame: call frame + * @type: + * @opcode: + * + */ + +int32_t +unknown_op_cbk (call_frame_t *frame, +                int32_t type, +                int32_t opcode) +{ +	gf_hdr_common_t    *hdr = NULL; +	gf_fop_flush_rsp_t *rsp = NULL; +	size_t  hdrlen = 0; +	int32_t gf_errno = 0; +	hdrlen = gf_hdr_len (rsp, 0); +	hdr    = gf_hdr_new (rsp, 0); +	rsp    = gf_param (hdr); + +	hdr->rsp.op_ret = hton32 (-1); +	gf_errno        = gf_errno_to_error (ENOSYS); +	hdr->rsp.op_errno = hton32 (gf_errno); + +	protocol_server_reply (frame, type, opcode, +			       hdr, hdrlen, NULL, 0, NULL); + +	return 0; +} + +/* + * get_frame_for_transport - get call frame for specified transport object + * + * @trans: transport object + * + */ +static call_frame_t * +get_frame_for_transport (transport_t *trans) +{ +	call_frame_t         *frame = NULL; +	call_pool_t          *pool = NULL; +	server_connection_t  *conn = NULL; +	server_state_t       *state = NULL;; +	 +	GF_VALIDATE_OR_GOTO("server", trans, out); + +	if (trans->xl && trans->xl->ctx) +		pool = trans->xl->ctx->pool; +	GF_VALIDATE_OR_GOTO("server", pool, out); + +	frame = create_frame (trans->xl, pool); +	GF_VALIDATE_OR_GOTO("server", frame, out); + +	state = CALLOC (1, sizeof (*state)); +	GF_VALIDATE_OR_GOTO("server", state, out); + +	conn = trans->xl_private; +	if (conn) { +		if (conn->bound_xl) +			state->itable = conn->bound_xl->itable; +		state->bound_xl = conn->bound_xl; +	} + +	state->trans = transport_ref (trans); + +	frame->root->trans = conn; +	frame->root->state = state;        /* which socket */ +	frame->root->unique = 0;           /* which call */ + +out: +	return frame; +} + +/* + * get_frame_for_call - create a frame into the capable of + *                      generating and replying the reply packet by itself. + *                      By making a call with this frame, the last UNWIND + *                      function will have all needed state from its + *                      frame_t->root to send reply. + * @trans: + * @blk: + * @params: + * + * not for external reference + */ +static call_frame_t * +get_frame_for_call (transport_t *trans, gf_hdr_common_t *hdr) +{ +	call_frame_t *frame = NULL; + +	frame = get_frame_for_transport (trans); + +	frame->root->op   = ntoh32 (hdr->op); +	frame->root->type = ntoh32 (hdr->type); + +	frame->root->uid         = ntoh32 (hdr->req.uid); +	frame->root->unique      = ntoh64 (hdr->callid);      /* which call */ +	frame->root->gid         = ntoh32 (hdr->req.gid); +	frame->root->pid         = ntoh32 (hdr->req.pid); + +	return frame; +} + +/* + * prototype of operations function for each of mop and + * fop at server protocol level + * + * @frame: call frame pointer + * @bound_xl: the xlator that this frame is bound to + * @params: parameters dictionary + * + * to be used by protocol interpret, _not_ for exterenal reference + */ +typedef int32_t (*gf_op_t) (call_frame_t *frame, xlator_t *bould_xl, +                            gf_hdr_common_t *hdr, size_t hdrlen, +                            char *buf, size_t buflen); + + +static gf_op_t gf_fops[] = { +	[GF_FOP_STAT]         =  server_stat, +	[GF_FOP_READLINK]     =  server_readlink, +	[GF_FOP_MKNOD]        =  server_mknod, +	[GF_FOP_MKDIR]        =  server_mkdir, +	[GF_FOP_UNLINK]       =  server_unlink, +	[GF_FOP_RMDIR]        =  server_rmdir, +	[GF_FOP_SYMLINK]      =  server_symlink, +	[GF_FOP_RENAME]       =  server_rename, +	[GF_FOP_LINK]         =  server_link, +	[GF_FOP_CHMOD]        =  server_chmod, +	[GF_FOP_CHOWN]        =  server_chown, +	[GF_FOP_TRUNCATE]     =  server_truncate, +	[GF_FOP_OPEN]         =  server_open, +	[GF_FOP_READ]         =  server_readv, +	[GF_FOP_WRITE]        =  server_writev, +	[GF_FOP_STATFS]       =  server_statfs, +	[GF_FOP_FLUSH]        =  server_flush, +	[GF_FOP_FSYNC]        =  server_fsync, +	[GF_FOP_SETXATTR]     =  server_setxattr, +	[GF_FOP_GETXATTR]     =  server_getxattr, +	[GF_FOP_REMOVEXATTR]  =  server_removexattr, +	[GF_FOP_OPENDIR]      =  server_opendir, +	[GF_FOP_GETDENTS]     =  server_getdents, +	[GF_FOP_FSYNCDIR]     =  server_fsyncdir, +	[GF_FOP_ACCESS]       =  server_access, +	[GF_FOP_CREATE]       =  server_create, +	[GF_FOP_FTRUNCATE]    =  server_ftruncate, +	[GF_FOP_FSTAT]        =  server_fstat, +	[GF_FOP_LK]           =  server_lk, +	[GF_FOP_UTIMENS]      =  server_utimens, +	[GF_FOP_FCHMOD]       =  server_fchmod, +	[GF_FOP_FCHOWN]       =  server_fchown, +	[GF_FOP_LOOKUP]       =  server_lookup, +	[GF_FOP_SETDENTS]     =  server_setdents, +	[GF_FOP_READDIR]      =  server_readdir, +	[GF_FOP_INODELK]      =  server_inodelk, +	[GF_FOP_FINODELK]     =  server_finodelk, +	[GF_FOP_ENTRYLK]      =  server_entrylk, +	[GF_FOP_FENTRYLK]     =  server_fentrylk, +	[GF_FOP_CHECKSUM]     =  server_checksum, +	[GF_FOP_XATTROP]      =  server_xattrop, +	[GF_FOP_FXATTROP]     =  server_fxattrop, +}; + + + +static gf_op_t gf_mops[] = { +	[GF_MOP_SETVOLUME] = mop_setvolume, +	[GF_MOP_GETVOLUME] = mop_getvolume, +	[GF_MOP_STATS]     = mop_stats, +	[GF_MOP_GETSPEC]   = mop_getspec, +	[GF_MOP_PING]      = mop_ping, +}; + +static gf_op_t gf_cbks[] = { +	[GF_CBK_FORGET]     = server_forget, +	[GF_CBK_RELEASE]    = server_release, +	[GF_CBK_RELEASEDIR] = server_releasedir +}; + +int +protocol_server_interpret (xlator_t *this, transport_t *trans, +                           char *hdr_p, size_t hdrlen, char *buf,  +			   size_t buflen) +{ +	server_connection_t *conn = NULL; +	gf_hdr_common_t             *hdr = NULL; +	xlator_t                    *bound_xl = NULL; +	call_frame_t                *frame = NULL; +	peer_info_t                 *peerinfo = NULL; +	int32_t                      type = -1; +	int32_t                      op = -1; +	int32_t                      ret = -1; + +	hdr  = (gf_hdr_common_t *)hdr_p; +	type = ntoh32 (hdr->type); +	op   = ntoh32 (hdr->op); + +	conn = trans->xl_private; +	if (conn) +		bound_xl = conn->bound_xl; + +	peerinfo = &trans->peerinfo; +	switch (type) { +	case GF_OP_TYPE_FOP_REQUEST: +		if ((op < 0) ||  +		    (op > GF_FOP_MAXVALUE)) { +			gf_log (this->name, GF_LOG_ERROR, +				"invalid fop %"PRId32" from client %s", +				op, peerinfo->identifier); +			break; +		} +		if (bound_xl == NULL) { +			gf_log (this->name, GF_LOG_ERROR, +				"Received fop %"PRId32" before " +				"authentication.", op); +			break; +		} +		frame = get_frame_for_call (trans, hdr); +		ret = gf_fops[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); +		break; + +	case GF_OP_TYPE_MOP_REQUEST: +		if (op < 0 || op > GF_MOP_MAXVALUE) { +			gf_log (this->name, GF_LOG_ERROR, +				"invalid mop %"PRId32" from client %s", +				op, peerinfo->identifier); +			break; +		} +		frame = get_frame_for_call (trans, hdr); +		ret = gf_mops[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); +		break; + +	case GF_OP_TYPE_CBK_REQUEST: +		if (op < 0 || op > GF_CBK_MAXVALUE) { +			gf_log (this->name, GF_LOG_ERROR, +				"invalid cbk %"PRId32" from client %s", +				op, peerinfo->identifier); +			break; +		} +		if (bound_xl == NULL) { +			gf_log (this->name, GF_LOG_ERROR, +				"Received cbk %d before authentication.", op); +			break; +		} + +		frame = get_frame_for_call (trans, hdr); +		ret = gf_cbks[op] (frame, bound_xl, hdr, hdrlen, buf, buflen); +		break; + +	default: +		break; +	} + +	return ret; +} + + +/* + * server_nop_cbk - nop callback for server protocol + * @frame: call frame + * @cookie: + * @this: + * @op_ret: return value + * @op_errno: errno + * + * not for external reference + */ +int +server_nop_cbk (call_frame_t *frame, void *cookie, +                xlator_t *this, int32_t op_ret, int32_t op_errno) +{ +	server_state_t *state = NULL; +	 +	state = CALL_STATE(frame); + +	if (state) +		free_state (state); +	STACK_DESTROY (frame->root); +	return 0; +} + + +static void +get_auth_types (dict_t *this, +                char *key, +                data_t *value, +                void *data) +{ +	dict_t *auth_dict = data; +	char *saveptr = NULL, *tmp = NULL; +	char *key_cpy = NULL; +	int32_t ret = -1; +	 +	key_cpy = strdup (key); +	GF_VALIDATE_OR_GOTO("server", key_cpy, out); + +	tmp = strtok_r (key_cpy, ".", &saveptr); +	ret = strcmp (tmp, "auth"); +	if (ret == 0) { +		tmp = strtok_r (NULL, ".", &saveptr); +		if (strcmp (tmp, "ip") == 0) { +			/* TODO: backward compatibility, remove when  +			   newer versions are available */ +			tmp = "addr"; +			gf_log ("server", GF_LOG_WARNING,  +				"assuming 'auth.ip' to be 'auth.addr'"); +		} +		ret = dict_set_dynptr (auth_dict, tmp, NULL, 0); +		if (ret < 0) { +			gf_log ("server", GF_LOG_ERROR, +				"failed to dict_set_dynptr"); +		}  +	} + +	FREE (key_cpy); +out: +	return; +} + + +static int +validate_auth_options (xlator_t *this, dict_t *dict) +{ +	int ret = -1; +	int error = 0; +	xlator_list_t *trav = NULL; +	data_pair_t *pair = NULL; +	char *saveptr = NULL, *tmp = NULL; +	char *key_cpy = NULL; +	 +	trav = this->children; +	while (trav) { +		error = -1; +		for (pair = dict->members_list; pair; pair = pair->next) { +			key_cpy = strdup (pair->key); +			tmp = strtok_r (key_cpy, ".", &saveptr); +			ret = strcmp (tmp, "auth"); +			if (ret == 0) { +				/* for module type */ +				tmp = strtok_r (NULL, ".", &saveptr);  +				/* for volume name */ +				tmp = strtok_r (NULL, ".", &saveptr);  +			} + +			if (strcmp (tmp, trav->xlator->name) == 0) { +				error = 0; +				free (key_cpy); +				break; +			} +			free (key_cpy); +		} +		if (-1 == error) { +			gf_log (this->name, GF_LOG_ERROR,  +				"volume '%s' defined as subvolume, but no " +				"authentication defined for the same", +				trav->xlator->name); +			break; +		} +		trav = trav->next; +	} + +	return error; +} + + +/* + * init - called during server protocol initialization + * + * @this: + * + */ +int +init (xlator_t *this) +{ +	int32_t ret = -1; +	transport_t *trans = NULL; +	server_conf_t *conf = NULL; + +	if (this->children == NULL) { +		gf_log (this->name, GF_LOG_ERROR, +			"protocol/server should have subvolume"); +		goto out; +	} + +	trans = transport_load (this->options, this); +	if (trans == NULL) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to load transport"); +		goto out; +	} + +	ret = transport_listen (trans); +	if (ret == -1) { +		gf_log (this->name, GF_LOG_ERROR, +			"failed to bind/listen on socket"); +		goto out; +	} + +	conf = CALLOC (1, sizeof (server_conf_t)); +	GF_VALIDATE_OR_GOTO(this->name, conf, out); + +	INIT_LIST_HEAD (&conf->conns); +	pthread_mutex_init (&conf->mutex, NULL); + +	conf->trans = trans; + +	conf->auth_modules = dict_new (); +	GF_VALIDATE_OR_GOTO(this->name, conf->auth_modules, out); + +	dict_foreach (this->options, get_auth_types,  +		      conf->auth_modules); +	ret = validate_auth_options (this, this->options); +	if (ret == -1) { +		/* logging already done in validate_auth_options function. */ +		goto out; +	} +	 +	ret = gf_auth_init (this, conf->auth_modules); +	if (ret) { +		dict_unref (conf->auth_modules); +		goto out; +	} + +	this->private = conf; + +	ret = dict_get_int32 (this->options, "inode-lru-limit",  +			      &conf->inode_lru_limit); +	if (ret < 0) { +		conf->inode_lru_limit = 1024; +	} + +	ret = dict_get_int32 (this->options, "limits.transaction-size",  +			      &conf->max_block_size); +	if (ret < 0) { +		gf_log (this->name, GF_LOG_DEBUG, +			"defaulting limits.transaction-size to %d", +			DEFAULT_BLOCK_SIZE); +		conf->max_block_size = DEFAULT_BLOCK_SIZE; +	} + +#ifndef GF_DARWIN_HOST_OS +	{ +		struct rlimit lim; + +		lim.rlim_cur = 1048576; +		lim.rlim_max = 1048576; + +		if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { +			gf_log (this->name, GF_LOG_WARNING, +				"WARNING: Failed to set 'ulimit -n 1M': %s", +				strerror(errno)); +			lim.rlim_cur = 65536; +			lim.rlim_max = 65536; + +			if (setrlimit (RLIMIT_NOFILE, &lim) == -1) { +				gf_log (this->name, GF_LOG_ERROR, +					"Failed to set max open fd to 64k: %s", +					strerror(errno)); +			} else { +				gf_log (this->name, GF_LOG_ERROR, +					"max open fd set to 64k"); +			} +		} +	} +#endif +	this->ctx->top = this; + +	ret = 0; +out: +	return ret; +} + + + +int +protocol_server_pollin (xlator_t *this, transport_t *trans) +{ +	char                *hdr = NULL; +	size_t               hdrlen = 0; +	char                *buf = NULL; +	size_t               buflen = 0; +	int                  ret = -1; + + +	ret = transport_receive (trans, &hdr, &hdrlen, &buf, &buflen); + +	if (ret == 0) +		ret = protocol_server_interpret (this, trans, hdr,  +						 hdrlen, buf, buflen); + +	/* TODO: use mem-pool */ +	FREE (hdr); + +	return ret; +} + + +/* + * fini - finish function for server protocol, called before + *        unloading server protocol. + * + * @this: + * + */ +void +fini (xlator_t *this) +{ +	server_conf_t *conf = this->private; +	 +	GF_VALIDATE_OR_GOTO(this->name, conf, out); + +	if (conf->auth_modules) { +		dict_unref (conf->auth_modules); +	} + +	FREE (conf); +	this->private = NULL; +out: +	return; +} + +/* + * server_protocol_notify - notify function for server protocol + * @this: + * @trans: + * @event: + * + */ +int +notify (xlator_t *this, int32_t event, void *data, ...) +{ +	int          ret = 0; +	transport_t *trans = data; + +	switch (event) { +	case GF_EVENT_POLLIN: +		ret = protocol_server_pollin (this, trans); +		break; +	case GF_EVENT_POLLERR: +	{ +		peer_info_t *peerinfo = NULL; + +		peerinfo = &(trans->peerinfo); +		gf_log (trans->xl->name, GF_LOG_INFO, "%s disconnected", +			peerinfo->identifier); + +		ret = -1; +		transport_disconnect (trans); +	} +	break; + +	case GF_EVENT_TRANSPORT_CLEANUP: +	{ +		if (trans->xl_private) +			server_connection_put (this, trans->xl_private); +	} +	break; + +	default: +		default_notify (this, event, data); +		break; +	} + +	return ret; +} + + +struct xlator_mops mops = { +}; + +struct xlator_fops fops = { +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { + 	{ .key   = {"transport-type"},  +	  .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp",  +		    "tcp/server", "ib-verbs/server"}, +	  .type  = GF_OPTION_TYPE_STR  +	}, +	{ .key   = {"volume-filename.*"},  +	  .type  = GF_OPTION_TYPE_PATH,  +	}, +	{ .key   = {"inode-lru-limit"},   +	  .type  = GF_OPTION_TYPE_INT, +	  .min   = 0,  +	  .max   = (1 * GF_UNIT_MB) +	}, +	{ .key   = {"client-volume-filename"},  +	  .type  = GF_OPTION_TYPE_PATH +	},  +	{ .key   = {NULL} }, +}; diff --git a/xlators/protocol/server/src/server-protocol.h b/xlators/protocol/server/src/server-protocol.h new file mode 100644 index 00000000000..cc5f6f9512c --- /dev/null +++ b/xlators/protocol/server/src/server-protocol.h @@ -0,0 +1,143 @@ +/* +  Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SERVER_PROTOCOL_H_ +#define _SERVER_PROTOCOL_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <pthread.h> + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "call-stub.h" +#include "authenticate.h" +#include "fd.h" +#include "byte-order.h" + +#define DEFAULT_BLOCK_SIZE     4194304   /* 4MB */ +#define GLUSTERFSD_SPEC_PATH   CONFDIR "/glusterfs-client.vol" + +typedef struct _server_state server_state_t; + +struct _locker { +	struct list_head  lockers; +	loc_t             loc; +	fd_t             *fd; +	pid_t             pid; +}; + +struct _lock_table { +	struct list_head  file_lockers; +	struct list_head  dir_lockers; +	gf_lock_t         lock; +	size_t            count; +}; + + +/* private structure per connection (transport object) + * used as transport_t->xl_private + */ +struct _server_connection { +	struct list_head    list; +	char               *id; +	int                 ref; +	pthread_mutex_t     lock; +	char                disconnected; +	fdtable_t          *fdtable;  +	struct _lock_table *ltable; +	xlator_t           *bound_xl; +}; + +typedef struct _server_connection server_connection_t; + + +server_connection_t * +server_connection_get (xlator_t *this, const char *id); + +void +server_connection_put (xlator_t *this, server_connection_t *conn); + +int +server_connection_destroy (xlator_t *this, server_connection_t *conn); + +int +server_nop_cbk (call_frame_t *frame, void *cookie, +		xlator_t *this, int32_t op_ret, int32_t op_errno); + + +typedef struct { +	dict_t           *auth_modules; +	transport_t      *trans; +	int32_t           max_block_size; +	int32_t           inode_lru_limit; +	pthread_mutex_t   mutex; +	struct list_head  conns; +} server_conf_t; + + +struct _server_state { +	transport_t      *trans; +	xlator_t         *bound_xl; +	loc_t             loc; +	loc_t             loc2; +	int               flags; +	fd_t             *fd; +	size_t            size; +	off_t             offset; +	mode_t            mode; +	dev_t             dev; +	uid_t             uid; +	gid_t             gid; +	size_t            nr_count; +	int               cmd; +	int               type; +	char             *name; +	int               name_len; +	inode_table_t    *itable; +	int64_t           fd_no; +	ino_t             ino; +	ino_t             par; +	ino_t             ino2; +	ino_t             par2; +	char             *path; +	char             *path2; +	char             *bname; +	char             *bname2; +	int               mask; +	char              is_revalidate; +	dict_t           *xattr_req; +	struct flock      flock; +	struct timespec   tv[2]; +	char             *resolved; +}; + + +int +server_stub_resume (call_stub_t *stub, int32_t op_ret, int32_t op_errno, +		    inode_t *inode, inode_t *parent); + +int +do_path_lookup (call_stub_t *stub, const loc_t *loc); + +#endif  | 
