diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-handshake.c')
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-handshake.c | 178 |
1 files changed, 103 insertions, 75 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c index c41a9459870..9124c46ee21 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handshake.c +++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c @@ -108,112 +108,140 @@ out: return ret; } -int -__server_getspec (rpcsvc_request_t *req) +/* Get and store op-versions of the clients sending the getspec request + * Clients of versions <= 3.3, don't send op-versions, their op-versions are + * defaulted to 1 + */ +static int +_get_client_op_versions (gf_getspec_req *args, peer_info_t *peerinfo) { - int32_t ret = -1; - int32_t op_errno = 0; - int32_t spec_fd = -1; - size_t file_len = 0; - char filename[PATH_MAX] = {0,}; - struct stat stbuf = {0,}; - char *volume = NULL; - char *tmp = NULL; - int cookie = 0; - rpc_transport_t *trans = NULL; - gf_getspec_req args = {0,}; - gf_getspec_rsp rsp = {0,}; - char addrstr[RPCSVC_PEER_STRLEN] = {0}; - dict_t *dict = NULL; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - int client_min_op_version = 1; // OP-VERSIONs start at 1 - int client_max_op_version = 1; - - this = THIS; - GF_ASSERT (this); + int ret = 0; + int client_max_op_version = 1; + int client_min_op_version = 1; + dict_t *dict = NULL; - conf = this->private; - GF_ASSERT (conf); + GF_ASSERT (args); + GF_ASSERT (peerinfo); - 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; - goto fail; - } - - if (!args.xdata.xdata_len) { - // For clients <= 3.3.0, only allow if op_version = 1 - if (1 != conf->op_version) { - ret = -1; - op_errno = ENOTSUP; - gf_log (this->name, GF_LOG_INFO, - "Client %s doesn't support required op-version. " - "Rejecting getspec request.", - req->trans->peerinfo.identifier); - goto fail; - } - } else { - // For clients > 3.3, only allow if they can support - // clusters' op_version + if (args->xdata.xdata_len) { dict = dict_new (); if (!dict) { ret = -1; - goto fail; + goto out; } - ret = dict_unserialize (args.xdata.xdata_val, - args.xdata.xdata_len, &dict); + ret = dict_unserialize (args->xdata.xdata_val, + args->xdata.xdata_len, &dict); if (ret) { - gf_log (this->name, GF_LOG_ERROR, + gf_log ("glusterd", GF_LOG_ERROR, "Failed to unserialize request dictionary"); - goto fail; + goto out; } ret = dict_get_int32 (dict, "min-op-version", &client_min_op_version); if (ret) { - gf_log (this->name, GF_LOG_ERROR, + gf_log ("glusterd", GF_LOG_ERROR, "Failed to get client-min-op-version"); - goto fail; + goto out; } ret = dict_get_int32 (dict, "max-op-version", &client_max_op_version); if (ret) { - gf_log (this->name, GF_LOG_ERROR, + gf_log ("glusterd", GF_LOG_ERROR, "Failed to get client-max-op-version"); - goto fail; + goto out; } + } - if ((client_min_op_version > conf->op_version) || - (client_max_op_version < conf->op_version)) { - ret = -1; - op_errno = ENOTSUP; - //TODO: Add client identifier - gf_log (this->name, GF_LOG_INFO, - "Client %s doesn't support required op-version. " - "Rejecting getspec request.", - req->trans->peerinfo.identifier); - goto fail; - } + peerinfo->max_op_version = client_max_op_version; + peerinfo->min_op_version = client_min_op_version; +out: + return ret; +} + +/* Checks if the client supports the volume, ie. client can understand all the + * options in the volfile + */ +static gf_boolean_t +_client_supports_volume (peer_info_t *peerinfo, int32_t *op_errno) +{ + gf_boolean_t ret = _gf_true; + glusterd_volinfo_t *volinfo = NULL; + + GF_ASSERT (peerinfo); + GF_ASSERT (op_errno); + + + /* Only check when the volfile being requested is a volume. Not finding + * a volinfo implies that the volfile requested for is not of a gluster + * volume. A non volume volfile is requested by the local gluster + * services like shd and nfs-server. These need not be checked as they + * will be running at the same op-version as glusterd and will be able + * to support all the features + */ + if ((glusterd_volinfo_find (peerinfo->volname, &volinfo) == 0) && + ((peerinfo->min_op_version > volinfo->client_op_version) || + (peerinfo->max_op_version < volinfo->client_op_version))) { + ret = _gf_false; + *op_errno = ENOTSUP; + gf_log ("glusterd", GF_LOG_INFO, + "Client %s (%d -> %d) doesn't support required " + "op-version (%d). Rejecting volfile request.", + peerinfo->identifier, peerinfo->min_op_version, + peerinfo->max_op_version, volinfo->client_op_version); } - // Store the op-versions supported by the client - req->trans->peerinfo.max_op_version = client_max_op_version; - req->trans->peerinfo.min_op_version = client_min_op_version; + return ret; +} - volume = args.key; +int +__server_getspec (rpcsvc_request_t *req) +{ + int32_t ret = -1; + int32_t op_errno = 0; + int32_t spec_fd = -1; + size_t file_len = 0; + char filename[PATH_MAX] = {0,}; + struct stat stbuf = {0,}; + char *volume = NULL; + char *tmp = NULL; + int cookie = 0; + rpc_transport_t *trans = NULL; + gf_getspec_req args = {0,}; + gf_getspec_rsp rsp = {0,}; + char addrstr[RPCSVC_PEER_STRLEN] = {0}; + peer_info_t *peerinfo = NULL; - // Store the name of volume being mounted + 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; + goto fail; + } + + peerinfo = &req->trans->peerinfo; + + volume = args.key; + /* Need to strip leading '/' from volnames. This was introduced to + * support nfs style mount parameters for native gluster mount + */ if (volume[0] == '/') - strncpy (req->trans->peerinfo.volname, &volume[1], - strlen(&volume[1])); + strncpy (peerinfo->volname, &volume[1], strlen(&volume[1])); else - strncpy (req->trans->peerinfo.volname, volume, strlen(volume)); + strncpy (peerinfo->volname, volume, strlen(volume)); + + ret = _get_client_op_versions (&args, peerinfo); + if (ret) + goto fail; + + if (!_client_supports_volume (peerinfo, &op_errno)) { + ret = -1; + goto fail; + } trans = req->trans; ret = rpcsvc_transport_peername (trans, (char *)&addrstr, |