diff options
author | Amar Tumballi <amar@gluster.com> | 2010-06-21 07:00:04 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-06-21 20:21:10 -0700 |
commit | fdd20492638fe98a62b5e6d5e82f18cf4799fd1a (patch) | |
tree | 98082d7bfdc66157f40666f2070d3a45b582327a /xlators/protocol/server | |
parent | b9b8734a9496ccf5f8ed5527dc7714930a59948b (diff) |
rpc protocol
Signed-off-by: Amar Tumballi <amar@gluster.com>
Signed-off-by: Raghavendra G <raghavendra@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 875 (Implement a new protocol to provide proper backward/forward compatibility)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=875
Diffstat (limited to 'xlators/protocol/server')
-rw-r--r-- | xlators/protocol/server/Makefile.am | 1 | ||||
-rw-r--r-- | xlators/protocol/server/src/Makefile.am | 22 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-handshake.c | 689 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-helpers.c | 1392 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-helpers.h | 89 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-mem-types.h | 37 | ||||
-rw-r--r-- | xlators/protocol/server/src/server-resolve.c | 655 | ||||
-rw-r--r-- | xlators/protocol/server/src/server.c | 687 | ||||
-rw-r--r-- | xlators/protocol/server/src/server.h | 203 | ||||
-rw-r--r-- | xlators/protocol/server/src/server3_1-fops.c | 4839 |
10 files changed, 8614 insertions, 0 deletions
diff --git a/xlators/protocol/server/Makefile.am b/xlators/protocol/server/Makefile.am new file mode 100644 index 00000000000..af437a64d6d --- /dev/null +++ b/xlators/protocol/server/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xlators/protocol/server/src/Makefile.am b/xlators/protocol/server/src/Makefile.am new file mode 100644 index 00000000000..842ab5e50fc --- /dev/null +++ b/xlators/protocol/server/src/Makefile.am @@ -0,0 +1,22 @@ +xlator_LTLIBRARIES = server.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/alpha/protocol + +server_la_LDFLAGS = -module -avoidversion + +server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ + $(top_builddir)/xlators/protocol/rpc/rpc-lib/src/libgfrpc.la \ + $(top_builddir)/xlators/protocol/lib/src/libgfproto1.la + +server_la_SOURCES = server.c server-resolve.c server-helpers.c \ + server3_1-fops.c server-handshake.c + +noinst_HEADERS = server.h server-helpers.h server-mem-types.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles \ + -DCONFDIR=\"$(sysconfdir)/glusterfs\" -D$(GF_HOST_OS) \ + $(GF_CFLAGS) -I$(top_srcdir)/xlators/protocol/lib/src \ + -I$(top_srcdir)/xlators/protocol/rpc/rpc-lib/src/ \ + -I$(top_srcdir)/contrib/md5/ + +CLEANFILES = *~ diff --git a/xlators/protocol/server/src/server-handshake.c b/xlators/protocol/server/src/server-handshake.c new file mode 100644 index 00000000000..8ce9f6b3a86 --- /dev/null +++ b/xlators/protocol/server/src/server-handshake.c @@ -0,0 +1,689 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server.h" +#include "server-helpers.h" +#include "glusterfs-xdr.h" +#include "compat-errno.h" +#include "msg-xdr.h" +#include "authenticate.h" + +struct __get_xl_struct { + const char *name; + xlator_t *reply; +}; +int +gf_compare_client_version (rpcsvc_request_t *req, int fop_prognum, + int mgmt_prognum) +{ + int ret = -1; + /* TODO: think.. */ + if (glusterfs3_1_fop_prog.prognum == fop_prognum) + ret = 0; + + return ret; +} + +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; +} + + +int +_volfile_update_checksum (xlator_t *this, char *key, uint32_t checksum) +{ + server_conf_t *conf = NULL; + struct _volfile_ctx *temp_volfile = NULL; + + conf = this->private; + temp_volfile = conf->volfile; + + while (temp_volfile) { + if ((NULL == key) && (NULL == temp_volfile->key)) + break; + if ((NULL == key) || (NULL == temp_volfile->key)) { + temp_volfile = temp_volfile->next; + continue; + } + if (strcmp (temp_volfile->key, key) == 0) + break; + temp_volfile = temp_volfile->next; + } + + if (!temp_volfile) { + temp_volfile = GF_CALLOC (1, sizeof (struct _volfile_ctx), + gf_server_mt_volfile_ctx_t); + + temp_volfile->next = conf->volfile; + temp_volfile->key = (key)? gf_strdup (key): NULL; + temp_volfile->checksum = checksum; + + conf->volfile = temp_volfile; + goto out; + } + + if (temp_volfile->checksum != checksum) { + gf_log (this->name, GF_LOG_CRITICAL, + "the volume file got modified between earlier access " + "and now, this may lead to inconsistency between " + "clients, advised to remount client"); + temp_volfile->checksum = checksum; + } + + out: + return 0; +} + + +size_t +build_volfile_path (xlator_t *this, const char *key, char *path, + size_t path_len) +{ + int ret = -1; + int free_filename = 0; + char *filename = NULL; + server_conf_t *conf = NULL; + char data_key[256] = {0,}; + + conf = this->private; + + /* Inform users that this option is changed now */ + ret = dict_get_str (this->options, "client-volume-filename", + &filename); + if (ret == 0) { + gf_log (this->name, GF_LOG_WARNING, + "option 'client-volume-filename' 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 (this->options, data_key, &filename); + if (ret < 0) { + /* Make sure that key doesn't contain "../" in path */ + if ((gf_strstr (key, "/", "..")) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "%s: invalid key", key); + goto out; + } + } + + ret = gf_asprintf (&filename, "%s/%s.vol", conf->conf_dir, key); + if (-1 == ret) + goto out; + + free_filename = 1; + } + + if (!filename) { + ret = dict_get_str (this->options, + "volume-filename.default", &filename); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "no default volume filename given, " + "defaulting to %s", DEFAULT_VOLUME_FILE_PATH); + filename = DEFAULT_VOLUME_FILE_PATH; + } + } + + ret = -1; + + if ((filename) && (path_len > strlen (filename))) { + strcpy (path, filename); + ret = strlen (filename); + } + +out: + if (free_filename) + GF_FREE (filename); + + return ret; +} + +int +_validate_volfile_checksum (xlator_t *this, char *key, + uint32_t checksum) +{ + char filename[ZR_PATH_MAX] = {0,}; + server_conf_t *conf = NULL; + struct _volfile_ctx *temp_volfile = NULL; + int ret = 0; + int fd = 0; + uint32_t local_checksum = 0; + + conf = this->private; + temp_volfile = conf->volfile; + + if (!checksum) + goto out; + + if (!temp_volfile) { + ret = build_volfile_path (this, key, filename, + sizeof (filename)); + if (ret <= 0) + goto out; + fd = open (filename, O_RDONLY); + if (-1 == fd) { + ret = 0; + gf_log (this->name, GF_LOG_DEBUG, + "failed to open volume file (%s) : %s", + filename, strerror (errno)); + goto out; + } + get_checksum_for_file (fd, &local_checksum); + _volfile_update_checksum (this, key, local_checksum); + close (fd); + } + + temp_volfile = conf->volfile; + while (temp_volfile) { + if ((NULL == key) && (NULL == temp_volfile->key)) + break; + if ((NULL == key) || (NULL == temp_volfile->key)) { + temp_volfile = temp_volfile->next; + continue; + } + if (strcmp (temp_volfile->key, key) == 0) + break; + temp_volfile = temp_volfile->next; + } + + if (!temp_volfile) + goto out; + + if ((temp_volfile->checksum) && + (checksum != temp_volfile->checksum)) + ret = -1; + +out: + return ret; +} + +int +build_program_list (server_conf_t *conf, char *list) +{ + /* Reply in "Name:Program-Number:Program-Version,..." format */ + sprintf (list, "%s:%d:%d", + glusterfs3_1_fop_prog.progname, + glusterfs3_1_fop_prog.prognum, + glusterfs3_1_fop_prog.progver); + /* TODO: keep adding new versions to the list here */ + return 0; +} + +int +server_dump_version (rpcsvc_request_t *req) +{ + char list[8192] = {0,}; + server_conf_t *conf = NULL; + int ret = -1; + int op_errno = EINVAL; + gf_dump_version_req args = {0,}; + gf_dump_version_rsp rsp = {0,}; + + conf = ((xlator_t *)req->conn->svc->mydata)->private; + + if (xdr_to_glusterfs_req (req, &args, xdr_to_dump_version_req)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto fail; + } + + build_program_list (conf, list); + rsp.msg.msg_val = list; + rsp.msg.msg_len = strlen (list) + 1; + ret = 0; +fail: + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.op_ret = ret; + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + (gfs_serialize_t)xdr_serialize_dump_version_rsp); + + if (args.key) + free (args.key); + + return 0; +} + +int +server_getspec (rpcsvc_request_t *req) +{ + int32_t ret = -1; + int32_t op_errno = ENOENT; + int32_t spec_fd = -1; + size_t file_len = 0; + char filename[ZR_PATH_MAX] = {0,}; + struct stat stbuf = {0,}; + uint32_t checksum = 0; + char *key = NULL; + server_conf_t *conf = NULL; + + gf_getspec_req args = {0,}; + gf_getspec_rsp rsp = {0,}; + server_connection_t *conn = NULL; + + conn = req->conn->trans->private; + conf = conn->this->private; + + if (xdr_to_glusterfs_req (req, &args, xdr_to_getspec_req)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto fail; + } + + ret = build_volfile_path (conn->this, args.key, + filename, sizeof (filename)); + if (ret > 0) { + /* to allocate the proper buffer to hold the file data */ + ret = stat (filename, &stbuf); + if (ret < 0){ + gf_log (conn->this->name, GF_LOG_ERROR, + "Unable to stat %s (%s)", + filename, strerror (errno)); + goto fail; + } + + spec_fd = open (filename, O_RDONLY); + if (spec_fd < 0) { + gf_log (conn->this->name, GF_LOG_ERROR, + "Unable to open %s (%s)", + filename, strerror (errno)); + goto fail; + } + ret = file_len = stbuf.st_size; + + if (conf->verify_volfile) { + get_checksum_for_file (spec_fd, &checksum); + _volfile_update_checksum (conn->this, key, checksum); + } + } else { + errno = ENOENT; + } + + if (file_len) { + rsp.spec = GF_CALLOC (file_len, sizeof (char), + gf_server_mt_rsp_buf_t); + if (!rsp.spec) { + ret = -1; + op_errno = ENOMEM; + goto fail; + } + ret = read (spec_fd, rsp.spec, file_len); + + close (spec_fd); + } + + /* convert to XDR */ +fail: + op_errno = errno; + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.op_ret = ret; + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + (gfs_serialize_t)xdr_serialize_getspec_rsp); + + return 0; +} + + +int +server_setvolume (rpcsvc_request_t *req) +{ + gf_setvolume_req args = {0,}; + gf_setvolume_rsp rsp = {0,}; + server_connection_t *conn = NULL; + server_conf_t *conf = NULL; + peer_info_t *peerinfo = NULL; + dict_t *reply = NULL; + dict_t *config_params = NULL; + dict_t *params = NULL; + char *name = NULL; + char *process_uuid = NULL; + xlator_t *xl = NULL; + char *msg = NULL; + char *volfile_key = NULL; + xlator_t *this = NULL; + uint32_t checksum = 0; + int32_t ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + int32_t fop_version = 0; + int32_t mgmt_version = 0; + + params = dict_new (); + reply = dict_new (); + if (xdr_to_glusterfs_req (req, &args, xdr_to_setvolume_req)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto fail; + } + + this = req->conn->svc->mydata; + + config_params = dict_copy_with_ref (this->options, NULL); + conf = this->private; + + ret = dict_unserialize (args.dict.dict_val, args.dict.dict_len, ¶ms); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "Internal error: failed to unserialize " + "request dictionary"); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "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 (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + + conn = server_connection_get (this, process_uuid); + if (req->conn->trans->xl_private != conn) + req->conn->trans->xl_private = conn; + + ret = dict_get_int32 (params, "fops-version", &fop_version); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No FOP version number specified"); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + } + + ret = dict_get_int32 (params, "mgmt-version", &mgmt_version); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "No MGMT version number specified"); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + } + + ret = gf_compare_client_version (req, fop_version, mgmt_version); + if (ret != 0) { + ret = gf_asprintf (&msg, "version mismatch: client(%d)" + " - client-mgmt(%d)", + fop_version, mgmt_version); + /* get_supported_version (req)); */ + if (-1 == ret) { + gf_log (this->name, GF_LOG_ERROR, + "asprintf failed while setting up error msg"); + goto fail; + } + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "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 (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + xl = get_xlator_by_name (this, name); + if (xl == NULL) { + ret = gf_asprintf (&msg, "remote-subvolume \"%s\" is not found", + name); + if (-1 == ret) { + gf_log (this->name, GF_LOG_ERROR, + "asprintf failed while setting error msg"); + goto fail; + } + ret = dict_set_dynstr (reply, "ERROR", msg); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = ENOENT; + goto fail; + } + + if (conf->verify_volfile) { + ret = dict_get_uint32 (params, "volfile-checksum", &checksum); + if (ret == 0) { + ret = dict_get_str (params, "volfile-key", + &volfile_key); + + ret = _validate_volfile_checksum (this, volfile_key, + checksum); + if (-1 == ret) { + ret = dict_set_str (reply, "ERROR", + "volume-file checksum " + "varies from earlier " + "access"); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + + op_ret = -1; + op_errno = ESTALE; + goto fail; + } + } + } + + + peerinfo = &req->conn->trans->peerinfo; + ret = dict_set_static_ptr (params, "peer-info", peerinfo); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set peer-info"); + + if (conf->auth_modules == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "Authentication module not initialized"); + } + + ret = gf_authenticate (params, config_params, + conf->auth_modules); + + if (ret == AUTH_ACCEPT) { + gf_log (this->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 (this->name, GF_LOG_DEBUG, + "failed to set error msg"); + } else { + gf_log (this->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 (this->name, GF_LOG_DEBUG, + "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 (this->name, GF_LOG_DEBUG, + "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 */ + + gf_log (this->name, GF_LOG_TRACE, + "creating inode table with lru_limit=%"PRId32", " + "xlator=%s", conf->inode_lru_limit, + conn->bound_xl->name); + + /* TODO: what is this ? */ + conn->bound_xl->itable = inode_table_new (conf->inode_lru_limit, + conn->bound_xl); + } + + ret = dict_set_str (reply, "process-uuid", + this->ctx->process_uuid); + + ret = dict_set_uint64 (reply, "transport-ptr", + ((uint64_t) (long) req->conn->trans)); + + +fail: + rsp.dict.dict_len = dict_serialized_length (reply); + if (rsp.dict.dict_len < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of reply dict"); + op_ret = -1; + op_errno = EINVAL; + rsp.dict.dict_len = 0; + } + + if (rsp.dict.dict_len) { + rsp.dict.dict_val = GF_CALLOC (1, rsp.dict.dict_len, 0); + if (rsp.dict.dict_val) { + ret = dict_serialize (reply, rsp.dict.dict_val); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to serialize reply dict"); + op_ret = -1; + op_errno = -ret; + } + } + } + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + (gfs_serialize_t)xdr_serialize_setvolume_rsp); + + + if (args.dict.dict_val) + free (args.dict.dict_val); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + dict_unref (params); + dict_unref (reply); + dict_unref (config_params); + + return 0; +} + + +int +server_ping (rpcsvc_request_t *req) +{ + gf_common_rsp rsp = {0,}; + + rsp.gfs_id = req->gfs_id; + /* Accepted */ + rsp.op_ret = 0; + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + + +rpcsvc_actor_t gluster_handshake_actors[] = { + [GF_HNDSK_NULL] = {"NULL", GF_HNDSK_NULL, server_null, NULL, NULL }, + [GF_HNDSK_DUMP_VERSION] = {"VERSION", GF_HNDSK_DUMP_VERSION, server_dump_version, NULL, NULL }, + [GF_HNDSK_SETVOLUME] = {"SETVOLUME", GF_HNDSK_SETVOLUME, server_setvolume, NULL, NULL }, + [GF_HNDSK_GETSPEC] = {"GETSPEC", GF_HNDSK_GETSPEC, server_getspec, NULL, NULL }, + [GF_HNDSK_PING] = {"PING", GF_HNDSK_PING, server_ping, NULL, NULL }, +}; + + +struct rpcsvc_program gluster_handshake_prog = { + .progname = "GlusterFS Handshake", + .prognum = GLUSTER_HNDSK_PROGRAM, + .progver = GLUSTER_HNDSK_VERSION, + + .actors = gluster_handshake_actors, + .numactors = 5, + .progport = 7008, +}; diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c new file mode 100644 index 00000000000..5cae205d76f --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.c @@ -0,0 +1,1392 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server.h" +#include "server-helpers.h" + +int +server_decode_groups (call_frame_t *frame, rpcsvc_request_t *req) +{ + int i = 0; + + if ((!frame) || (!req)) + return 0; + + frame->root->ngrps = req->auxgidcount; + if (frame->root->ngrps == 0) + return 0; + + if (frame->root->ngrps > GF_REQUEST_MAXGROUPS) + return -1; + + for (; i < frame->root->ngrps; ++i) + frame->root->groups[i] = req->auxgids[i]; + + return 0; +} + +/* 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->conn->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->conn->bound_xl->name, GF_LOG_DEBUG, + "failed to build path for %"PRId64": %s", + inode->ino, strerror (-ret)); + } + } + + if (dentry_path) { + if (strcmp (dentry_path, path)) { + gf_log (state->conn->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 = gf_strdup (path); + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + } + +out: + return ret; +} + +/* + * stat_to_str - convert struct iatt to a ASCII string + * @stbuf: struct iatt pointer + * + * not for external reference + */ +char * +stat_to_str (struct iatt *stbuf) +{ + int ret = 0; + char *tmp_buf = NULL; + + uint64_t dev = stbuf->ia_gen; + uint64_t ino = stbuf->ia_ino; + uint32_t mode = st_mode_from_ia (stbuf->ia_prot, stbuf->ia_type); + uint32_t nlink = stbuf->ia_nlink; + uint32_t uid = stbuf->ia_uid; + uint32_t gid = stbuf->ia_gid; + uint64_t rdev = stbuf->ia_rdev; + uint64_t size = stbuf->ia_size; + uint32_t blksize = stbuf->ia_blksize; + uint64_t blocks = stbuf->ia_blocks; + uint32_t atime = stbuf->ia_atime; + uint32_t mtime = stbuf->ia_mtime; + uint32_t ctime = stbuf->ia_ctime; + + uint32_t atime_nsec = stbuf->ia_atime_nsec; + uint32_t mtime_nsec = stbuf->ia_mtime_nsec; + uint32_t ctime_nsec = stbuf->ia_ctime_nsec; + + + ret = gf_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); + if (-1 == ret) { + gf_log ("protocol/server", GF_LOG_DEBUG, + "asprintf failed while setting up stat buffer string"); + return NULL; + } + return tmp_buf; +} + + +void +server_loc_wipe (loc_t *loc) +{ + if (loc->parent) { + inode_unref (loc->parent); + loc->parent = NULL; + } + + if (loc->inode) { + inode_unref (loc->inode); + loc->inode = NULL; + } + + if (loc->path) + GF_FREE ((void *)loc->path); +} + + +void +server_resolve_wipe (server_resolve_t *resolve) +{ + struct resolve_comp *comp = NULL; + int i = 0; + + if (resolve->path) + GF_FREE ((void *)resolve->path); + + if (resolve->bname) + GF_FREE ((void *)resolve->bname); + + if (resolve->resolved) + GF_FREE ((void *)resolve->resolved); + + loc_wipe (&resolve->deep_loc); + + comp = resolve->components; + if (comp) { + for (i = 0; comp[i].basename; i++) { + if (comp[i].inode) + inode_unref (comp[i].inode); + } + GF_FREE ((void *)resolve->components); + } +} + + +void +free_state (server_state_t *state) +{ + if (state->conn) { + //xprt_svc_unref (state->conn); + state->conn = NULL; + } + + if (state->fd) { + fd_unref (state->fd); + state->fd = NULL; + } + + if (state->iobref) { + iobref_unref (state->iobref); + state->iobref = NULL; + } + + if (state->iobuf) { + iobuf_unref (state->iobuf); + state->iobuf = NULL; + } + + if (state->dict) { + dict_unref (state->dict); + state->dict = NULL; + } + + if (state->volume) + GF_FREE ((void *)state->volume); + + if (state->name) + GF_FREE ((void *)state->name); + + server_loc_wipe (&state->loc); + server_loc_wipe (&state->loc2); + + server_resolve_wipe (&state->resolve); + server_resolve_wipe (&state->resolve2); + + GF_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 = GF_CALLOC (1, sizeof (server_state_t), 0); + + new_frame->root->op = frame->root->op; + new_frame->root->type = frame->root->type; + new_frame->root->trans = state->conn; + new_frame->root->state = new_state; + + new_state->itable = state->itable; + new_state->conn = state->conn; + //new_state->conn = xprt_ref (state->conn); + + new_state->resolve.fd_no = -1; + new_state->resolve2.fd_no = -1; + + return new_frame; +} + + +int +gf_add_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, pid_t pid) +{ + int32_t ret = -1; + struct _locker *new = NULL; + uint8_t dir = 0; + + new = GF_CALLOC (1, sizeof (struct _locker), 0); + if (new == NULL) { + gf_log ("server", GF_LOG_ERROR, + "failed to allocate memory for \'struct _locker\'"); + goto out; + } + INIT_LIST_HEAD (&new->lockers); + + new->volume = gf_strdup (volume); + + if (fd == NULL) { + loc_copy (&new->loc, loc); + dir = IA_ISDIR (new->loc.inode->ia_type); + } else { + new->fd = fd_ref (fd); + dir = IA_ISDIR (fd->inode->ia_type); + } + + 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; +} + + +int +gf_del_locker (struct _lock_table *table, const char *volume, + loc_t *loc, fd_t *fd, pid_t pid) +{ + struct _locker *locker = NULL; + struct _locker *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 = IA_ISDIR (fd->inode->ia_type); + } else { + dir = IA_ISDIR (loc->inode->ia_type); + } + + 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) + && !strcmp (locker->volume, volume)) { + list_move_tail (&locker->lockers, &del); + } else if (locker->loc.inode && + loc && + (locker->loc.inode == loc->inode) && + (locker->pid == pid) + && !strcmp (locker->volume, volume)) { + 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); + + GF_FREE (locker->volume); + GF_FREE (locker); + } + + return ret; +} + + +int +gf_direntry_to_bin (dir_entry_t *head, char *buffer) +{ + dir_entry_t *trav = NULL; + uint32_t len = 0; + uint32_t this_len = 0; + 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; + } + + 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); + + GF_FREE (tmp_buf); + trav = trav->next; + ptr += this_len; + } + + buflen = strlen (buffer); + + return buflen; +} + + +static struct _lock_table * +gf_lock_table_new (void) +{ + struct _lock_table *new = NULL; + + new = GF_CALLOC (1, sizeof (struct _lock_table), 0); + 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; +} + +static 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; +} + +int +do_lock_table_cleanup (xlator_t *this, server_connection_t *conn, + call_frame_t *frame, struct _lock_table *ltable) +{ + struct list_head file_lockers, dir_lockers; + call_frame_t *tmp_frame = NULL; + struct flock flock = {0, }; + xlator_t *bound_xl = NULL; + struct _locker *locker = NULL, *tmp = NULL; + int ret = -1; + + bound_xl = conn->bound_xl; + 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); + + GF_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); + if (tmp_frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "out of memory"); + goto out; + } + /* + 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->volume, + locker->fd, F_SETLK, &flock); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, bound_xl, + bound_xl->fops->inodelk, + locker->volume, + &(locker->loc), F_SETLK, &flock); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_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->volume, + 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->volume, + &(locker->loc), NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + ret = 0; + +out: + return ret; +} + + +static int +server_connection_cleanup_flush_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno) +{ + fd_t *fd = NULL; + + fd = frame->local; + + fd_unref (fd); + frame->local = NULL; + + STACK_DESTROY (frame->root); + return 0; +} + + +int +do_fd_cleanup (xlator_t *this, server_connection_t *conn, call_frame_t *frame, + fdentry_t *fdentries, int fd_count) +{ + fd_t *fd = NULL; + int i = 0, ret = -1; + call_frame_t *tmp_frame = NULL; + xlator_t *bound_xl = NULL; + + bound_xl = conn->bound_xl; + for (i = 0;i < fd_count; i++) { + fd = fdentries[i].fd; + + if (fd != NULL) { + tmp_frame = copy_frame (frame); + if (tmp_frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "out of memory"); + goto out; + } + tmp_frame->local = fd; + + tmp_frame->root->pid = 0; + tmp_frame->root->trans = conn; + tmp_frame->root->lk_owner = 0; + STACK_WIND (tmp_frame, + server_connection_cleanup_flush_cbk, + bound_xl, bound_xl->fops->flush, fd); + } + } + + GF_FREE (fdentries); + ret = 0; + +out: + return ret; +} + +int +do_connection_cleanup (xlator_t *this, server_connection_t *conn, + struct _lock_table *ltable, fdentry_t *fdentries, int fd_count) +{ + int ret = 0; + int saved_ret = 0; + call_frame_t *frame = NULL; + server_state_t *state = NULL; + + frame = create_frame (this, this->ctx->pool); + if (frame == NULL) { + gf_log (this->name, GF_LOG_ERROR, "out of memory"); + goto out; + } + + saved_ret = do_lock_table_cleanup (this, conn, frame, ltable); + + if (fdentries != NULL) { + ret = do_fd_cleanup (this, conn, frame, fdentries, fd_count); + } + + state = CALL_STATE (frame); + if (state) + GF_FREE (state); + + STACK_DESTROY (frame->root); + + if (saved_ret || ret) { + ret = -1; + } + +out: + return ret; +} + + +int +server_connection_cleanup (xlator_t *this, server_connection_t *conn) +{ + char do_cleanup = 0; + struct _lock_table *ltable = NULL; + fdentry_t *fdentries = NULL; + uint32_t fd_count = 0; + int ret = 0; + + if (conn == NULL) { + goto out; + } + + pthread_mutex_lock (&conn->lock); + { + conn->active_transports--; + if (conn->active_transports == 0) { + if (conn->ltable) { + ltable = conn->ltable; + conn->ltable = gf_lock_table_new (); + } + + if (conn->fdtable) { + fdentries = gf_fd_fdtable_get_all_fds (conn->fdtable, + &fd_count); + } + do_cleanup = 1; + } + } + pthread_mutex_unlock (&conn->lock); + + if (do_cleanup && conn->bound_xl) + ret = do_connection_cleanup (this, conn, ltable, fdentries, fd_count); + +out: + return ret; +} + + +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,}; + fd_t *fd = NULL; + int32_t i = 0; + fdentry_t *fdentries = NULL; + uint32_t fd_count = 0; + + if (conn == NULL) { + ret = 0; + goto out; + } + + 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); + GF_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->volume, + locker->fd, F_SETLK, &flock); + fd_unref (locker->fd); + } else { + STACK_WIND (tmp_frame, server_nop_cbk, bound_xl, + bound_xl->fops->inodelk, + locker->volume, + &(locker->loc), F_SETLK, &flock); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_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->volume, + 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->volume, + &(locker->loc), NULL, + ENTRYLK_UNLOCK, ENTRYLK_WRLCK); + loc_wipe (&locker->loc); + } + + GF_FREE (locker->volume); + + list_del_init (&locker->lockers); + GF_FREE (locker); + } + + pthread_mutex_lock (&(conn->lock)); + { + if (conn->fdtable) { + fdentries = gf_fd_fdtable_get_all_fds (conn->fdtable, + &fd_count); + gf_fd_fdtable_destroy (conn->fdtable); + conn->fdtable = NULL; + } + } + pthread_mutex_unlock (&conn->lock); + + if (fdentries != NULL) { + for (i = 0; i < fd_count; i++) { + fd = fdentries[i].fd; + if (fd != NULL) { + tmp_frame = copy_frame (frame); + tmp_frame->local = fd; + + STACK_WIND (tmp_frame, + server_connection_cleanup_flush_cbk, + bound_xl, + bound_xl->fops->flush, + fd); + } + } + GF_FREE (fdentries); + } + } + + if (frame) { + state = CALL_STATE (frame); + if (state) + GF_FREE (state); + STACK_DESTROY (frame->root); + } + + gf_log (this->name, GF_LOG_INFO, "destroyed connection of %s", + conn->id); + + GF_FREE (conn->id); + GF_FREE (conn); + +out: + 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 *) GF_CALLOC (1, sizeof (*conn), 0); + + conn->id = gf_strdup (id); + conn->fdtable = gf_fd_fdtable_alloc (); + conn->ltable = gf_lock_table_new (); + conn->this = this; + pthread_mutex_init (&conn->lock, NULL); + + list_add (&conn->list, &conf->conns); + } + + conn->ref++; + conn->active_transports++; + } + 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; + + if (conn == NULL) { + goto out; + } + + 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); + } + +out: + return; +} + +static call_frame_t * +server_alloc_frame (rpcsvc_request_t *req) +{ + call_frame_t *frame = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + + GF_VALIDATE_OR_GOTO("server", req, out); + + conn = (server_connection_t *)req->conn->trans->xl_private; + if (!conn) + goto out; + frame = create_frame (conn->this, req->conn->svc->ctx->pool); + GF_VALIDATE_OR_GOTO("server", frame, out); + + state = GF_CALLOC (1, sizeof (*state), 0); + GF_VALIDATE_OR_GOTO("server", state, out); + + if (conn->bound_xl) + state->itable = conn->bound_xl->itable; + + state->xprt = req->conn->trans; + state->conn = conn; + + state->resolve.fd_no = -1; + state->resolve2.fd_no = -1; + + frame->root->state = state; /* which socket */ + frame->root->unique = 0; /* which call */ + + frame->this = conn->this; +out: + return frame; +} + + + +call_frame_t * +get_frame_from_request (rpcsvc_request_t *req) +{ + call_frame_t *frame = NULL; + + frame = server_alloc_frame (req); + if (!frame) + goto out; + + frame->root->op = req->procnum; + frame->root->type = req->type; + + frame->root->unique = req->xid; + + frame->root->uid = req->uid; + frame->root->gid = req->gid; + frame->root->pid = req->pid; + frame->root->lk_owner = req->lk_owner; + + server_decode_groups (frame, req); + + frame->local = req; +out: + return frame; +} + + +int +server_build_config (xlator_t *this, server_conf_t *conf) +{ + data_t *data = NULL; + int ret = -1; + struct stat buf = {0,}; + + ret = dict_get_int32 (this->options, "inode-lru-limit", + &conf->inode_lru_limit); + if (ret < 0) { + conf->inode_lru_limit = 1024; + } + + conf->verify_volfile = 1; + data = dict_get (this->options, "verify-volfile-checksum"); + if (data) { + ret = gf_string2boolean(data->data, &conf->verify_volfile); + if (ret != 0) { + gf_log (this->name, GF_LOG_WARNING, + "wrong value for 'verify-volfile-checksum', " + "Neglecting option"); + } + } + + data = dict_get (this->options, "trace"); + if (data) { + ret = gf_string2boolean (data->data, &conf->trace); + if (ret != 0) { + gf_log (this->name, GF_LOG_WARNING, + "'trace' takes on only boolean values. " + "Neglecting option"); + } + } + + /* TODO: build_rpc_config (); */ + ret = dict_get_int32 (this->options, "limits.transaction-size", + &conf->rpc_conf.max_block_size); + if (ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "defaulting limits.transaction-size to %d", + DEFAULT_BLOCK_SIZE); + conf->rpc_conf.max_block_size = DEFAULT_BLOCK_SIZE; + } + + data = dict_get (this->options, "config-directory"); + if (data) { + /* Check whether the specified directory exists, + or directory specified is non standard */ + ret = stat (data->data, &buf); + if ((ret != 0) || !S_ISDIR (buf.st_mode)) { + gf_log (this->name, GF_LOG_ERROR, + "Directory '%s' doesn't exist, exiting.", + data->data); + ret = -1; + goto out; + } + /* Make sure that conf-dir doesn't contain ".." in path */ + if ((gf_strstr (data->data, "/", "..")) == -1) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, + "%s: invalid conf_dir", data->data); + goto out; + } + + conf->conf_dir = gf_strdup (data->data); + } + ret = 0; +out: + return ret; +} + +server_connection_t * +get_server_conn_state (xlator_t *this, rpc_transport_t *xprt) +{ + return (server_connection_t *)xprt->xl_private; +} + +server_connection_t * +create_server_conn_state (xlator_t *this, rpc_transport_t *xprt) +{ + server_connection_t *conn = NULL; + int ret = -1; + + conn = GF_CALLOC (1, sizeof (*conn), 0); + if (!conn) + goto out; + + pthread_mutex_init (&conn->lock, NULL); + + conn->fdtable = gf_fd_fdtable_alloc (); + if (!conn->fdtable) + goto out; + + conn->ltable = gf_lock_table_new (); + if (!conn->ltable) + goto out; + + conn->this = this; + + xprt->xl_private = conn; + + ret = 0; +out: + if (ret) + destroy_server_conn_state (conn); + + return conn; +} + +void +destroy_server_conn_state (server_connection_t *conn) +{ + if (!conn) { + return; + } + + if (conn->ltable) { + /* TODO */ + //FREE (conn->ltable); + ; + } + + if (conn->fdtable) + gf_fd_fdtable_destroy (conn->fdtable); + + pthread_mutex_destroy (&conn->lock); + + GF_FREE (conn); + + return; +} + + +void +print_caller (char *str, int size, call_frame_t *frame) +{ + int filled = 0; + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + filled += snprintf (str + filled, size - filled, + " Callid=%"PRId64", Client=%s", + frame->root->unique, + state->xprt->peerinfo.identifier); + + return; +} + + +void +server_print_resolve (char *str, int size, server_resolve_t *resolve) +{ + int filled = 0; + + if (!resolve) { + snprintf (str, size, "<nul>"); + return; + } + + filled += snprintf (str + filled, size - filled, + " Resolve={"); + if (resolve->fd_no != -1) + filled += snprintf (str + filled, size - filled, + "fd=%"PRId64",", (uint64_t) resolve->fd_no); + if (resolve->ino) + filled += snprintf (str + filled, size - filled, + "ino=%"PRIu64",", (uint64_t) resolve->ino); + if (resolve->par) + filled += snprintf (str + filled, size - filled, + "par=%"PRIu64",", (uint64_t) resolve->par); + if (resolve->gen) + filled += snprintf (str + filled, size - filled, + "gen=%"PRIu64",", (uint64_t) resolve->gen); + if (resolve->bname) + filled += snprintf (str + filled, size - filled, + "bname=%s,", resolve->bname); + if (resolve->path) + filled += snprintf (str + filled, size - filled, + "path=%s", resolve->path); + + filled += snprintf (str + filled, size - filled, "}"); +} + + +void +server_print_loc (char *str, int size, loc_t *loc) +{ + int filled = 0; + + if (!loc) { + snprintf (str, size, "<nul>"); + return; + } + + filled += snprintf (str + filled, size - filled, + " Loc={"); + + if (loc->path) + filled += snprintf (str + filled, size - filled, + "path=%s,", loc->path); + if (loc->inode) + filled += snprintf (str + filled, size - filled, + "inode=%p,", loc->inode); + if (loc->parent) + filled += snprintf (str + filled, size - filled, + "parent=%p", loc->parent); + + filled += snprintf (str + filled, size - filled, "}"); +} + + +void +server_print_params (char *str, int size, server_state_t *state) +{ + int filled = 0; + + filled += snprintf (str + filled, size - filled, + " Params={"); + + if (state->fd) + filled += snprintf (str + filled, size - filled, + "fd=%p,", state->fd); + if (state->valid) + filled += snprintf (str + filled, size - filled, + "valid=%d,", state->valid); + if (state->flags) + filled += snprintf (str + filled, size - filled, + "flags=%d,", state->flags); + if (state->wbflags) + filled += snprintf (str + filled, size - filled, + "wbflags=%d,", state->wbflags); + if (state->size) + filled += snprintf (str + filled, size - filled, + "size=%Zu,", state->size); + if (state->offset) + filled += snprintf (str + filled, size - filled, + "offset=%"PRId64",", state->offset); + if (state->cmd) + filled += snprintf (str + filled, size - filled, + "cmd=%d,", state->cmd); + if (state->type) + filled += snprintf (str + filled, size - filled, + "type=%d,", state->type); + if (state->name) + filled += snprintf (str + filled, size - filled, + "name=%s,", state->name); + if (state->mask) + filled += snprintf (str + filled, size - filled, + "mask=%d,", state->mask); + if (state->volume) + filled += snprintf (str + filled, size - filled, + "volume=%s,", state->volume); + + filled += snprintf (str + filled, size - filled, + "bound_xl=%s}", state->conn->bound_xl->name); +} + +int +server_resolve_is_empty (server_resolve_t *resolve) +{ + if (resolve->fd_no != -1) + return 0; + + if (resolve->ino != 0) + return 0; + + if (resolve->gen != 0) + return 0; + + if (resolve->par != 0) + return 0; + + if (resolve->path != 0) + return 0; + + if (resolve->bname != 0) + return 0; + + return 1; +} + +void +server_print_reply (call_frame_t *frame, int op_ret, int op_errno) +{ + server_conf_t *conf = NULL; + server_state_t *state = NULL; + xlator_t *this = NULL; + char caller[512]; + char fdstr[32]; + char *op = "UNKNOWN"; + + this = frame->this; + conf = this->private; + + if (!conf->trace) + return; + + state = CALL_STATE (frame); + + print_caller (caller, 256, frame); + + switch (frame->root->type) { + case GF_OP_TYPE_FOP: + op = gf_fop_list[frame->root->op]; + break; + case GF_OP_TYPE_MGMT: + op = gf_mgmt_list[frame->root->op]; + break; + default: + op = ""; + } + + fdstr[0] = '\0'; + if (state->fd) + snprintf (fdstr, 32, " fd=%p", state->fd); + + gf_log (this->name, GF_LOG_NORMAL, + "%s%s => (%d, %d)%s", + op, caller, op_ret, op_errno, fdstr); +} + + +void +server_print_request (call_frame_t *frame) +{ + server_conf_t *conf = NULL; + xlator_t *this = NULL; + server_state_t *state = NULL; + char resolve_vars[256]; + char resolve2_vars[256]; + char loc_vars[256]; + char loc2_vars[256]; + char other_vars[512]; + char caller[512]; + char *op = "UNKNOWN"; + + this = frame->this; + conf = this->private; + + state = CALL_STATE (frame); + + if (!conf->trace) + return; + + memset (resolve_vars, '\0', 256); + memset (resolve2_vars, '\0', 256); + memset (loc_vars, '\0', 256); + memset (loc2_vars, '\0', 256); + memset (other_vars, '\0', 256); + + print_caller (caller, 256, frame); + + if (!server_resolve_is_empty (&state->resolve)) { + server_print_resolve (resolve_vars, 256, &state->resolve); + server_print_loc (loc_vars, 256, &state->loc); + } + + if (!server_resolve_is_empty (&state->resolve2)) { + server_print_resolve (resolve2_vars, 256, &state->resolve2); + server_print_loc (loc2_vars, 256, &state->loc2); + } + + server_print_params (other_vars, 512, state); + + switch (frame->root->type) { + case GF_OP_TYPE_FOP: + op = gf_fop_list[frame->root->op]; + break; + case GF_OP_TYPE_MGMT: + op = gf_mgmt_list[frame->root->op]; + break; + default: + op = ""; + break; + } + + gf_log (this->name, GF_LOG_NORMAL, + "%s%s%s%s%s%s%s", + op, caller, + resolve_vars, loc_vars, resolve2_vars, loc2_vars, other_vars); +} diff --git a/xlators/protocol/server/src/server-helpers.h b/xlators/protocol/server/src/server-helpers.h new file mode 100644 index 00000000000..4897336af69 --- /dev/null +++ b/xlators/protocol/server/src/server-helpers.h @@ -0,0 +1,89 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SERVER_HELPERS_H +#define _SERVER_HELPERS_H + +#include "server.h" + +#define CALL_STATE(frame) ((server_state_t *)frame->root->state) + +#define BOUND_XL(frame) ((xlator_t *) CALL_STATE(frame)->conn->bound_xl) + +#define XPRT_FROM_FRAME(frame) ((rpc_transport_t *) CALL_STATE(frame)->xprt) + +#define SERVER_CONNECTION(frame) \ + ((server_connection_t *) CALL_STATE(frame)->conn) + +#define SERVER_CONF(frame) \ + ((server_conf_t *)XPRT_FROM_FRAME(frame)->this->private) + +#define XPRT_FROM_XLATOR(this) ((((server_conf_t *)this->private))->listen) + +#define INODE_LRU_LIMIT(this) \ + (((server_conf_t *)(this->private))->config.inode_lru_limit) + +#define IS_ROOT_INODE(inode) (inode == inode->table->root) + +#define IS_NOT_ROOT(pathlen) ((pathlen > 2)? 1 : 0) + +char * +stat_to_str (struct iatt *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, const char *volume, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_del_locker (struct _lock_table *table, const char *volume, + loc_t *loc, + fd_t *fd, + pid_t pid); + +int32_t +gf_direntry_to_bin (dir_entry_t *head, char *bufferp); + +void +server_print_request (call_frame_t *frame); + +call_frame_t * +get_frame_from_request (rpcsvc_request_t *req); + +server_connection_t * +get_server_conn_state (xlator_t *this, rpc_transport_t *xptr); + +server_connection_t * +create_server_conn_state (xlator_t *this, rpc_transport_t *xptr); + +void +destroy_server_conn_state (server_connection_t *conn); + +int +server_build_config (xlator_t *this, server_conf_t *conf); + +#endif /* !_SERVER_HELPERS_H */ diff --git a/xlators/protocol/server/src/server-mem-types.h b/xlators/protocol/server/src/server-mem-types.h new file mode 100644 index 00000000000..76c5ae1ac0c --- /dev/null +++ b/xlators/protocol/server/src/server-mem-types.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef __SERVER_MEM_TYPES_H__ +#define __SERVER_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gf_server_mem_types_ { + gf_server_mt_server_conf_t = gf_common_mt_end + 1, + gf_server_mt_resolv_comp_t, + gf_server_mt_state_t, + gf_server_mt_locker_t, + gf_server_mt_lock_table_t, + gf_server_mt_conn_t, + gf_server_mt_rsp_buf_t, + gf_server_mt_volfile_ctx_t, + gf_server_mt_end, +}; +#endif /* __SERVER_MEM_TYPES_H__ */ diff --git a/xlators/protocol/server/src/server-resolve.c b/xlators/protocol/server/src/server-resolve.c new file mode 100644 index 00000000000..77336216f19 --- /dev/null +++ b/xlators/protocol/server/src/server-resolve.c @@ -0,0 +1,655 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server.h" +#include "server-helpers.h" + + +int +server_resolve_all (call_frame_t *frame); +int +resolve_entry_simple (call_frame_t *frame); +int +resolve_inode_simple (call_frame_t *frame); +int +resolve_path_simple (call_frame_t *frame); + +int +component_count (const char *path) +{ + int count = 0; + const char *trav = NULL; + + trav = path; + + for (trav = path; *trav; trav++) { + if (*trav == '/') + count++; + } + + return count + 2; +} + + +int +prepare_components (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + char *resolved = NULL; + int count = 0; + struct resolve_comp *components = NULL; + int i = 0; + char *trav = NULL; + + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + resolved = gf_strdup (resolve->path); + resolve->resolved = resolved; + + count = component_count (resolve->path); + components = GF_CALLOC (sizeof (*components), count, + gf_server_mt_resolv_comp_t); + resolve->components = components; + + components[0].basename = ""; + components[0].ino = 1; + components[0].gen = 0; + components[0].inode = state->itable->root; + + i = 1; + for (trav = resolved; *trav; trav++) { + if (*trav == '/') { + components[i].basename = trav + 1; + *trav = 0; + i++; + } + } + + return 0; +} + + +int +resolve_loc_touchup (call_frame_t *frame) +{ + server_state_t *state = NULL; + server_resolve_t *resolve = NULL; + loc_t *loc = NULL; + char *path = NULL; + int ret = 0; + + state = CALL_STATE (frame); + + resolve = state->resolve_now; + loc = state->loc_now; + + if (!loc->path) { + if (loc->parent) { + ret = inode_path (loc->parent, resolve->bname, &path); + } else if (loc->inode) { + ret = inode_path (loc->inode, NULL, &path); + } + + if (!path) + path = gf_strdup (resolve->path); + + loc->path = path; + } + + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + + if (!loc->parent && loc->inode) { + loc->parent = inode_parent (loc->inode, 0, NULL); + } + + return 0; +} + + +int +resolve_deep_continue (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + resolve->op_ret = 0; + resolve->op_errno = 0; + + if (resolve->par) + ret = resolve_entry_simple (frame); + else if (resolve->ino) + ret = resolve_inode_simple (frame); + else if (resolve->path) + ret = resolve_path_simple (frame); + + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +resolve_deep_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, inode_t *inode, struct iatt *buf, + dict_t *xattr, struct iatt *postparent) +{ + server_state_t *state = NULL; + server_resolve_t *resolve = NULL; + struct resolve_comp *components = NULL; + int i = 0; + inode_t *link_inode = NULL; + + state = CALL_STATE (frame); + resolve = state->resolve_now; + components = resolve->components; + + i = (long) cookie; + + if (op_ret == -1) { + goto get_out_of_here; + } + + if (i != 0) { + /* no linking for root inode */ + link_inode = inode_link (inode, resolve->deep_loc.parent, + resolve->deep_loc.name, buf); + inode_lookup (link_inode); + components[i].inode = link_inode; + link_inode = NULL; + } + + loc_wipe (&resolve->deep_loc); + + i++; /* next component */ + + if (!components[i].basename) { + /* all components of the path are resolved */ + goto get_out_of_here; + } + + /* join the current component with the path resolved until now */ + *(components[i].basename - 1) = '/'; + + resolve->deep_loc.path = gf_strdup (resolve->resolved); + resolve->deep_loc.parent = inode_ref (components[i-1].inode); + resolve->deep_loc.inode = inode_new (state->itable); + resolve->deep_loc.name = components[i].basename; + + STACK_WIND_COOKIE (frame, resolve_deep_cbk, (void *) (long) i, + BOUND_XL (frame), BOUND_XL (frame)->fops->lookup, + &resolve->deep_loc, NULL); + return 0; + +get_out_of_here: + resolve_deep_continue (frame); + return 0; +} + + +int +resolve_path_deep (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int i = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + gf_log (BOUND_XL (frame)->name, GF_LOG_TRACE, + "RESOLVE %s() seeking deep resolution of %s", + gf_fop_list[frame->root->op], resolve->path); + + prepare_components (frame); + + /* start from the root */ + resolve->deep_loc.inode = state->itable->root; + resolve->deep_loc.path = gf_strdup ("/"); + resolve->deep_loc.name = ""; + + STACK_WIND_COOKIE (frame, resolve_deep_cbk, (void *) (long) i, + BOUND_XL (frame), BOUND_XL (frame)->fops->lookup, + &resolve->deep_loc, NULL); + return 0; +} + + +int +resolve_path_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + struct resolve_comp *components = NULL; + int ret = -1; + int par_idx = 0; + int ino_idx = 0; + int i = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + components = resolve->components; + + if (!components) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + for (i = 0; components[i].basename; i++) { + par_idx = ino_idx; + ino_idx = i; + } + + if (!components[par_idx].inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (!components[ino_idx].inode && + (resolve->type == RESOLVE_MUST || resolve->type == RESOLVE_EXACT)) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (components[ino_idx].inode && resolve->type == RESOLVE_NOT) { + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + goto out; + } + + if (components[ino_idx].inode) + state->loc_now->inode = inode_ref (components[ino_idx].inode); + state->loc_now->parent = inode_ref (components[par_idx].inode); + + ret = 0; + +out: + return ret; +} + +/* + Check if the requirements are fulfilled by entries in the inode cache itself + Return value: + <= 0 - simple resolution was decisive and complete (either success or failure) + > 0 - indecisive, need to perform deep resolution +*/ + +int +resolve_entry_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + inode_t *parent = NULL; + inode_t *inode = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + parent = inode_get (state->itable, resolve->par, 0); + if (!parent) { + /* simple resolution is indecisive. need to perform + deep resolution */ + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + + inode = inode_grep (state->itable, parent, resolve->bname); + if (inode != NULL) { + gf_log (this->name, GF_LOG_DEBUG, "%"PRId64": inode " + "(pointer:%p ino: %"PRIu64") present but parent" + " is NULL for path (%s)", frame->root->unique, + inode, inode->ino, resolve->path); + inode_unref (inode); + } + goto out; + } + + if (parent->ino != 1 && parent->generation != resolve->gen) { + /* simple resolution is decisive - request was for a + stale handle */ + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = -1; + goto out; + } + + /* expected @parent was found from the inode cache */ + state->loc_now->parent = inode_ref (parent); + + inode = inode_grep (state->itable, parent, resolve->bname); + if (!inode) { + switch (resolve->type) { + case RESOLVE_DONTCARE: + case RESOLVE_NOT: + ret = 0; + break; + case RESOLVE_MAY: + ret = 1; + break; + default: + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + break; + } + + goto out; + } + + if (resolve->type == RESOLVE_NOT) { + gf_log (this->name, GF_LOG_DEBUG, "inode (pointer: %p ino:%" + PRIu64") found for path (%s) while type is RESOLVE_NOT", + inode, inode->ino, resolve->path); + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + ret = -1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (parent) + inode_unref (parent); + + if (inode) + inode_unref (inode); + + return ret; +} + + +int +server_resolve_entry (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + loc_t *loc = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + loc = state->loc_now; + + ret = resolve_entry_simple (frame); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (frame); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +resolve_inode_simple (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + inode_t *inode = NULL; + int ret = 0; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + if (resolve->type == RESOLVE_EXACT) { + inode = inode_get (state->itable, resolve->ino, resolve->gen); + } else { + inode = inode_get (state->itable, resolve->ino, 0); + } + + if (!inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + goto out; + } + + if (inode->ino != 1 && inode->generation != resolve->gen) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = -1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (inode) + inode_unref (inode); + + return ret; +} + + +int +server_resolve_inode (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + int ret = 0; + loc_t *loc = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + loc = state->loc_now; + + ret = resolve_inode_simple (frame); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (frame); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (frame); + + server_resolve_all (frame); + + return 0; +} + + +int +server_resolve_fd (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + server_connection_t *conn = NULL; + uint64_t fd_no = -1; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + conn = SERVER_CONNECTION (frame); + + fd_no = resolve->fd_no; + + state->fd = gf_fd_fdptr_get (conn->fdtable, fd_no); + + if (!state->fd) { + resolve->op_ret = -1; + resolve->op_errno = EBADF; + } + + server_resolve_all (frame); + + return 0; +} + + +int +server_resolve (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + server_resolve_t *resolve = NULL; + + state = CALL_STATE (frame); + this = frame->this; + resolve = state->resolve_now; + + if (resolve->fd_no != -1) { + + server_resolve_fd (frame); + + } else if (resolve->par) { + + server_resolve_entry (frame); + + } else if (resolve->ino) { + + server_resolve_inode (frame); + + } else if (resolve->path) { + + resolve_path_deep (frame); + + } else { + + resolve->op_ret = -1; + resolve->op_errno = EINVAL; + + server_resolve_all (frame); + } + + return 0; +} + + +int +server_resolve_done (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *bound_xl = NULL; + + state = CALL_STATE (frame); + bound_xl = BOUND_XL (frame); + + server_print_request (frame); + + state->resume_fn (frame, bound_xl); + + return 0; +} + + +/* + * This function is called multiple times, once per resolving one location/fd. + * state->resolve_now is used to decide which location/fd is to be resolved now + */ +int +server_resolve_all (call_frame_t *frame) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + + this = frame->this; + state = CALL_STATE (frame); + + if (state->resolve_now == NULL) { + + state->resolve_now = &state->resolve; + state->loc_now = &state->loc; + + server_resolve (frame); + + } else if (state->resolve_now == &state->resolve) { + + state->resolve_now = &state->resolve2; + state->loc_now = &state->loc2; + + server_resolve (frame); + + } else if (state->resolve_now == &state->resolve2) { + + server_resolve_done (frame); + + } else { + gf_log (this->name, GF_LOG_ERROR, + "Invalid pointer for state->resolve_now"); + } + + return 0; +} + + +int +resolve_and_resume (call_frame_t *frame, server_resume_fn_t fn) +{ + server_state_t *state = NULL; + xlator_t *this = NULL; + + state = CALL_STATE (frame); + state->resume_fn = fn; + + this = frame->this; + + server_resolve_all (frame); + + return 0; +} diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c new file mode 100644 index 00000000000..18be607a94d --- /dev/null +++ b/xlators/protocol/server/src/server.c @@ -0,0 +1,687 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <sys/time.h> +#include <sys/resource.h> + +#include "server.h" +#include "server-helpers.h" +#include "glusterfs-xdr.h" +#include "call-stub.h" +#include "statedump.h" +#include "defaults.h" +#include "authenticate.h" +#include "rpcsvc.h" + +struct iobuf * +gfs_serialize_reply (rpcsvc_request_t *req, void *arg, gfs_serialize_t sfunc, + struct iovec *outmsg) +{ + struct iobuf *iob = NULL; + ssize_t retlen = -1; + + /* First, get the io buffer into which the reply in arg will + * be serialized. + */ + iob = iobuf_get (req->conn->svc->ctx->iobuf_pool); + if (!iob) { + gf_log ("", GF_LOG_ERROR, "Failed to get iobuf"); + goto ret; + } + + iobuf_to_iovec (iob, outmsg); + /* Use the given serializer to translate the give C structure in arg + * to XDR format which will be written into the buffer in outmsg. + */ + /* retlen is used to received the error since size_t is unsigned and we + * need -1 for error notification during encoding. + */ + retlen = sfunc (*outmsg, arg); + if (retlen == -1) { + gf_log ("", GF_LOG_ERROR, "Failed to encode message"); + goto ret; + } + + outmsg->iov_len = retlen; +ret: + if (retlen == -1) { + iobuf_unref (iob); + iob = NULL; + } + + return iob; +} + + + +/* Generic reply function for NFSv3 specific replies. */ +int +server_submit_reply (call_frame_t *frame, rpcsvc_request_t *req, void *arg, + struct iovec *payload, int payloadcount, + struct iobref *iobref, gfs_serialize_t sfunc) +{ + struct iobuf *iob = NULL; + int ret = -1; + struct iovec rsp = {0,}; + server_state_t *state = NULL; + char new_iobref = 0; + + if (!req) { + goto ret; + } + + if (frame) { + state = CALL_STATE (frame); + } + + if (!iobref) { + iobref = iobref_new (); + if (!iobref) { + gf_log ("", GF_LOG_ERROR, "out of memory"); + goto ret; + } + + new_iobref = 1; + } + + iob = gfs_serialize_reply (req, arg, sfunc, &rsp); + if (!iob) { + gf_log ("", GF_LOG_ERROR, "Failed to serialize reply"); + goto ret; + } + + iobref_add (iobref, iob); + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_generic (req, &rsp, 1, payload, payloadcount, + iobref); + + /* Now that we've done our job of handing the message to the RPC layer + * we can safely unref the iob in the hope that RPC layer must have + * ref'ed the iob on receiving into the txlist. + */ + iobuf_unref (iob); + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "Reply submission failed"); + goto ret; + } + + ret = 0; +ret: + if (state) { + free_state (state); + } + + if (frame) { + STACK_DESTROY (frame->root); + } + + if (new_iobref) { + iobref_unref (iobref); + } + + return ret; +} + +/* */ +int +xdr_to_glusterfs_req (rpcsvc_request_t *req, void *arg, gfs_serialize_t sfunc) +{ + int ret = -1; + + if (!req) + return -1; + + ret = sfunc (req->msg[0], arg); + + if (ret > 0) + ret = 0; + + return ret; +} + + +#if 0 +/* + * 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, + struct iobuf *iobuf); + + +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_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_FGETXATTR] = server_fgetxattr, + [GF_FOP_FSETXATTR] = server_fsetxattr, + [GF_FOP_REMOVEXATTR] = server_removexattr, + [GF_FOP_OPENDIR] = server_opendir, + [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_LOOKUP] = server_lookup, + [GF_FOP_READDIR] = server_readdir, + [GF_FOP_READDIRP] = server_readdirp, + [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_RCHECKSUM] = server_rchecksum, + [GF_FOP_XATTROP] = server_xattrop, + [GF_FOP_FXATTROP] = server_fxattrop, + [GF_FOP_SETATTR] = server_setattr, + [GF_FOP_FSETATTR] = server_fsetattr, + [GF_FOP_SETDENTS] = server_setdents, + [GF_FOP_GETDENTS] = server_getdents, + [GF_FOP_LOCK_NOTIFY] = server_lock_notify, + [GF_FOP_LOCK_FNOTIFY] = server_lock_fnotify, +}; + +static gf_op_t gf_cbks[] = { + [GF_CBK_FORGET] = server_forget, + [GF_CBK_RELEASE] = server_release, + [GF_CBK_RELEASEDIR] = server_releasedir +}; + +#endif + +int +server_fd (xlator_t *this) +{ + server_conf_t *conf = NULL; + server_connection_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + int ret = -1; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + gf_proc_dump_add_section("xlator.protocol.server.conn"); + + ret = pthread_mutex_trylock (&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump fdtable" + " errno: %d", errno); + return -1; + } + + list_for_each_entry (trav, &conf->conns, list) { + if (trav->id) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + gf_proc_dump_write(key, "%s", trav->id); + } + + gf_proc_dump_build_key(key,"xlator.protocol.server.conn", + "%d.ref",i) + gf_proc_dump_write(key, "%d", trav->ref); + if (trav->bound_xl) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.bound_xl", i); + gf_proc_dump_write(key, "%s", trav->bound_xl->name); + } + + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + fdtable_dump(trav->fdtable,key); + i++; + } + pthread_mutex_unlock (&conf->mutex); + + + return 0; + } + +int +server_priv (xlator_t *this) +{ + return 0; +} + +int +server_inode (xlator_t *this) +{ + server_conf_t *conf = NULL; + server_connection_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + int ret = -1; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + ret = pthread_mutex_trylock (&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump itable" + " errno: %d", errno); + return -1; + } + + list_for_each_entry (trav, &conf->conns, list) { + if (trav->bound_xl && trav->bound_xl->itable) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.bound_xl.%s", + i, trav->bound_xl->name); + inode_table_dump(trav->bound_xl->itable,key); + i++; + } + } + pthread_mutex_unlock (&conf->mutex); + + + return 0; +} + + +static void +get_auth_types (dict_t *this, char *key, data_t *value, void *data) +{ + dict_t *auth_dict = NULL; + char *saveptr = NULL; + char *tmp = NULL; + char *key_cpy = NULL; + int32_t ret = -1; + + auth_dict = data; + key_cpy = gf_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_DEBUG, + "failed to dict_set_dynptr"); + } + } + + GF_FREE (key_cpy); +out: + return; +} + + +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; + char *tmp = NULL; + char *key_cpy = NULL; + + trav = this->children; + while (trav) { + error = -1; + for (pair = dict->members_list; pair; pair = pair->next) { + key_cpy = gf_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; + GF_FREE (key_cpy); + break; + } + GF_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; +} + + +int +server_rpc_notify (rpcsvc_t *rpc, void *xl, rpcsvc_event_t event, + void *data) +{ + xlator_t *this = NULL; + rpc_transport_t *xprt = NULL; + server_connection_t *conn = NULL; + + if (!xl || !data) { + gf_log ("server", GF_LOG_WARNING, + "Calling rpc_notify without initializing"); + goto out; + } + + this = xl; + xprt = data; + + switch (event) { + case RPCSVC_EVENT_ACCEPT: + { + /* Have a structure per new connection */ + /* TODO: Should we create anything here at all ? * / + conn = create_server_conn_state (this, xprt); + if (!conn) + goto out; + + xprt->protocol_private = conn; + */ + xprt->mydata = this; + break; + } + case RPCSVC_EVENT_DISCONNECT: + conn = get_server_conn_state (this, xprt); + if (conn) + destroy_server_conn_state (conn); + + break; + default: + break; + } + +out: + return 0; +} + +static int32_t +mem_acct_init (xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_server_mt_end + 1); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, "Memory accounting init" + "failed"); + return ret; + } + + return ret; +} + +int +init (xlator_t *this) +{ + int32_t ret = -1; + server_conf_t *conf = NULL; + + if (this->children == NULL) { + gf_log (this->name, GF_LOG_ERROR, + "protocol/server should have subvolume"); + goto out; + } + + if (this->parents != NULL) { + gf_log (this->name, GF_LOG_ERROR, + "protocol/server should not have parent volumes"); + goto out; + } + + ret = mem_acct_init (this); + if (ret) + goto out; + + conf = GF_CALLOC (1, sizeof (server_conf_t), 0); + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + INIT_LIST_HEAD (&conf->conns); + pthread_mutex_init (&conf->mutex, NULL); + + this->private = conf; + + ret = server_build_config (this, conf); + if (ret) + goto out; + + /* Authentication modules */ + 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; + } + + /* RPC related */ + //conf->rpc = rpc_svc_init (&conf->rpc_conf); + conf->rpc = rpcsvc_init (this->ctx, this->options); + if (!conf->rpc) { + ret = -1; + goto out; + } + + ret = rpcsvc_register_notify (conf->rpc, server_rpc_notify, this); + if (ret) + goto out; + + glusterfs3_1_fop_prog.options = this->options; + ret = rpcsvc_program_register (conf->rpc, glusterfs3_1_fop_prog); + if (ret) + goto out; + + gluster_handshake_prog.options = this->options; + ret = rpcsvc_program_register (conf->rpc, gluster_handshake_prog); + if (ret) + goto out; + +#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_WARNING, + "Failed to set max open fd to 64k: %s", + strerror(errno)); + } else { + gf_log (this->name, GF_LOG_TRACE, + "max open fd set to 64k"); + } + } + } +#endif + + ret = 0; +out: + if (ret) + this->fini (this); + + + return ret; +} + + +void +fini (xlator_t *this) +{ + server_conf_t *conf = NULL; + + conf = this->private; + + if (conf) { + if (conf->rpc) { + /* TODO: memory leak here, have to free RPC */ + /* + if (conf->rpc->conn) { + rpcsvc_conn_destroy (conf->rpc->conn); + } + rpcsvc_fini (conf->rpc); + */ + ; + } + + if (conf->conf_dir) + GF_FREE (conf->conf_dir); + + if (conf->auth_modules) + dict_unref (conf->auth_modules); + + GF_FREE (conf); + } + + this->private = NULL; + + return; +} + +int +notify (xlator_t *this, int32_t event, void *data, ...) +{ + int ret = 0; + switch (event) { + default: + default_notify (this, event, data); + break; + } + + return ret; +} + + +struct xlator_fops fops = { +}; + +struct xlator_cbks cbks = { +}; + +struct xlator_dumpops dumpops = { + .priv = server_priv, + .fd = server_fd, + .inode = server_inode, +}; + + +struct volume_options options[] = { + { .key = {"transport-type"}, + .value = {"rpc", "rpc-over-rdma", "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 = {"verify-volfile-checksum"}, + .type = GF_OPTION_TYPE_BOOL + }, + { .key = {"trace"}, + .type = GF_OPTION_TYPE_BOOL + }, + { .key = {"config-directory", + "conf-dir"}, + .type = GF_OPTION_TYPE_PATH, + }, + + { .key = {NULL} }, +}; diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h new file mode 100644 index 00000000000..aaa036e83b6 --- /dev/null +++ b/xlators/protocol/server/src/server.h @@ -0,0 +1,203 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SERVER_H +#define _SERVER_H + +#include <pthread.h> + +#include "rpcsvc.h" + +#include "fd.h" +#include "protocol-common.h" + +#include "server-mem-types.h" + +#define DEFAULT_BLOCK_SIZE 4194304 /* 4MB */ +#define DEFAULT_VOLUME_FILE_PATH CONFDIR "/glusterfs.vol" + +typedef struct _server_state server_state_t; + +struct _locker { + struct list_head lockers; + char *volume; + 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; + int active_transports; + pthread_mutex_t lock; + char disconnected; + fdtable_t *fdtable; + struct _lock_table *ltable; + xlator_t *bound_xl; + xlator_t *this; +}; + +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_connection_cleanup (xlator_t *this, server_connection_t *conn); + +int server_null (rpcsvc_request_t *req); + +struct _volfile_ctx { + struct _volfile_ctx *next; + char *key; + uint32_t checksum; +}; + +struct server_conf { + rpcsvc_t *rpc; + struct rpcsvc_config rpc_conf; + int inode_lru_limit; + gf_boolean_t verify_volfile; + gf_boolean_t trace; + char *conf_dir; + struct _volfile_ctx *volfile; + + dict_t *auth_modules; + pthread_mutex_t mutex; + struct list_head conns; +}; +typedef struct server_conf server_conf_t; + + +typedef enum { + RESOLVE_MUST = 1, + RESOLVE_NOT, + RESOLVE_MAY, + RESOLVE_DONTCARE, + RESOLVE_EXACT +} server_resolve_type_t; + + +struct resolve_comp { + char *basename; + ino_t ino; + uint64_t gen; + inode_t *inode; +}; + +typedef struct { + server_resolve_type_t type; + uint64_t fd_no; + ino_t ino; + uint64_t gen; + ino_t par; + char *path; + char *bname; + char *resolved; + int op_ret; + int op_errno; + loc_t deep_loc; + struct resolve_comp *components; + int comp_count; +} server_resolve_t; + + +typedef int (*server_resume_fn_t) (call_frame_t *frame, xlator_t *bound_xl); + +int +resolve_and_resume (call_frame_t *frame, server_resume_fn_t fn); + +struct _server_state { + server_connection_t *conn; + rpc_transport_t *xprt; + inode_table_t *itable; + + server_resume_fn_t resume_fn; + + loc_t loc; + loc_t loc2; + server_resolve_t resolve; + server_resolve_t resolve2; + + /* used within resolve_and_resume */ + loc_t *loc_now; + server_resolve_t *resolve_now; + + struct iatt stbuf; + int valid; + + fd_t *fd; + int flags; + int wbflags; + struct iobuf *iobuf; + struct iobref *iobref; + + size_t size; + off_t offset; + mode_t mode; + dev_t dev; + size_t nr_count; + int cmd; + int type; + char *name; + int name_len; + + int mask; + char is_revalidate; + dict_t *dict; + struct flock flock; + const char *volume; + dir_entry_t *entry; +}; + +extern struct rpcsvc_program gluster_handshake_prog; +extern struct rpcsvc_program glusterfs3_1_fop_prog; +extern struct rpcsvc_program gluster_ping_prog; + +typedef ssize_t (*gfs_serialize_t) (struct iovec outmsg, void *args); + +int +server_submit_reply (call_frame_t *frame, rpcsvc_request_t *req, void *arg, + struct iovec *payload, int payloadcount, + struct iobref *iobref, gfs_serialize_t sfunc); + +int xdr_to_glusterfs_req (rpcsvc_request_t *req, void *arg, + gfs_serialize_t sfunc); + +#endif /* !_SERVER_H */ diff --git a/xlators/protocol/server/src/server3_1-fops.c b/xlators/protocol/server/src/server3_1-fops.c new file mode 100644 index 00000000000..4156e7be96f --- /dev/null +++ b/xlators/protocol/server/src/server3_1-fops.c @@ -0,0 +1,4839 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "server.h" +#include "server-helpers.h" +#include "glusterfs-xdr.h" +#include "msg-xdr.h" +#include "compat-errno.h" + +#include "md5.h" + +#define SERVER_PATH_MAX (16 * 1024) + +/* Callback function section */ +int +server_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf) +{ + gfs3_statfs_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + if (op_ret >= 0) { + gf_statfs_from_statfs (&rsp.statfs, buf); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_statfs_rsp); + + return 0; +} + +int +server_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *stbuf, dict_t *dict, + struct iatt *postparent) +{ + rpcsvc_request_t *req = NULL; + server_state_t *state = NULL; + inode_t *root_inode = NULL; + inode_t *link_inode = NULL; + loc_t fresh_loc = {0,}; + gfs3_lookup_rsp rsp = {0, }; + int32_t ret = -1; + + state = CALL_STATE(frame); + + req = frame->local; + frame->local = NULL; + + if (state->is_revalidate == 1 && op_ret == -1) { + state->is_revalidate = 2; + loc_copy (&fresh_loc, &state->loc); + inode_unref (fresh_loc.inode); + fresh_loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_lookup_cbk, BOUND_XL (frame), + BOUND_XL (frame)->fops->lookup, + &fresh_loc, state->dict); + + loc_wipe (&fresh_loc); + return 0; + } + + if (dict) { + rsp.dict.dict_len = dict_serialized_length (dict); + if (rsp.dict.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; + rsp.dict.dict_len = 0; + } + } + + if ((op_ret >= 0) && dict) { + rsp.dict.dict_val = GF_CALLOC (1, rsp.dict.dict_len, 0); + if (!rsp.dict.dict_val) { + op_ret = -1; + op_errno = ENOMEM; + rsp.dict.dict_len = 0; + goto out; + } + ret = dict_serialize (dict, rsp.dict.dict_val); + 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; + rsp.dict.dict_len = 0; + } + } + + gf_stat_from_iatt (&rsp.postparent, postparent); + + if (op_ret == 0) { + root_inode = BOUND_XL(frame)->itable->root; + if (inode == root_inode) { + /* we just looked up root ("/") */ + stbuf->ia_ino = 1; + if (inode->ia_type == 0) + inode->ia_type = stbuf->ia_type; + } + + gf_stat_from_iatt (&rsp.stat, stbuf); + + if (inode->ino != 1) { + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } + } else { + if (state->is_revalidate && op_errno == ENOENT) { + if (state->loc.inode->ino != 1) { + inode_unlink (state->loc.inode, + state->loc.parent, + state->loc.name); + } + } + + gf_log (this->name, + (op_errno == ENOENT ? GF_LOG_TRACE : 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)); + } +out: + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + (gfs_serialize_t)xdr_serialize_lookup_rsp); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + return 0; +} + + +int +server_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct flock *lock) +{ + gfs3_lk_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + server_state_t *state = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + gf_flock_from_flock (&rsp.flock, lock); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": LK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_lk_rsp); + + return 0; +} + + +int +server_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + server_connection_t *conn = NULL; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + conn = SERVER_CONNECTION(frame); + state = CALL_STATE(frame); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"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_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + + +int +server_finodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + conn = SERVER_CONNECTION(frame); + state = CALL_STATE(frame); + + if (op_ret >= 0) { + if (state->flock.l_type == F_UNLCK) + gf_del_locker (conn->ltable, state->volume, + NULL, state->fd, + frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + NULL, state->fd, + frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FINODELK %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +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; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + gf_common_rsp rsp = {0,}; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + conn = SERVER_CONNECTION(frame); + state = CALL_STATE(frame); + + if (op_ret >= 0) { + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + &state->loc, NULL, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"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_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + return 0; +} + + +int +server_fentrylk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + server_connection_t *conn = NULL; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + conn = SERVER_CONNECTION(frame); + state = CALL_STATE(frame); + if (op_ret >= 0) { + if (state->cmd == ENTRYLK_UNLOCK) + gf_del_locker (conn->ltable, state->volume, + NULL, state->fd, frame->root->pid); + else + gf_add_locker (conn->ltable, state->volume, + NULL, state->fd, frame->root->pid); + } else if (op_errno != ENOSYS) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FENTRYLK %"PRId64" (%"PRId64") " + " ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + + +int +server_access_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_rmdir_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *parent = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); + parent = inode_parent (state->loc.inode, 0, NULL); + if (parent) + inode_unref (parent); + else + inode_forget (state->loc.inode, 0); + + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"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)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_rmdir_rsp); + + return 0; +} + +int +server_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_mkdir_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *link_inode = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.stat, stbuf); + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": MKDIR %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_mkdir_rsp); + + return 0; +} + +int +server_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_mknod_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *link_inode = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.stat, stbuf); + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_inode); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": MKNOD %s ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + op_ret, strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_mknod_rsp); + + + return 0; +} + +int +server_fsyncdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": FSYNCDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +server_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) +{ + gfs3_readdir_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + state = CALL_STATE(frame); + if (op_ret > 0) { + rsp.buf.buf_len = gf_dirent_serialize (entries, NULL, 0); + if (rsp.buf.buf_len > 0) { + rsp.buf.buf_val = GF_CALLOC (1, rsp.buf.buf_len, 0); + if (!rsp.buf.buf_val) { + op_ret = -1; + op_errno = ENOMEM; + goto unwind; + } + gf_dirent_serialize (entries, rsp.buf.buf_val, + rsp.buf.buf_len); + } + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": READDIR %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } +unwind: + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_readdir_rsp); + + if (rsp.buf.buf_val) + GF_FREE (rsp.buf.buf_val); + + return 0; +} + + +int +server_releasedir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +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; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + gfs3_opendir_rsp rsp = {0,}; + uint64_t fd_no = 0; + + conn = SERVER_CONNECTION (frame); + state = CALL_STATE (frame); + + if (op_ret >= 0) { + fd_bind (fd); + + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (fd); // on behalf of the client + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"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)); + } + + req = frame->local; + frame->local = NULL; + + rsp.fd = fd_no; + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_opendir_rsp); + + return 0; +} + +int +server_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +server_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gfs3_getxattr_rsp rsp = {0,}; + int32_t len = 0; + int32_t ret = -1; + rpcsvc_request_t *req = NULL; + server_state_t *state = NULL; + + 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->resolve.ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + goto out; + } + + rsp.dict.dict_val = GF_CALLOC (len, sizeof (char), 0); + if (!rsp.dict.dict_val) { + op_ret = -1; + op_errno = ENOMEM; + len = 0; + goto out; + } + ret = dict_serialize (dict, rsp.dict.dict_val); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + } + } +out: + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.dict.dict_len = len; + + req = frame->local; + frame->local = NULL; + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_getxattr_rsp); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + return 0; +} + + +int +server_fgetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gfs3_fgetxattr_rsp rsp = {0,}; + int32_t len = 0; + int32_t ret = -1; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + 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->resolve.ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + goto out; + } + rsp.dict.dict_val = GF_CALLOC (1, len, 0); + if (!rsp.dict.dict_val) { + op_ret = -1; + op_errno = ENOMEM; + len = 0; + goto out; + } + ret = dict_serialize (dict, rsp.dict.dict_val); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "%s (%"PRId64"): failed to serialize reply dict", + state->loc.path, state->resolve.ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } + +out: + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.dict.dict_len = len; + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_fgetxattr_rsp); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + return 0; +} + +int +server_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + + +int +server_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + return 0; +} + +int +server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent) +{ + gfs3_rename_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + stbuf->ia_ino = state->loc.inode->ino; + stbuf->ia_type = state->loc.inode->ia_type; + + gf_log (state->conn->bound_xl->name, GF_LOG_TRACE, + "%"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_iatt (&rsp.stat, stbuf); + + gf_stat_from_iatt (&rsp.preoldparent, preoldparent); + gf_stat_from_iatt (&rsp.postoldparent, postoldparent); + + gf_stat_from_iatt (&rsp.prenewparent, prenewparent); + gf_stat_from_iatt (&rsp.postnewparent, postnewparent); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_rename_rsp); + + return 0; +} + +int +server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_unlink_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *parent = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + gf_log (state->conn->bound_xl->name, GF_LOG_TRACE, + "%"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); + + parent = inode_parent (state->loc.inode, 0, NULL); + if (parent) + inode_unref (parent); + else + inode_forget (state->loc.inode, 0); + + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + + } 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)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_unlink_rsp); + + return 0; +} + +int +server_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_symlink_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *link_inode = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.stat, stbuf); + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + inode_lookup (link_inode); + inode_unref (link_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_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_symlink_rsp); + + return 0; +} + + +int +server_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent) +{ + gfs3_link_rsp rsp = {0,}; + server_state_t *state = NULL; + inode_t *link_inode = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + stbuf->ia_ino = state->loc.inode->ino; + + gf_stat_from_iatt (&rsp.stat, stbuf); + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + + gf_log (state->conn->bound_xl->name, GF_LOG_TRACE, + "%"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); + + link_inode = inode_link (inode, state->loc2.parent, + state->loc2.name, stbuf); + inode_unref (link_inode); + } else { + gf_log (state->conn->bound_xl->name, GF_LOG_DEBUG, + "%"PRId64": LINK (%"PRId64") %"PRId64"/%s ==> %"PRId64"/%s " + " ==> %"PRId32" (%s)", + frame->root->unique, state->resolve2.ino, + state->resolve2.par, + state->resolve2.bname, state->resolve.par, + state->resolve.bname, + op_ret, strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_link_rsp); + + return 0; +} + +int +server_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gfs3_truncate_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE (frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp.prestat, prebuf); + gf_stat_from_iatt (&rsp.poststat, postbuf); + } 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_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_truncate_rsp); + + return 0; +} + +int +server_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf) +{ + gfs3_fstat_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp.stat, stbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSTAT %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_fstat_rsp); + + return 0; +} + +int +server_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gfs3_ftruncate_rsp rsp = {0}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE (frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp.prestat, prebuf); + gf_stat_from_iatt (&rsp.poststat, postbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FTRUNCATE %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_ftruncate_rsp); + + return 0; +} + +int +server_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FLUSH %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + + + return 0; +} + +int +server_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gfs3_fsync_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + + if (op_ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSYNC %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } else { + gf_stat_from_iatt (&(rsp.prestat), prebuf); + gf_stat_from_iatt (&(rsp.poststat), postbuf); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_fsync_rsp); + + return 0; +} + +int +server_release_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + gf_common_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); + return 0; +} + + +int +server_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + gfs3_write_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.prestat, prebuf); + gf_stat_from_iatt (&rsp.poststat, postbuf); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": WRITEV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_writev_rsp); + + return 0; +} + + +int +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 iatt *stbuf, struct iobref *iobref) +{ + gfs3_read_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE(frame); + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.stat, stbuf); + rsp.size = op_ret; + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": READV %"PRId64" (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, vector, count, iobref, + xdr_serialize_readv_rsp); + + return 0; +} + +int +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) +{ + gfs3_checksum_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + if (op_ret >= 0) { + rsp.fchecksum.fchecksum_val = (char *)fchecksum; + rsp.fchecksum.fchecksum_len = NAME_MAX; + rsp.dchecksum.dchecksum_val = (char *)dchecksum; + rsp.dchecksum.dchecksum_len = NAME_MAX; + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_checksum_rsp); + + return 0; +} + + +int +server_rchecksum_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + uint32_t weak_checksum, uint8_t *strong_checksum) +{ + gfs3_rchecksum_rsp rsp = {0,}; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + if (op_ret >= 0) { + rsp.weak_checksum = weak_checksum; + + rsp.strong_checksum.strong_checksum_val = (char *)strong_checksum; + rsp.strong_checksum.strong_checksum_len = MD5_DIGEST_LEN; + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_rchecksum_rsp); + + return 0; +} + + +int +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; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + uint64_t fd_no = 0; + gfs3_open_rsp rsp = {0,}; + + conn = SERVER_CONNECTION (frame); + state = CALL_STATE (frame); + + if (op_ret >= 0) { + fd_bind (fd); + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (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)); + } + + req = frame->local; + frame->local = NULL; + + rsp.fd = fd_no; + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_open_rsp); + return 0; +} + + +int +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 iatt *stbuf, + struct iatt *preparent, struct iatt *postparent) +{ + server_connection_t *conn = NULL; + server_state_t *state = NULL; + inode_t *link_inode = NULL; + rpcsvc_request_t *req = NULL; + uint64_t fd_no = 0; + gfs3_create_rsp rsp = {0,}; + + conn = SERVER_CONNECTION (frame); + state = CALL_STATE (frame); + + if (op_ret >= 0) { + gf_log (state->conn->bound_xl->name, GF_LOG_TRACE, + "%"PRId64": CREATE %"PRId64"/%s (%"PRId64")", + frame->root->unique, state->loc.parent->ino, + state->loc.name, stbuf->ia_ino); + + link_inode = inode_link (inode, state->loc.parent, + state->loc.name, stbuf); + + if (link_inode != inode) { + gf_log (this->name, GF_LOG_DEBUG, + "create(%s) inode (ptr=%p, ino=%"PRId64", " + "gen=%"PRId64") found conflict (ptr=%p, " + "ino=%"PRId64", gen=%"PRId64")", + state->loc.path, inode, inode->ino, + inode->generation, link_inode, + link_inode->ino, link_inode->generation); + + /* + VERY racy code (if used anywhere else) + -- don't do this without understanding + */ + + inode_unref (fd->inode); + fd->inode = inode_ref (link_inode); + } + + inode_lookup (link_inode); + inode_unref (link_inode); + + fd_bind (fd); + + fd_no = gf_fd_unused_get (conn->fdtable, fd); + fd_ref (fd); + + if ((fd_no < 0) || (fd == 0)) { + op_ret = fd_no; + op_errno = errno; + } + + gf_stat_from_iatt (&rsp.stat, stbuf); + gf_stat_from_iatt (&rsp.preparent, preparent); + gf_stat_from_iatt (&rsp.postparent, postparent); + } 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)); + } + + req = frame->local; + frame->local = NULL; + + rsp.fd = fd_no; + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_create_rsp); + + return 0; +} + +int +server_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *buf, + struct iatt *stbuf) +{ + gfs3_readlink_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + + state = CALL_STATE(frame); + + if (op_ret >= 0) { + gf_stat_from_iatt (&rsp.buf, stbuf); + rsp.path = (char *)buf; + } 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)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_readlink_rsp); + + return 0; +} + +int +server_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf) +{ + gfs3_stat_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE (frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&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_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_stat_rsp); + + return 0; +} + + +int +server_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost) +{ + gfs3_setattr_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + state = CALL_STATE (frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp.statpre, statpre); + gf_stat_from_iatt (&rsp.statpost, statpost); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": SETATTR %s (%"PRId64") ==> %"PRId32" (%s)", + frame->root->unique, state->loc.path, + state->loc.inode ? state->loc.inode->ino : 0, + op_ret, strerror (op_errno)); + } + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_setattr_rsp); + + return 0; +} + +int +server_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost) +{ + gfs3_fsetattr_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + state = CALL_STATE (frame); + + if (op_ret == 0) { + gf_stat_from_iatt (&rsp.statpre, statpre); + gf_stat_from_iatt (&rsp.statpost, statpost); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "%"PRId64": FSETATTR %"PRId64" (%"PRId64") ==> " + "%"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, + op_ret, strerror (op_errno)); + } + + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_fsetattr_rsp); + + return 0; +} + + +int +server_xattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gfs3_xattrop_rsp rsp = {0,}; + int32_t len = 0; + int32_t ret = -1; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + 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)); + goto out; + } + + 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; + goto out; + } + rsp.dict.dict_val = GF_CALLOC (1, len, 0); + if (!rsp.dict.dict_val) { + op_ret = -1; + op_errno = ENOMEM; + len = 0; + goto out; + } + ret = dict_serialize (dict, rsp.dict.dict_val); + 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; + } + } +out: + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.dict.dict_len = len; + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_xattrop_rsp); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + return 0; +} + + +int +server_fxattrop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + gfs3_xattrop_rsp rsp = {0,}; + int32_t len = 0; + int32_t ret = -1; + server_state_t *state = NULL; + rpcsvc_request_t *req = 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->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + goto out; + } + + 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->resolve.fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = EINVAL; + len = 0; + goto out; + } + rsp.dict.dict_val = GF_CALLOC (1, len, 0); + if (!rsp.dict.dict_val) { + op_ret = -1; + op_errno = ENOMEM; + len = 0; + goto out; + } + ret = dict_serialize (dict, rsp.dict.dict_val); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to " + "serialize reply dict", + state->resolve.fd_no, state->fd->inode->ino); + op_ret = -1; + op_errno = -ret; + len = 0; + } + } +out: + req = frame->local; + frame->local = NULL; + + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + rsp.dict.dict_len = len; + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_fxattrop_rsp); + + if (rsp.dict.dict_val) + GF_FREE (rsp.dict.dict_val); + + return 0; +} + + +int +server_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) +{ + gfs3_readdirp_rsp rsp = {0,}; + server_state_t *state = NULL; + rpcsvc_request_t *req = NULL; + + req = frame->local; + frame->local = NULL; + + state = CALL_STATE(frame); + if (op_ret > 0) { + rsp.buf.buf_len = gf_dirent_serialize (entries, NULL, 0); + rsp.buf.buf_val = GF_CALLOC (1, rsp.buf.buf_len, 0); + if (!rsp.buf.buf_val) { + op_ret = -1; + op_errno = ENOMEM; + rsp.buf.buf_len = 0; + goto out; + } + gf_dirent_serialize (entries, rsp.buf.buf_val, rsp.buf.buf_len); + } else { + gf_log (this->name, GF_LOG_TRACE, + "%"PRId64": READDIRP %"PRId64" (%"PRId64") ==>" + "%"PRId32" (%s)", + frame->root->unique, state->resolve.fd_no, + state->fd ? state->fd->inode->ino : 0, op_ret, + strerror (op_errno)); + } + +out: + rsp.op_ret = op_ret; + rsp.op_errno = gf_errno_to_error (op_errno); + + server_submit_reply (frame, req, &rsp, NULL, 0, NULL, + xdr_serialize_readdirp_rsp); + + if (rsp.buf.buf_val) + GF_FREE (rsp.buf.buf_val); + + return 0; +} + +/* Resume function section */ + +int +server_rchecksum_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + STACK_WIND (frame, server_rchecksum_cbk, bound_xl, + bound_xl->fops->rchecksum, state->fd, + state->offset, state->size); + + return 0; +err: + server_rchecksum_cbk (frame, NULL, frame->this, -1, EINVAL, 0, NULL); + + return 0; + +} + +int +server_checksum_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + STACK_WIND (frame, server_checksum_cbk, bound_xl, + bound_xl->fops->checksum, &state->loc, state->flags); + + return 0; +err: + server_checksum_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + +int +server_lk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_lk_cbk, bound_xl, bound_xl->fops->lk, + state->fd, state->cmd, &state->flock); + + return 0; + +err: + server_lk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +int +server_rename_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + if (state->resolve2.op_ret != 0) { + op_ret = state->resolve2.op_ret; + op_errno = state->resolve2.op_errno; + goto err; + } + + STACK_WIND (frame, server_rename_cbk, + bound_xl, bound_xl->fops->rename, + &state->loc, &state->loc2); + return 0; +err: + server_rename_cbk (frame, NULL, frame->this, op_ret, op_errno, + NULL, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_link_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + int op_ret = 0; + int op_errno = 0; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) { + op_ret = state->resolve.op_ret; + op_errno = state->resolve.op_errno; + goto err; + } + + if (state->resolve2.op_ret != 0) { + op_ret = state->resolve2.op_ret; + op_errno = state->resolve2.op_errno; + goto err; + } + + state->loc2.inode = inode_ref (state->loc.inode); + + STACK_WIND (frame, server_link_cbk, bound_xl, bound_xl->fops->link, + &state->loc, &state->loc2); + + return 0; +err: + server_link_cbk (frame, NULL, frame->this, op_ret, op_errno, + NULL, NULL, NULL, NULL); + return 0; +} + +int +server_symlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_symlink_cbk, + bound_xl, bound_xl->fops->symlink, + state->name, &state->loc); + + return 0; +err: + server_symlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_access_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_access_cbk, + bound_xl, bound_xl->fops->access, + &state->loc, state->mask); + return 0; +err: + server_access_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + +int +server_fentrylk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fentrylk_cbk, bound_xl, + bound_xl->fops->fentrylk, + state->volume, state->fd, state->name, + state->cmd, state->type); + + return 0; +err: + server_fentrylk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_entrylk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_entrylk_cbk, + bound_xl, bound_xl->fops->entrylk, + state->volume, &state->loc, state->name, + state->cmd, state->type); + return 0; +err: + server_entrylk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int +server_finodelk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_finodelk_cbk, bound_xl, + bound_xl->fops->finodelk, + state->volume, state->fd, state->cmd, &state->flock); + + return 0; +err: + server_finodelk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + +int +server_inodelk_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_inodelk_cbk, + bound_xl, bound_xl->fops->inodelk, + state->volume, &state->loc, state->cmd, &state->flock); + return 0; +err: + server_inodelk_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + +int +server_rmdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_rmdir_cbk, + bound_xl, bound_xl->fops->rmdir, &state->loc); + return 0; +err: + server_rmdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + +int +server_mkdir_resume (call_frame_t *frame, xlator_t *bound_xl) + +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_mkdir_cbk, + bound_xl, bound_xl->fops->mkdir, + &(state->loc), state->mode); + + return 0; +err: + server_mkdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_mknod_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + STACK_WIND (frame, server_mknod_cbk, + bound_xl, bound_xl->fops->mknod, + &(state->loc), state->mode, state->dev); + + return 0; +err: + server_mknod_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + return 0; +} + + +int +server_fsyncdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsyncdir_cbk, + bound_xl, + bound_xl->fops->fsyncdir, + state->fd, state->flags); + return 0; + +err: + server_fsyncdir_cbk (frame, NULL, frame->this, + state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + + +int + server_readdir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readdir_cbk, + bound_xl, + bound_xl->fops->readdir, + state->fd, state->size, state->offset); + + return 0; +err: + server_readdir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +int +server_readdirp_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readdirp_cbk, bound_xl, + bound_xl->fops->readdirp, state->fd, state->size, + state->offset); + + return 0; +err: + server_readdirp_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_opendir_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->fd = fd_create (state->loc.inode, frame->root->pid); + + STACK_WIND (frame, server_opendir_cbk, + bound_xl, bound_xl->fops->opendir, + &state->loc, state->fd); + return 0; +err: + server_opendir_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_statfs_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret !=0) + goto err; + + STACK_WIND (frame, server_statfs_cbk, + bound_xl, bound_xl->fops->statfs, + &state->loc); + return 0; + +err: + server_statfs_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_removexattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_removexattr_cbk, + bound_xl, bound_xl->fops->removexattr, + &state->loc, state->name); + return 0; +err: + server_removexattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + return 0; +} + +int +server_fgetxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fgetxattr_cbk, + bound_xl, bound_xl->fops->fgetxattr, + state->fd, state->name); + return 0; +err: + server_fgetxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_xattrop_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_xattrop_cbk, + bound_xl, bound_xl->fops->xattrop, + &state->loc, state->flags, state->dict); + return 0; +err: + server_xattrop_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +int +server_fxattrop_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fxattrop_cbk, + bound_xl, bound_xl->fops->fxattrop, + state->fd, state->flags, state->dict); + return 0; +err: + server_fxattrop_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +int +server_fsetxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setxattr_cbk, + bound_xl, bound_xl->fops->fsetxattr, + state->fd, state->dict, state->flags); + return 0; +err: + server_fsetxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + +int +server_unlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_unlink_cbk, + bound_xl, bound_xl->fops->unlink, + &state->loc); + return 0; +err: + server_unlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + +int +server_truncate_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_truncate_cbk, + bound_xl, bound_xl->fops->truncate, + &state->loc, state->offset); + return 0; +err: + server_truncate_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + + +int +server_fstat_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fstat_cbk, + bound_xl, bound_xl->fops->fstat, + state->fd); + return 0; +err: + server_fstat_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_setxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setxattr_cbk, + bound_xl, bound_xl->fops->setxattr, + &state->loc, state->dict, state->flags); + return 0; +err: + server_setxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + + +int +server_getxattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_getxattr_cbk, + bound_xl, bound_xl->fops->getxattr, + &state->loc, state->name); + return 0; +err: + server_getxattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_ftruncate_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_ftruncate_cbk, + bound_xl, bound_xl->fops->ftruncate, + state->fd, state->offset); + return 0; +err: + server_ftruncate_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_flush_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_flush_cbk, + bound_xl, bound_xl->fops->flush, state->fd); + return 0; +err: + server_flush_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno); + + return 0; +} + + +int +server_fsync_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsync_cbk, + bound_xl, bound_xl->fops->fsync, + state->fd, state->flags); + return 0; +err: + server_fsync_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + +int +server_writev_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + struct iovec iov = {0, }; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + iov.iov_len = state->size; + + if (state->iobuf) { + iov.iov_base = state->iobuf->ptr; + } + + STACK_WIND (frame, server_writev_cbk, + bound_xl, bound_xl->fops->writev, + state->fd, &iov, 1, state->offset, state->iobref); + + return 0; +err: + server_writev_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + +int +server_readv_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readv_cbk, + bound_xl, bound_xl->fops->readv, + state->fd, state->size, state->offset); + + return 0; +err: + server_readv_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, 0, NULL, NULL); + return 0; +} + + +int +server_create_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->loc.inode = inode_new (state->itable); + + state->fd = fd_create (state->loc.inode, frame->root->pid); + state->fd->flags = state->flags; + + STACK_WIND (frame, server_create_cbk, + bound_xl, bound_xl->fops->create, + &(state->loc), state->flags, state->mode, state->fd); + + return 0; +err: + server_create_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, + NULL, NULL); + return 0; +} + + +int +server_open_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + state->fd = fd_create (state->loc.inode, frame->root->pid); + state->fd->flags = state->flags; + + STACK_WIND (frame, server_open_cbk, + bound_xl, bound_xl->fops->open, + &state->loc, state->flags, state->fd, 0); + + return 0; +err: + server_open_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + + +int +server_readlink_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_readlink_cbk, + bound_xl, bound_xl->fops->readlink, + &state->loc, state->size); + return 0; +err: + server_readlink_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + return 0; +} + + +int +server_fsetattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_fsetattr_cbk, + bound_xl, bound_xl->fops->fsetattr, + state->fd, &state->stbuf, state->valid); + return 0; +err: + server_fsetattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_setattr_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_setattr_cbk, + bound_xl, bound_xl->fops->setattr, + &state->loc, &state->stbuf, state->valid); + return 0; +err: + server_setattr_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL); + + return 0; +} + + +int +server_stat_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + STACK_WIND (frame, server_stat_cbk, + bound_xl, bound_xl->fops->stat, &state->loc); + return 0; +err: + server_stat_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL); + return 0; +} + +int +server_lookup_resume (call_frame_t *frame, xlator_t *bound_xl) +{ + server_state_t *state = NULL; + + state = CALL_STATE (frame); + + if (state->resolve.op_ret != 0) + goto err; + + if (!state->loc.inode) + state->loc.inode = inode_new (state->itable); + else + state->is_revalidate = 1; + + STACK_WIND (frame, server_lookup_cbk, + bound_xl, bound_xl->fops->lookup, + &state->loc, state->dict); + + return 0; +err: + server_lookup_cbk (frame, NULL, frame->this, state->resolve.op_ret, + state->resolve.op_errno, NULL, NULL, NULL, NULL); + + return 0; +} + + + + +/* Fop section */ + +int +server_stat (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_stat_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + /* Initialize args first, then decode */ + args.path = path; + + if (!xdr_to_stat_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + { + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + } + + resolve_and_resume (frame, server_stat_resume); +out: + return 0; +} + + +int +server_setattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_setattr_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + + if (!xdr_to_setattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + gf_stat_to_iatt (&args.stbuf, &state->stbuf); + state->valid = args.valid; + + resolve_and_resume (frame, server_setattr_resume); +out: + return 0; +} + + +int +server_fsetattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_fsetattr_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_fsetattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + + gf_stat_to_iatt (&args.stbuf, &state->stbuf); + state->valid = args.valid; + + resolve_and_resume (frame, server_fsetattr_resume); +out: + return 0; +} + + +int +server_readlink (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_readlink_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + + if (!xdr_to_readlink_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + state->size = args.size; + + resolve_and_resume (frame, server_readlink_resume); +out: + return 0; +} + + +int +server_create (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_create_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + args.bname = bname; + + if (!xdr_to_create_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + state->mode = args.mode; + state->flags = gf_flags_to_flags (args.flags); + + resolve_and_resume (frame, server_create_resume); +out: + return 0; +} + + +int +server_open (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_open_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + + if (!xdr_to_open_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + state->flags = gf_flags_to_flags (args.flags); + + resolve_and_resume (frame, server_open_resume); +out: + return 0; +} + + +int +server_readv (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_read_req args = {0,}; + + if (!req) + goto out; + + if (!xdr_to_readv_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->size = args.size; + state->offset = args.offset; + + resolve_and_resume (frame, server_readv_resume); +out: + return 0; +} + + +int +server_writev (rpcsvc_request_t *req) +{ + /* TODO : */ + assert (0); + return 0; +} + + +int +server_writev_vec (rpcsvc_request_t *req, struct iobuf *iobuf) +{ + server_state_t *state = NULL; + struct iobref *iobref = NULL; + call_frame_t *frame = NULL; + gfs3_write_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_writev_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->offset = args.offset; + + if (iobuf) { + iobref = iobref_new (); + iobref_add (iobref, iobuf); + + state->iobref = iobref; + state->iobuf = iobuf_ref (iobuf); + + state->size = req->msg[1].iov_len; + } + + resolve_and_resume (frame, server_writev_resume); +out: + return 0; +} + + +int +server_release (rpcsvc_request_t *req) +{ + server_connection_t *conn = NULL; + gfs3_release_req args = {0,}; + gf_common_rsp rsp = {0,}; + + if (!xdr_to_release_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + conn = req->conn->trans->xl_private; + gf_fd_put (conn->fdtable, args.fd); + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); +out: + return 0; +} + +int +server_releasedir (rpcsvc_request_t *req) +{ + server_connection_t *conn = NULL; + gfs3_releasedir_req args = {0,}; + gf_common_rsp rsp = {0,}; + + if (!xdr_to_release_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + conn = req->conn->trans->xl_private; + gf_fd_put (conn->fdtable, args.fd); + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + xdr_serialize_common_rsp); +out: + return 0; +} + + +int +server_fsync (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_fsync_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_fsync_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->flags = args.data; + + resolve_and_resume (frame, server_fsync_resume); +out: + return 0; +} + + + +int +server_flush (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_flush_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_flush_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + + resolve_and_resume (frame, server_flush_resume); +out: + return 0; +} + + + +int +server_ftruncate (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_ftruncate_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_ftruncate_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->offset = args.offset; + + resolve_and_resume (frame, server_ftruncate_resume); +out: + return 0; +} + + +int +server_fstat (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_write_req args = {0,}; + + if (!req) + return 0; + + if (!xdr_to_fstat_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + + resolve_and_resume (frame, server_fstat_resume); +out: + return 0; +} + + +int +server_truncate (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_truncate_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + if (!xdr_to_truncate_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->offset = args.offset; + + resolve_and_resume (frame, server_truncate_resume); +out: + return 0; +} + + + +int +server_unlink (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_unlink_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + args.bname = bname; + + if (!xdr_to_unlink_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + + resolve_and_resume (frame, server_unlink_resume); +out: + return 0; +} + + +int +server_setxattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + server_connection_t *conn = NULL; + char *buf = NULL; + gfs3_setxattr_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char dict_val[(16 * 1024)] = {0, }; + int32_t ret = -1; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + args.dict.dict_val = dict_val; + + if (!xdr_to_setxattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->flags = args.flags; + + if (args.dict.dict_len) { + dict = dict_new (); + buf = memdup (args.dict.dict_val, args.dict.dict_len); + GF_VALIDATE_OR_GOTO (conn->bound_xl->name, buf, out); + + ret = dict_unserialize (buf, args.dict.dict_len, &dict); + if (ret < 0) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->resolve.ino); + goto err; + } + + dict->extra_free = buf; + buf = NULL; + + state->dict = dict; + } + + resolve_and_resume (frame, server_setxattr_resume); + + return 0; +err: + if (dict) + dict_unref (dict); + + server_setxattr_cbk (frame, NULL, frame->this, -1, EINVAL); +out: + if (buf) + GF_FREE (buf); + return 0; + +} + + + +int +server_fsetxattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + dict_t *dict = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + char *buf = NULL; + gfs3_fsetxattr_req args = {0,}; + char dict_val[(16 *1024)] = {0,}; + int32_t ret = -1; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.dict.dict_val = dict_val; + if (!xdr_to_fsetxattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->flags = args.flags; + + if (args.dict.dict_len) { + dict = dict_new (); + buf = memdup (args.dict.dict_val, args.dict.dict_len); + GF_VALIDATE_OR_GOTO (conn->bound_xl->name, buf, out); + + ret = dict_unserialize (buf, args.dict.dict_len, &dict); + if (ret < 0) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize request buffer to dictionary", + frame->root->unique, state->loc.path, + state->resolve.ino); + goto err; + } + dict->extra_free = buf; + buf = NULL; + state->dict = dict; + } + + resolve_and_resume (frame, server_fsetxattr_resume); + + return 0; +err: + if (dict) + dict_unref (dict); + + server_setxattr_cbk (frame, NULL, frame->this, -1, EINVAL); +out: + if (buf) + GF_FREE (buf); + return 0; +} + + + +int +server_fxattrop (rpcsvc_request_t *req) +{ + dict_t *dict = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + char *buf = NULL; + gfs3_fxattrop_req args = {0,}; + char dict_val[(16 *1024)] = {0,}; + int32_t ret = -1; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.dict.dict_val = dict_val; + if (!xdr_to_fxattrop_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->flags = args.flags; + + if (args.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + buf = memdup (args.dict.dict_val, args.dict.dict_len); + GF_VALIDATE_OR_GOTO (conn->bound_xl->name, buf, out); + + ret = dict_unserialize (buf, args.dict.dict_len, &dict); + if (ret < 0) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->resolve.fd_no, state->fd->inode->ino); + goto fail; + } + dict->extra_free = buf; + buf = NULL; + + state->dict = dict; + } + + resolve_and_resume (frame, server_fxattrop_resume); + + return 0; + +fail: + if (dict) + dict_unref (dict); + + server_fxattrop_cbk (frame, NULL, frame->this, -1, EINVAL, NULL); +out: + return 0; +} + + + +int +server_xattrop (rpcsvc_request_t *req) +{ + dict_t *dict = NULL; + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + char *buf = NULL; + gfs3_xattrop_req args = {0,}; + char dict_val[(16 *1024)] = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + int32_t ret = -1; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.dict.dict_val = dict_val; + args.path = path; + + if (!xdr_to_xattrop_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->flags = args.flags; + + if (args.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + buf = memdup (args.dict.dict_val, args.dict.dict_len); + GF_VALIDATE_OR_GOTO (conn->bound_xl->name, buf, out); + + ret = dict_unserialize (buf, args.dict.dict_len, &dict); + if (ret < 0) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): failed to unserialize " + "request buffer to dictionary", + state->resolve.fd_no, state->fd->inode->ino); + goto fail; + } + dict->extra_free = buf; + buf = NULL; + + state->dict = dict; + } + + resolve_and_resume (frame, server_xattrop_resume); + + return 0; +fail: + if (dict) + dict_unref (dict); + + server_xattrop_cbk (frame, NULL, frame->this, -1, EINVAL, NULL); +out: + return 0; +} + + +int +server_getxattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_getxattr_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char name[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + args.name = name; + + if (!xdr_to_getxattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + + if (args.namelen) + state->name = gf_strdup (args.name); + + resolve_and_resume (frame, server_getxattr_resume); +out: + return 0; +} + + +int +server_fgetxattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_fgetxattr_req args = {0,}; + char name[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.name = name; + if (!xdr_to_fgetxattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + + if (args.namelen) + state->name = gf_strdup (args.name); + + resolve_and_resume (frame, server_fgetxattr_resume); +out: + return 0; +} + + + +int +server_removexattr (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_removexattr_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char name[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + args.name = name; + if (!xdr_to_removexattr_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->name = gf_strdup (args.name); + + resolve_and_resume (frame, server_removexattr_resume); +out: + return 0; +} + + + + +int +server_opendir (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + call_frame_t *frame = NULL; + gfs3_opendir_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + args.path = path; + + if (!xdr_to_opendir_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + + resolve_and_resume (frame, server_opendir_resume); +out: + return 0; +} + + +int +server_readdirp (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_readdirp_req args = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_readdirp_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->size = args.size; + state->offset = args.offset; + + resolve_and_resume (frame, server_readdirp_resume); +out: + return 0; +} + +int +server_readdir (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_readdir_req args = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_readdir_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->size = args.size; + state->offset = args.offset; + + resolve_and_resume (frame, server_readdir_resume); +out: + return 0; +} + +int +server_fsyncdir (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_fsyncdir_req args = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_fsyncdir_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.fd_no = args.fd; + state->flags = args.data; + + resolve_and_resume (frame, server_fsyncdir_resume); +out: + return 0; +} + + + +int +server_mknod (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_mknod_req args = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + args.bname = bname; + + if (!xdr_to_mknod_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + + state->mode = args.mode; + state->dev = args.dev; + + resolve_and_resume (frame, server_mknod_resume); +out: + return 0; +} + + +int +server_mkdir (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_mkdir_req args = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + args.bname = bname; + + if (!xdr_to_mkdir_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + + state->mode = args.mode; + + resolve_and_resume (frame, server_mkdir_resume); +out: + return 0; +} + + +int +server_rmdir (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_rmdir_req args = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + args.bname = bname; + + if (!xdr_to_rmdir_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + + resolve_and_resume (frame, server_rmdir_resume); +out: + return 0; +} + + + +int +server_inodelk (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_inodelk_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char volume[4096] = {0,}; + int cmd = 0; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + args.volume = volume; + + if (!xdr_to_inodelk_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + cmd = args.cmd; + switch (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 = args.type; + state->volume = gf_strdup (args.volume); + + gf_flock_to_flock (&args.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; + } + + resolve_and_resume (frame, server_inodelk_resume); +out: + return 0; +} + +int +server_finodelk (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_finodelk_req args = {0,}; + char volume[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.volume = volume; + if (!xdr_to_finodelk_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_EXACT; + state->volume = gf_strdup (args.volume); + state->resolve.fd_no = args.fd; + state->cmd = args.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 = args.type; + + gf_flock_to_flock (&args.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; + } + + resolve_and_resume (frame, server_finodelk_resume); +out: + return 0; +} + + +int +server_entrylk (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_entrylk_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char name[4096] = {0,}; + char volume[4096] = {0,}; + + if (!req) + return 0; + + args.path = path; + args.volume = volume; + args.name = name; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_entrylk_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.path = gf_strdup (args.path); + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + + if (args.namelen) + state->name = gf_strdup (args.name); + state->volume = gf_strdup (args.volume); + + state->cmd = args.cmd; + state->type = args.type; + + resolve_and_resume (frame, server_entrylk_resume); +out: + return 0; +} + +int +server_fentrylk (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_fentrylk_req args = {0,}; + char name[4096] = {0,}; + char volume[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.name = name; + args.volume = volume; + if (!xdr_to_fentrylk_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_EXACT; + state->resolve.fd_no = args.fd; + state->cmd = args.cmd; + state->type = args.type; + + if (args.namelen) + state->name = gf_strdup (args.name); + state->volume = gf_strdup (args.volume); + + resolve_and_resume (frame, server_finodelk_resume); +out: + return 0; +} + +int +server_access (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_access_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + if (!xdr_to_access_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->mask = args.mask; + + resolve_and_resume (frame, server_access_resume); +out: + return 0; +} + + + +int +server_symlink (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_symlink_req args = {0,}; + char linkname[4096] = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + char bname[4096] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + args.bname = bname; + args.linkname = linkname; + + if (!xdr_to_symlink_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_NOT; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + state->resolve.bname = gf_strdup (args.bname); + state->name = gf_strdup (args.linkname); + + resolve_and_resume (frame, server_symlink_resume); +out: + return 0; +} + + + +int +server_link (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_link_req args = {0,}; + char oldpath[SERVER_PATH_MAX] = {0,}; + char newpath[SERVER_PATH_MAX] = {0,}; + char newbname[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.oldpath = oldpath; + args.newpath = newpath; + args.newbname = newbname; + + if (!xdr_to_link_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.oldpath); + state->resolve.ino = args.oldino; + state->resolve.gen = args.oldgen; + + state->resolve2.type = RESOLVE_NOT; + state->resolve2.path = gf_strdup (args.newpath); + state->resolve2.bname = gf_strdup (args.newbname); + state->resolve2.par = args.newpar; + state->resolve2.gen = args.newgen; + + resolve_and_resume (frame, server_link_resume); +out: + return 0; +} + + +int +server_rename (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_rename_req args = {0,}; + char oldpath[SERVER_PATH_MAX] = {0,}; + char oldbname[SERVER_PATH_MAX] = {0,}; + char newpath[SERVER_PATH_MAX] = {0,}; + char newbname[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.oldpath = oldpath; + args.oldbname = oldbname; + args.newpath = newpath; + args.newbname = newbname; + if (!xdr_to_rename_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.path = gf_strdup (args.oldpath); + state->resolve.bname = gf_strdup (args.oldbname); + state->resolve.par = args.oldpar; + state->resolve.gen = args.oldgen; + + state->resolve2.type = RESOLVE_MAY; + state->resolve2.path = gf_strdup (args.newpath); + state->resolve2.bname = gf_strdup (args.newbname); + state->resolve2.par = args.newpar; + state->resolve2.gen = args.newgen; + + resolve_and_resume (frame, server_rename_resume); +out: + return 0; +} + +int +server_lk (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_lk_req args = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_lk_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.fd_no = args.fd; + state->cmd = args.cmd; + state->type = args.type; + + 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; + } + + gf_flock_to_flock (&args.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; + default: + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "fd - %"PRId64" (%"PRId64"): Unknown lock type: %"PRId32"!", + state->resolve.fd_no, state->fd->inode->ino, state->type); + break; + } + + + resolve_and_resume (frame, server_lk_resume); +out: + return 0; +} + +int +server_checksum (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_checksum_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + if (!xdr_to_checksum_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MAY; + state->resolve.path = gf_strdup (args.path); + state->resolve.gen = args.gen; + state->resolve.ino = args.ino; + state->flags = args.flag; + + resolve_and_resume (frame, server_checksum_resume); +out: + return 0; +} + + + +int +server_rchecksum (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_rchecksum_req args = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + if (!xdr_to_rchecksum_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE(frame); + + state->resolve.type = RESOLVE_MAY; + state->resolve.fd_no = args.fd; + state->offset = args.offset; + state->size = args.len; + + resolve_and_resume (frame, server_rchecksum_resume); +out: + return 0; +} + +int +server_null (rpcsvc_request_t *req) +{ + gf_common_rsp rsp = {0,}; + + rsp.gfs_id = req->gfs_id; + /* Accepted */ + rsp.op_ret = 0; + + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + (gfs_serialize_t)xdr_serialize_common_rsp); + + return 0; +} + +int +server_lookup (rpcsvc_request_t *req) +{ + call_frame_t *frame = NULL; + server_connection_t *conn = NULL; + server_state_t *state = NULL; + dict_t *xattr_req = NULL; + char *buf = NULL; + gfs3_lookup_req args = {0,}; + int ret = 0; + char path[SERVER_PATH_MAX] = {0,}; + char bname[SERVER_PATH_MAX] = {0,}; + char dict_val[(16 * 1024)] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + + args.path = path; + args.bname = bname; + args.dict.dict_val = dict_val; + + if (!xdr_to_lookup_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto err; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; + goto err; + } + + /* NOTE: lookup() uses req->ino only to identify if a lookup() + * is requested for 'root' or not + */ + + state = CALL_STATE (frame); + state->resolve.ino = args.ino; + if (state->resolve.ino != 1) + state->resolve.ino = 0; + + state->resolve.type = RESOLVE_DONTCARE; + state->resolve.par = args.par; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + if (IS_NOT_ROOT (STRLEN_0 (args.path))) { + state->resolve.bname = gf_strdup (args.bname); + } + + if (args.dict.dict_len) { + /* Unserialize the dictionary */ + xattr_req = dict_new (); + + buf = memdup (args.dict.dict_val, args.dict.dict_len); + if (buf == NULL) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "out of memory"); + goto err; + } + + ret = dict_unserialize (buf, args.dict.dict_len, + &xattr_req); + if (ret < 0) { + gf_log (conn->bound_xl->name, GF_LOG_ERROR, + "%"PRId64": %s (%"PRId64"): failed to " + "unserialize req-buffer to dictionary", + frame->root->unique, state->resolve.path, + state->resolve.ino); + goto err; + } + + state->dict = xattr_req; + + xattr_req->extra_free = buf; + + buf = NULL; + } + + resolve_and_resume (frame, server_lookup_resume); + + return 0; +err: + if (xattr_req) + dict_unref (xattr_req); + + if (buf) { + GF_FREE (buf); + } + + server_lookup_cbk (frame, NULL, frame->this, -1, EINVAL, NULL, NULL, + NULL, NULL); + + return 0; +} + +int +server_statfs (rpcsvc_request_t *req) +{ + server_state_t *state = NULL; + server_connection_t *conn = NULL; + call_frame_t *frame = NULL; + gfs3_statfs_req args = {0,}; + char path[SERVER_PATH_MAX] = {0,}; + + if (!req) + return 0; + + conn = req->conn->trans->xl_private; + args.path = path; + if (!xdr_to_statfs_req (req->msg[0], &args)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + frame = get_frame_from_request (req); + if (!frame) { + // something wrong, mostly insufficient memory + req->rpc_err = GARBAGE_ARGS; /* TODO */ + goto out; + } + + state = CALL_STATE (frame); + + state->resolve.type = RESOLVE_MUST; + state->resolve.ino = args.ino; + if (!state->resolve.ino) + state->resolve.ino = 1; + state->resolve.gen = args.gen; + state->resolve.path = gf_strdup (args.path); + + resolve_and_resume (frame, server_statfs_resume); +out: + return 0; +} + + +rpcsvc_actor_t glusterfs3_1_fop_actors[] = { + [GFS3_OP_NULL] = { "NULL", GFS3_OP_NULL, server_null, NULL, NULL}, + [GFS3_OP_STAT] = { "STAT", GFS3_OP_STAT, server_stat, NULL, NULL }, + [GFS3_OP_READLINK] = { "READLINK", GFS3_OP_READLINK, server_readlink, NULL, NULL }, + [GFS3_OP_MKNOD] = { "MKNOD", GFS3_OP_MKNOD, server_mknod, NULL, NULL }, + [GFS3_OP_MKDIR] = { "MKDIR", GFS3_OP_MKDIR, server_mkdir, NULL, NULL }, + [GFS3_OP_UNLINK] = { "UNLINK", GFS3_OP_UNLINK, server_unlink, NULL, NULL }, + [GFS3_OP_RMDIR] = { "RMDIR", GFS3_OP_RMDIR, server_rmdir, NULL, NULL }, + [GFS3_OP_SYMLINK] = { "SYMLINK", GFS3_OP_SYMLINK, server_symlink, NULL, NULL }, + [GFS3_OP_RENAME] = { "RENAME", GFS3_OP_RENAME, server_rename, NULL, NULL }, + [GFS3_OP_LINK] = { "LINK", GFS3_OP_LINK, server_link, NULL, NULL }, + [GFS3_OP_TRUNCATE] = { "TRUNCATE", GFS3_OP_TRUNCATE, server_truncate, NULL, NULL }, + [GFS3_OP_OPEN] = { "OPEN", GFS3_OP_OPEN, server_open, NULL, NULL }, + [GFS3_OP_READ] = { "READ", GFS3_OP_READ, server_readv, NULL, NULL }, + [GFS3_OP_WRITE] = { "WRITE", GFS3_OP_WRITE, server_writev, server_writev_vec, NULL }, + [GFS3_OP_STATFS] = { "STATFS", GFS3_OP_STATFS, server_statfs, NULL, NULL }, + [GFS3_OP_FLUSH] = { "FLUSH", GFS3_OP_FLUSH, server_flush, NULL, NULL }, + [GFS3_OP_FSYNC] = { "FSYNC", GFS3_OP_FSYNC, server_fsync, NULL, NULL }, + [GFS3_OP_SETXATTR] = { "SETXATTR", GFS3_OP_SETXATTR, server_setxattr, NULL, NULL }, + [GFS3_OP_GETXATTR] = { "GETXATTR", GFS3_OP_GETXATTR, server_getxattr, NULL, NULL }, + [GFS3_OP_REMOVEXATTR] = { "REMOVEXATTR", GFS3_OP_REMOVEXATTR, server_removexattr, NULL, NULL }, + [GFS3_OP_OPENDIR] = { "OPENDIR", GFS3_OP_OPENDIR, server_opendir, NULL, NULL }, + [GFS3_OP_FSYNCDIR] = { "FSYNCDIR", GFS3_OP_FSYNCDIR, server_fsyncdir, NULL, NULL }, + [GFS3_OP_ACCESS] = { "ACCESS", GFS3_OP_ACCESS, server_access, NULL, NULL }, + [GFS3_OP_CREATE] = { "CREATE", GFS3_OP_CREATE, server_create, NULL, NULL }, + [GFS3_OP_FTRUNCATE] = { "FTRUNCATE", GFS3_OP_FTRUNCATE, server_ftruncate, NULL, NULL }, + [GFS3_OP_FSTAT] = { "FSTAT", GFS3_OP_FSTAT, server_fstat, NULL, NULL }, + [GFS3_OP_LK] = { "LK", GFS3_OP_LK, server_lk, NULL, NULL }, + [GFS3_OP_LOOKUP] = { "LOOKUP", GFS3_OP_LOOKUP, server_lookup, NULL, NULL }, + [GFS3_OP_READDIR] = { "READDIR", GFS3_OP_READDIR, server_readdir, NULL, NULL }, + [GFS3_OP_INODELK] = { "INODELK", GFS3_OP_INODELK, server_inodelk, NULL, NULL }, + [GFS3_OP_FINODELK] = { "FINODELK", GFS3_OP_FINODELK, server_finodelk, NULL, NULL }, + [GFS3_OP_ENTRYLK] = { "ENTRYLK", GFS3_OP_ENTRYLK, server_entrylk, NULL, NULL }, + [GFS3_OP_FENTRYLK] = { "FENTRYLK", GFS3_OP_FENTRYLK, server_fentrylk, NULL, NULL }, + [GFS3_OP_CHECKSUM] = { "CHECKSUM", GFS3_OP_CHECKSUM, server_checksum, NULL, NULL }, + [GFS3_OP_XATTROP] = { "XATTROP", GFS3_OP_XATTROP, server_xattrop, NULL, NULL }, + [GFS3_OP_FXATTROP] = { "FXATTROP", GFS3_OP_FXATTROP, server_fxattrop, NULL, NULL }, + [GFS3_OP_FGETXATTR] = { "FGETXATTR", GFS3_OP_FGETXATTR, server_fgetxattr, NULL, NULL }, + [GFS3_OP_FSETXATTR] = { "FSETXATTR", GFS3_OP_FSETXATTR, server_fsetxattr, NULL, NULL }, + [GFS3_OP_RCHECKSUM] = { "RCHECKSUM", GFS3_OP_RCHECKSUM, server_rchecksum, NULL, NULL }, + [GFS3_OP_SETATTR] = { "SETATTR", GFS3_OP_SETATTR, server_setattr, NULL, NULL }, + [GFS3_OP_FSETATTR] = { "FSETATTR", GFS3_OP_FSETATTR, server_fsetattr, NULL, NULL }, + [GFS3_OP_READDIRP] = { "READDIRP", GFS3_OP_READDIRP, server_readdirp, NULL, NULL }, + [GFS3_OP_RELEASE] = { "RELEASE", GFS3_OP_RELEASE, server_release, NULL, NULL }, + [GFS3_OP_RELEASEDIR] = { "RELEASEDIR", GFS3_OP_RELEASEDIR, server_releasedir, NULL, NULL }, +}; + + +struct rpcsvc_program glusterfs3_1_fop_prog = { + .progname = "GlusterFS-3.1.0", + .prognum = GLUSTER3_1_FOP_PROGRAM, + .progver = GLUSTER3_1_FOP_VERSION, + .numactors = GLUSTER3_1_FOP_PROCCNT, + .actors = glusterfs3_1_fop_actors, + .progport = 7007, +}; |