diff options
Diffstat (limited to 'xlators/protocol/server/src/server-handshake.c')
| -rw-r--r-- | xlators/protocol/server/src/server-handshake.c | 327 |
1 files changed, 227 insertions, 100 deletions
diff --git a/xlators/protocol/server/src/server-handshake.c b/xlators/protocol/server/src/server-handshake.c index 689648838..d4941011d 100644 --- a/xlators/protocol/server/src/server-handshake.c +++ b/xlators/protocol/server/src/server-handshake.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2013 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ @@ -40,7 +31,7 @@ gf_compare_client_version (rpcsvc_request_t *req, int fop_prognum, { int ret = -1; /* TODO: think.. */ - if (glusterfs3_1_fop_prog.prognum == fop_prognum) + if (glusterfs3_3_fop_prog.prognum == fop_prognum) ret = 0; return ret; @@ -102,26 +93,26 @@ _volfile_update_checksum (xlator_t *this, char *key, uint32_t checksum) } 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"); + gf_log (this->name, GF_LOG_INFO, + "the volume file was modified between a prior access " + "and now. This may lead to inconsistency between " + "clients, you are advised to remount client"); temp_volfile->checksum = checksum; } - out: +out: return 0; } -size_t -build_volfile_path (xlator_t *this, const char *key, char *path, - size_t path_len) +static size_t +getspec_build_volfile_path (xlator_t *this, const char *key, char *path, + size_t path_len) { - int ret = -1; + char *filename = NULL; + server_conf_t *conf = NULL; + int ret = -1; int free_filename = 0; - char *filename = NULL; - server_conf_t *conf = NULL; char data_key[256] = {0,}; conf = this->private; @@ -150,12 +141,6 @@ build_volfile_path (xlator_t *this, const char *key, char *path, goto out; } } - - ret = gf_asprintf (&filename, "%s/%s.vol", conf->conf_dir, key); - if (-1 == ret) - goto out; - - free_filename = 1; } if (!filename) { @@ -165,10 +150,19 @@ build_volfile_path (xlator_t *this, const char *key, char *path, gf_log (this->name, GF_LOG_DEBUG, "no default volume filename given, " "defaulting to %s", DEFAULT_VOLUME_FILE_PATH); - filename = DEFAULT_VOLUME_FILE_PATH; } } + if (!filename && key) { + ret = gf_asprintf (&filename, "%s/%s.vol", conf->conf_dir, key); + if (-1 == ret) + goto out; + + free_filename = 1; + } + if (!filename) + filename = DEFAULT_VOLUME_FILE_PATH; + ret = -1; if ((filename) && (path_len > strlen (filename))) { @@ -187,7 +181,7 @@ int _validate_volfile_checksum (xlator_t *this, char *key, uint32_t checksum) { - char filename[ZR_PATH_MAX] = {0,}; + char filename[PATH_MAX] = {0,}; server_conf_t *conf = NULL; struct _volfile_ctx *temp_volfile = NULL; int ret = 0; @@ -201,14 +195,14 @@ _validate_volfile_checksum (xlator_t *this, char *key, goto out; if (!temp_volfile) { - ret = build_volfile_path (this, key, filename, - sizeof (filename)); + ret = getspec_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, + gf_log (this->name, GF_LOG_INFO, "failed to open volume file (%s) : %s", filename, strerror (errno)); goto out; @@ -246,37 +240,37 @@ out: 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)) { + int32_t ret = -1; + int32_t op_errno = ENOENT; + int32_t spec_fd = -1; + size_t file_len = 0; + char filename[PATH_MAX] = {0,}; + struct stat stbuf = {0,}; + uint32_t checksum = 0; + char *key = NULL; + server_conf_t *conf = NULL; + xlator_t *this = NULL; + gf_getspec_req args = {0,}; + gf_getspec_rsp rsp = {0,}; + + this = req->svc->mydata; + conf = this->private; + ret = xdr_to_generic (req->msg[0], &args, + (xdrproc_t)xdr_gf_getspec_req); + if (ret < 0) { //failed to decode msg; req->rpc_err = GARBAGE_ARGS; op_errno = EINVAL; goto fail; } - ret = build_volfile_path (conn->this, args.key, - filename, sizeof (filename)); + ret = getspec_build_volfile_path (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, + gf_log (this->name, GF_LOG_ERROR, "Unable to stat %s (%s)", filename, strerror (errno)); op_errno = errno; @@ -285,7 +279,7 @@ server_getspec (rpcsvc_request_t *req) spec_fd = open (filename, O_RDONLY); if (spec_fd < 0) { - gf_log (conn->this->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "Unable to open %s (%s)", filename, strerror (errno)); op_errno = errno; @@ -295,7 +289,7 @@ server_getspec (rpcsvc_request_t *req) if (conf->verify_volfile) { get_checksum_for_file (spec_fd, &checksum); - _volfile_update_checksum (conn->this, key, checksum); + _volfile_update_checksum (this, key, checksum); } } else { op_errno = ENOENT; @@ -310,18 +304,21 @@ server_getspec (rpcsvc_request_t *req) goto fail; } ret = read (spec_fd, rsp.spec, file_len); - - close (spec_fd); } /* convert to XDR */ op_errno = errno; fail: + if (!rsp.spec) + rsp.spec = ""; rsp.op_errno = gf_errno_to_error (op_errno); rsp.op_ret = ret; + if (spec_fd != -1) + close (spec_fd); + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, - (gfs_serialize_t)xdr_serialize_getspec_rsp); + (xdrproc_t)xdr_gf_getspec_rsp); return 0; } @@ -330,16 +327,18 @@ fail: int server_setvolume (rpcsvc_request_t *req) { - gf_setvolume_req args = {0,}; + gf_setvolume_req args = {{0,},}; gf_setvolume_rsp rsp = {0,}; - server_connection_t *conn = NULL; + client_t *client = NULL; + server_ctx_t *serv_ctx = 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; + char *client_uid = NULL; + char *clnt_version = NULL; xlator_t *xl = NULL; char *msg = NULL; char *volfile_key = NULL; @@ -350,21 +349,33 @@ server_setvolume (rpcsvc_request_t *req) int32_t op_errno = EINVAL; int32_t fop_version = 0; int32_t mgmt_version = 0; + uint32_t lk_version = 0; + char *buf = NULL; + gf_boolean_t cancelled = _gf_false; params = dict_new (); reply = dict_new (); - if (xdr_to_glusterfs_req (req, &args, xdr_to_setvolume_req)) { + ret = xdr_to_generic (req->msg[0], &args, + (xdrproc_t)xdr_gf_setvolume_req); + if (ret < 0) { //failed to decode msg; req->rpc_err = GARBAGE_ARGS; goto fail; } - this = req->conn->svc->mydata; + this = req->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); + buf = memdup (args.dict.dict_val, args.dict.dict_len); + if (buf == NULL) { + op_ret = -1; + op_errno = ENOMEM; + goto fail; + } + + ret = dict_unserialize (buf, args.dict.dict_len, ¶ms); if (ret < 0) { ret = dict_set_str (reply, "ERROR", "Internal error: failed to unserialize " @@ -380,7 +391,10 @@ server_setvolume (rpcsvc_request_t *req) goto fail; } - ret = dict_get_str (params, "process-uuid", &process_uuid); + params->extra_free = buf; + buf = NULL; + + ret = dict_get_str (params, "process-uuid", &client_uid); if (ret < 0) { ret = dict_set_str (reply, "ERROR", "UUID not specified"); @@ -393,10 +407,46 @@ server_setvolume (rpcsvc_request_t *req) goto fail; } + /*lk_verion :: [1..2^31-1]*/ + ret = dict_get_uint32 (params, "clnt-lk-version", &lk_version); + if (ret < 0) { + ret = dict_set_str (reply, "ERROR", + "lock state version not supplied"); + if (ret < 0) + gf_log (this->name, GF_LOG_DEBUG, + "failed to set error msg"); - conn = server_connection_get (this, process_uuid); - if (req->conn->trans->xl_private != conn) - req->conn->trans->xl_private = conn; + op_ret = -1; + op_errno = EINVAL; + goto fail; + } + + client = gf_client_get (this, &req->cred, client_uid); + if (client == NULL) { + op_ret = -1; + op_errno = ENOMEM; + goto fail; + } + + gf_log (this->name, GF_LOG_DEBUG, "Connected to %s", client->client_uid); + cancelled = server_cancel_grace_timer (this, client); + if (cancelled)//Do gf_client_put on behalf of grace-timer-handler. + gf_client_put (client, NULL); + + serv_ctx = server_ctx_get (client, client->this); + if (serv_ctx == NULL) { + gf_log (this->name, GF_LOG_INFO, "server_ctx_get() failed"); + goto fail; + } + + if (serv_ctx->lk_version != 0 && + serv_ctx->lk_version != lk_version) { + (void) server_connection_cleanup (this, client, + INTERNAL_LOCKS | POSIX_LOCKS); + } + + if (req->trans->xl_private != client) + req->trans->xl_private = client; ret = dict_get_int32 (params, "fops-version", &fop_version); if (ret < 0) { @@ -421,7 +471,7 @@ server_setvolume (rpcsvc_request_t *req) ret = gf_asprintf (&msg, "version mismatch: client(%d)" " - client-mgmt(%d)", fop_version, mgmt_version); - /* get_supported_version (req)); */ + /* get_supported_version (req)); */ if (-1 == ret) { gf_log (this->name, GF_LOG_ERROR, "asprintf failed while setting up error msg"); @@ -453,7 +503,7 @@ server_setvolume (rpcsvc_request_t *req) xl = get_xlator_by_name (this, name); if (xl == NULL) { ret = gf_asprintf (&msg, "remote-subvolume \"%s\" is not found", - name); + name); if (-1 == ret) { gf_log (this->name, GF_LOG_ERROR, "asprintf failed while setting error msg"); @@ -497,7 +547,7 @@ server_setvolume (rpcsvc_request_t *req) } - peerinfo = &req->conn->trans->peerinfo; + peerinfo = &req->trans->peerinfo; if (peerinfo) { ret = dict_set_static_ptr (params, "peer-info", peerinfo); if (ret < 0) @@ -509,34 +559,42 @@ server_setvolume (rpcsvc_request_t *req) "Authentication module not initialized"); } + ret = dict_get_str (params, "client-version", &clnt_version); + if (ret) + gf_log (this->name, GF_LOG_INFO, "client-version not set, " + "may be of older version"); + 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)?peerinfo->identifier:""); + "accepted client from %s (version: %s)", + client->client_uid, + (clnt_version) ? clnt_version : "old"); op_ret = 0; - conn->bound_xl = xl; + client->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)? peerinfo->identifier:"<>"); + "Cannot authenticate client from %s %s", + client->client_uid, + (clnt_version) ? clnt_version : "old"); + 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) { + if (client->bound_xl == NULL) { ret = dict_set_str (reply, "ERROR", "Check volfile and handshake " "options in protocol/client"); @@ -549,20 +607,21 @@ server_setvolume (rpcsvc_request_t *req) goto fail; } - if ((conn->bound_xl != NULL) && + if ((client->bound_xl != NULL) && (ret >= 0) && - (conn->bound_xl->itable == NULL)) { + (client->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); + client->bound_xl->name); /* TODO: what is this ? */ - conn->bound_xl->itable = inode_table_new (conf->inode_lru_limit, - conn->bound_xl); + client->bound_xl->itable = + inode_table_new (conf->inode_lru_limit, + client->bound_xl); } ret = dict_set_str (reply, "process-uuid", @@ -571,8 +630,13 @@ server_setvolume (rpcsvc_request_t *req) gf_log (this->name, GF_LOG_DEBUG, "failed to set 'process-uuid'"); + ret = dict_set_uint32 (reply, "clnt-lk-version", serv_ctx->lk_version); + if (ret) + gf_log (this->name, GF_LOG_WARNING, + "failed to set 'clnt-lk-version'"); + ret = dict_set_uint64 (reply, "transport-ptr", - ((uint64_t) (long) req->conn->trans)); + ((uint64_t) (long) req->trans)); if (ret) gf_log (this->name, GF_LOG_DEBUG, "failed to set 'transport-ptr'"); @@ -603,20 +667,35 @@ fail: rsp.op_ret = op_ret; rsp.op_errno = gf_errno_to_error (op_errno); + /* if bound_xl is NULL or something fails, then put the connection + * back. Otherwise the connection would have been added to the + * list of connections the server is maintaining and might segfault + * during statedump when bound_xl of the connection is accessed. + */ + if (op_ret && !xl) { + /* We would have set the xl_private of the transport to the + * @conn. But if we have put the connection i.e shutting down + * the connection, then we should set xl_private to NULL as it + * would be pointing to a freed memory and would segfault when + * accessed upon getting DISCONNECT. + */ + gf_client_put (client, NULL); + req->trans->xl_private = NULL; + } server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, - (gfs_serialize_t)xdr_serialize_setvolume_rsp); + (xdrproc_t)xdr_gf_setvolume_rsp); - if (args.dict.dict_val) - free (args.dict.dict_val); + free (args.dict.dict_val); - if (rsp.dict.dict_val) - GF_FREE (rsp.dict.dict_val); + GF_FREE (rsp.dict.dict_val); dict_unref (params); dict_unref (reply); dict_unref (config_params); + GF_FREE (buf); + return 0; } @@ -626,22 +705,70 @@ 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); + (xdrproc_t)xdr_gf_common_rsp); return 0; } +int +server_set_lk_version (rpcsvc_request_t *req) +{ + int op_ret = -1; + int op_errno = EINVAL; + gf_set_lk_ver_req args = {0,}; + gf_set_lk_ver_rsp rsp = {0,}; + client_t *client = NULL; + server_ctx_t *serv_ctx = NULL; + xlator_t *this = NULL; + + this = req->svc->mydata; + //TODO: Decide on an appropriate errno for the error-path + //below + if (!this) + goto fail; + + op_ret = xdr_to_generic (req->msg[0], &args, + (xdrproc_t)xdr_gf_set_lk_ver_req); + if (op_ret < 0) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto fail; + } + + client = gf_client_get (this, &req->cred, args.uid); + serv_ctx = server_ctx_get (client, client->this); + if (serv_ctx == NULL) { + gf_log (this->name, GF_LOG_INFO, "server_ctx_get() failed"); + goto fail; + } + + serv_ctx->lk_version = args.lk_ver; + gf_client_put (client, NULL); + + rsp.lk_ver = args.lk_ver; + + op_ret = 0; +fail: + rsp.op_ret = op_ret; + rsp.op_errno = op_errno; + server_submit_reply (NULL, req, &rsp, NULL, 0, NULL, + (xdrproc_t)xdr_gf_set_lk_ver_rsp); + + free (args.uid); + + return 0; +} rpcsvc_actor_t gluster_handshake_actors[] = { - [GF_HNDSK_NULL] = {"NULL", GF_HNDSK_NULL, server_null, 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 }, + [GF_HNDSK_NULL] = {"NULL", GF_HNDSK_NULL, server_null, NULL, 0, DRC_NA}, + [GF_HNDSK_SETVOLUME] = {"SETVOLUME", GF_HNDSK_SETVOLUME, server_setvolume, NULL, 0, DRC_NA}, + [GF_HNDSK_GETSPEC] = {"GETSPEC", GF_HNDSK_GETSPEC, server_getspec, NULL, 0, DRC_NA}, + [GF_HNDSK_PING] = {"PING", GF_HNDSK_PING, server_ping, NULL, 0, DRC_NA}, + [GF_HNDSK_SET_LK_VER] = {"SET_LK_VER", GF_HNDSK_SET_LK_VER, server_set_lk_version, NULL, 0, DRC_NA}, }; |
